@sequenceholdings/orm 2.7.1 → 2.8.1

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.
Files changed (47) hide show
  1. package/README.md +18 -4
  2. package/dist/authoring.cjs +21 -0
  3. package/dist/authoring.cjs.map +1 -1
  4. package/dist/authoring.d.cts +1 -1
  5. package/dist/authoring.d.ts +1 -1
  6. package/dist/authoring.js +21 -0
  7. package/dist/authoring.js.map +1 -1
  8. package/dist/canonical.d.cts +71 -71
  9. package/dist/canonical.d.ts +71 -71
  10. package/dist/cli.cjs +3460 -3337
  11. package/dist/cli.cjs.map +1 -1
  12. package/dist/cli.d.cts +13 -1
  13. package/dist/cli.d.ts +13 -1
  14. package/dist/cli.js +3459 -3338
  15. package/dist/cli.js.map +1 -1
  16. package/dist/client.cjs +24 -6
  17. package/dist/client.cjs.map +1 -1
  18. package/dist/client.d.cts +12 -3
  19. package/dist/client.d.ts +12 -3
  20. package/dist/client.js +24 -6
  21. package/dist/client.js.map +1 -1
  22. package/dist/compiler.cjs +844 -15
  23. package/dist/compiler.cjs.map +1 -1
  24. package/dist/compiler.d.cts +12 -2
  25. package/dist/compiler.d.ts +12 -2
  26. package/dist/compiler.js +844 -17
  27. package/dist/compiler.js.map +1 -1
  28. package/dist/index.cjs +21 -0
  29. package/dist/index.cjs.map +1 -1
  30. package/dist/index.d.cts +57 -57
  31. package/dist/index.d.ts +57 -57
  32. package/dist/index.js +21 -0
  33. package/dist/index.js.map +1 -1
  34. package/dist/ir.d.cts +72 -72
  35. package/dist/ir.d.ts +72 -72
  36. package/dist/sdl.cjs +3 -3
  37. package/dist/sdl.cjs.map +1 -1
  38. package/dist/sdl.d.cts +2 -0
  39. package/dist/sdl.d.ts +2 -0
  40. package/dist/sdl.js +3 -3
  41. package/dist/sdl.js.map +1 -1
  42. package/package.json +1 -1
  43. package/templates/orm-namespace/graphql/example/queries.ts +52 -5
  44. package/templates/orm-namespace/schema/tables.ts +5 -2
  45. package/templates/orm-namespace/sequence.config.ts +6 -4
  46. package/dist/{definition-DjfC7Lll.d.cts → definition-B99BsOAO.d.cts} +4 -4
  47. package/dist/{definition-DjfC7Lll.d.ts → definition-B99BsOAO.d.ts} +4 -4
package/dist/compiler.cjs CHANGED
@@ -1841,9 +1841,15 @@ function typeName(table) {
1841
1841
  if (last === void 0) return pascalCase(table);
1842
1842
  return [...segments.slice(0, -1), singularizeWord(last)].map(capitalizeFirst).join("");
1843
1843
  }
1844
+ function fieldName(column) {
1845
+ return camelCase(column);
1846
+ }
1844
1847
  function enumTypeName(name2) {
1845
1848
  return pascalCase(name2);
1846
1849
  }
