Skip to content

Commit 4395915

Browse files
committed
fix: several fixes about Json and Unsupported field types
1 parent fd8e944 commit 4395915

File tree

15 files changed

+135
-50
lines changed

15 files changed

+135
-50
lines changed

.coderabbit.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@ early_access: false
44
reviews:
55
auto_review:
66
enabled: true
7+
sequence_diagrams: false
78
chat:
89
auto_reply: true

packages/runtime/package.json

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,6 @@
2929
"default": "./dist/index.cjs"
3030
}
3131
},
32-
"./client": {
33-
"import": {
34-
"types": "./dist/client.d.ts",
35-
"default": "./dist/client.js"
36-
},
37-
"require": {
38-
"types": "./dist/client.d.cts",
39-
"default": "./dist/client.cjs"
40-
}
41-
},
4232
"./schema": {
4333
"import": {
4434
"types": "./dist/schema.d.ts",

packages/runtime/src/client/crud/dialects/base.ts

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -416,15 +416,24 @@ export abstract class BaseCrudDialect<Schema extends SchemaDef> {
416416
return this.buildEnumFilter(eb, modelAlias, field, fieldDef, payload);
417417
}
418418

419-
return match(fieldDef.type as BuiltinType)
420-
.with('String', () => this.buildStringFilter(eb, modelAlias, field, payload))
421-
.with(P.union('Int', 'Float', 'Decimal', 'BigInt'), (type) =>
422-
this.buildNumberFilter(eb, model, modelAlias, field, type, payload),
423-
)
424-
.with('Boolean', () => this.buildBooleanFilter(eb, modelAlias, field, payload))
425-
.with('DateTime', () => this.buildDateTimeFilter(eb, modelAlias, field, payload))
426-
.with('Bytes', () => this.buildBytesFilter(eb, modelAlias, field, payload))
427-
.exhaustive();
419+
return (
420+
match(fieldDef.type as BuiltinType)
421+
.with('String', () => this.buildStringFilter(eb, modelAlias, field, payload))
422+
.with(P.union('Int', 'Float', 'Decimal', 'BigInt'), (type) =>
423+
this.buildNumberFilter(eb, model, modelAlias, field, type, payload),
424+
)
425+
.with('Boolean', () => this.buildBooleanFilter(eb, modelAlias, field, payload))
426+
.with('DateTime', () => this.buildDateTimeFilter(eb, modelAlias, field, payload))
427+
.with('Bytes', () => this.buildBytesFilter(eb, modelAlias, field, payload))
428+
// TODO: JSON filters
429+
.with('Json', () => {
430+
throw new InternalError('JSON filters are not supported yet');
431+
})
432+
.with('Unsupported', () => {
433+
throw new QueryError(`Unsupported field cannot be used in filters`);
434+
})
435+
.exhaustive()
436+
);
428437
}
429438

430439
private buildLiteralFilter(eb: ExpressionBuilder<any, any>, lhs: Expression<any>, type: BuiltinType, rhs: unknown) {

packages/runtime/src/client/crud/dialects/postgresql.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export class PostgresCrudDialect<Schema extends SchemaDef> extends BaseCrudDiale
3737
.with('DateTime', () =>
3838
value instanceof Date ? value : typeof value === 'string' ? new Date(value) : value,
3939
)
40+
.with('Decimal', () => (value !== null ? value.toString() : value))
4041
.otherwise(() => value);
4142
}
4243
}

packages/runtime/src/client/crud/dialects/sqlite.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ export class SqliteCrudDialect<Schema extends SchemaDef> extends BaseCrudDialect
3939
.with('DateTime', () => (value instanceof Date ? value.toISOString() : value))
4040
.with('Decimal', () => (value as Decimal).toString())
4141
.with('Bytes', () => Buffer.from(value as Uint8Array))
42+
.with('Json', () => JSON.stringify(value))
4243
.otherwise(() => value);
4344
}
4445
}

packages/runtime/src/client/crud/validator.ts

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -379,15 +379,20 @@ export class InputValidator<Schema extends SchemaDef> {
379379
}
380380

381381
private makePrimitiveFilterSchema(type: BuiltinType, optional: boolean) {
382-
return match(type)
383-
.with('String', () => this.makeStringFilterSchema(optional))
384-
.with(P.union('Int', 'Float', 'Decimal', 'BigInt'), (type) =>
385-
this.makeNumberFilterSchema(this.makePrimitiveSchema(type), optional),
386-
)
387-
.with('Boolean', () => this.makeBooleanFilterSchema(optional))
388-
.with('DateTime', () => this.makeDateTimeFilterSchema(optional))
389-
.with('Bytes', () => this.makeBytesFilterSchema(optional))
390-
.exhaustive();
382+
return (
383+
match(type)
384+
.with('String', () => this.makeStringFilterSchema(optional))
385+
.with(P.union('Int', 'Float', 'Decimal', 'BigInt'), (type) =>
386+
this.makeNumberFilterSchema(this.makePrimitiveSchema(type), optional),
387+
)
388+
.with('Boolean', () => this.makeBooleanFilterSchema(optional))
389+
.with('DateTime', () => this.makeDateTimeFilterSchema(optional))
390+
.with('Bytes', () => this.makeBytesFilterSchema(optional))
391+
// TODO: JSON filters
392+
.with('Json', () => z.any())
393+
.with('Unsupported', () => z.never())
394+
.exhaustive()
395+
);
391396
}
392397

