@sequenceholdings/orm 2.4.0 → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/dist/authoring.cjs +53 -7
  2. package/dist/authoring.cjs.map +1 -1
  3. package/dist/authoring.d.cts +11 -7
  4. package/dist/authoring.d.ts +11 -7
  5. package/dist/authoring.js +53 -7
  6. package/dist/authoring.js.map +1 -1
  7. package/dist/canonical.cjs +48 -2
  8. package/dist/canonical.cjs.map +1 -1
  9. package/dist/canonical.d.cts +72 -72
  10. package/dist/canonical.d.ts +72 -72
  11. package/dist/canonical.js +48 -2
  12. package/dist/canonical.js.map +1 -1
  13. package/dist/cli.cjs +237 -20
  14. package/dist/cli.cjs.map +1 -1
  15. package/dist/cli.js +237 -20
  16. package/dist/cli.js.map +1 -1
  17. package/dist/client.cjs +1 -1
  18. package/dist/client.cjs.map +1 -1
  19. package/dist/client.d.cts +1 -1
  20. package/dist/client.d.ts +1 -1
  21. package/dist/client.js +1 -1
  22. package/dist/client.js.map +1 -1
  23. package/dist/compiler.cjs +386 -14
  24. package/dist/compiler.cjs.map +1 -1
  25. package/dist/compiler.d.cts +16 -3
  26. package/dist/compiler.d.ts +16 -3
  27. package/dist/compiler.js +386 -15
  28. package/dist/compiler.js.map +1 -1
  29. package/dist/{constants-C6EG6Wq7.d.cts → constants-Dou1RkTo.d.cts} +7 -2
  30. package/dist/{constants-C6EG6Wq7.d.ts → constants-Dou1RkTo.d.ts} +7 -2
  31. package/dist/dynamic-input.d.cts +1 -1
  32. package/dist/dynamic-input.d.ts +1 -1
  33. package/dist/index.cjs +329 -130
  34. package/dist/index.cjs.map +1 -1
  35. package/dist/index.d.cts +66 -58
  36. package/dist/index.d.ts +66 -58
  37. package/dist/index.js +329 -131
  38. package/dist/index.js.map +1 -1
  39. package/dist/ir.cjs +50 -3
  40. package/dist/ir.cjs.map +1 -1
  41. package/dist/ir.d.cts +71 -71
  42. package/dist/ir.d.ts +71 -71
  43. package/dist/ir.js +50 -3
  44. package/dist/ir.js.map +1 -1
  45. package/dist/predicate-v2.cjs +50 -3
  46. package/dist/predicate-v2.cjs.map +1 -1
  47. package/dist/predicate-v2.d.cts +1 -1
  48. package/dist/predicate-v2.d.ts +1 -1
  49. package/dist/predicate-v2.js +50 -3
  50. package/dist/predicate-v2.js.map +1 -1
  51. package/dist/sdl.cjs +53 -3
  52. package/dist/sdl.cjs.map +1 -1
  53. package/dist/sdl.d.cts +3 -1
  54. package/dist/sdl.d.ts +3 -1
  55. package/dist/sdl.js +53 -3
  56. package/dist/sdl.js.map +1 -1
  57. package/package.json +1 -1
  58. package/dist/{definition-DjfC7Lll.d.cts → definition-B99BsOAO.d.cts} +4 -4
  59. package/dist/{definition-DjfC7Lll.d.ts → definition-B99BsOAO.d.ts} +4 -4
@@ -154,7 +154,7 @@ var t = {
154
154
  };
155
155
 
156
156
  // src/constants.ts
157
- var NAMESPACE_PATTERN = /^[a-z][a-z0-9_]{0,40}$/;
157
+ var NAMESPACE_PATTERN = /^(?!(?:events|native_sources)$)[a-z][a-z0-9_]{0,40}$/;
158
158
  var IDENTIFIER_PATTERN = /^[a-z][a-z0-9_]*$/;
159
159
  var COLUMN_IDENTIFIER_PATTERN = /^_?[a-z][a-z0-9_]*$/;
160
160
  var MAX_IDENTIFIER_LENGTH = 63;
@@ -368,10 +368,10 @@ function defineSyncedTable(name2, columnsOrConfig, maybeConfig) {
368
368
  if (builder.isPrimaryKey) columnLevelPk.push(propertyName);
369
369
  }