1850
+ function comparisonExpName(gqlTypeName) {
1851
+ return `${capitalizeFirst(gqlTypeName)}ComparisonExp`;
1852
+ }
1847
1853
  var SCALAR_FOR_COLUMN_TYPE = {
1848
1854
  uuid: "uuid",
1849
1855
  text: "String",
@@ -1867,7 +1873,19 @@ function columnTypeForScalar(scalarName) {
1867
1873
  return COLUMN_TYPE_BY_SCALAR.get(scalarName);
1868
1874
  }
1869
1875
  var VARIABLE_SCALAR_NAMES = [...COLUMN_TYPE_BY_SCALAR.keys()];
1876
+ var CUSTOM_SCALARS = ["bigint", "date", "jsonb", "numeric", "timestamptz", "uuid"];
1877
+ var NUMERICISH_COLUMN_TYPES = ["integer", "bigint", "numeric", "double"];
1878
+ var ORDER_BY_ENUM = "OrderBy";
1879
+ var ORDER_BY_ENUM_VALUES = [
1880
+ "ASC",
1881
+ "ASC_NULLS_FIRST",
1882
+ "ASC_NULLS_LAST",
1883
+ "DESC",
1884
+ "DESC_NULLS_FIRST",
1885
+ "DESC_NULLS_LAST"
1886
+ ];
1870
1887
  var PLATFORM_USER_TYPENAME = "PlatformUser";
1888
+ var DATE_BUCKET_ENUM = "DateBucket";
1871
1889
  function tableNames(table) {
1872
1890
  const root = camelCase(table);
1873
1891
  const rootPascal = pascalCase(table);
@@ -3480,8 +3498,8 @@ var COMPILER_MAJOR = 1;
3480
3498
  var OP_HASH_DOMAIN = "sequence-orm-op\0";
3481
3499
  var OPS_HASH_DOMAIN = "sequence-orm-opset\0";
3482
3500
  function canonicalOperationText(definition) {
3483
- const document = { kind: graphql.Kind.DOCUMENT, definitions: [definition] };
3484
- return graphql.print(document);
3501
+ const document2 = { kind: graphql.Kind.DOCUMENT, definitions: [definition] };
3502
+ return graphql.print(document2);
3485
3503
  }
3486
3504
  function computeOpHash({
3487
3505
  definition,
@@ -4729,9 +4747,9 @@ function parseDocuments({
4729
4747
  const parsed = [];
4730
4748
  const diagnostics = [];
4731
4749
  for (const source of documents) {
4732
- let document;
4750
+ let document2;
4733
4751
  try {
4734
- document = graphql.parse(source.contents);
4752
+ document2 = graphql.parse(source.contents);
4735
4753
  } catch (error) {
4736
4754
  diagnostics.push({
4737
4755
  severity: "error",
@@ -4741,7 +4759,7 @@ function parseDocuments({
4741
4759
  });
4742
4760
  continue;
4743
4761
  }
4744
- const validationErrors = graphql.validate(schema, document);
4762
+ const validationErrors = graphql.validate(schema, document2);
4745
4763
  if (validationErrors.length > 0) {
4746
4764
  for (const validationError of validationErrors) {
4747
4765
  diagnostics.push({
@@ -4755,11 +4773,11 @@ function parseDocuments({
4755
4773
  }
4756
4774
  const operations = [];
4757
4775
  const fragments = /* @__PURE__ */ new Map();
4758
- for (const definition of document.definitions) {
4776
+ for (const definition of document2.definitions) {
4759
4777
  if (definition.kind === graphql.Kind.OPERATION_DEFINITION) operations.push(definition);
4760
4778
  if (definition.kind === graphql.Kind.FRAGMENT_DEFINITION) fragments.set(definition.name.value, definition);
4761
4779
  }
4762
- parsed.push({ path: source.path, document, operations, fragments });
4780
+ parsed.push({ path: source.path, document: document2, operations, fragments });
4763
4781
  }
4764
4782
  return { documents: parsed, diagnostics };
4765
4783
  }
@@ -4957,12 +4975,12 @@ function compileNamespace({ canonical, sdl, documents }) {
4957
4975
  diagnostics.push(...parsed.diagnostics);
4958
4976
  const operations = {};
4959
4977
  const operationSources = /* @__PURE__ */ new Map();
4960
- for (const document of parsed.documents) {
4961
- for (const operationNode of document.operations) {
4978
+ for (const document2 of parsed.documents) {
4979
+ for (const operationNode of document2.operations) {
4962
4980
  const operationName = operationNode.name?.value;
4963
4981
  try {
4964
4982
  const restricted = restrictOperation({ operation: operationNode, ctx });
4965
- const flattened = flattenOperation({ operation: restricted.definition, fragments: document.fragments });
4983
+ const flattened = flattenOperation({ operation: restricted.definition, fragments: document2.fragments });
4966
4984
  const previousSource = operationSources.get(restricted.name);
4967
4985
  if (previousSource !== void 0) {
4968
4986
  throw new DocumentCompileError(
@@ -4994,14 +5012,14 @@ function compileNamespace({ canonical, sdl, documents }) {
4994
5012
  tableSet,
4995
5013
  roots
4996
5014
  };
4997
- operationSources.set(restricted.name, document.path);
5015
+ operationSources.set(restricted.name, document2.path);
4998
5016
  } catch (error) {
4999
5017
  if (error instanceof DocumentCompileError) {
5000
5018
  diagnostics.push({
5001
5019
  severity: "error",
5002
5020
  code: error.code,
5003
5021
  message: error.message,
5004
- document: document.path,
5022
+ document: document2.path,
5005
5023
  ...operationName !== void 0 ? { operation: operationName } : {}
5006
5024
  });
5007
5025
  continue;
@@ -5429,6 +5447,815 @@ function validateOnConflictInput({
5429
5447
  return finish(collector, { constraint, updateColumns });
5430
5448
  }
5431
5449
 
5450
+ // src/sdl/generate.ts
5451
+ var SdlGenerationError = class extends Error {
5452
+ constructor(message) {
5453
+ super(message);
5454
+ this.name = "SdlGenerationError";
5455
+ }
5456
+ };
5457
+ var GRAPHQL_NAME_RE = /^[_A-Za-z][_0-9A-Za-z]*$/;
5458
+ var RESERVED_ENUM_VALUES = /* @__PURE__ */ new Set(["true", "false", "null"]);
5459
+ var NUMERICISH = new Set(NUMERICISH_COLUMN_TYPES);
5460
+ var PLATFORM_USER_FIELDS = [
5461
+ { name: "sub", gqlType: "String", nullable: false },
5462
+ { name: "email", gqlType: "String", nullable: true },
5463
+ { name: "name", gqlType: "String", nullable: true },
5464
+ { name: "organization", gqlType: "String", nullable: true },
5465
+ { name: "role", gqlType: "String", nullable: true },
5466
+ { name: "managerId", gqlType: "String", nullable: true },
5467
+ { name: "accountEnabled", gqlType: "Boolean", nullable: false }
5468
+ ];
5469
+ function generateSdl(canonical, options = {}) {
5470
+ const def = composeNamespace(normalizeCanonical(canonicalDefinitionSchema.parse(canonical))).definition;
5471
+ const exposed = canonicalRelations(def).filter((table) => table.internal !== true && (table.source === void 0 || options.includeSyncedReads === true && (table.primaryKey?.length ?? 0) > 0));
5472
+ const cellsByTable = new Map(exposed.map((table) => [table.table, trackedCells(table)]));
5473
+ const tables = exposed.map((table) => ({ ...table, columns: table.columns.filter((column) => column.cell === void 0) }));
5474
+ if (tables.length === 0) {
5475
+ throw new SdlGenerationError(
5476
+ `Namespace "${def.namespace}" exposes no relations (synced tables are excluded from SDL in v2.0) \u2014 nothing to generate.`
5477
+ );
5478
+ }
5479
+ for (const table of tables) {
5480
+ if (table.columns.length === 0) {
5481
+ throw new SdlGenerationError(`Relation "${table.table}" has no columns \u2014 cannot generate an object type.`);
5482
+ }
5483
+ }
5484
+ const namesByTable = new Map(tables.map((table) => [table.table, tableNames(table.table)]));
5485
+ const enumByName = new Map(def.enums.map((entry) => [entry.name, entry]));
5486
+ const hasPlatformUser = tables.some((table) => table.links.some((link) => link.kind === "toPlatformUser"));
5487
+ const usedEnums = /* @__PURE__ */ new Set();
5488
+ for (const table of tables) {
5489
+ for (const column of table.columns) {
5490
+ if (typeof column.type === "object") {
5491
+ if (!enumByName.has(column.type.enum)) {
5492
+ throw new SdlGenerationError(
5493
+ `Column "${table.table}.${column.columnName}" references undeclared enum "${column.type.enum}".`
5494
+ );
5495
+ }
5496
+ usedEnums.add(column.type.enum);
5497
+ }
5498
+ }
5499
+ }
5500
+ const aggregateBoolExpTargets = /* @__PURE__ */ new Set();
5501
+ for (const table of tables) {
5502
+ for (const link of table.links) {
5503
+ if (link.kind === "toMany" && link.target !== void 0 && namesByTable.has(link.target)) {
5504
+ aggregateBoolExpTargets.add(link.target);
5505
+ }
5506
+ }
5507
+ }
5508
+ const usedComparisonScalars = /* @__PURE__ */ new Set();
5509
+ for (const table of tables) {
5510
+ for (const column of table.columns) {
5511
+ if (typeof column.type !== "object") usedComparisonScalars.add(graphqlScalarFor(column.type));
5512
+ }
5513
+ }
5514
+ if (hasPlatformUser) {
5515
+ usedComparisonScalars.add("String");
5516
+ usedComparisonScalars.add("Boolean");
5517
+ }
5518
+ if (aggregateBoolExpTargets.size > 0) usedComparisonScalars.add("Int");
5519
+ const blocks = [];
5520
+ blocks.push(
5521
+ `# Generated by @sequenceholdings/orm \u2014 GraphQL SDL for namespace "${def.namespace}".
5522
+ # Do not edit: regenerate with \`seq-studio orm generate\`.`
5523
+ );
5524
+ blocks.push("directive @include(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT");
5525
+ blocks.push(
5526
+ '"""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'
5527
+ );
5528
+ if (!options.omitReadBudgetDirective) blocks.push(
5529
+ '"""Sets a document-authored ceiling of 1\u201350001 rows for one flat select root. Runtime variables cannot raise it."""\ndirective @readBudget(maxRows: Int!) on QUERY'
5530
+ );
5531
+ blocks.push("directive @skip(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT");
5532
+ blocks.push(
5533
+ '"""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'
5534
+ );
5535
+ if (tables.some((table) => table.resolved !== void 0)) blocks.push(...RESOLVED_DIRECTIVE_BLOCKS);
5536
+ for (const scalar of CUSTOM_SCALARS) blocks.push(`scalar ${scalar}`);
5537
+ blocks.push(...renderSharedCellTypes([...cellsByTable.values()]));
5538
+ blocks.push(renderEnum(ORDER_BY_ENUM, [...ORDER_BY_ENUM_VALUES]));
5539
+ blocks.push(renderEnum(DATE_BUCKET_ENUM, DATE_BUCKETS.map((bucket) => bucket.toUpperCase())));
5540
+ for (const enumName of [...usedEnums].sort()) {
5541
+ const entry = enumByName.get(enumName);
5542
+ if (!entry) continue;
5543
+ for (const value of entry.values) assertEnumValue(value, `enum "${enumName}"`);
5544
+ blocks.push(renderEnum(enumTypeName(enumName), entry.values));
5545
+ }
5546
+ const patternTypes = options.stringOnlyPatternOperators ? STRING_PATTERN_COMPARISON_TYPES : PATTERN_COMPARISON_TYPES;
5547
+ for (const scalar of [...usedComparisonScalars].sort()) {
5548
+ blocks.push(renderComparisonExp({ gqlTypeName: scalar, patternTypes }));
5549
+ }
5550
+ for (const enumName of [...usedEnums].sort()) {
5551
+ blocks.push(renderComparisonExp({ gqlTypeName: enumTypeName(enumName), patternTypes }));
5552
+ }
5553
+ if (hasPlatformUser) blocks.push(...renderPlatformUserBlocks());
5554
+ for (const table of tables) {
5555
+ const names = namesByTable.get(table.table);
5556
+ if (!names) continue;
5557
+ blocks.push(
5558
+ ...renderTableBlocks({
5559
+ table,
5560
+ names,
5561
+ namesByTable,
5562
+ emitAggregateBoolExp: aggregateBoolExpTargets.has(table.table),
5563
+ pinned: options.pinnedColumns?.[table.table] ?? [],
5564
+ cells: cellsByTable.get(table.table) ?? null
5565
+ })
5566
+ );
5567
+ }
5568
+ blocks.push(renderQueryRoot(tables, namesByTable));
5569
+ const mutationRoot = renderMutationRoot(tables, namesByTable);
5570
+ if (mutationRoot !== null) blocks.push(mutationRoot);
5571
+ assertNoDuplicateTypeNames(blocks);
5572
+ return `${blocks.join("\n\n")}
5573
+ `;
5574
+ }
5575
+ var TYPE_DECLARATION_RE = /^(?:type|input|enum|scalar|interface|union)\s+([_A-Za-z][_0-9A-Za-z]*)/;
5576
+ function assertNoDuplicateTypeNames(blocks) {
5577
+ const seen = /* @__PURE__ */ new Set();
5578
+ for (const block of blocks) {
5579
+ const declared = TYPE_DECLARATION_RE.exec(block)?.[1];
5580
+ if (declared === void 0) continue;
5581
+ if (seen.has(declared)) {
5582
+ throw new SdlGenerationError(
5583
+ `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.`
5584
+ );
5585
+ }
5586
+ seen.add(declared);
5587
+ }
5588
+ }
5589
+ function assertEnumValue(value, context) {
5590
+ if (!GRAPHQL_NAME_RE.test(value) || RESERVED_ENUM_VALUES.has(value)) {
5591
+ throw new SdlGenerationError(
5592
+ `Value "${value}" in ${context} is not a valid GraphQL enum value (must match ${GRAPHQL_NAME_RE} and not be true/false/null).`
5593
+ );
5594
+ }
5595
+ }
5596
+ function renderEnum(name2, values) {
5597
+ return `enum ${name2} {
5598
+ ${values.map((value) => ` ${value}`).join("\n")}
5599
+ }`;
5600
+ }
5601
+ function descriptionLines(text, indent) {
5602
+ const escaped = text.replace(/"""/g, '\\"""');
5603
+ return [`${indent}"""`, ...escaped.split("\n").map((line) => `${indent}${line}`), `${indent}"""`];
5604
+ }
5605
+ var PATTERN_COMPARISON_TYPES = /* @__PURE__ */ new Set(["String", "Int", "bigint", "uuid"]);
5606
+ var STRING_PATTERN_COMPARISON_TYPES = /* @__PURE__ */ new Set(["String"]);
5607
+ function renderComparisonExp({ gqlTypeName, patternTypes }) {
5608
+ const fields = [
5609
+ ["_eq", gqlTypeName],
5610
+ ["_neq", gqlTypeName],
5611
+ ["_gt", gqlTypeName],
5612
+ ["_gte", gqlTypeName],
5613
+ ["_lt", gqlTypeName],
5614
+ ["_lte", gqlTypeName],
5615
+ ["_in", `[${gqlTypeName}!]`],
5616
+ ["_nin", `[${gqlTypeName}!]`],
5617
+ ["_isNull", "Boolean"]
5618
+ ];
5619
+ if (patternTypes.has(gqlTypeName)) {
5620
+ fields.push(["_like", "String"], ["_ilike", "String"]);
5621
+ }
5622
+ if (gqlTypeName === "jsonb") {
5623
+ fields.push(["_contains", "jsonb"], ["_hasKey", "String"]);
5624
+ }
5625
+ fields.sort(([a], [b]) => a.localeCompare(b));
5626
+ const body = fields.map(([field, type]) => ` ${field}: ${type}`).join("\n");
5627
+ return `input ${comparisonExpName(gqlTypeName)} {
5628
+ ${body}
5629
+ }`;
5630
+ }
5631
+ function renderPlatformUserBlocks() {
5632
+ const typeFields = PLATFORM_USER_FIELDS.map(
5633
+ (field) => ` ${field.name}: ${field.gqlType}${field.nullable ? "" : "!"}`
5634
+ ).join("\n");
5635
+ const boolExpName = `${PLATFORM_USER_TYPENAME}BoolExp`;
5636
+ const boolFields = [
5637
+ ` _and: [${boolExpName}!]`,
5638
+ ` _not: ${boolExpName}`,
5639
+ ` _or: [${boolExpName}!]`,
5640
+ ...PLATFORM_USER_FIELDS.map((field) => ` ${field.name}: ${comparisonExpName(field.gqlType)}`)
5641
+ ].join("\n");
5642
+ const orderFields = PLATFORM_USER_FIELDS.map((field) => ` ${field.name}: ${ORDER_BY_ENUM}`).join("\n");
5643
+ return [
5644
+ `"""Curated read-only view over platform users (plan \xA74b) \u2014 reachable only through \`toPlatformUser\` links."""
5645
+ type ${PLATFORM_USER_TYPENAME} {
5646
+ ${typeFields}
5647
+ }`,
5648
+ `input ${boolExpName} {
5649
+ ${boolFields}
5650
+ }`,
5651
+ `input ${PLATFORM_USER_TYPENAME}OrderBy {
5652
+ ${orderFields}
5653
+ }`
5654
+ ];
5655
+ }
5656
+ var RESOLVED_DIRECTIVE_BLOCKS = [
5657
+ '"""Refresh this resolved-table root from a prefetch source before reading. Key-addressed roots only; the source must support the root shape."""\ndirective @prefetch(source: String!, maxStaleness: String) repeatable on FIELD',
5658
+ renderEnum("WritebackMode", ["SYNC", "ASYNC"]),
5659
+ '"""Write this resolved-table mutation back to a prefetch source (SYNC rolls back on failure; ASYNC queues)."""\ndirective @writeback(source: String!, mode: WritebackMode) repeatable on FIELD',
5660
+ '"""Declare that this mutation deliberately keeps writeback columns local to the named source."""\ndirective @localOnly(source: String!) repeatable on FIELD'
5661
+ ];
5662
+ function trackedCells(table) {
5663
+ const columns = [...new Set(table.columns.flatMap((column) => column.cell ? [column.cell.of] : []))];
5664
+ if (columns.length === 0) return null;
5665
+ return { resolved: table.columns.some((column) => column.cell?.part === "source"), columns };
5666
+ }
5667
+ function renderSharedCellTypes(all) {
5668
+ const present = all.filter((cells) => cells !== null);
5669
+ const blocks = [];
5670
+ if (present.some((cells) => !cells.resolved)) {
5671
+ blocks.push(`"""When, and by whom, a cell was last written."""
5672
+ type ${CELL_TYPENAMES.stamp} {
5673
+ at: timestamptz!
5674
+ by: String
5675
+ }`);
5676
+ }
5677
+ if (present.some((cells) => cells.resolved)) {
5678
+ blocks.push(`"""A newer candidate value that lost to the column's resolve rule."""
5679
+ type ${CELL_TYPENAMES.conflict} {
5680
+ source: String!
5681
+ at: timestamptz
5682
+ value: jsonb
5683
+ }`);
5684
+ blocks.push(`"""How a resolved cell was decided: the winning source, its time and actor, and newer losers."""
5685
+ type ${CELL_TYPENAMES.resolved} {
5686
+ source: String!
5687
+ at: timestamptz
5688
+ by: String
5689
+ conflicts: [${CELL_TYPENAMES.conflict}!]!
5690
+ }`);
5691
+ }
5692
+ return blocks;
5693
+ }
5694
+ function renderCellsType(ctx) {
5695
+ if (!ctx.cells) return [];
5696
+ const cellType = ctx.cells.resolved ? CELL_TYPENAMES.resolved : CELL_TYPENAMES.stamp;
5697
+ const lines = ctx.cells.columns.map((column) => ` ${fieldName(column)}: ${cellType}`);
5698
+ return [`type ${cellsTypename(ctx.names.typename)} {
5699
+ ${lines.join("\n")}
5700
+ }`];
5701
+ }
5702
+ function relationArgs(target) {
5703
+ return `where: ${target.boolExp}, orderBy: [${target.orderBy}!], limit: Int, offset: Int`;
5704
+ }
5705
+ function rootArgs(names) {
5706
+ return `where: ${names.boolExp}, orderBy: [${names.orderBy}!], distinctOn: [${names.selectColumn}!], limit: Int, offset: Int`;
5707
+ }
5708
+ function primaryKeyColumns(table) {
5709
+ if (!table.primaryKey || table.primaryKey.length === 0) return [];
5710
+ return table.primaryKey.map((identifier3) => {
5711
+ const column = table.columns.find((c) => c.columnName === identifier3 || c.name === identifier3);
5712
+ if (!column) {
5713
+ throw new SdlGenerationError(`Primary key column "${identifier3}" not found on table "${table.table}".`);
5714
+ }
5715
+ return column;
5716
+ });
5717
+ }
5718
+ function renderTableBlocks(ctx) {
5719
+ const { table, names } = ctx;
5720
+ const blocks = [
5721
+ renderObjectType(ctx),
5722
+ ...renderCellsType(ctx),
5723
+ renderSelectColumnEnum(ctx),
5724
+ renderOrderByInput(ctx),
5725
+ renderBoolExp(ctx),
5726
+ ...renderAggregateTypes(ctx),
5727
+ ...renderGroupByTypes(ctx)
5728
+ ];
5729
+ if (ctx.emitAggregateBoolExp) blocks.push(...renderAggregateBoolExp(ctx));
5730
+ const pk = primaryKeyColumns(table);
5731
+ if (pk.length > 0) {
5732
+ const fields = pk.map((column) => ` ${fieldName(column.name)}: ${columnGqlTypeOf(table, column)}!`).join("\n");
5733
+ blocks.push(`input ${names.pkColumnsInput} {
5734
+ ${fields}
5735
+ }`);
5736
+ }
5737
+ if (ctx.table.resolved !== void 0) {
5738
+ blocks.push(...renderResolvedWriteBlocks(ctx));
5739
+ } else if (allowsInsert(table) || allowsUpdate(table)) {
5740
+ blocks.push(...renderWriteBlocks(ctx, { insert: allowsInsert(table), update: allowsUpdate(table) }));
5741
+ }
5742
+ return blocks;
5743
+ }
5744
+ function resolvedWritableColumns(table) {
5745
+ const system = new Set(Object.values(RESOLVED_VIEW_SYSTEM_COLUMNS).map((column) => column.name));
5746
+ return table.columns.filter((column) => !system.has(column.name));
5747
+ }
5748
+ function renderResolvedWriteBlocks(ctx) {
5749
+ const { table, names } = ctx;
5750
+ const writable = resolvedWritableColumns(table);
5751
+ const pk = new Set(table.primaryKey ?? []);
5752
+ const settable = writable.filter((column) => !pk.has(column.columnName));
5753
+ const line = (column) => ` ${fieldName(column.name)}: ${columnGqlTypeOf(table, column)}`;
5754
+ const blocks = [];
5755
+ if (allowsInsert(table)) blocks.push(`input ${names.insertInput} {
5756
+ ${writable.map(line).join("\n")}
5757
+ }`);
5758
+ if (allowsUpdate(table)) {
5759
+ blocks.push(`input ${names.setInput} {
5760
+ ${settable.map(line).join("\n")}
5761
+ }`);
5762
+ blocks.push(renderEnum(names.updateColumnEnum, settable.map((column) => fieldName(column.name))));
5763
+ }
5764
+ return blocks;
5765
+ }
5766
+ function renderResolvedMutationFields(table, names) {
5767
+ const lines = [];
5768
+ const pk = primaryKeyColumns(table);
5769
+ if (allowsInsert(table)) lines.push(` ${names.insertOneRoot}(object: ${names.insertInput}!): ${names.typename}`);
5770
+ if (allowsUpdate(table) && pk.length > 0) {
5771
+ lines.push(` ${names.updateByPkRoot}(pkColumns: ${names.pkColumnsInput}!, _set: ${names.setInput}!): ${names.typename}`);
5772
+ lines.push(` ${names.revertByPkRoot}(pkColumns: ${names.pkColumnsInput}!, columns: [${names.updateColumnEnum}!]!): ${names.typename}`);
5773
+ if ((table.resolved?.deletedBy.length ?? 0) > 0) {
5774
+ const args = pk.map((column) => `${fieldName(column.name)}: ${columnGqlTypeOf(table, column)}!`).join(", ");
5775
+ lines.push(` ${names.deleteByPkRoot}(${args}): ${names.typename}`);
5776
+ }
5777
+ }
5778
+ return lines;
5779
+ }
5780
+ function allowsInsert(table) {
5781
+ return table.source === void 0 && (table.policies.write !== void 0 || table.policies.insert !== void 0);
5782
+ }
5783
+ function allowsUpdate(table) {
5784
+ return table.source === void 0 && (table.policies.write !== void 0 || table.policies.update !== void 0);
5785
+ }
5786
+ function allowsOnConflict(table) {
5787
+ if (!allowsInsert(table) || !allowsUpdate(table)) return false;
5788
+ if (table.policies.insert !== void 0 || table.policies.update !== void 0) return false;
5789
+ return table.policies.write !== void 0;
5790
+ }
5791
+ function renderObjectType(ctx) {
5792
+ const { table, names } = ctx;
5793
+ const lines = [];
5794
+ if (table.description !== void 0) lines.push(...descriptionLines(table.description, ""));
5795
+ lines.push(`type ${names.typename} {`);
5796
+ for (const column of table.columns) {
5797
+ if (column.description !== void 0) lines.push(...descriptionLines(column.description, " "));
5798
+ const bang = column.nullable ? "" : "!";
5799
+ const deprecated = column.deprecated ? " @deprecated" : "";
5800
+ lines.push(` ${fieldName(column.name)}: ${columnGqlTypeOf(table, column)}${bang}${deprecated}`);
5801
+ }
5802
+ if (ctx.cells) {
5803
+ lines.push(' """Per-cell metadata: when each field was last written, and by whom."""');
5804
+ lines.push(` ${CELLS_FIELD}: ${cellsTypename(names.typename)}!`);
5805
+ }
5806
+ for (const link of table.links) {
5807
+ if (link.description !== void 0) lines.push(...descriptionLines(link.description, " "));
5808
+ if (link.kind === "toPlatformUser") {
5809
+ lines.push(` ${fieldName(link.name)}: ${PLATFORM_USER_TYPENAME}`);
5810
+ continue;
5811
+ }
5812
+ const target = link.target !== void 0 ? ctx.namesByTable.get(link.target) : void 0;
5813
+ if (!target) continue;
5814
+ if (link.kind === "toOne") {
5815
+ lines.push(` ${fieldName(link.name)}: ${target.typename}`);
5816
+ } else {
5817
+ lines.push(` ${fieldName(link.name)}(${relationArgs(target)}): [${target.typename}!]!`);
5818
+ lines.push(` ${fieldName(link.name)}Aggregate(${relationArgs(target)}): ${target.aggregate}!`);
5819
+ }
5820
+ }
5821
+ lines.push("}");
5822
+ return lines.join("\n");
5823
+ }
5824
+ function renderSelectColumnEnum(ctx) {
5825
+ const values = ctx.table.columns.map((column) => fieldName(column.name));
5826
+ for (const value of values) assertEnumValue(value, `select-column enum for table "${ctx.table.table}"`);
5827
+ return renderEnum(ctx.names.selectColumn, values);
5828
+ }
5829
+ function renderOrderByInput(ctx) {
5830
+ const { table, names } = ctx;
5831
+ const lines = table.columns.map((column) => ` ${fieldName(column.name)}: ${ORDER_BY_ENUM}`);
5832
+ for (const link of table.links) {
5833
+ if (link.kind === "toPlatformUser") {
5834
+ lines.push(` ${fieldName(link.name)}: ${PLATFORM_USER_TYPENAME}OrderBy`);
5835
+ } else if (link.kind === "toOne" && link.target !== void 0) {
5836
+ const target = ctx.namesByTable.get(link.target);
5837
+ if (target) lines.push(` ${fieldName(link.name)}: ${target.orderBy}`);
5838
+ }
5839
+ }
5840
+ return `input ${names.orderBy} {
5841
+ ${lines.join("\n")}
5842
+ }`;
5843
+ }
5844
+ function renderBoolExp(ctx) {
5845
+ const { table, names } = ctx;
5846
+ const lines = [
5847
+ ` _and: [${names.boolExp}!]`,
5848
+ ` _not: ${names.boolExp}`,
5849
+ ` _or: [${names.boolExp}!]`
5850
+ ];
5851
+ for (const column of table.columns) {
5852
+ lines.push(` ${fieldName(column.name)}: ${comparisonExpName(columnGqlTypeOf(table, column))}`);
5853
+ }
5854
+ for (const link of table.links) {
5855
+ if (link.kind === "toPlatformUser") {
5856
+ lines.push(` ${fieldName(link.name)}: ${PLATFORM_USER_TYPENAME}BoolExp`);
5857
+ continue;
5858
+ }
5859
+ const target = link.target !== void 0 ? ctx.namesByTable.get(link.target) : void 0;
5860
+ if (!target) continue;
5861
+ lines.push(` ${fieldName(link.name)}: ${target.boolExp}`);
5862
+ if (link.kind === "toMany") {
5863
+ lines.push(` ${fieldName(link.name)}Aggregate: ${target.aggregateBoolExp}`);
5864
+ }
5865
+ }
5866
+ return `input ${names.boolExp} {
5867
+ ${lines.join("\n")}
5868
+ }`;
5869
+ }
5870
+ function numericishColumns(table) {
5871
+ return table.columns.filter((column) => typeof column.type !== "object" && NUMERICISH.has(column.type));
5872
+ }
5873
+ function jsonbColumns(table) {
5874
+ return clientWritableColumns(table).filter((column) => column.type === "jsonb");
5875
+ }
5876
+ function clientWritableColumns(table) {
5877
+ return table.columns;
5878
+ }
5879
+ function renderAggregateTypes(ctx) {
5880
+ const { table, names } = ctx;
5881
+ const numericish = numericishColumns(table);
5882
+ const blocks = [];
5883
+ blocks.push(
5884
+ `type ${names.aggregate} {
5885
+ aggregate: ${names.aggregateFields}
5886
+ nodes: [${names.typename}!]!
5887
+ }`
5888
+ );
5889
+ const fieldLines = [` count(columns: [${names.selectColumn}!], distinct: Boolean): Int!`];
5890
+ if (numericish.length > 0) {
5891
+ fieldLines.push(` avg: ${names.avgFields}`);
5892
+ fieldLines.push(` sum: ${names.sumFields}`);
5893
+ }
5894
+ blocks.push(`type ${names.aggregateFields} {
5895
+ ${fieldLines.join("\n")}
5896
+ }`);
5897
+ if (numericish.length > 0) {
5898
+ const avgLines = numericish.map((column) => ` ${fieldName(column.name)}: Float`);
5899
+ blocks.push(`type ${names.avgFields} {
5900
+ ${avgLines.join("\n")}
5901
+ }`);
5902
+ const sumLines = numericish.map((column) => ` ${fieldName(column.name)}: ${columnGqlTypeOf(table, column)}`);
5903
+ blocks.push(`type ${names.sumFields} {
5904
+ ${sumLines.join("\n")}
5905
+ }`);
5906
+ }
5907
+ return blocks;
5908
+ }
5909
+ function groupableColumns(table) {
5910
+ return table.columns.filter((column) => column.type !== "jsonb");
5911
+ }
5912
+ function renderGroupByTypes(ctx) {
5913
+ const { table, names } = ctx;
5914
+ const groupable = groupableColumns(table);
5915
+ if (groupable.length === 0) return [];
5916
+ const keyLines = groupable.map((column) => ` ${fieldName(column.name)}: ${columnGqlTypeOf(table, column)}`);
5917
+ return [
5918
+ renderEnum(names.groupByColumnEnum, groupable.map((column) => fieldName(column.name))),
5919
+ `input ${names.groupByInput} {
5920
+ column: ${names.groupByColumnEnum}!
5921
+ bucket: ${DATE_BUCKET_ENUM}
5922
+ }`,
5923
+ `type ${names.groupKey} {
5924
+ ${keyLines.join("\n")}
5925
+ }`,
5926
+ `type ${names.aggregateGroup} {
5927
+ key: ${names.groupKey}!
5928
+ aggregate: ${names.aggregateFields}
5929
+ }`
5930
+ ];
5931
+ }
5932
+ function groupRootArgs(names) {
5933
+ return `where: ${names.boolExp}, groupBy: [${names.groupByInput}!]!, limit: Int, offset: Int`;
5934
+ }
5935
+ function renderAggregateBoolExp(ctx) {
5936
+ const { names } = ctx;
5937
+ return [
5938
+ `input ${names.aggregateBoolExp} {
5939
+ count: ${names.aggregateBoolExpCount}
5940
+ }`,
5941
+ `input ${names.aggregateBoolExpCount} {
5942
+ arguments: [${names.selectColumn}!]
5943
+ distinct: Boolean
5944
+ filter: ${names.boolExp}
5945
+ predicate: IntComparisonExp!
5946
+ }`
5947
+ ];
5948
+ }
5949
+ function constraintValues(table) {
5950
+ const values = /* @__PURE__ */ new Set();
5951
+ if (table.primaryKey && table.primaryKey.length > 0) values.add(`${table.table}_pkey`);
5952
+ for (const column of table.columns) {
5953
+ if (column.unique) values.add(`${table.table}_${column.columnName}_unique`);
5954
+ }
5955
+ for (const index of table.indexes) {
5956
+ if (index.unique) values.add(index.name ?? `${table.table}_${index.columns.join("_")}_key`);
5957
+ }
5958
+ return [...values].sort();
5959
+ }
5960
+ function clientSettableColumns(table) {
5961
+ return clientWritableColumns(table).filter((column) => column.onUpdateFn === void 0);
5962
+ }
5963
+ function renderWriteBlocks(ctx, access) {
5964
+ const { table, names, pinned } = ctx;
5965
+ const blocks = [];
5966
+ if (access.insert) {
5967
+ const pinnedSet = new Set(pinned);
5968
+ const insertable = clientWritableColumns(table).filter(
5969
+ (column) => !pinnedSet.has(column.name) && !pinnedSet.has(column.columnName)
5970
+ );
5971
+ if (insertable.length === 0) {
5972
+ throw new SdlGenerationError(
5973
+ `Table "${table.table}" has no insertable columns after excluding pinned columns [${pinned.join(", ")}].`
5974
+ );
5975
+ }
5976
+ const insertLines = insertable.map(
5977
+ (column) => ` ${fieldName(column.name)}: ${columnGqlTypeOf(table, column)}`
5978
+ );
5979
+ blocks.push(`input ${names.insertInput} {
5980
+ ${insertLines.join("\n")}
5981
+ }`);
5982
+ }
5983
+ if (access.update) {
5984
+ const setLines = clientSettableColumns(table).map(
5985
+ (column) => ` ${fieldName(column.name)}: ${columnGqlTypeOf(table, column)}`
5986
+ );
5987
+ blocks.push(`input ${names.setInput} {
5988
+ ${setLines.join("\n")}
5989
+ }`);
5990
+ }
5991
+ const jsonb = jsonbColumns(table);
5992
+ if (access.update && jsonb.length > 0) {
5993
+ const appendLines = jsonb.map((column) => ` ${fieldName(column.name)}: jsonb`);
5994
+ blocks.push(`input ${names.appendInput} {
5995
+ ${appendLines.join("\n")}
5996
+ }`);
5997
+ }
5998
+ const numericish = numericishColumns(table);
5999
+ if (access.update && numericish.length > 0) {
6000
+ const incLines = numericish.map(
6001
+ (column) => ` ${fieldName(column.name)}: ${columnGqlTypeOf(table, column)}`
6002
+ );
6003
+ blocks.push(`input ${names.incInput} {
6004
+ ${incLines.join("\n")}
6005
+ }`);
6006
+ }
6007
+ const constraints = constraintValues(table);
6008
+ if (access.insert && allowsOnConflict(table) && constraints.length > 0) {
6009
+ for (const value of constraints) assertEnumValue(value, `constraint enum for table "${table.table}"`);
6010
+ blocks.push(renderEnum(names.constraintEnum, constraints));
6011
+ const updateColumns = clientSettableColumns(table).map((column) => fieldName(column.name));
6012
+ blocks.push(renderEnum(names.updateColumnEnum, updateColumns));
6013
+ blocks.push(
6014
+ `input ${names.onConflict} {
6015
+ constraint: ${names.constraintEnum}!
6016
+ updateColumns: [${names.updateColumnEnum}!]! = []
6017
+ where: ${names.boolExp}
6018
+ }`
6019
+ );
6020
+ }
6021
+ if (access.insert || access.update) {
6022
+ blocks.push(
6023
+ `type ${names.mutationResponse} {
6024
+ affectedRows: Int!
6025
+ returning: [${names.typename}!]!
6026
+ }`
6027
+ );
6028
+ }
6029
+ return blocks;
6030
+ }
6031
+ function renderQueryRoot(tables, namesByTable) {
6032
+ const lines = ["type Query {"];
6033
+ for (const table of tables) {
6034
+ const names = namesByTable.get(table.table);
6035
+ if (!names) continue;
6036
+ lines.push(` ${names.selectRoot}(${rootArgs(names)}): [${names.typename}!]!`);
6037
+ const pk = primaryKeyColumns(table);
6038
+ if (pk.length > 0) {
6039
+ const args = pk.map((column) => `${fieldName(column.name)}: ${columnGqlTypeOf(table, column)}!`).join(", ");
6040
+ lines.push(` ${names.byPkRoot}(${args}): ${names.typename}`);
6041
+ }
6042
+ lines.push(` ${names.aggregateRoot}(${rootArgs(names)}): ${names.aggregate}!`);
6043
+ if (groupableColumns(table).length > 0) {
6044
+ lines.push(` ${names.aggregateGroupsRoot}(${groupRootArgs(names)}): [${names.aggregateGroup}!]!`);
6045
+ }
6046
+ }
6047
+ lines.push("}");
6048
+ return lines.join("\n");
6049
+ }
6050
+ function columnGqlTypeOf(table, column) {
6051
+ return typeof column.type === "object" ? enumTypeName(column.type.enum) : graphqlScalarFor(column.type);
6052
+ }
6053
+ function renderMutationRoot(tables, namesByTable) {
6054
+ const lines = [];
6055
+ for (const table of tables) {
6056
+ const canInsert = allowsInsert(table);
6057
+ const canUpdate = allowsUpdate(table);
6058
+ if (!canInsert && !canUpdate) continue;
6059
+ const names = namesByTable.get(table.table);
6060
+ if (!names) continue;
6061
+ if (table.resolved !== void 0) {
6062
+ lines.push(...renderResolvedMutationFields(table, names));
6063
+ continue;
6064
+ }
6065
+ const constraints = constraintValues(table);
6066
+ const onConflictArg = canInsert && allowsOnConflict(table) && constraints.length > 0 ? `, onConflict: ${names.onConflict}` : "";
6067
+ const updateArgs = [`_set: ${names.setInput}`];
6068
+ if (jsonbColumns(table).length > 0) updateArgs.push(`_append: ${names.appendInput}`);
6069
+ if (numericishColumns(table).length > 0) updateArgs.push(`_inc: ${names.incInput}`);
6070
+ const updateArgList = updateArgs.join(", ");
6071
+ if (canInsert) {
6072
+ lines.push(` ${names.insertRoot}(objects: [${names.insertInput}!]!${onConflictArg}): ${names.mutationResponse}`);
6073
+ lines.push(` ${names.insertOneRoot}(object: ${names.insertInput}!${onConflictArg}): ${names.typename}`);
6074
+ }
6075
+ if (canUpdate) {
6076
+ lines.push(` ${names.updateRoot}(where: ${names.boolExp}!, ${updateArgList}): ${names.mutationResponse}`);
6077
+ const pk = primaryKeyColumns(table);
6078
+ if (pk.length > 0) {
6079
+ lines.push(
6080
+ ` ${names.updateByPkRoot}(pkColumns: ${names.pkColumnsInput}!, ${updateArgList}): ${names.typename}`
6081
+ );
6082
+ }
6083
+ lines.push(` ${names.deleteRoot}(where: ${names.boolExp}!): ${names.mutationResponse}`);
6084
+ if (pk.length > 0) {
6085
+ const args = pk.map((column) => `${fieldName(column.name)}: ${columnGqlTypeOf(table, column)}!`).join(", ");
6086
+ lines.push(` ${names.deleteByPkRoot}(${args}): ${names.typename}`);
6087
+ }
6088
+ }
6089
+ lines.push(...renderCowMutationFields(table, names));
6090
+ }
6091
+ if (lines.length === 0) return null;
6092
+ return `type Mutation {
6093
+ ${lines.join("\n")}
6094
+ }`;
6095
+ }
6096
+ function renderCowMutationFields(table, names) {
6097
+ const lines = [];
6098
+ const columnByName = new Map(table.columns.map((column) => [column.name, column]));
6099
+ for (const mutation of table.cowMutations ?? []) {
6100
+ const pkColumn = columnByName.get(mutation.pk);
6101
+ if (!pkColumn) continue;
6102
+ const pkArg = `${fieldName(mutation.pk)}: ${columnGqlTypeOf(table, pkColumn)}!`;
6103
+ if (mutation.kind === "revert") {
6104
+ lines.push(` ${fieldName(mutation.name)}(${pkArg}): ${names.typename}`);
6105
+ continue;
6106
+ }
6107
+ const setArgs = mutation.set.map((property) => {
6108
+ const column = columnByName.get(property);
6109
+ if (!column) return null;
6110
+ const bang = column.nullable === false ? "!" : "";
6111
+ return `${fieldName(property)}: ${columnGqlTypeOf(table, column)}${bang}`;
6112
+ });
6113
+ if (setArgs.some((arg) => arg === null)) continue;
6114
+ lines.push(` ${fieldName(mutation.name)}(${pkArg}, ${setArgs.join(", ")}): ${names.typename}`);
6115
+ }
6116
+ return lines;
6117
+ }
6118
+
6119
+ // src/compiler-gql/default-operations.ts
6120
+ var DEFAULT_LIST_LIMIT = 100;
6121
+ function typeReference(type, nonNull = false) {
6122
+ if (type instanceof graphql.GraphQLNonNull) return `${typeReference(type.ofType, true)}`;
6123
+ const inner = type instanceof graphql.GraphQLList ? `[${typeReference(type.ofType)}]` : graphql.getNamedType(type).name;
6124
+ return `${inner}${nonNull ? "!" : ""}`;
6125
+ }
6126
+ function objectScalarFields(type) {
6127
+ return Object.entries(type.getFields()).filter(([, field]) => {
6128
+ const named = graphql.getNamedType(field.type);
6129
+ return named instanceof graphql.GraphQLScalarType || named instanceof graphql.GraphQLEnumType;
6130
+ }).map(([name2]) => name2);
6131
+ }
6132
+ function argumentInputFields(arg) {
6133
+ if (arg.name !== "pkColumns") return void 0;
6134
+ const input = graphql.getNamedType(arg.type);
6135
+ if (!(input instanceof graphql.GraphQLInputObjectType)) return void 0;
6136
+ return Object.values(input.getFields()).map((field) => ({
6137
+ name: field.name,
6138
+ type: field.type,
6139
+ variable: field.name
6140
+ }));
6141
+ }
6142
+ function inputFieldsTouchWriteback(root, writebackColumns) {
6143
+ if (!root) return false;
6144
+ const input = graphql.getNamedType(root.type);
6145
+ return input instanceof graphql.GraphQLInputObjectType && Object.keys(input.getFields()).some((field) => writebackColumns.has(field));
6146
+ }
6147
+ function variableDefinitions(args, defaults = {}) {
6148
+ return args.flatMap((arg) => {
6149
+ const inputFields = argumentInputFields(arg);
6150
+ if (inputFields) {
6151
+ return inputFields.map((field) => `$${field.variable}: ${typeReference(field.type)}`);
6152
+ }
6153
+ const defaultValue = defaults[arg.name];
6154
+ return [`$${arg.name}: ${typeReference(arg.type)}${defaultValue === void 0 ? "" : ` = ${defaultValue}`}`];
6155
+ }).join(", ");
6156
+ }
6157
+ function argumentUses(args) {
6158
+ return args.map((arg) => {
6159
+ const inputFields = argumentInputFields(arg);
6160
+ if (inputFields) {
6161
+ const values = inputFields.map((field) => `${field.name}: $${field.variable}`);
6162
+ return `${arg.name}: { ${values.join(", ")} }`;
6163
+ }
6164
+ return `${arg.name}: $${arg.name}`;
6165
+ }).join(", ");
6166
+ }
6167
+ function callArguments(args) {
6168
+ const uses = argumentUses(args);
6169
+ return uses ? `(${uses})` : "";
6170
+ }
6171
+ function listOperationName(table) {
6172
+ const raw = pascalCase(table);
6173
+ if (raw !== typeName(table)) return `List${raw}`;
6174
+ if (raw.endsWith("y") && !/[aeiou]y$/.test(raw)) return `List${raw.slice(0, -1)}ies`;
6175
+ if (/(s|x|ch|sh)$/.test(raw)) return `List${raw}es`;
6176
+ return `List${raw}s`;
6177
+ }
6178
+ function document(path, operation) {
6179
+ return { path: `graphql/__generated__/${path}.graphql`, contents: `${operation.trim()}
6180
+ ` };
6181
+ }
6182
+ function generateDefaultOperations(canonical, sdl, existingOperationNames = []) {
6183
+ const definition = canonicalDefinitionSchema.parse(canonical);
6184
+ const composed = composeNamespace(definition).definition;
6185
+ const schema = parseSdl(sdl);
6186
+ const query = schema.getQueryType();
6187
+ const mutation = schema.getMutationType();
6188
+ if (!query) return [];
6189
+ const owned = /* @__PURE__ */ new Set([
6190
+ ...definition.tables.map((table) => table.table),
6191
+ ...(definition.views ?? []).map((view) => view.view)
6192
+ ]);
6193
+ const occupied = new Set(existingOperationNames);
6194
+ const generatedNames = /* @__PURE__ */ new Map();
6195
+ const results = [];
6196
+ const claimName = (name2, relation) => {
6197
+ if (occupied.has(name2)) return false;
6198
+ const previous = generatedNames.get(name2);
6199
+ if (previous !== void 0) throw new Error(`default operation name collision '${name2}' for '${previous}' and '${relation}'`);
6200
+ generatedNames.set(name2, relation);
6201
+ return true;
6202
+ };
6203
+ for (const relation of canonicalRelations(composed).filter((item) => owned.has(item.table) && item.internal !== true)) {
6204
+ const names = tableNames(relation.table);
6205
+ const fields = query.getFields();
6206
+ const objectType = schema.getType(names.typename);
6207
+ const scalarSelection = objectType instanceof graphql.GraphQLObjectType ? objectScalarFields(objectType) : [];
6208
+ const selection = scalarSelection.length > 0 ? `{ ${scalarSelection.join(" ")} }` : "";
6209
+ const byPk = fields[names.byPkRoot];
6210
+ const getName = `Get${names.typename}`;
6211
+ if (byPk && selection && claimName(getName, relation.table)) {
6212
+ const vars = variableDefinitions(byPk.args);
6213
+ results.push(document(getName, `query ${getName}${vars ? `(${vars})` : ""} { record: ${names.byPkRoot}${callArguments(byPk.args)} ${selection} }`));
6214
+ }
6215
+ const list2 = fields[names.selectRoot];
6216
+ const listName = listOperationName(relation.table);
6217
+ if (list2 && selection && claimName(listName, relation.table)) {
6218
+ const listArgs = list2.args.filter((arg) => ["where", "orderBy", "limit", "offset"].includes(arg.name));
6219
+ const defaults = { limit: String(DEFAULT_LIST_LIMIT), offset: "0" };
6220
+ const vars = variableDefinitions(listArgs, defaults);
6221
+ results.push(document(listName, `query ${listName}${vars ? `(${vars})` : ""} { records: ${names.selectRoot}${callArguments(listArgs)} ${selection} }`));
6222
+ }
6223
+ if (!mutation || !selection) continue;
6224
+ const mutationFields = mutation.getFields();
6225
+ const mutationOps = [
6226
+ { root: names.insertOneRoot, name: `Create${names.typename}`, args: ["object"], writeArg: "object" },
6227
+ { root: names.updateByPkRoot, name: `Update${names.typename}`, args: ["pkColumns", "_set"], writeArg: "_set" },
6228
+ { root: names.deleteByPkRoot, name: `Delete${names.typename}` }
6229
+ ];
6230
+ const writebackColumns = new Set((relation.resolved?.sources.flatMap((source) => source.writeback?.columns ?? []) ?? []).map(fieldName));
6231
+ for (const item of mutationOps) {
6232
+ const root = mutationFields[item.root];
6233
+ if (root && item.writeArg && inputFieldsTouchWriteback(root.args.find((arg) => arg.name === item.writeArg), writebackColumns)) continue;
6234
+ if (!root || !claimName(item.name, relation.table)) continue;
6235
+ const args = item.args ? root.args.filter((arg) => item.args?.includes(arg.name)) : root.args;
6236
+ const vars = variableDefinitions(args);
6237
+ results.push(document(item.name, `mutation ${item.name}${vars ? `(${vars})` : ""} { record: ${item.root}${callArguments(args)} ${selection} }`));
6238
+ }
6239
+ }
6240
+ return results.map((source) => {
6241
+ try {
6242
+ return { ...source, contents: `${graphql.print(graphql.parse(source.contents)).trim()}
6243
+ ` };
6244
+ } catch (error) {
6245
+ throw new Error(`${error instanceof Error ? error.message : String(error)}
6246
+ ${source.contents}`);
6247
+ }
6248
+ });
6249
+ }
6250
+ function compileDefaultOperations(canonical, existingOperationNames = []) {
6251
+ const pinnedColumns = Object.fromEntries(
6252
+ Object.entries(computePinnedColumnsByTable(canonical)).map(([table, pins]) => [table, pins.map((pin) => pin.column)])
6253
+ );
6254
+ const sdl = generateSdl(canonical, { pinnedColumns, includeSyncedReads: true });
6255
+ const documents = generateDefaultOperations(canonical, sdl, existingOperationNames);
6256
+ return compileNamespaceOrThrow({ canonical, sdl, documents }).artifact;
6257
+ }
6258
+
5432
6259
  // src/engine/types.ts
5433
6260
  var SQL_TYPE_NAMES = {
5434
6261
  double: "double precision",
@@ -6159,9 +6986,9 @@ async function compileOperationDocuments(input) {
6159
6986
  return compileSqlDocuments({ input, result, sqlDocuments });
6160
6987
  }
6161
6988
  async function compileSqlDocuments({ input, result, sqlDocuments }) {
6162
- for (const document of sqlDocuments) {
6989
+ for (const document2 of sqlDocuments) {
6163
6990
  try {
6164
- const definition = defineOperation(JSON.parse(document.contents));
6991
+ const definition = defineOperation(JSON.parse(document2.contents));
6165
6992
  if (definition.namespace !== input.canonical.namespace) throw new Error("SQL operation namespace does not match its owner");
6166
6993
  if (result.artifact.operations[definition.name]) throw new Error("duplicate operation name");
6167
6994
  const roles = input.canonical.capabilities.roles;
@@ -6241,7 +7068,7 @@ async function compileSqlDocuments({ input, result, sqlDocuments }) {
6241
7068
  return { ok: false, diagnostics: [...result.diagnostics, {
6242
7069
  severity: "error",
6243
7070
  code: "invalid-sql-operation",
6244
- document: document.path,
7071
+ document: document2.path,
6245
7072
  message: error instanceof Error ? error.message : "invalid SQL operation"
6246
7073
  }] };
6247
7074
  }
@@ -6449,6 +7276,7 @@ exports.classifyInputType = classifyInputType;
6449
7276
  exports.collectPinnedColumns = collectPinnedColumns;
6450
7277
  exports.compileBuiltinSqlArtifact = compileBuiltinSqlArtifact;
6451
7278
  exports.compileDatasetPreviews = compileDatasetPreviews;
7279
+ exports.compileDefaultOperations = compileDefaultOperations;
6452
7280
  exports.compileNamespace = compileNamespace;
6453
7281
  exports.compileNamespaceOrThrow = compileNamespaceOrThrow;
6454
7282
  exports.compileOperationDocuments = compileOperationDocuments;
@@ -6462,6 +7290,7 @@ exports.computeSchemaHash = computeSchemaHash;
6462
7290
  exports.defineOperation = defineOperation;
6463
7291
  exports.enumTypeName = enumTypeName;
6464
7292
  exports.flattenOperation = flattenOperation;
7293
+ exports.generateDefaultOperations = generateDefaultOperations;
6465
7294
  exports.injectPolicies = injectPolicies;
6466
7295
  exports.inputTypeName = inputTypeName;
6467
7296
  exports.isSqlOperationDocument = isSqlOperationDocument;