393398
private makeDateTimeFilterSchema(optional: boolean): ZodType {

packages/runtime/src/client/helpers/schema-db-pusher.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ export class SchemaDbPusher<Schema extends SchemaDef> {
154154
.with('Decimal', () => 'decimal')
155155
.with('DateTime', () => 'timestamp')
156156
.with('Bytes', () => (this.schema.provider.type === 'postgresql' ? 'bytea' : 'blob'))
157+
.with('Json', () => 'jsonb')
157158
.otherwise(() => {
158159
throw new Error(`Unsupported field type: ${type}`);
159160
});

packages/runtime/src/client/result-processor.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ export class ResultProcessor<Schema extends SchemaDef> {
9090
.with('Bytes', () => this.transformBytes(value))
9191
.with('Decimal', () => this.transformDecimal(value))
9292
.with('BigInt', () => this.transformBigInt(value))
93+
.with('Json', () => this.transformJson(value))
9394
.otherwise(() => value);
9495
}
9596

@@ -156,4 +157,14 @@ export class ResultProcessor<Schema extends SchemaDef> {
156157
}
157158
}
158159
}
160+
161+
private transformJson(value: unknown) {
162+
return match(this.schema.provider.type)
163+
.with('sqlite', () => {
164+
// better-sqlite3 returns JSON as string
165+
invariant(typeof value === 'string', 'Expected string, got ' + typeof value);
166+
return JSON.parse(value as string);
167+
})
168+
.otherwise(() => value);
169+
}
159170
}

packages/runtime/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
export { ZenStackClient, type ClientContract } from './client';
1+
export * from './client';

packages/runtime/test/client-api/type-coverage.test.ts

Lines changed: 73 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,28 @@ import Decimal from 'decimal.js';
22
import { describe, expect, it } from 'vitest';
33
import { createTestClient } from '../utils';
44

5-
describe('zmodel type coverage tests', () => {
6-
it('supports all types', async () => {
7-
const db = await createTestClient(
8-
`
5+
const PG_DB_NAME = 'client-api-type-coverage-tests';
6+
7+
describe.each(['sqlite', 'postgresql'] as const)('zmodel type coverage tests', (provider) => {
8+
it('supports all types - plain', async () => {
9+
const date = new Date();
10+
const data = {
11+
id: '1',
12+
String: 'string',
13+
Int: 100,
14+
BigInt: BigInt(9007199254740991),
15+
DateTime: date,
16+
Float: 1.23,
17+
Decimal: new Decimal(1.2345),
18+
Boolean: true,
19+
Bytes: new Uint8Array([1, 2, 3, 4]),
20+
Json: { foo: 'bar' },
21+
};
22+
23+
let db: any;
24+
try {
25+
db = await createTestClient(
26+
`
927
model Foo {
1028
id String @id @default(cuid())
1129
@@ -17,28 +35,67 @@ describe('zmodel type coverage tests', () => {
1735
Decimal Decimal
1836
Boolean Boolean
1937
Bytes Bytes
38+
Json Json
2039
2140
@@allow('all', true)
2241
}
2342
`,
24-
);
43+
{ provider, dbName: PG_DB_NAME },
44+
);
45+
46+
await db.foo.create({ data });
47+
await expect(db.foo.findUnique({ where: { id: '1' } })).resolves.toMatchObject(data);
48+
} finally {
49+
await db?.$disconnect();
50+
}
51+
});
52+
53+
it('supports all types - array', async () => {
54+
if (provider === 'sqlite') {
55+
return;
56+
}
2557

2658
const date = new Date();
2759
const data = {
2860
id: '1',
29-
String: 'string',
30-
Int: 100,
31-
BigInt: BigInt(9007199254740991),
32-
DateTime: date,
33-
Float: 1.23,
34-
Decimal: new Decimal(1.2345),
35-
Boolean: true,
36-
Bytes: new Uint8Array([1, 2, 3, 4]),
61+
String: ['string'],
62+
Int: [100],
63+
BigInt: [BigInt(9007199254740991)],
64+
DateTime: [date],
65+
Float: [1.23],
66+
Decimal: [new Decimal(1.2345)],
67+
Boolean: [true],
68+
Bytes: [new Uint8Array([1, 2, 3, 4])],
69+
Json: [{ foo: 'bar' }],
3770
};
3871

39-
await db.foo.create({ data });
72+
let db: any;
73+
try {
74+
db = await createTestClient(
75+
`
76+
model Foo {
77+
id String @id @default(cuid())
78+
79+
String String[]
80+
Int Int[]
81+
BigInt BigInt[]
82+
DateTime DateTime[]
83+
Float Float[]
84+
Decimal Decimal[]
85+
Boolean Boolean[]
86+
Bytes Bytes[]
87+
Json Json[]
88+
89+
@@allow('all', true)
90+
}
91+
`,
92+
{ provider, dbName: PG_DB_NAME },
93+
);
4094

41-
const r = await db.foo.findUnique({ where: { id: '1' } });
42-
expect(r.Bytes).toEqual(data.Bytes);
95+
await db.foo.create({ data });
96+
await expect(db.foo.findUnique({ where: { id: '1' } })).resolves.toMatchObject(data);
97+
} finally {
98+
await db?.$disconnect();
99+
}
43100
});
44101
});

0 commit comments

Comments
 (0)