@sequenceholdings/orm 0.1.3 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +108 -38
- package/dist/authoring.cjs +128 -16
- package/dist/authoring.cjs.map +1 -1
- package/dist/authoring.d.cts +21 -4
- package/dist/authoring.d.ts +21 -4
- package/dist/authoring.js +128 -16
- package/dist/authoring.js.map +1 -1
- package/dist/canonical.cjs +83 -9
- package/dist/canonical.cjs.map +1 -1
- package/dist/canonical.d.cts +47 -1
- package/dist/canonical.d.ts +47 -1
- package/dist/canonical.js +83 -10
- package/dist/canonical.js.map +1 -1
- package/dist/cli.cjs +816 -134
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +818 -136
- package/dist/cli.js.map +1 -1
- package/dist/client.cjs.map +1 -1
- package/dist/client.js.map +1 -1
- package/dist/compiler.cjs +488 -96
- package/dist/compiler.cjs.map +1 -1
- package/dist/compiler.d.cts +34 -2
- package/dist/compiler.d.ts +34 -2
- package/dist/compiler.js +489 -97
- package/dist/compiler.js.map +1 -1
- package/dist/index.cjs +420 -71
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +266 -9
- package/dist/index.d.ts +266 -9
- package/dist/index.js +410 -73
- package/dist/index.js.map +1 -1
- package/dist/ir.cjs +146 -12
- package/dist/ir.cjs.map +1 -1
- package/dist/ir.d.cts +161 -5
- package/dist/ir.d.ts +161 -5
- package/dist/ir.js +144 -13
- package/dist/ir.js.map +1 -1
- package/dist/{naming-CTvWSRTf.d.ts → naming-DCn94LJ4.d.ts} +15 -1
- package/dist/{naming-DRyinU4u.d.cts → naming-DPglwzkB.d.cts} +15 -1
- package/dist/predicate-v2.cjs +136 -11
- package/dist/predicate-v2.cjs.map +1 -1
- package/dist/predicate-v2.d.cts +3 -0
- package/dist/predicate-v2.d.ts +3 -0
- package/dist/predicate-v2.js +136 -11
- package/dist/predicate-v2.js.map +1 -1
- package/dist/sdl.cjs +460 -13
- package/dist/sdl.cjs.map +1 -1
- package/dist/sdl.d.cts +1 -1
- package/dist/sdl.d.ts +1 -1
- package/dist/sdl.js +459 -14
- package/dist/sdl.js.map +1 -1
- package/package.json +6 -4
- package/src/codegen-gql/preset.cjs +64 -0
- package/src/codegen-gql/server-fns.cjs +11 -6
- package/templates/orm-namespace/codegen.preset.cjs +17 -0
- package/templates/orm-namespace/codegen.ts +1 -1
- package/templates/orm-namespace/package.json +3 -0
- package/templates/orm-namespace/schema/tables.ts +1 -1
- package/templates/orm-namespace/sequence.config.ts +1 -1
package/dist/sdl.cjs
CHANGED
|
@@ -3,10 +3,16 @@
|
|
|
3
3
|
var zod = require('zod');
|
|
4
4
|
var crypto = require('crypto');
|
|
5
5
|
|
|
6
|
+
// src/canonical/v2.ts
|
|
7
|
+
|
|
8
|
+
// src/constants.ts
|
|
9
|
+
var COLUMN_IDENTIFIER_PATTERN = /^_?[a-z][a-z0-9_]*$/;
|
|
10
|
+
|
|
6
11
|
// src/canonical/v2.ts
|
|
7
12
|
var CANONICAL_FORMAT = 2;
|
|
8
13
|
var IDENTIFIER_RE = /^[a-z][a-z0-9_]*$/;
|
|
9
14
|
var identifier = zod.z.string().min(1).max(63).regex(IDENTIFIER_RE);
|
|
15
|
+
var columnIdentifier = zod.z.string().min(1).max(63).regex(COLUMN_IDENTIFIER_PATTERN);
|
|
10
16
|
var COLUMN_TYPES = [
|
|
11
17
|
"uuid",
|
|
12
18
|
"text",
|
|
@@ -27,18 +33,33 @@ var canonicalEnumSchema = zod.z.object({
|
|
|
27
33
|
var canonicalColumnSchema = zod.z.object({
|
|
28
34
|
/** Property name in TS (camelCase); columnName is the Postgres name. */
|
|
29
35
|
name: zod.z.string().min(1).max(63),
|
|
30
|
-
columnName:
|
|
36
|
+
columnName: columnIdentifier,
|
|
31
37
|
type: zod.z.union([columnTypeSchema, zod.z.object({ enum: identifier })]),
|
|
32
38
|
nullable: zod.z.boolean().default(true),
|
|
33
39
|
unique: zod.z.boolean().default(false),
|
|
34
40
|
/** Literal default, or one of the allowlisted SQL functions. */
|
|
35
41
|
default: zod.z.union([zod.z.string(), zod.z.number(), zod.z.boolean(), zod.z.null()]).optional(),
|
|
36
42
|
defaultFn: zod.z.enum(["gen_random_uuid()", "now()"]).optional(),
|
|
43
|
+
/**
|
|
44
|
+
* Stamp this column from the database clock on UPDATE (`now()`). The
|
|
45
|
+
* column stays insertable (defaults fill gaps) but is omitted from
|
|
46
|
+
* SetInput / settable so callers cannot backdate it.
|
|
47
|
+
*/
|
|
48
|
+
onUpdateFn: zod.z.enum(["now()"]).optional(),
|
|
37
49
|
description: zod.z.string().max(500).optional(),
|
|
38
50
|
/** Migration hints — same semantics as v1. */
|
|
39
|
-
renamedFrom:
|
|
51
|
+
renamedFrom: columnIdentifier.optional(),
|
|
40
52
|
cast: zod.z.string().max(200).optional(),
|
|
41
53
|
deprecated: zod.z.boolean().default(false)
|
|
54
|
+
}).superRefine((column, ctx) => {
|
|
55
|
+
if (column.onUpdateFn === void 0) return;
|
|
56
|
+
if (typeof column.type !== "string" || column.type !== "timestamptz" && column.type !== "date") {
|
|
57
|
+
ctx.addIssue({
|
|
58
|
+
code: "custom",
|
|
59
|
+
path: ["onUpdateFn"],
|
|
60
|
+
message: `onUpdateFn '${column.onUpdateFn}' is only valid on timestamptz/date columns`
|
|
61
|
+
});
|
|
62
|
+
}
|
|
42
63
|
});
|
|
43
64
|
var canonicalLinkSchema = zod.z.object({
|
|
44
65
|
name: zod.z.string().min(1).max(63),
|
|
@@ -46,15 +67,15 @@ var canonicalLinkSchema = zod.z.object({
|
|
|
46
67
|
/** Target table name (namespace-local). Absent for toPlatformUser. */
|
|
47
68
|
target: identifier.optional(),
|
|
48
69
|
/** FK column on the owning side (toOne/toPlatformUser: on this table; toMany: on the target). */
|
|
49
|
-
on:
|
|
70
|
+
on: columnIdentifier,
|
|
50
71
|
/** Referenced column on the target (default: target's PK / platform user `sub`). */
|
|
51
|
-
references:
|
|
72
|
+
references: columnIdentifier.optional(),
|
|
52
73
|
/** enforce: true emits a real FK constraint (same-namespace toOne only). */
|
|
53
74
|
enforce: zod.z.boolean().default(false),
|
|
54
75
|
description: zod.z.string().max(500).optional()
|
|
55
76
|
});
|
|
56
77
|
var canonicalIndexSchema = zod.z.object({
|
|
57
|
-
columns: zod.z.array(
|
|
78
|
+
columns: zod.z.array(columnIdentifier).min(1),
|
|
58
79
|
unique: zod.z.boolean().default(false),
|
|
59
80
|
name: identifier.optional()
|
|
60
81
|
});
|
|
@@ -145,6 +166,13 @@ var canonicalCowMutationSchema = zod.z.object({
|
|
|
145
166
|
}
|
|
146
167
|
}
|
|
147
168
|
});
|
|
169
|
+
var canonicalForeignKeySchema = zod.z.object({
|
|
170
|
+
name: identifier,
|
|
171
|
+
columns: zod.z.array(columnIdentifier).min(1).max(8),
|
|
172
|
+
target: identifier,
|
|
173
|
+
references: zod.z.array(columnIdentifier).min(1).max(8),
|
|
174
|
+
deferrable: zod.z.enum(["initially-immediate", "initially-deferred"]).optional()
|
|
175
|
+
}).strict();
|
|
148
176
|
var canonicalTableSchema = zod.z.object({
|
|
149
177
|
table: identifier,
|
|
150
178
|
description: zod.z.string().max(2e3).optional(),
|
|
@@ -153,7 +181,7 @@ var canonicalTableSchema = zod.z.object({
|
|
|
153
181
|
/** Synced/reflected read-only tables (`source: gold.*`) — v1 semantics. */
|
|
154
182
|
source: zod.z.string().regex(/^gold\.[a-z][a-z0-9_]*$/).optional(),
|
|
155
183
|
columns: zod.z.array(canonicalColumnSchema).default([]),
|
|
156
|
-
primaryKey: zod.z.array(
|
|
184
|
+
primaryKey: zod.z.array(columnIdentifier).min(1).max(8).optional(),
|
|
157
185
|
links: zod.z.array(canonicalLinkSchema).default([]),
|
|
158
186
|
indexes: zod.z.array(canonicalIndexSchema).default([]),
|
|
159
187
|
policies: canonicalPoliciesSchema.default({}),
|
|
@@ -164,14 +192,16 @@ var canonicalTableSchema = zod.z.object({
|
|
|
164
192
|
*/
|
|
165
193
|
actions: zod.z.array(canonicalActionSchema).default([]),
|
|
166
194
|
/** Optional (not defaulted) so pre-CoW canonical documents keep byte-identical hashes. */
|
|
167
|
-
cowMutations: zod.z.array(canonicalCowMutationSchema).optional()
|
|
195
|
+
cowMutations: zod.z.array(canonicalCowMutationSchema).optional(),
|
|
196
|
+
/** Omitted by old definitions, preserving their existing content hashes. */
|
|
197
|
+
foreignKeys: zod.z.array(canonicalForeignKeySchema).max(100).optional()
|
|
168
198
|
});
|
|
169
199
|
var canonicalViewSchema = zod.z.object({
|
|
170
200
|
view: identifier,
|
|
171
201
|
description: zod.z.string().max(2e3).optional(),
|
|
172
202
|
columns: zod.z.array(canonicalColumnSchema).min(1),
|
|
173
203
|
/** Logical identity for GraphQL only; PostgreSQL views have no PK constraint. */
|
|
174
|
-
primaryKey: zod.z.array(
|
|
204
|
+
primaryKey: zod.z.array(columnIdentifier).min(1).max(8).optional(),
|
|
175
205
|
links: zod.z.array(canonicalLinkSchema).default([]),
|
|
176
206
|
policies: zod.z.object({ read: policyExpressionSchema }).strict(),
|
|
177
207
|
query: zod.z.string().min(1).max(1e5).refine(isSingleViewQuerySql, {
|
|
@@ -184,6 +214,9 @@ var canonicalViewSchema = zod.z.object({
|
|
|
184
214
|
if (column.default !== void 0 || column.defaultFn !== void 0) {
|
|
185
215
|
ctx.addIssue({ code: "custom", path: ["columns", index], message: `view column '${column.name}' cannot declare a default` });
|
|
186
216
|
}
|
|
217
|
+
if (column.onUpdateFn !== void 0) {
|
|
218
|
+
ctx.addIssue({ code: "custom", path: ["columns", index], message: `view column '${column.name}' cannot declare onUpdateFn` });
|
|
219
|
+
}
|
|
187
220
|
if (column.unique) {
|
|
188
221
|
ctx.addIssue({ code: "custom", path: ["columns", index], message: `view column '${column.name}' cannot declare unique` });
|
|
189
222
|
}
|
|
@@ -217,6 +250,45 @@ var canonicalDefinitionSchema = zod.z.object({
|
|
|
217
250
|
ctx.addIssue({ code: "custom", path: ["tables", index, "table"], message: `duplicate relation '${table.table}'` });
|
|
218
251
|
}
|
|
219
252
|
seen.add(table.table);
|
|
253
|
+
if (table.source !== void 0) {
|
|
254
|
+
for (const [columnIndex, column] of table.columns.entries()) {
|
|
255
|
+
if (column.onUpdateFn !== void 0) {
|
|
256
|
+
ctx.addIssue({
|
|
257
|
+
code: "custom",
|
|
258
|
+
path: ["tables", index, "columns", columnIndex],
|
|
259
|
+
message: `synced table '${table.table}' column '${column.name}' cannot declare onUpdateFn`
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
const fkTables = new Map(definition.tables.map((table) => [table.table, table]));
|
|
266
|
+
for (const [tableIndex, table] of definition.tables.entries()) {
|
|
267
|
+
const names = /* @__PURE__ */ new Set([
|
|
268
|
+
...table.primaryKey?.length ? [`${table.table}_pkey`] : [],
|
|
269
|
+
...table.columns.filter((column) => column.unique && !(table.primaryKey?.length === 1 && table.primaryKey[0] === column.columnName)).map((column) => `${table.table}_${column.columnName}_unique`),
|
|
270
|
+
...table.links.filter((link) => link.enforce).map((link) => `fk_${table.table}_${link.name}`)
|
|
271
|
+
]);
|
|
272
|
+
for (const [index, fk] of (table.foreignKeys ?? []).entries()) {
|
|
273
|
+
const fail = (message) => ctx.addIssue({ code: "custom", path: ["tables", tableIndex, "foreignKeys", index], message });
|
|
274
|
+
if (names.has(fk.name)) fail(`duplicate foreign key '${fk.name}'`);
|
|
275
|
+
names.add(fk.name);
|
|
276
|
+
const target = fkTables.get(fk.target);
|
|
277
|
+
if (table.source || !target || target.source) {
|
|
278
|
+
fail("foreign keys must connect owned tables in the same namespace");
|
|
279
|
+
continue;
|
|
280
|
+
}
|
|
281
|
+
if (fk.columns.length !== fk.references.length) fail("foreign key columns and references must have the same number of columns");
|
|
282
|
+
if (new Set(fk.columns).size !== fk.columns.length || new Set(fk.references).size !== fk.references.length) fail("foreign key columns must not repeat");
|
|
283
|
+
for (const [position, name] of fk.columns.entries()) {
|
|
284
|
+
const sourceColumn = table.columns.find((column) => column.columnName === name);
|
|
285
|
+
const targetColumn = target.columns.find((column) => column.columnName === fk.references[position]);
|
|
286
|
+
if (!sourceColumn || !targetColumn) fail("foreign key references an unknown column");
|
|
287
|
+
else if (JSON.stringify(sourceColumn.type) !== JSON.stringify(targetColumn.type)) fail("foreign key column types must match");
|
|
288
|
+
}
|
|
289
|
+
const uniqueKeys = [target.primaryKey ?? [], ...target.indexes.filter((index2) => index2.unique).map((index2) => index2.columns), ...target.columns.filter((column) => column.unique).map((column) => [column.columnName])];
|
|
290
|
+
if (!uniqueKeys.some((key) => key.length === fk.references.length && key.every((column) => fk.references.includes(column)))) fail("foreign key target columns must form a unique key");
|
|
291
|
+
}
|
|
220
292
|
}
|
|
221
293
|
const tableByName = new Map(definition.tables.map((table) => [table.table, table]));
|
|
222
294
|
for (const [tableIndex, table] of definition.tables.entries()) {
|
|
@@ -352,12 +424,13 @@ function normalizeCanonical(definition) {
|
|
|
352
424
|
...definition,
|
|
353
425
|
enums: sortByName(definition.enums),
|
|
354
426
|
tables: [...definition.tables].sort((a, b) => a.table.localeCompare(b.table)).map((t) => {
|
|
355
|
-
const { cowMutations, ...rest } = t;
|
|
427
|
+
const { cowMutations, foreignKeys, ...rest } = t;
|
|
356
428
|
return {
|
|
357
429
|
...rest,
|
|
358
430
|
links: sortByName(t.links),
|
|
359
431
|
indexes: [...t.indexes].sort((a, b) => (a.name ?? a.columns.join("_")).localeCompare(b.name ?? b.columns.join("_"))),
|
|
360
432
|
actions: sortByName(t.actions),
|
|
433
|
+
...foreignKeys?.length ? { foreignKeys: sortByName(foreignKeys) } : {},
|
|
361
434
|
// Omitted entirely when absent/empty so pre-CoW documents hash unchanged.
|
|
362
435
|
...cowMutations !== void 0 && cowMutations.length > 0 ? { cowMutations: sortByName(cowMutations) } : {}
|
|
363
436
|
};
|
|
@@ -446,6 +519,8 @@ var ORDER_BY_ENUM_VALUES = [
|
|
|
446
519
|
"DESC_NULLS_LAST"
|
|
447
520
|
];
|
|
448
521
|
var PLATFORM_USER_TYPENAME = "PlatformUser";
|
|
522
|
+
var DATE_BUCKET_ENUM = "DateBucket";
|
|
523
|
+
var BUCKETABLE_COLUMN_TYPES = ["timestamptz", "date"];
|
|
449
524
|
function tableNames(table) {
|
|
450
525
|
const root = camelCase(table);
|
|
451
526
|
const rootPascal = pascalCase(table);
|
|
@@ -478,9 +553,327 @@ function tableNames(table) {
|
|
|
478
553
|
sumFields: `${type}SumFields`,
|
|
479
554
|
avgFields: `${type}AvgFields`,
|
|
480
555
|
aggregateBoolExp: `${type}AggregateBoolExp`,
|
|
481
|
-
aggregateBoolExpCount: `${type}AggregateBoolExpCount
|
|
556
|
+
aggregateBoolExpCount: `${type}AggregateBoolExpCount`,
|
|
557
|
+
aggregateGroupsRoot: `${root}AggregateGroups`,
|
|
558
|
+
groupByColumnEnum: `${type}GroupByColumn`,
|
|
559
|
+
groupByInput: `${type}GroupBy`,
|
|
560
|
+
groupKey: `${type}GroupKey`,
|
|
561
|
+
aggregateGroup: `${type}AggregateGroup`
|
|
482
562
|
};
|
|
483
563
|
}
|
|
564
|
+
var IR_VERSION = 2;
|
|
565
|
+
var LEGACY_IR_VERSION = 1;
|
|
566
|
+
var irVersionSchema = zod.z.union([zod.z.literal(LEGACY_IR_VERSION), zod.z.literal(IR_VERSION)]);
|
|
567
|
+
zod.z.object({ irVersion: irVersionSchema });
|
|
568
|
+
var scalarLiteral = zod.z.union([zod.z.string(), zod.z.number(), zod.z.boolean(), zod.z.null()]);
|
|
569
|
+
var valueIrSchema = zod.z.discriminatedUnion("kind", [
|
|
570
|
+
zod.z.object({ kind: zod.z.literal("literal"), value: zod.z.union([scalarLiteral, zod.z.array(scalarLiteral)]) }),
|
|
571
|
+
zod.z.object({ kind: zod.z.literal("variable"), name: zod.z.string() }),
|
|
572
|
+
zod.z.object({ kind: zod.z.literal("claim"), key: zod.z.enum(["sub", "org"]) })
|
|
573
|
+
]);
|
|
574
|
+
var CMP_OPS = [
|
|
575
|
+
"eq",
|
|
576
|
+
"neq",
|
|
577
|
+
"gt",
|
|
578
|
+
"gte",
|
|
579
|
+
"lt",
|
|
580
|
+
"lte",
|
|
581
|
+
"in",
|
|
582
|
+
"nin",
|
|
583
|
+
"like",
|
|
584
|
+
"ilike",
|
|
585
|
+
"isNull",
|
|
586
|
+
"contains",
|
|
587
|
+
"hasKey"
|
|
588
|
+
];
|
|
589
|
+
var predIrSchema = zod.z.lazy(
|
|
590
|
+
() => zod.z.discriminatedUnion("kind", [
|
|
591
|
+
zod.z.object({ kind: zod.z.literal("and"), operands: zod.z.array(predIrSchema).min(1) }),
|
|
592
|
+
zod.z.object({ kind: zod.z.literal("or"), operands: zod.z.array(predIrSchema).min(1) }),
|
|
593
|
+
zod.z.object({ kind: zod.z.literal("not"), operand: predIrSchema }),
|
|
594
|
+
zod.z.object({ kind: zod.z.literal("cmp"), op: zod.z.enum(CMP_OPS), column: zod.z.string(), value: valueIrSchema }),
|
|
595
|
+
zod.z.object({ kind: zod.z.literal("exists"), link: zod.z.string(), where: predIrSchema }),
|
|
596
|
+
zod.z.object({
|
|
597
|
+
kind: zod.z.literal("aggPredicate"),
|
|
598
|
+
link: zod.z.string(),
|
|
599
|
+
fn: zod.z.literal("count"),
|
|
600
|
+
op: zod.z.enum(["eq", "neq", "gt", "gte", "lt", "lte"]),
|
|
601
|
+
value: zod.z.number(),
|
|
602
|
+
where: predIrSchema.optional()
|
|
603
|
+
}),
|
|
604
|
+
zod.z.object({ kind: zod.z.literal("capability"), key: zod.z.string() }),
|
|
605
|
+
zod.z.object({ kind: zod.z.literal("role"), key: zod.z.string() }),
|
|
606
|
+
zod.z.object({ kind: zod.z.literal("dynamicFilter"), slot: zod.z.string() }),
|
|
607
|
+
zod.z.object({ kind: zod.z.literal("const"), value: zod.z.boolean() })
|
|
608
|
+
])
|
|
609
|
+
);
|
|
610
|
+
var orderIrSchema = zod.z.discriminatedUnion("kind", [
|
|
611
|
+
zod.z.object({
|
|
612
|
+
kind: zod.z.literal("column"),
|
|
613
|
+
column: zod.z.string(),
|
|
614
|
+
/** Order through a to-one link: `link` is set and `column` is on the target. */
|
|
615
|
+
link: zod.z.string().optional(),
|
|
616
|
+
direction: zod.z.enum(["asc", "desc"]),
|
|
617
|
+
nulls: zod.z.enum(["first", "last"]).optional()
|
|
618
|
+
}),
|
|
619
|
+
/** §4f: `$orderBy: [FooOrderBy!]` variable — validated + lowered at runtime. */
|
|
620
|
+
zod.z.object({ kind: zod.z.literal("dynamic"), slot: zod.z.string() })
|
|
621
|
+
]);
|
|
622
|
+
var limitIrSchema = zod.z.object({
|
|
623
|
+
/** Fixed value or a variable, clamped to [1, max]; absent → default. */
|
|
624
|
+
variable: zod.z.string().optional(),
|
|
625
|
+
value: zod.z.number().int().positive().optional(),
|
|
626
|
+
default: zod.z.number().int().positive(),
|
|
627
|
+
max: zod.z.number().int().positive()
|
|
628
|
+
});
|
|
629
|
+
var selectionIrSchema = zod.z.lazy(
|
|
630
|
+
() => zod.z.object({
|
|
631
|
+
typename: zod.z.string(),
|
|
632
|
+
columns: zod.z.array(zod.z.object({ alias: zod.z.string(), column: zod.z.string() })),
|
|
633
|
+
relations: zod.z.array(zod.z.object({
|
|
634
|
+
alias: zod.z.string(),
|
|
635
|
+
link: zod.z.string(),
|
|
636
|
+
selection: selectionIrSchema,
|
|
637
|
+
where: predIrSchema.optional(),
|
|
638
|
+
orderBy: zod.z.array(orderIrSchema).optional(),
|
|
639
|
+
limit: limitIrSchema.optional(),
|
|
640
|
+
offset: zod.z.object({ variable: zod.z.string().optional(), value: zod.z.number().int().optional() }).optional()
|
|
641
|
+
})),
|
|
642
|
+
aggregates: zod.z.array(zod.z.object({
|
|
643
|
+
alias: zod.z.string(),
|
|
644
|
+
link: zod.z.string().optional(),
|
|
645
|
+
where: predIrSchema.optional(),
|
|
646
|
+
count: zod.z.object({ columns: zod.z.array(zod.z.string()).optional(), distinct: zod.z.boolean().optional() }).optional(),
|
|
647
|
+
sum: zod.z.array(zod.z.string()).optional(),
|
|
648
|
+
avg: zod.z.array(zod.z.string()).optional(),
|
|
649
|
+
nodes: selectionIrSchema.optional()
|
|
650
|
+
}))
|
|
651
|
+
})
|
|
652
|
+
);
|
|
653
|
+
var includeIfSchema = zod.z.object({ variable: zod.z.string(), negated: zod.z.boolean() });
|
|
654
|
+
var selectRootSchema = zod.z.object({
|
|
655
|
+
kind: zod.z.literal("select"),
|
|
656
|
+
alias: zod.z.string(),
|
|
657
|
+
table: zod.z.string(),
|
|
658
|
+
selection: selectionIrSchema,
|
|
659
|
+
/** Composed at compile time: AND(policy, documentWhere?, dynamicFilter?). */
|
|
660
|
+
where: predIrSchema,
|
|
661
|
+
orderBy: zod.z.array(orderIrSchema).default([]),
|
|
662
|
+
distinctOn: zod.z.union([zod.z.array(zod.z.string()), zod.z.object({ slot: zod.z.string() })]).optional(),
|
|
663
|
+
limit: limitIrSchema,
|
|
664
|
+
offset: zod.z.object({ variable: zod.z.string().optional(), value: zod.z.number().int().optional() }).optional(),
|
|
665
|
+
includeIf: includeIfSchema.optional()
|
|
666
|
+
});
|
|
667
|
+
var byPkRootSchema = zod.z.object({
|
|
668
|
+
kind: zod.z.literal("byPk"),
|
|
669
|
+
alias: zod.z.string(),
|
|
670
|
+
table: zod.z.string(),
|
|
671
|
+
selection: selectionIrSchema,
|
|
672
|
+
pk: zod.z.array(zod.z.object({ column: zod.z.string(), value: valueIrSchema })).min(1),
|
|
673
|
+
/** Policy predicate — ANDed with the PK match. */
|
|
674
|
+
where: predIrSchema,
|
|
675
|
+
includeIf: includeIfSchema.optional()
|
|
676
|
+
});
|
|
677
|
+
var aggregateRootSchema = zod.z.object({
|
|
678
|
+
kind: zod.z.literal("aggregate"),
|
|
679
|
+
alias: zod.z.string(),
|
|
680
|
+
table: zod.z.string(),
|
|
681
|
+
where: predIrSchema,
|
|
682
|
+
count: zod.z.object({ columns: zod.z.array(zod.z.string()).optional(), distinct: zod.z.boolean().optional() }).optional(),
|
|
683
|
+
sum: zod.z.array(zod.z.string()).optional(),
|
|
684
|
+
avg: zod.z.array(zod.z.string()).optional(),
|
|
685
|
+
nodes: selectionIrSchema.optional(),
|
|
686
|
+
includeIf: includeIfSchema.optional()
|
|
687
|
+
});
|
|
688
|
+
var DATE_BUCKETS = ["year", "quarter", "month", "week", "day", "hour"];
|
|
689
|
+
var groupByKeyIrSchema = zod.z.object({
|
|
690
|
+
column: zod.z.string(),
|
|
691
|
+
bucket: zod.z.enum(DATE_BUCKETS).optional()
|
|
692
|
+
});
|
|
693
|
+
var aggregateGroupsRootSchema = zod.z.object({
|
|
694
|
+
kind: zod.z.literal("aggregateGroups"),
|
|
695
|
+
alias: zod.z.string(),
|
|
696
|
+
table: zod.z.string(),
|
|
697
|
+
/** Composed at compile time: AND(policy, documentWhere?, dynamicFilter?). */
|
|
698
|
+
where: predIrSchema,
|
|
699
|
+
groupBy: zod.z.array(groupByKeyIrSchema).min(1),
|
|
700
|
+
/**
|
|
701
|
+
* The `key { … }` projection: which group columns appear in each entry's key
|
|
702
|
+
* object, in selection order. A subset of `groupBy` (the compiler rejects a
|
|
703
|
+
* key field that is not a group key — it would be indeterminate within the
|
|
704
|
+
* group). Empty when the document selects only `aggregate`.
|
|
705
|
+
*/
|
|
706
|
+
key: zod.z.array(zod.z.object({ alias: zod.z.string(), column: zod.z.string() })).default([]),
|
|
707
|
+
count: zod.z.object({ columns: zod.z.array(zod.z.string()).optional(), distinct: zod.z.boolean().optional() }).optional(),
|
|
708
|
+
sum: zod.z.array(zod.z.string()).optional(),
|
|
709
|
+
avg: zod.z.array(zod.z.string()).optional(),
|
|
710
|
+
/** Bounds the GROUP count, not the scanned rows — see MAX_GROUPS. */
|
|
711
|
+
limit: limitIrSchema,
|
|
712
|
+
offset: zod.z.object({ variable: zod.z.string().optional(), value: zod.z.number().int().optional() }).optional(),
|
|
713
|
+
includeIf: includeIfSchema.optional()
|
|
714
|
+
});
|
|
715
|
+
var writeValuesSchema = zod.z.union([
|
|
716
|
+
zod.z.object({ slot: zod.z.string() }),
|
|
717
|
+
zod.z.object({ entries: zod.z.array(zod.z.object({ column: zod.z.string(), value: valueIrSchema })) })
|
|
718
|
+
]);
|
|
719
|
+
var onConflictIrSchema = zod.z.union([
|
|
720
|
+
zod.z.object({ slot: zod.z.string() }),
|
|
721
|
+
zod.z.object({ constraint: zod.z.string(), updateColumns: zod.z.array(zod.z.string()) })
|
|
722
|
+
]);
|
|
723
|
+
var mutationRootSchema = zod.z.object({
|
|
724
|
+
kind: zod.z.literal("mutation"),
|
|
725
|
+
/**
|
|
726
|
+
* CRUD verbs plus the structured copy-on-write ops. `cowOverride` copies the
|
|
727
|
+
* synced row into the overlay (INSERT…SELECT, ON CONFLICT DO NOTHING) then
|
|
728
|
+
* applies `set` — both statements generated by the executor from this
|
|
729
|
+
* metadata, never authored SQL. `cowRevert` deletes the override so the
|
|
730
|
+
* coalesce view falls back to synced. Both are gated on a matching synced
|
|
731
|
+
* row and carry the write policy in `where` like update/delete.
|
|
732
|
+
*/
|
|
733
|
+
op: zod.z.enum(["insert", "insertOne", "update", "updateByPk", "delete", "deleteByPk", "cowOverride", "cowRevert"]),
|
|
734
|
+
alias: zod.z.string(),
|
|
735
|
+
table: zod.z.string(),
|
|
736
|
+
/** CoW ops: logical name of the synced twin (read through its policy-filtered view). */
|
|
737
|
+
cowSynced: zod.z.string().optional(),
|
|
738
|
+
/** cowOverride: logical properties copied INSERT…SELECT from synced (pk included). */
|
|
739
|
+
cowCopyColumns: zod.z.array(zod.z.string()).optional(),
|
|
740
|
+
/** cowOverride: insert-policy WITH CHECK evaluated over the copied rows. */
|
|
741
|
+
cowCopyCheck: predIrSchema.optional(),
|
|
742
|
+
/** insert/insertOne: rows come from a slot ($object/$objects) or literals. */
|
|
743
|
+
objects: zod.z.union([
|
|
744
|
+
zod.z.object({ slot: zod.z.string() }),
|
|
745
|
+
zod.z.object({ rows: zod.z.array(zod.z.array(zod.z.object({ column: zod.z.string(), value: valueIrSchema }))) })
|
|
746
|
+
]).optional(),
|
|
747
|
+
/** Server-pinned columns (e.g. author_sub ← claim('sub')) merged into every inserted row. */
|
|
748
|
+
pinnedColumns: zod.z.array(zod.z.object({ column: zod.z.string(), value: valueIrSchema })).default([]),
|
|
749
|
+
onConflict: onConflictIrSchema.optional(),
|
|
750
|
+
set: writeValuesSchema.optional(),
|
|
751
|
+
append: writeValuesSchema.optional(),
|
|
752
|
+
inc: writeValuesSchema.optional(),
|
|
753
|
+
/** update/delete row filter: AND(writePolicy, documentWhere/pk, dynamicFilter?). */
|
|
754
|
+
where: predIrSchema.optional(),
|
|
755
|
+
pk: zod.z.array(zod.z.object({ column: zod.z.string(), value: valueIrSchema })).optional(),
|
|
756
|
+
/** WITH CHECK analogue evaluated against NEW row values (insert/update). */
|
|
757
|
+
insertCheck: predIrSchema.optional(),
|
|
758
|
+
returning: selectionIrSchema.nullable(),
|
|
759
|
+
affectedRows: zod.z.boolean().default(false),
|
|
760
|
+
/** v2: abort the transaction when the actual write count differs, regardless of selection. */
|
|
761
|
+
assertAffectedRows: zod.z.number().int().min(0).max(2147483647).optional(),
|
|
762
|
+
includeIf: includeIfSchema.optional()
|
|
763
|
+
});
|
|
764
|
+
var rootIrSchema = zod.z.discriminatedUnion("kind", [
|
|
765
|
+
selectRootSchema,
|
|
766
|
+
byPkRootSchema,
|
|
767
|
+
aggregateRootSchema,
|
|
768
|
+
aggregateGroupsRootSchema,
|
|
769
|
+
mutationRootSchema
|
|
770
|
+
]);
|
|
771
|
+
var INPUT_REF_KINDS = [
|
|
772
|
+
"boolExp",
|
|
773
|
+
"orderBy",
|
|
774
|
+
"selectColumn",
|
|
775
|
+
"insertInput",
|
|
776
|
+
"setInput",
|
|
777
|
+
"appendInput",
|
|
778
|
+
"onConflict"
|
|
779
|
+
];
|
|
780
|
+
var variableDefaultIrSchema = zod.z.object({
|
|
781
|
+
value: zod.z.union([scalarLiteral, zod.z.array(scalarLiteral)])
|
|
782
|
+
});
|
|
783
|
+
var variableIrSchema = zod.z.object({
|
|
784
|
+
name: zod.z.string(),
|
|
785
|
+
type: zod.z.union([
|
|
786
|
+
zod.z.object({ kind: zod.z.literal("scalar"), scalar: zod.z.enum(COLUMN_TYPES) }),
|
|
787
|
+
/** `values` is the declared membership whitelist — the executor validates against it. */
|
|
788
|
+
zod.z.object({ kind: zod.z.literal("enum"), name: zod.z.string(), values: zod.z.array(zod.z.string()).min(1) }),
|
|
789
|
+
/** §4f dynamic slot: validated against `tables[table]` whitelists at runtime. */
|
|
790
|
+
zod.z.object({ kind: zod.z.literal("inputRef"), input: zod.z.enum(INPUT_REF_KINDS), table: zod.z.string() })
|
|
791
|
+
]),
|
|
792
|
+
nullable: zod.z.boolean(),
|
|
793
|
+
list: zod.z.boolean(),
|
|
794
|
+
/** Absent = no default declared; see {@link variableDefaultIrSchema}. */
|
|
795
|
+
defaultValue: variableDefaultIrSchema.optional()
|
|
796
|
+
});
|
|
797
|
+
var compiledOperationSchema = zod.z.object({
|
|
798
|
+
irVersion: irVersionSchema,
|
|
799
|
+
name: zod.z.string(),
|
|
800
|
+
opHash: zod.z.string().regex(/^sha256:[0-9a-f]{64}$/),
|
|
801
|
+
kind: zod.z.enum(["query", "mutation"]),
|
|
802
|
+
requires: zod.z.object({
|
|
803
|
+
capability: zod.z.string().optional(),
|
|
804
|
+
role: zod.z.string().optional()
|
|
805
|
+
}).nullable(),
|
|
806
|
+
variables: zod.z.array(variableIrSchema),
|
|
807
|
+
/** Every table the op touches — data-token scoping + audit. */
|
|
808
|
+
tableSet: zod.z.array(zod.z.string()).min(1),
|
|
809
|
+
roots: zod.z.array(rootIrSchema).min(1)
|
|
810
|
+
}).superRefine((operation, ctx) => {
|
|
811
|
+
for (const [index, root] of operation.roots.entries()) {
|
|
812
|
+
if (root.kind !== "mutation" || root.assertAffectedRows === void 0) continue;
|
|
813
|
+
if (operation.irVersion < 2 || operation.kind !== "mutation" || root.includeIf !== void 0) {
|
|
814
|
+
ctx.addIssue({ code: "custom", path: ["roots", index], message: "affected-row assertions require unconditional mutation roots and IR v2" });
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
});
|
|
818
|
+
var tableMetaIrSchema = zod.z.object({
|
|
819
|
+
table: zod.z.string(),
|
|
820
|
+
schema: zod.z.string(),
|
|
821
|
+
typename: zod.z.string(),
|
|
822
|
+
/**
|
|
823
|
+
* True when statements over this relation evaluate a claims-gated synced
|
|
824
|
+
* view: synced twins (`source: gold.*`) materialize as views whose baked
|
|
825
|
+
* policy reads `current_setting('request.jwt.claims')`, and namespace views
|
|
826
|
+
* inherit the gate transitively through their declared dependencies. The
|
|
827
|
+
* executor must stamp that GUC (transaction-scoped) before any statement
|
|
828
|
+
* touching such a relation, or the synced arm yields zero rows regardless
|
|
829
|
+
* of the compiled predicates.
|
|
830
|
+
*/
|
|
831
|
+
claimsGated: zod.z.boolean().default(false),
|
|
832
|
+
columns: zod.z.array(zod.z.object({
|
|
833
|
+
name: zod.z.string(),
|
|
834
|
+
columnName: zod.z.string(),
|
|
835
|
+
type: zod.z.union([zod.z.enum(COLUMN_TYPES), zod.z.object({ enum: zod.z.string(), values: zod.z.array(zod.z.string()) })]),
|
|
836
|
+
nullable: zod.z.boolean()
|
|
837
|
+
})),
|
|
838
|
+
/** Empty for keyless read-only views; keyed tables and views list logical columns. */
|
|
839
|
+
primaryKey: zod.z.array(zod.z.string()),
|
|
840
|
+
links: zod.z.array(zod.z.object({
|
|
841
|
+
name: zod.z.string(),
|
|
842
|
+
kind: zod.z.enum(["toOne", "toMany", "toPlatformUser"]),
|
|
843
|
+
target: zod.z.string(),
|
|
844
|
+
on: zod.z.string(),
|
|
845
|
+
references: zod.z.string()
|
|
846
|
+
})),
|
|
847
|
+
/** §4f whitelists: what dynamic inputs may reference. */
|
|
848
|
+
filterable: zod.z.array(zod.z.string()),
|
|
849
|
+
orderable: zod.z.array(zod.z.string()),
|
|
850
|
+
insertable: zod.z.array(zod.z.string()),
|
|
851
|
+
settable: zod.z.array(zod.z.string()),
|
|
852
|
+
appendable: zod.z.array(zod.z.string()),
|
|
853
|
+
/**
|
|
854
|
+
* Logical columns stamped with Postgres `now()` on UPDATE (canonical
|
|
855
|
+
* `onUpdateFn`). Omitted when empty so pre-onUpdate artifacts still parse.
|
|
856
|
+
*/
|
|
857
|
+
touchOnUpdate: zod.z.array(zod.z.string()).optional(),
|
|
858
|
+
constraints: zod.z.array(zod.z.object({ name: zod.z.string(), columns: zod.z.array(zod.z.string()) })),
|
|
859
|
+
/** Depth/node caps for dynamic filter trees on this table. */
|
|
860
|
+
dynamicFilterMaxDepth: zod.z.number().int().positive().default(6),
|
|
861
|
+
dynamicFilterMaxNodes: zod.z.number().int().positive().default(64)
|
|
862
|
+
});
|
|
863
|
+
zod.z.object({
|
|
864
|
+
irVersion: irVersionSchema,
|
|
865
|
+
namespace: zod.z.string(),
|
|
866
|
+
schemaHash: zod.z.string(),
|
|
867
|
+
opsHash: zod.z.string(),
|
|
868
|
+
tables: zod.z.record(zod.z.string(), tableMetaIrSchema),
|
|
869
|
+
operations: zod.z.record(zod.z.string(), compiledOperationSchema)
|
|
870
|
+
}).superRefine((artifact, ctx) => {
|
|
871
|
+
for (const [name, operation] of Object.entries(artifact.operations)) {
|
|
872
|
+
if (operation.irVersion > artifact.irVersion) {
|
|
873
|
+
ctx.addIssue({ code: "custom", path: ["operations", name, "irVersion"], message: "operation requires a newer IR version than its artifact" });
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
});
|
|
484
877
|
|
|
485
878
|
// src/sdl/generate.ts
|
|
486
879
|
var SdlGenerationError = class extends Error {
|
|
@@ -559,8 +952,12 @@ function generateSdl(canonical, options = {}) {
|
|
|
559
952
|
'"""Gates an operation behind a platform capability or custom role \u2014 checked by the data plane before execution."""\ndirective @requires(capability: String, role: String) on QUERY | MUTATION'
|
|
560
953
|
);
|
|
561
954
|
blocks.push("directive @skip(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT");
|
|
955
|
+
blocks.push(
|
|
956
|
+
'"""Abort the entire mutation unless this root affects exactly the document-authored number of rows. Mutation roots only; cannot be conditional."""\ndirective @assertAffectedRows(exactly: Int!) on FIELD'
|
|
957
|
+
);
|
|
562
958
|
for (const scalar of CUSTOM_SCALARS) blocks.push(`scalar ${scalar}`);
|
|
563
959
|
blocks.push(renderEnum(ORDER_BY_ENUM, [...ORDER_BY_ENUM_VALUES]));
|
|
960
|
+
blocks.push(renderEnum(DATE_BUCKET_ENUM, DATE_BUCKETS.map((bucket) => bucket.toUpperCase())));
|
|
564
961
|
for (const enumName of [...usedEnums].sort()) {
|
|
565
962
|
const entry = enumByName.get(enumName);
|
|
566
963
|
if (!entry) continue;
|
|
@@ -590,9 +987,24 @@ function generateSdl(canonical, options = {}) {
|
|
|
590
987
|
blocks.push(renderQueryRoot(tables, namesByTable));
|
|
591
988
|
const mutationRoot = renderMutationRoot(tables, namesByTable);
|
|
592
989
|
if (mutationRoot !== null) blocks.push(mutationRoot);
|
|
990
|
+
assertNoDuplicateTypeNames(blocks);
|
|
593
991
|
return `${blocks.join("\n\n")}
|
|
594
992
|
`;
|
|
595
993
|
}
|
|
994
|
+
var TYPE_DECLARATION_RE = /^(?:type|input|enum|scalar|interface|union)\s+([_A-Za-z][_0-9A-Za-z]*)/;
|
|
995
|
+
function assertNoDuplicateTypeNames(blocks) {
|
|
996
|
+
const seen = /* @__PURE__ */ new Set();
|
|
997
|
+
for (const block of blocks) {
|
|
998
|
+
const declared = TYPE_DECLARATION_RE.exec(block)?.[1];
|
|
999
|
+
if (declared === void 0) continue;
|
|
1000
|
+
if (seen.has(declared)) {
|
|
1001
|
+
throw new SdlGenerationError(
|
|
1002
|
+
`Generated schema declares "${declared}" twice. A canonical enum or table name is PascalCased into this GraphQL type name and collides with another declaration (for example an enum named "date_bucket" renders as "DateBucket", the shared bucket enum). Rename the offending enum or table.`
|
|
1003
|
+
);
|
|
1004
|
+
}
|
|
1005
|
+
seen.add(declared);
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
596
1008
|
function assertEnumValue(value, context) {
|
|
597
1009
|
if (!GRAPHQL_NAME_RE.test(value) || RESERVED_ENUM_VALUES.has(value)) {
|
|
598
1010
|
throw new SdlGenerationError(
|
|
@@ -681,7 +1093,8 @@ function renderTableBlocks(ctx) {
|
|
|
681
1093
|
renderSelectColumnEnum(ctx),
|
|
682
1094
|
renderOrderByInput(ctx),
|
|
683
1095
|
renderBoolExp(ctx),
|
|
684
|
-
...renderAggregateTypes(ctx)
|
|
1096
|
+
...renderAggregateTypes(ctx),
|
|
1097
|
+
...renderGroupByTypes(ctx)
|
|
685
1098
|
];
|
|
686
1099
|
if (ctx.emitAggregateBoolExp) blocks.push(...renderAggregateBoolExp(ctx));
|
|
687
1100
|
const pk = primaryKeyColumns(table);
|
|
@@ -818,6 +1231,32 @@ ${sumLines.join("\n")}
|
|
|
818
1231
|
}
|
|
819
1232
|
return blocks;
|
|
820
1233
|
}
|
|
1234
|
+
function groupableColumns(table) {
|
|
1235
|
+
return table.columns.filter((column) => column.type !== "jsonb");
|
|
1236
|
+
}
|
|
1237
|
+
function renderGroupByTypes(ctx) {
|
|
1238
|
+
const { table, names } = ctx;
|
|
1239
|
+
const groupable = groupableColumns(table);
|
|
1240
|
+
if (groupable.length === 0) return [];
|
|
1241
|
+
const keyLines = groupable.map((column) => ` ${fieldName(column.name)}: ${columnGqlTypeOf(table, column)}`);
|
|
1242
|
+
return [
|
|
1243
|
+
renderEnum(names.groupByColumnEnum, groupable.map((column) => fieldName(column.name))),
|
|
1244
|
+
`input ${names.groupByInput} {
|
|
1245
|
+
column: ${names.groupByColumnEnum}!
|
|
1246
|
+
bucket: ${DATE_BUCKET_ENUM}
|
|
1247
|
+
}`,
|
|
1248
|
+
`type ${names.groupKey} {
|
|
1249
|
+
${keyLines.join("\n")}
|
|
1250
|
+
}`,
|
|
1251
|
+
`type ${names.aggregateGroup} {
|
|
1252
|
+
key: ${names.groupKey}!
|
|
1253
|
+
aggregate: ${names.aggregateFields}
|
|
1254
|
+
}`
|
|
1255
|
+
];
|
|
1256
|
+
}
|
|
1257
|
+
function groupRootArgs(names) {
|
|
1258
|
+
return `where: ${names.boolExp}, groupBy: [${names.groupByInput}!]!, limit: Int, offset: Int`;
|
|
1259
|
+
}
|
|
821
1260
|
function renderAggregateBoolExp(ctx) {
|
|
822
1261
|
const { names } = ctx;
|
|
823
1262
|
return [
|
|
@@ -843,6 +1282,9 @@ function constraintValues(table) {
|
|
|
843
1282
|
}
|
|
844
1283
|
return [...values].sort();
|
|
845
1284
|
}
|
|
1285
|
+
function clientSettableColumns(table) {
|
|
1286
|
+
return table.columns.filter((column) => column.onUpdateFn === void 0);
|
|
1287
|
+
}
|
|
846
1288
|
function renderWriteBlocks(ctx, access) {
|
|
847
1289
|
const { table, names, pinned } = ctx;
|
|
848
1290
|
const blocks = [];
|
|
@@ -864,7 +1306,7 @@ ${insertLines.join("\n")}
|
|
|
864
1306
|
}`);
|
|
865
1307
|
}
|
|
866
1308
|
if (access.update) {
|
|
867
|
-
const setLines = table.
|
|
1309
|
+
const setLines = clientSettableColumns(table).map(
|
|
868
1310
|
(column) => ` ${fieldName(column.name)}: ${columnGqlTypeOf(table, column)}`
|
|
869
1311
|
);
|
|
870
1312
|
blocks.push(`input ${names.setInput} {
|
|
@@ -891,7 +1333,7 @@ ${incLines.join("\n")}
|
|
|
891
1333
|
if (access.insert && allowsOnConflict(table) && constraints.length > 0) {
|
|
892
1334
|
for (const value of constraints) assertEnumValue(value, `constraint enum for table "${table.table}"`);
|
|
893
1335
|
blocks.push(renderEnum(names.constraintEnum, constraints));
|
|
894
|
-
const updateColumns = table.
|
|
1336
|
+
const updateColumns = clientSettableColumns(table).map((column) => fieldName(column.name));
|
|
895
1337
|
blocks.push(renderEnum(names.updateColumnEnum, updateColumns));
|
|
896
1338
|
blocks.push(
|
|
897
1339
|
`input ${names.onConflict} {
|
|
@@ -923,6 +1365,9 @@ function renderQueryRoot(tables, namesByTable) {
|
|
|
923
1365
|
lines.push(` ${names.byPkRoot}(${args}): ${names.typename}`);
|
|
924
1366
|
}
|
|
925
1367
|
lines.push(` ${names.aggregateRoot}(${rootArgs(names)}): ${names.aggregate}!`);
|
|
1368
|
+
if (groupableColumns(table).length > 0) {
|
|
1369
|
+
lines.push(` ${names.aggregateGroupsRoot}(${groupRootArgs(names)}): [${names.aggregateGroup}!]!`);
|
|
1370
|
+
}
|
|
926
1371
|
}
|
|
927
1372
|
lines.push("}");
|
|
928
1373
|
return lines.join("\n");
|
|
@@ -1095,7 +1540,9 @@ ${body}
|
|
|
1095
1540
|
`;
|
|
1096
1541
|
}
|
|
1097
1542
|
|
|
1543
|
+
exports.BUCKETABLE_COLUMN_TYPES = BUCKETABLE_COLUMN_TYPES;
|
|
1098
1544
|
exports.CUSTOM_SCALARS = CUSTOM_SCALARS;
|
|
1545
|
+
exports.DATE_BUCKET_ENUM = DATE_BUCKET_ENUM;
|
|
1099
1546
|
exports.MANIFEST_VERSION = MANIFEST_VERSION;
|
|
1100
1547
|
exports.NUMERICISH_COLUMN_TYPES = NUMERICISH_COLUMN_TYPES;
|
|
1101
1548
|
exports.ORDER_BY_ENUM = ORDER_BY_ENUM;
|