@sequenceholdings/orm 2.3.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 +337 -86
  14. package/dist/cli.cjs.map +1 -1
  15. package/dist/cli.js +337 -86
  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 +493 -52
  24. package/dist/compiler.cjs.map +1 -1
  25. package/dist/compiler.d.cts +22 -7
  26. package/dist/compiler.d.ts +22 -7
  27. package/dist/compiler.js +493 -53
  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 +145 -22
  46. package/dist/predicate-v2.cjs.map +1 -1
  47. package/dist/predicate-v2.d.cts +41 -4
  48. package/dist/predicate-v2.d.ts +41 -4
  49. package/dist/predicate-v2.js +145 -22
  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
@@ -1,9 +1,9 @@
1
1
  import { ColumnType, CanonicalColumn, ComparatorKind, CanonicalFunctionRef, CanonicalFetchShape, CanonicalDefinition, CanonicalTable } from './canonical.cjs';
2
- import { b as CellPart } from './constants-C6EG6Wq7.cjs';
2
+ import { b as CellPart } from './constants-Dou1RkTo.cjs';
3
3
  import { ColumnsSelection } from 'drizzle-orm';
4
4
  import { TypedQueryBuilder } from 'drizzle-orm/query-builders/query-builder';
5
5
  import { QueryBuilder, PgView, PgTable, AnyPgColumn } from 'drizzle-orm/pg-core';
6
- export { S as SqlOperationDefinition, d as defineOperation } from './definition-DjfC7Lll.cjs';
6
+ export { S as SqlOperationDefinition, d as defineOperation } from './definition-B99BsOAO.cjs';
7
7
  import 'zod';
8
8
  import './policy-1iZbGnZZ.cjs';
9
9
 
