Skip to content

Commit

Permalink
feat(infra): better orm
Browse files Browse the repository at this point in the history
  • Loading branch information
EYHN committed Jul 15, 2024
1 parent 2f784ae commit 978a410
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 15 deletions.
17 changes: 17 additions & 0 deletions packages/common/infra/src/orm/core/__tests__/yjs.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,9 +211,11 @@ describe('ORM entity CRUD', () => {
test('should be able to subscribe to entity key list', t => {
const { client } = t;

let callbackCount = 0;
let keys: string[] = [];
const subscription = client.tags.keys$().subscribe(data => {
keys = data;
callbackCount++;
});

client.tags.create({
Expand All @@ -229,16 +231,19 @@ describe('ORM entity CRUD', () => {

client.tags.delete('test');
expect(keys).toStrictEqual([]);
expect(callbackCount).toStrictEqual(3); // init, create, delete

subscription.unsubscribe();
});

test('should be able to subscribe to filtered entity changes', t => {
const { client } = t;

let callbackCount = 0;
let entities: any[] = [];
const subscription = client.tags.find$({ name: 'test' }).subscribe(data => {
entities = data;
callbackCount++;
});

const tag1 = client.tags.create({
Expand All @@ -257,6 +262,18 @@ describe('ORM entity CRUD', () => {

expect(entities).toStrictEqual([tag1, tag2]);

client.tags.create({
id: '3',
name: 'not-test',
color: 'yellow',
});

expect(entities).toStrictEqual([tag1, tag2]);
expect(callbackCount).toStrictEqual(3);

client.tags.update('1', { color: 'green' });
expect(entities).toStrictEqual([{ ...tag1, color: 'green' }, tag2]);

subscription.unsubscribe();
});

Expand Down
48 changes: 33 additions & 15 deletions packages/common/infra/src/orm/core/adapters/yjs/table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,36 +104,54 @@ export class YjsTableAdapter implements TableAdapter {
const { where, select, callback } = query;

let listeningOnAll = false;
const obKeys = new Set<any>();
const results = [];
const resultKeys: string[] = [];
const results: any[] = [];

if (!where) {
listeningOnAll = true;
} else if ('byKey' in where) {
obKeys.add(where.byKey.toString());
}

for (const record of this.iterate(where)) {
if (!listeningOnAll) {
obKeys.add(this.keyof(record));
}
resultKeys.push(this.keyof(record));
results.push(this.value(record, select));
}

callback(results);

const ob = (tx: Transaction) => {
let hasChanged = false;
for (const [ty] of tx.changed) {
const record = ty as unknown as AbstractType<any>;
if (
listeningOnAll ||
obKeys.has(this.keyof(record)) ||
(where && this.match(record, where))
) {
callback(this.find({ where, select }));
return;
const record = ty;
const key = this.keyof(record);
const isMatch =
(listeningOnAll || (where && this.match(record, where))) &&
!this.isDeleted(record);
const prevMatchedIndex = resultKeys.findIndex(v => v === key);
const prevMatch =
prevMatchedIndex !== -1 ? results[prevMatchedIndex] : null;
const isPrevMatched = prevMatchedIndex !== -1;

if (isMatch && isPrevMatched) {
const newValue = this.value(record, select);
if (prevMatch !== newValue) {
results[prevMatchedIndex] = newValue;

hasChanged = true;
}
} else if (isMatch && !isPrevMatched) {
resultKeys.push(key);
results.push(this.value(record, select));
hasChanged = true;
} else if (!isMatch && isPrevMatched) {
resultKeys.splice(prevMatchedIndex, 1);
results.splice(prevMatchedIndex, 1);
hasChanged = true;
}
}

if (hasChanged) {
callback(results);
}
};

this.doc.on('afterTransaction', ob);
Expand Down

0 comments on commit 978a410

Please sign in to comment.