Skip to content

Commit

Permalink
Update import URL for dump.js, refactor asyncHandler in multiple file…
Browse files Browse the repository at this point in the history
…s, update mocha and chai versions in test files, fix nested key assignment in proxy object, update header level in intro.md, update library introduction and headings, start working on docs, add btc-driver, update uhtml version in imports, update README.md
  • Loading branch information
nuxodin committed Apr 25, 2024
1 parent 7d661ce commit f669d3a
Show file tree
Hide file tree
Showing 11 changed files with 112 additions and 47 deletions.
6 changes: 6 additions & 0 deletions drivers/localStorage.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ export function getStore(){
addEventListener('storage', e => { // does not trigger on source window!
root.item(e.key).value = e.newValue;
});
root.loadItems = function(){
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i);
root.item(key);
}
}
}
return root;
}
Expand Down
1 change: 1 addition & 0 deletions drivers/sql/Items/Db.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,6 @@ export class Db extends Item {
}
}

static isPrimitive() { return false; }
static ChildClass = Table;
}
3 changes: 1 addition & 2 deletions drivers/sql/Items/Row.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ export class Row extends Item {
for (const field of fields) this.item(field.name);
}



// select
// async selectAll() {
// await this.loadItems();
Expand Down Expand Up @@ -105,6 +103,7 @@ export class Row extends Item {
toString() { return this.key; }
valueOf() { return this.key; }

static isPrimitive() { return false; }
static ChildClass = Cell;
}