@@ -611,7 +611,10 @@ interface SyncedTableConfig {
611
611
  /** Reflected read-only source as a safe qualified identifier: `<schema>.<table>`. */
612
612
  source: string;
613
613
  description?: string;
614
- /** Composite primary key: property names (or column names). Mutually exclusive with column-level `.primaryKey()`. */
614
+ /**
615
+ * Primary-key property/column names, mutually exclusive with column-level
616
+ * `.primaryKey()`. Explicit `[]` declares a read-only bag with no row identity.
617
+ */
615
618
  primaryKey?: readonly string[];
616
619
  links?: Record<string, SeqLink>;
617
620
  policies?: SyncedTablePoliciesInput;
@@ -726,11 +729,12 @@ declare function syncedContractSurface({ namespace, table, columns, primary_key,
726
729
  }): Record<string, unknown>;
727
730
  declare function computeSyncedContractHash(surface: Record<string, unknown>): string;
728
731
  /**
729
- * Extract the Managed Pipelines contract from a typed canonical synced table.
732
+ * Extract the source contract from a typed canonical synced table.
730
733
  *
731
- * Requires non-empty columns and a primary key (the typed `defineSyncedTable`
732
- * authoring rules). Enum columns are rejected — they have no pipeline-type
733
- * preimage in the ORM↔pipeline bijection.
734
+ * Requires non-empty columns and an explicit key contract. An empty primary
735
+ * key describes an unkeyed read-only source; Managed Pipelines additionally
736
+ * requires a non-empty key. Enum columns are rejected — they have no
737
+ * pipeline-type preimage in the shared type bijection.
734
738
  */
735
739
  declare function extractOrmSyncedTableContract({ namespace, table, }: {
736
740
  namespace: string;
@@ -1,9 +1,9 @@
1
1
  import { ColumnType, CanonicalColumn, ComparatorKind, CanonicalFunctionRef, CanonicalFetchShape, CanonicalDefinition, CanonicalTable } from './canonical.js';
2
- import { b as CellPart } from './constants-C6EG6Wq7.js';
2
+ import { b as CellPart } from './constants-Dou1RkTo.js';
3
3
  import { ColumnsSelection } from 'drizzle-orm';
4
4
  import { TypedQueryBuilder } from 'drizzle-orm/query-builders/query-builder';
5
5
  import { QueryBuilder, PgView, PgTable, AnyPgColumn } from 'drizzle-orm/pg-core';
6
- export { S as SqlOperationDefinition, d as defineOperation } from './definition-DjfC7Lll.js';
6
+ export { S as SqlOperationDefinition, d as defineOperation } from './definition-B99BsOAO.js';
7
7
  import 'zod';
8
8
  import './policy-1iZbGnZZ.js';
9
9
 
@@ -611,7 +611,10 @@ interface SyncedTableConfig {
611
611
  /** Reflected read-only source as a safe qualified identifier: `<schema>.<table>`. */
612
612
  source: string;
613
613
  description?: string;
614
- /** Composite primary key: property names (or column names). Mutually exclusive with column-level `.primaryKey()`. */
614
+ /**
615
+ * Primary-key property/column names, mutually exclusive with column-level
616
+ * `.primaryKey()`. Explicit `[]` declares a read-only bag with no row identity.
617
+ */
615
618
  primaryKey?: readonly string[];
616
619
  links?: Record<string, SeqLink>;
617
620
  policies?: SyncedTablePoliciesInput;
@@ -726,11 +729,12 @@ declare function syncedContractSurface({ namespace, table, columns, primary_key,
726
729
  }): Record<string, unknown>;
727
730
  declare function computeSyncedContractHash(surface: Record<string, unknown>): string;
728
731
  /**
729
- * Extract the Managed Pipelines contract from a typed canonical synced table.
732
+ * Extract the source contract from a typed canonical synced table.
730
733
  *
731
- * Requires non-empty columns and a primary key (the typed `defineSyncedTable`
732
- * authoring rules). Enum columns are rejected — they have no pipeline-type
733
- * preimage in the ORM↔pipeline bijection.
734
+ * Requires non-empty columns and an explicit key contract. An empty primary
735
+ * key describes an unkeyed read-only source; Managed Pipelines additionally
736
+ * requires a non-empty key. Enum columns are rejected — they have no
737
+ * pipeline-type preimage in the shared type bijection.
734
738
  */
735
739
  declare function extractOrmSyncedTableContract({ namespace, table, }: {
736
740
  namespace: string;
package/dist/authoring.js CHANGED
@@ -151,7 +151,7 @@ var t = {
151
151
  };
152
152
 
153
153
  // src/constants.ts
154
- var NAMESPACE_PATTERN = /^[a-z][a-z0-9_]{0,40}$/;
154
+ var NAMESPACE_PATTERN = /^(?!(?:events|native_sources)$)[a-z][a-z0-9_]{0,40}$/;
155
155
  var IDENTIFIER_PATTERN = /^[a-z][a-z0-9_]*$/;
156
156
  var COLUMN_IDENTIFIER_PATTERN = /^_?[a-z][a-z0-9_]*$/;
157
157
  var MAX_IDENTIFIER_LENGTH = 63;
@@ -365,10 +365,10 @@ function defineSyncedTable(name2, columnsOrConfig, maybeConfig) {
365
365
  if (builder.isPrimaryKey) columnLevelPk.push(propertyName);
366
366
  }
367
367
  if (entries.length > 0) {
368
- const hasConfigPk = config.primaryKey !== void 0 && config.primaryKey.length > 0;
368
+ const hasConfigPk = config.primaryKey !== void 0;
369
369
  if (columnLevelPk.length === 0 && !hasConfigPk) {
370
370
  throw new OrmDefinitionError(
371
- `synced table "${name2}" declares columns but no primary key \u2014 use .primaryKey() or config.primaryKey`,
371
+ `synced table "${name2}" declares columns but no primary key \u2014 use .primaryKey(), config.primaryKey, or explicit primaryKey: [] for an unkeyed read-only source`,
372
372
  file
373
373
  );
374
374
  }
@@ -1229,6 +1229,7 @@ function validateResolvedView({ view, tables, views = [] }) {
1229
1229
  function validateSource({ scope, source, table }) {
1230
1230
  const { fail } = scope;
1231
1231
  if (source.kind === "etl" && table.source === void 0) fail(`etl source '${source.name}' must reference a synced table`);
1232
+ if (source.kind === "etl" && table.primaryKey?.length === 0) fail(`etl source '${source.name}' cannot use an unkeyed synced table for resolved row identity`);
1232
1233
  if (source.kind !== "etl" && (table.internal !== true || table.cellMetadata !== true)) {
1233
1234
  fail(`${source.kind} source '${source.name}' must reference an internal table with cell metadata`);
1234
1235
  }
@@ -1677,7 +1678,7 @@ var canonicalTableSchema = z.object({
1677
1678
  /** Synced/reflected read-only tables (`source: schema.table`) — v1 semantics. */
1678
1679
  source: z.string().regex(QUALIFIED_TABLE_PATTERN).optional(),
1679
1680
  columns: z.array(canonicalColumnSchema).default([]),
1680
- primaryKey: z.array(columnIdentifier).min(1).max(8).optional(),
1681
+ primaryKey: z.array(columnIdentifier).max(8).optional(),
1681
1682
  links: z.array(canonicalLinkSchema).default([]),
1682
1683
  indexes: z.array(canonicalIndexSchema).default([]),
1683
1684
  /** Omitted by old definitions, preserving their existing content hashes. */
@@ -1713,6 +1714,29 @@ var canonicalTableSchema = z.object({
1713
1714
  * data plane. Omitted otherwise.
1714
1715
  */
1715
1716
  materializes: identifier2.optional()
1717
+ }).superRefine((table, ctx) => {
1718
+ if (table.primaryKey?.length !== 0) return;
1719
+ const fail = (message, path = ["primaryKey"]) => ctx.addIssue({ code: "custom", path, message: `unkeyed table '${table.table}' ${message}` });
1720
+ if (table.source === void 0 || table.columns.length === 0) {
1721
+ fail("requires a typed synced source");
1722
+ }
1723
+ if ([table.policies.write, table.policies.insert, table.policies.update].some((policy) => policy !== void 0)) {
1724
+ fail("is read-only and cannot declare write policies", ["policies"]);
1725
+ }
1726
+ const ownedCollections = [table.indexes, table.actions, table.checks, table.foreignKeys, table.cowMutations];
1727
+ const ownedMetadata = [table.cellMetadata, table.internal, table.materializes, table.renamedFrom];
1728
+ if (ownedCollections.some((items) => items !== void 0 && items.length > 0) || ownedMetadata.some((value) => value !== void 0)) {
1729
+ fail("cannot declare owned storage, constraints or identity operations");
1730
+ }
1731
+ for (const [index, column] of table.columns.entries()) {
1732
+ const ownedColumnMetadata = [column.default, column.defaultFn, column.onUpdateFn, column.renamedFrom, column.cast, column.cell];
1733
+ if (column.unique || ownedColumnMetadata.some((value) => value !== void 0)) {
1734
+ fail("cannot declare column uniqueness, mutation defaults or migration metadata", ["columns", index]);
1735
+ }
1736
+ }
1737
+ for (const [index, link] of table.links.entries()) {
1738
+ if (link.enforce || link.kind === "toMany") fail("cannot provide an identity for this link", ["links", index]);
1739
+ }
1716
1740
  });
1717
1741
  var MAX_VIEW_QUERY = 1e5;
1718
1742
  var MAX_RESOLVED_VIEW_QUERY = 5e6;
@@ -1769,6 +1793,26 @@ var canonicalViewSchema = z.object({
1769
1793
  }
1770
1794
  }
1771
1795
  });
1796
+ function validateUnkeyedLinkIdentities({ definition, ctx }) {
1797
+ const tables = new Map(definition.tables.map((table) => [table.table, table]));
1798
+ const relations = [
1799
+ ...definition.tables.map((table, index) => ({ kind: "tables", index, links: table.links })),
1800
+ ...(definition.views ?? []).map((view, index) => ({ kind: "views", index, links: view.links }))
1801
+ ];
1802
+ for (const relation of relations) {
1803
+ for (const [linkIndex, link] of relation.links.entries()) {
1804
+ if (link.kind !== "toOne" || link.namespace !== void 0 && link.namespace !== definition.namespace) continue;
1805
+ const target = link.target === void 0 ? void 0 : tables.get(link.target);
1806
+ if (target?.source !== void 0 && target.primaryKey?.length === 0) {
1807
+ ctx.addIssue({
1808
+ code: "custom",
1809
+ path: [relation.kind, relation.index, "links", linkIndex],
1810
+ message: `link '${link.name}' cannot use unkeyed table '${target.table}' as a to-one identity`
1811
+ });
1812
+ }
1813
+ }
1814
+ }
1815
+ }
1772
1816
  var CELL_PART_TYPES = {
1773
1817
  at: "timestamptz",
1774
1818
  by: "text",
@@ -1832,7 +1876,7 @@ var exportGateSchema = z.union([z.literal(true), z.object({ capability: z.string
1832
1876
  var relationExportSchema = z.object({ read: exportGateSchema, write: exportGateSchema.optional() }).strict();
1833
1877
  var localDefinitionSchema = z.object({
1834
1878
  definition_format: z.literal(CANONICAL_FORMAT),
1835
- namespace: identifier2.max(41),
1879
+ namespace: identifier2.max(41).regex(NAMESPACE_PATTERN, "invalid or reserved ORM namespace"),
1836
1880
  description: z.string().max(2e3).optional(),
1837
1881
  enums: z.array(canonicalEnumSchema).default([]),
1838
1882
  tables: z.array(canonicalTableSchema).min(0).max(500),
@@ -1866,6 +1910,7 @@ var localDefinitionSchema = z.object({
1866
1910
  }
1867
1911
  }
1868
1912
  const fkTables = new Map(definition.tables.map((table) => [table.table, table]));
1913
+ validateUnkeyedLinkIdentities({ definition, ctx });
1869
1914
  const relations = /* @__PURE__ */ new Set([...fkTables.keys(), ...(definition.views ?? []).map((view) => view.view)]);
1870
1915
  for (const name2 of Object.keys(definition.exports ?? {})) {
1871
1916
  if (!relations.has(name2)) ctx.addIssue({ code: "custom", path: ["exports", name2], message: `export '${name2}' is not a local object` });
@@ -2155,6 +2200,7 @@ function planEtl(input, source) {
2155
2200
  const table = typeof source.table === "function" ? source.table() : source.table;
2156
2201
  if (!isSeqTable(table) || table.source === void 0) fail(`etl source "${sourceName}" must reference a defineSyncedTable`);
2157
2202
  const synced = table;
2203
+ if (synced.config.primaryKey?.length === 0) fail(`etl source "${sourceName}" cannot use an unkeyed synced table for resolved row identity`);
2158
2204
  if (!(pk in synced.columns)) fail(`etl source "${sourceName}" table "${synced.tableName}" has no "${pk}" column`);
2159
2205
  const supplied = source.columns ? [...source.columns] : dataColumns.filter((column) => column in synced.columns);
2160
2206
  assertColumns(input, supplied, `etl source "${sourceName}"`);
@@ -3164,9 +3210,9 @@ function extractOrmSyncedTableContract({
3164
3210
  );
3165
3211
  }
3166
3212
  const primaryKey = table.primaryKey;
3167
- if (primaryKey === void 0 || primaryKey.length === 0) {
3213
+ if (primaryKey === void 0) {
3168
3214
  throw new OrmDefinitionError(
3169
- `synced table "${table.table}" has no primary key \u2014 typed synced contracts require a primary key`
3215
+ `synced table "${table.table}" has no primary key contract \u2014 declare a key or explicit primaryKey: []`
3170
3216
  );
3171
3217
  }
3172
3218
  const pkSet = new Set(primaryKey);