Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(infra): add not-condition to orm #9466

Merged
merged 1 commit into from
Jan 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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]
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
Loading