370
370
  if (entries.length > 0) {
371
- const hasConfigPk = config.primaryKey !== void 0 && config.primaryKey.length > 0;
371
+ const hasConfigPk = config.primaryKey !== void 0;
372
372
  if (columnLevelPk.length === 0 && !hasConfigPk) {
373
373
  throw new OrmDefinitionError(
374
- `synced table "${name2}" declares columns but no primary key \u2014 use .primaryKey() or config.primaryKey`,
374
+ `synced table "${name2}" declares columns but no primary key \u2014 use .primaryKey(), config.primaryKey, or explicit primaryKey: [] for an unkeyed read-only source`,
375
375
  file
376
376
  );
377
377
  }
@@ -1232,6 +1232,7 @@ function validateResolvedView({ view, tables, views = [] }) {
1232
1232
  function validateSource({ scope, source, table }) {
1233
1233
  const { fail } = scope;
1234
1234
  if (source.kind === "etl" && table.source === void 0) fail(`etl source '${source.name}' must reference a synced table`);
1235
+ if (source.kind === "etl" && table.primaryKey?.length === 0) fail(`etl source '${source.name}' cannot use an unkeyed synced table for resolved row identity`);
1235
1236
  if (source.kind !== "etl" && (table.internal !== true || table.cellMetadata !== true)) {
1236
1237
  fail(`${source.kind} source '${source.name}' must reference an internal table with cell metadata`);
1237
1238
  }
@@ -1680,7 +1681,7 @@ var canonicalTableSchema = zod.z.object({
1680
1681
  /** Synced/reflected read-only tables (`source: schema.table`) — v1 semantics. */
1681
1682
  source: zod.z.string().regex(QUALIFIED_TABLE_PATTERN).optional(),
1682
1683
  columns: zod.z.array(canonicalColumnSchema).default([]),
1683
- primaryKey: zod.z.array(columnIdentifier).min(1).max(8).optional(),
1684
+ primaryKey: zod.z.array(columnIdentifier).max(8).optional(),
1684
1685
  links: zod.z.array(canonicalLinkSchema).default([]),
1685
1686
  indexes: zod.z.array(canonicalIndexSchema).default([]),
1686
1687
  /** Omitted by old definitions, preserving their existing content hashes. */
@@ -1716,6 +1717,29 @@ var canonicalTableSchema = zod.z.object({
1716
1717
  * data plane. Omitted otherwise.
1717
1718
  */
1718
1719
  materializes: identifier2.optional()
1720
+ }).superRefine((table, ctx) => {
1721
+ if (table.primaryKey?.length !== 0) return;
1722
+ const fail = (message, path = ["primaryKey"]) => ctx.addIssue({ code: "custom", path, message: `unkeyed table '${table.table}' ${message}` });
1723
+ if (table.source === void 0 || table.columns.length === 0) {
1724
+ fail("requires a typed synced source");
1725
+ }
1726
+ if ([table.policies.write, table.policies.insert, table.policies.update].some((policy) => policy !== void 0)) {
1727
+ fail("is read-only and cannot declare write policies", ["policies"]);
1728
+ }
1729
+ const ownedCollections = [table.indexes, table.actions, table.checks, table.foreignKeys, table.cowMutations];
1730
+ const ownedMetadata = [table.cellMetadata, table.internal, table.materializes, table.renamedFrom];
1731
+ if (ownedCollections.some((items) => items !== void 0 && items.length > 0) || ownedMetadata.some((value) => value !== void 0)) {
1732
+ fail("cannot declare owned storage, constraints or identity operations");
1733
+ }
1734
+ for (const [index, column] of table.columns.entries()) {
1735
+ const ownedColumnMetadata = [column.default, column.defaultFn, column.onUpdateFn, column.renamedFrom, column.cast, column.cell];
1736
+ if (column.unique || ownedColumnMetadata.some((value) => value !== void 0)) {
1737
+ fail("cannot declare column uniqueness, mutation defaults or migration metadata", ["columns", index]);
1738
+ }
1739
+ }
1740
+ for (const [index, link] of table.links.entries()) {
1741
+ if (link.enforce || link.kind === "toMany") fail("cannot provide an identity for this link", ["links", index]);
1742
+ }
1719
1743
  });
1720
1744
  var MAX_VIEW_QUERY = 1e5;
1721
1745
  var MAX_RESOLVED_VIEW_QUERY = 5e6;
@@ -1772,6 +1796,26 @@ var canonicalViewSchema = zod.z.object({
1772
1796
  }
1773
1797
  }
1774
1798
  });
1799
+ function validateUnkeyedLinkIdentities({ definition, ctx }) {
1800
+ const tables = new Map(definition.tables.map((table) => [table.table, table]));
1801
+ const relations = [
1802
+ ...definition.tables.map((table, index) => ({ kind: "tables", index, links: table.links })),
1803
+ ...(definition.views ?? []).map((view, index) => ({ kind: "views", index, links: view.links }))
1804
+ ];
1805
+ for (const relation of relations) {
1806
+ for (const [linkIndex, link] of relation.links.entries()) {
1807
+ if (link.kind !== "toOne" || link.namespace !== void 0 && link.namespace !== definition.namespace) continue;
1808
+ const target = link.target === void 0 ? void 0 : tables.get(link.target);
1809
+ if (target?.source !== void 0 && target.primaryKey?.length === 0) {
1810
+ ctx.addIssue({
1811
+ code: "custom",
1812
+ path: [relation.kind, relation.index, "links", linkIndex],
1813
+ message: `link '${link.name}' cannot use unkeyed table '${target.table}' as a to-one identity`
1814
+ });
1815
+ }
1816
+ }
1817
+ }
1818
+ }
1775
1819
  var CELL_PART_TYPES = {
1776
1820
  at: "timestamptz",
1777
1821
  by: "text",
@@ -1835,7 +1879,7 @@ var exportGateSchema = zod.z.union([zod.z.literal(true), zod.z.object({ capabili
1835
1879
  var relationExportSchema = zod.z.object({ read: exportGateSchema, write: exportGateSchema.optional() }).strict();
1836
1880
  var localDefinitionSchema = zod.z.object({
1837
1881
  definition_format: zod.z.literal(CANONICAL_FORMAT),
1838
- namespace: identifier2.max(41),
1882
+ namespace: identifier2.max(41).regex(NAMESPACE_PATTERN, "invalid or reserved ORM namespace"),
1839
1883
  description: zod.z.string().max(2e3).optional(),
1840
1884
  enums: zod.z.array(canonicalEnumSchema).default([]),
1841
1885
  tables: zod.z.array(canonicalTableSchema).min(0).max(500),
@@ -1869,6 +1913,7 @@ var localDefinitionSchema = zod.z.object({
1869
1913
  }
1870
1914
  }
1871
1915
  const fkTables = new Map(definition.tables.map((table) => [table.table, table]));
1916
+ validateUnkeyedLinkIdentities({ definition, ctx });
1872
1917
  const relations = /* @__PURE__ */ new Set([...fkTables.keys(), ...(definition.views ?? []).map((view) => view.view)]);
1873
1918
  for (const name2 of Object.keys(definition.exports ?? {})) {
1874
1919
  if (!relations.has(name2)) ctx.addIssue({ code: "custom", path: ["exports", name2], message: `export '${name2}' is not a local object` });
@@ -2158,6 +2203,7 @@ function planEtl(input, source) {
2158
2203
  const table = typeof source.table === "function" ? source.table() : source.table;
2159
2204
  if (!isSeqTable(table) || table.source === void 0) fail(`etl source "${sourceName}" must reference a defineSyncedTable`);
2160
2205
  const synced = table;
2206
+ if (synced.config.primaryKey?.length === 0) fail(`etl source "${sourceName}" cannot use an unkeyed synced table for resolved row identity`);
2161
2207
  if (!(pk in synced.columns)) fail(`etl source "${sourceName}" table "${synced.tableName}" has no "${pk}" column`);
2162
2208
  const supplied = source.columns ? [...source.columns] : dataColumns.filter((column) => column in synced.columns);
2163
2209
  assertColumns(input, supplied, `etl source "${sourceName}"`);
@@ -3167,9 +3213,9 @@ function extractOrmSyncedTableContract({
3167
3213
  );
3168
3214
  }
3169
3215
  const primaryKey = table.primaryKey;
3170
- if (primaryKey === void 0 || primaryKey.length === 0) {
3216
+ if (primaryKey === void 0) {
3171
3217
  throw new OrmDefinitionError(
3172
- `synced table "${table.table}" has no primary key \u2014 typed synced contracts require a primary key`
3218
+ `synced table "${table.table}" has no primary key contract \u2014 declare a key or explicit primaryKey: []`
3173
3219
  );
3174
3220
  }
3175
3221
  const pkSet = new Set(primaryKey);