Expand Down
47 changes: 24 additions & 23 deletions drivers/sql/Items/Table.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export const Table = class extends Item {
this._fields = {};
}
async loadItems() {
const rows = await this.parent.query("SELECT * FROM "+this.key);b // todo, just get primaries?
const rows = await this.parent.query("SELECT * FROM "+this.key); // todo, just get primaries?
for (const data of rows) {
const id = await this.rowId(data);
const row = this.item(id);
Expand All @@ -23,28 +23,28 @@ export const Table = class extends Item {
}


async ensure(filter) {
console.error('used?')
const rows = await this.rows(filter);
for (const row of rows) return row; // return first
return this.insert(filter); // else insert, todo: filter?
}
async rows(filter /* limit? */) {
console.error('used?')
const where = await this.objectToWhere(filter); // todo
const all = await this.parent.query("SELECT * FROM "+this.key+" WHERE " + where);
const rows = [];
for (const data of all) {
const id = await this.rowId(data);
const row = this.item(id);
for (const i in data) {
console.log('asyncHandler?');
row.cell(i).setFromMaster(data[i]); // todo: asyncHandler??
}
rows.push( row );
}
return rows;
}
// async ensure(filter) {
// console.error('used?')
// const rows = await this.rows(filter);
// for (const row of rows) return row; // return first
// return this.insert(filter); // else insert, todo: filter?
// }
// async rows(filter /* limit? */) {
// console.error('used?')
// const where = await this.objectToWhere(filter); // todo
// const all = await this.parent.query("SELECT * FROM "+this.key+" WHERE " + where);
// const rows = [];
// for (const data of all) {
// const id = await this.rowId(data);
// const row = this.item(id);
// for (const i in data) {
// console.log('asyncHandler?');
// row.cell(i).setFromMaster(data[i]); // todo: asyncHandler??
// }
// rows.push( row );
// }
// return rows;
// }


field(name) {
Expand Down Expand Up @@ -190,5 +190,6 @@ export const Table = class extends Item {
*/


static isPrimitive() { return false; }
static ChildClass = Row;
};
3 changes: 2 additions & 1 deletion drivers/sql/Mysql.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Item } from '../../item.js';
import { Db } from "./Items/Db.js";
import { Client } from "https://deno.land/x/mysql@v2.10.0/mod.ts"; // Warning: v2.11.0 has a breaking bug!
//import { Client } from "https://deno.land/x/mysql@v2.10.0/mod.ts"; // Warning: v2.11.0 has a breaking bug!
import { Client } from "https://deno.land/x/mysql@v2.12.1/mod.ts"; // Warning: v2.11.0 has a breaking bug!

class MysqlDb extends Db {
async connect(){
Expand Down
19 changes: 9 additions & 10 deletions item.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export class Item extends EventTarget {
$set(value){
const oldValue = this.#value;
if (this.constructor.isPrimitive(value)) {
if (!this.#filled || oldValue !== value) { // TODO: we shoul use deepEqual as "primitive" can be an object
if (!this.#filled || !this.constructor.equals(oldValue, value)) {
this.#value = value; // structuralClone(value); // TODO: should we clone the value? or should we just use the reference? (if its an object)
this.#filled = true;
if (!this.#isGetting) {
Expand Down Expand Up @@ -84,15 +84,11 @@ export class Item extends EventTarget {
return this.#value[key];
}
remove(){
if (this.#parent) {
delete this.#parent.#value[this.#key];
dispatchEvent(this.#parent, 'change', { item: this.#parent, remove: this });
} else {
throw new Error('cannot remove root item');
}
if (!this.#parent) throw new Error('cannot remove root item');
delete this.#parent.#value[this.#key];
dispatchEvent(this.#parent, 'change', { item: this.#parent, remove: this });
}
has(key){ return key in this.#value; }
//asyncHas(key){ return Promise.resolve(key in this.#value) }

get proxy(){ return toProxy(this); }

Expand Down Expand Up @@ -132,6 +128,9 @@ export class Item extends EventTarget {
static isPrimitive(value){
return value !== Object(value) || 'toJSON' in value || value instanceof Promise;
}
static equals(a, b){ // comparison function between old and new value in case of primitive
if (Object.is(a, b)) return true; // // TODO: we shoul use deepEqual as "primitive" can be an object
}

static ChildClass;
ChildClass = this.constructor.ChildClass;
Expand Down Expand Up @@ -159,15 +158,15 @@ let currentEffect = null;
* @param {function} fn - A function that executes imeediately and collects the containing items.
* @return {function} A function to dispose the effect.
*/
export function effect(fn){
export function effect(fn){ // async?
const outer = currentEffect;
if (outer) {
(outer.nested ??= new Set()).add(fn);
if (fn.parent && fn.parent !== outer) throw('effect(cb) callbacks should not be reused for other effects');
fn.parent = outer;
}
currentEffect = fn;
fn();
fn(); // await, so that signals in async functions are collected?
currentEffect = outer;
return () => fn.disposed = true
}
Expand Down
1 change: 0 additions & 1 deletion tests/denoMysql.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,6 @@ Deno.test("database table", async () => {
const row = await table.insert({name: 'Tobias', age: 42});
assertEquals( row.key, '1' );


const values = table.item(1).item('name').get();
const values2 = table.item(1).item('age').get();
console.log(await Promise.all([values, values2])); // generates only one query
Expand Down
4 changes: 1 addition & 3 deletions tests/mocha.async.html
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@

asyncItem.createGetter = async function(...args){
getterRequested++;
console.log('getterRequested')
await delay(10);
return asyncRootValue;
}
Expand Down Expand Up @@ -160,7 +159,6 @@
asyncItem.value = {b:'new value2', c:'new value2'};
const c = await asyncItem.item('c').value;
chai.expect(c).to.equal('new value2');
console.log(asyncItem)
});

/*
Expand Down Expand Up @@ -232,7 +230,7 @@


describe('normal items with promises', () => {
it('Promise is promitive', async () => {
it('Promise is primitive', async () => {
const i = item( Promise.resolve(2) );
const value = await i.value;
chai.expect(value).to.equal(2);
Expand Down
16 changes: 16 additions & 0 deletions tests/mocha.html
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,22 @@
let i = item(date);
chai.expect(i.value).to.equal(date);
});

it('0 not equals -0', () => {
let i = item(0);
let changed = false;
i.addEventListener('change', e => changed = true);
i.value = -0;
chai.expect(changed).to.equal(true);
});
it('NaN equals NaN', () => {
let i = item(NaN);
let changed = false;
i.addEventListener('change', e => changed = true);
i.value = NaN;
chai.expect(changed).to.equal(false);
});

});

describe('object value', () => {
Expand Down
49 changes: 49 additions & 0 deletions tests/tree1.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<!DOCTYPE HTML>
<html lang=en>
<head>
<meta charset="utf-8">
<meta name=viewport content="width=device-width">

<link href="https://cdn.jsdelivr.net/gh/u2ui/u2@main/el/tree1/tree1.min.css" rel=stylesheet>
<script src="https://cdn.jsdelivr.net/gh/u2ui/u2@main/el/tree1/tree1.min.js" type=module async></script>

<body>

<section class=main>

<u2-tree1 aria-expanded="false" id=treeEl aria-live=off>localStorage
</u2-tree1>

</section>


<script type=module class=main>

import {getStore} from "../drivers/localStorage.js";

const store = getStore();

treeEl.addEventListener('u2-tree1-expand', event => {
if (!event.load) return;
const treeItem = event.target;

let item = store;
const path = treeItem.path();
path.shift(); // first is root

for (const parent of path) {
item = item.item(parent.getAttribute('name'));
}

event.load(async (treeEl) => {
await item.loadItems();
for (const child of item) {
treeEl.innerHTML +=
`<u2-tree1 aria-expanded=false aria-live=off name="${child.key}">
${child.key}
</u2-tree1>`;
}
});
});

</script>
10 changes: 3 additions & 7 deletions tools/AsyncDataPoint.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,22 @@
/*
Ussage:
// Ussage:
const datapoint = new AsyncDataPoint({
get: () => fetch('https://example.com/todos/1').then(res => res.json()),
set: value => fetch('https://example.com/todos/1', {method: 'PUT', body: JSON.stringify(value)}).then(res => res.json())
});
datapoint.set({title: 'foo', completed: true});
datapoint.get().then(value => console.log(value));
// api
// API
datapoint.onchange = ({value}) => console.log('value changed', value);
datapoint.cacheDuration = 1000; // cache for 1 second
datapoint.trustSendingValue = true; // trust sending value: until the sending is done, the value is the new value, despite the uncertainty that the server will fail
datapoint.setDebouncePeriod = 5; // debounce period for setter in ms, default 5
datapoint.setFromMaster({title: 'foo', completed: true}); // set value without saving it to the server
datapoint.setFromMaster({title: 'foo', completed: true}); // set value without saving it to the server (the value comes from the master through an other channel / trusted source)
*/

export class AsyncDataPoint {

// trustSendingValue = true;
// cacheDuration = 2000; // cache for 2 seconds, false = no cache, true = cache forever
// setDebouncePeriod = 5; // debounce period for setter in ms
createGetter = null; // function that returns a promise
createSetter = null; // function that returns a promise, if it failed, the promise must be rejected

Expand Down

0 comments on commit f669d3a

Please sign in to comment.