Skip to content

Commit

Permalink
feat(infra): add not-condition to orm
Browse files Browse the repository at this point in the history
  • Loading branch information
forehalo committed Dec 31, 2024
1 parent 9dc1b5e commit 2838b34
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 10 deletions.
55 changes: 55 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 @@ -102,6 +102,61 @@ describe('ORM entity CRUD', () => {
expect(user2).toEqual(user);
});

test('should be able to filter with nullable condition', t => {
const { client } = t;

client.users.create({
name: 'u1',
email: 'e1@example.com',
});

client.users.create({
name: 'u2',
});

const users = client.users.find({
email: null,
});

expect(users).toHaveLength(1);
expect(users[0].email).toBeFalsy();

const users2 = client.users.find({
email: {
not: null,
},
});

expect(users2).toHaveLength(1);
expect(users2[0].email).toEqual('e1@example.com');
});

test('should be able to filter with `not` condition', t => {
const { client } = t;

client.users.create({
name: 'u1',
email: 'e1@example.com',
});

const users = client.users.find({
email: {
not: 'e1@example.com',
},
});

expect(users).toHaveLength(0);

const users2 = client.users.find({
name: {
not: 'u2',
},
});

expect(users2).toHaveLength(1);
expect(users2[0].name).toEqual('u1');
});

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

Expand Down
23 changes: 20 additions & 3 deletions packages/common/infra/src/orm/core/adapters/memory/table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,26 @@ export class MemoryTableAdapter implements TableAdapter {
}

private match(record: any, where: WhereCondition) {
return Array.isArray(where)
? where.every(c => record[c.field] === c.value)
: where.byKey === record[this.keyField];
if (Array.isArray(where)) {
return where.every(c => {
const value = record[c.field] || null;
const condition = c.value;

if (typeof condition === 'object') {
if (condition === null) {
return value === null;
}

if ('not' in condition) {
return value !== condition.not;
}
}

return value === condition;
});
}

return where.byKey === record[this.keyField];
}

private dispatch(key: string, data: any) {
Expand Down
16 changes: 12 additions & 4 deletions packages/common/infra/src/orm/core/adapters/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,26 @@ export interface TableAdapterOptions extends TableOptions {
keyField: string;
}

type WhereEqCondition = {
type OrmPrimitiveValues = string | number | boolean | null;

type SimpleCondition =
| OrmPrimitiveValues
| {
not: OrmPrimitiveValues;
};

type WhereSimpleCondition = {
field: string;
value: any;
value: SimpleCondition;
};

type WhereByKeyCondition = {
byKey: Key;
};

// currently only support eq condition
// TODO(@forehalo): on the way [gt, gte, lt, lte, in, notIn, like, notLike, isNull, isNotNull, And, Or]
export type WhereCondition = WhereEqCondition[] | WhereByKeyCondition;
// TODO(@forehalo): on the way [gt, gte, lt, lte, in, notIn, like, notLike, Or, Not]
export type WhereCondition = Array<WhereSimpleCondition> | WhereByKeyCondition;
export type Select = '*' | 'key' | string[];

export type InsertQuery = {
Expand Down
26 changes: 24 additions & 2 deletions packages/common/infra/src/orm/core/adapters/yjs/table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,22 @@ export class YjsTableAdapter implements TableAdapter {
(Array.isArray(where)
? where.length === 0
? false
: where.every(c => this.field(record, c.field) === c.value)
: where.every(c => {
const field = this.field(record, c.field);
const condition = c.value;

if (typeof condition === 'object') {
if (condition === null) {
return field === null;
}

if ('not' in condition) {
return field !== condition.not;
}
}

return field === condition;
})
: where.byKey === this.keyof(record))
);
}
Expand All @@ -242,7 +257,14 @@ export class YjsTableAdapter implements TableAdapter {
}

private field(ty: AbstractType<any>, field: string) {
return YMap.prototype.get.call(ty, field);
const val = YMap.prototype.get.call(ty, field);

// only handle null will make the day easier
if (val === undefined) {
return null;
}

return val;
}

private setField(ty: AbstractType<any>, field: string, value: any) {
Expand Down
5 changes: 4 additions & 1 deletion packages/common/infra/src/orm/core/table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,10 @@ export type FindEntityInput<T extends TableSchemaBuilder> = Pretty<
T,
{
[key in TableDefinedFieldNames<T>]?: key extends keyof TableDefinedEntity<T>
? TableDefinedEntity<T>[key]
?
| TableDefinedEntity<T>[key]
| { not: TableDefinedEntity<T>[key] | null }
| null
: never;
}
>
Expand Down

0 comments on commit 2838b34

Please sign in to comment.