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