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