Skip to content
This repository was archived by the owner on Mar 1, 2026. It is now read-only.

Commit 02dec0c

Browse files
authored
feat(orm): enable JSON filter for typed-json fields; consolidate generation scripts (#471)
1 parent e129278 commit 02dec0c

40 files changed

Lines changed: 24956 additions & 1381 deletions

File tree

packages/clients/tanstack-query/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
"lint": "eslint src --ext ts",
1111
"test": "vitest run",
1212
"pack": "pnpm pack",
13-
"test:generate": "tsx scripts/generate.ts",
13+
"test:generate": "tsx ../../../scripts/test-generate.ts tests",
1414
"test:typecheck": "tsc --noEmit --project tsconfig.test.json"
1515
},
1616
"keywords": [

packages/clients/tanstack-query/scripts/generate.ts

Lines changed: 0 additions & 27 deletions
This file was deleted.

packages/orm/src/client/crud-types.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -305,12 +305,14 @@ export type WhereInput<
305305
ModelFieldIsOptional<Schema, Model, Key>,
306306
WithAggregations
307307
>
308-
: // primitive
309-
PrimitiveFilter<
310-
GetModelFieldType<Schema, Model, Key>,
311-
ModelFieldIsOptional<Schema, Model, Key>,
312-
WithAggregations
313-
>;
308+
: GetModelFieldType<Schema, Model, Key> extends GetTypeDefs<Schema>
309+
? TypedJsonFilter
310+
: // primitive
311+
PrimitiveFilter<
312+
GetModelFieldType<Schema, Model, Key>,
313+
ModelFieldIsOptional<Schema, Model, Key>,
314+
WithAggregations
315+
>;
314316
} & {
315317
$expr?: (eb: ExpressionBuilder<ToKyselySchema<Schema>, Model>) => OperandExpression<SqlBool>;
316318
} & {
@@ -460,6 +462,9 @@ export type JsonFilter = {
460462
not?: JsonValue | JsonNullValues;
461463
};
462464

465+
// TODO: extra typedef filtering
466+
export type TypedJsonFilter = JsonFilter;
467+
463468
export type SortOrder = 'asc' | 'desc';
464469
export type NullsOrder = 'first' | 'last';
465470

packages/orm/src/client/crud/dialects/base-dialect.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import {
2828
isEnum,
2929
isInheritedField,
3030
isRelationField,
31+
isTypeDef,
3132
makeDefaultOrderBy,
3233
requireField,
3334
requireIdFields,
@@ -500,6 +501,11 @@ export abstract class BaseCrudDialect<Schema extends SchemaDef> {
500501
return this.buildEnumFilter(fieldRef, fieldDef, payload);
501502
}
502503

504+
if (isTypeDef(this.schema, fieldDef.type)) {
505+
// TODO: type-def field filtering
506+
return this.buildJsonFilter(fieldRef, payload);
507+
}
508+
503509
return match(fieldDef.type as BuiltinType)
504510
.with('String', () => this.buildStringFilter(fieldRef, payload))
505511
.with(P.union('Int', 'Float', 'Decimal', 'BigInt'), (type) =>

packages/orm/src/client/crud/validator/index.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -378,8 +378,13 @@ export class InputValidator<Schema extends SchemaDef> {
378378
}),
379379
),
380380
);
381-
this.setSchemaCache(key!, schema);
382-
return schema;
381+
382+
// zod doesn't preserve object field order after parsing, here we use a
383+
// validation-only custom schema and use the original data if parsing
384+
// is successful
385+
const finalSchema = z.custom((v) => schema!.safeParse(v).success);
386+
this.setSchemaCache(key!, finalSchema);
387+
return finalSchema;
383388
}
384389

385390
private makeWhereSchema(
@@ -434,6 +439,8 @@ export class InputValidator<Schema extends SchemaDef> {
434439
} else if (fieldDef.array) {
435440
// array field
436441
fieldSchema = this.makeArrayFilterSchema(fieldDef.type as BuiltinType);
442+
} else if (this.isTypeDefType(fieldDef.type)) {
443+
fieldSchema = this.makeTypedJsonFilterSchema(fieldDef.type, !!fieldDef.optional);
437444
} else {
438445
// primitive field
439446
fieldSchema = this.makePrimitiveFilterSchema(
@@ -528,6 +535,15 @@ export class InputValidator<Schema extends SchemaDef> {
528535
return result;
529536
}
530537

538+
private makeTypedJsonFilterSchema(_type: string, optional: boolean) {
539+
// TODO: direct typed JSON filtering
540+
return this.makeJsonFilterSchema(optional);
541+
}
542+
543+
private isTypeDefType(type: string) {
544+
return this.schema.typeDefs && type in this.schema.typeDefs;
545+
}
546+
531547
private makeEnumFilterSchema(enumDef: EnumDef, optional: boolean, withAggregations: boolean) {
532548
const baseSchema = z.enum(Object.keys(enumDef.values) as [string, ...string[]]);
533549
const components = this.makeCommonPrimitiveFilterComponents(

packages/orm/src/client/query-utils.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,10 @@ export function getEnum(schema: SchemaDef, type: string) {
190190
return schema.enums?.[type];
191191
}
192192

193+
export function isTypeDef(schema: SchemaDef, type: string) {
194+
return !!schema.typeDefs?.[type];
195+
}
196+
193197
export function buildJoinPairs(
194198
schema: SchemaDef,
195199
model: string,

scripts/test-generate.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { glob } from 'glob';
2+
import { execSync } from 'node:child_process';
3+
import path from 'node:path';
4+
import { fileURLToPath } from 'node:url';
5+
6+
const _dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));
7+
8+
async function main() {
9+
const baseDir = process.argv[2] || '.';
10+
11+
const zmodelFiles = [...glob.sync(path.resolve(baseDir, '**/schema.zmodel'), { ignore: '**/node_modules/**' })];
12+
for (const file of zmodelFiles) {
13+
console.log(`Generating TS schema for: ${file}`);
14+
await generate(file);
15+
}
16+
}
17+
18+
async function generate(schemaPath: string) {
19+
const cliPath = path.join(_dirname, '../packages/cli/dist/index.js');
20+
const RUNTIME = process.env.RUNTIME ?? 'node';
21+
execSync(`${RUNTIME} ${cliPath} generate --schema ${schemaPath}`, { cwd: path.dirname(schemaPath) });
22+
}
23+
24+
main();

tests/e2e/github-repos/cal.com/cal-com.test.ts

Lines changed: 0 additions & 12 deletions
This file was deleted.

0 commit comments

Comments
 (0)