@substrat-run/contracts 0.76.0 → 0.77.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/model.d.ts CHANGED
@@ -44,6 +44,31 @@ export interface EntityDef<Names extends string = string> {
44
44
  * kernel means and cannot express the real cases.
45
45
  */
46
46
  readonly parents?: readonly Names[];
47
+ /**
48
+ * The table's identity. Defaults to `['id']`.
49
+ *
50
+ * **Declared, because not every table's identity is an `id`.** The `vertical_`
51
+ * side table keyed by an engine's id — the composition pattern the design
52
+ * rules prescribe — has no id of its own to have, and inventing one would be
53
+ * wrong: it would permit two side rows for one work order, which is the very
54
+ * thing the primary key exists to prevent. Value-keyed tables are the same
55
+ * shape: a counter per `(kind, year)`, a budget per `(customer, year, month)`.
56
+ *
57
+ * **Kept distinct from `key`, because SQL's own distinction is the useful
58
+ * one.** `primaryKey` is identity; `key` is an additional uniqueness rule. A
59
+ * table legitimately has both — a composite primary key and a separate
60
+ * natural key — so reading `key` as the primary key when an entity has no
61
+ * `id` would conflate two facts to save a field.
62
+ *
63
+ * Order is significant and preserved: a composite primary key is also the
64
+ * index its columns are searched by, left to right.
65
+ *
66
+ * An entity with neither `primaryKey` nor an `id` field is an ERROR, not a
67
+ * table without a primary key. That silence is what let 15 of one production
68
+ * vertical's 63 tables emit with no primary key at all while a column-by-column
69
+ * parity check reported 63/63 (#804).
70
+ */
71
+ readonly primaryKey?: readonly string[];
47
72
  /** Natural key, if any. Must name fields that exist. */
48
73
  readonly key?: readonly string[];
49
74
  /** Fields an erasure must be able to reach (§12). Must name fields that exist. */
@@ -80,6 +105,7 @@ export type EntityFields<E> = E extends {
80
105
  */
81
106
  export declare function defineEntities<T extends {
82
107
  readonly [K in keyof T]: EntityDef<keyof T & string> & {
108
+ primaryKey?: readonly EntityFields<T[K]>[];
83
109
  key?: readonly EntityFields<T[K]>[];
84
110
  erasable?: readonly EntityFields<T[K]>[];
85
111
  renamedFrom?: Readonly<Partial<Record<EntityFields<T[K]>, string>>>;
@@ -87,6 +113,20 @@ export declare function defineEntities<T extends {
87
113
  }>(entities: T): T;
88
114
  /** The declared entity names. */
89
115
  export type EntityName<T> = keyof T & string;
116
+ /**
117
+ * The entity's primary key — declared, or `['id']` if it has an `id` field.
118
+ *
119
+ * Resolved in one place because two callers need the same answer and the same
120
+ * refusal: the DDL emitter, which cannot write a `CREATE TABLE` without it, and
121
+ * `emitModel`, so the artifact of record carries the fact rather than leaving it
122
+ * to be re-derived by whoever reads it.
123
+ *
124
+ * **It throws rather than returning nothing.** A table with no primary key is
125
+ * not a shape the model may express: it accepts duplicate rows silently, and a
126
+ * parity check that compares columns — the natural one to write — reports a
127
+ * perfect match over it (#804).
128
+ */
129
+ export declare function primaryKeyOf(name: string, entity: EntityDef): readonly string[];
90
130
  /**
91
131
  * The serialisable form — the artifact of record.
92
132
  *
@@ -104,6 +144,12 @@ export interface EmittedEntity {
104
144
  readonly fields: Record<string, unknown>;
105
145
  /** The permitted parent types, sorted. One shape, always. */
106
146
  readonly parents?: readonly string[];
147
+ /**
148
+ * Present only when it is not the `['id']` default, and **unsorted** — unlike
149
+ * `key`, a primary key's column order is part of the fact, so sorting it for a
150
+ * tidier diff would emit a different index than the one declared.
151
+ */
152
+ readonly primaryKey?: readonly string[];
107
153
  readonly key?: readonly string[];
108
154
  readonly erasable?: readonly string[];
109
155
  }
@@ -1 +1 @@
1
- {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"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"}
package/dist/model.js CHANGED
@@ -35,6 +35,39 @@ import { z } from 'zod';
35
35
  export function defineEntities(entities) {
36
36
  return entities;
37
37
  }
38
+ /**
39
+ * The entity's primary key — declared, or `['id']` if it has an `id` field.
40
+ *
41
+ * Resolved in one place because two callers need the same answer and the same
42
+ * refusal: the DDL emitter, which cannot write a `CREATE TABLE` without it, and
43
+ * `emitModel`, so the artifact of record carries the fact rather than leaving it
44
+ * to be re-derived by whoever reads it.
45
+ *
46
+ * **It throws rather than returning nothing.** A table with no primary key is
47
+ * not a shape the model may express: it accepts duplicate rows silently, and a
48
+ * parity check that compares columns — the natural one to write — reports a
49
+ * perfect match over it (#804).
50
+ */
51
+ export function primaryKeyOf(name, entity) {
52
+ const shape = entity.fields.shape;
53
+ const declared = entity.primaryKey;
54
+ if (declared?.length) {
55
+ for (const col of declared) {
56
+ if (!(col in shape)) {
57
+ throw new Error(`model: ${name}.primaryKey names '${col}', which is not a field`);
58
+ }
59
+ }
60
+ if (new Set(declared).size !== declared.length) {
61
+ throw new Error(`model: ${name}.primaryKey repeats a column — (${declared.join(', ')})`);
62
+ }
63
+ return declared;
64
+ }
65
+ if ('id' in shape)
66
+ return ['id'];
67
+ throw new Error(`model: ${name} has no 'id' field and declares no \`primaryKey\` — a table without a ` +
68
+ 'primary key accepts duplicate rows. Declare the columns that identify a row, e.g. ' +
69
+ "`primaryKey: ['workorder_id']` for a side table keyed by an engine's id");
70
+ }
38
71
  /**
39
72
  * Render the registry to plain JSON. Deterministic: entities and their fields
40
73
  * are emitted in sorted order, so the checked-in artifact diffs cleanly and a
@@ -51,6 +84,10 @@ export function emitModel(entities) {
51
84
  table: e.table,
52
85
  fields,
53
86
  ...(e.parents?.length ? { parents: [...e.parents].sort() } : {}),
87
+ // Resolved, not just copied: this also refuses an entity with no identity
88
+ // at all, so `lint:model --check` goes red on it the same way the DDL
89
+ // emitter does.
90
+ ...(primaryKeyOf(name, e).join() === 'id' ? {} : { primaryKey: primaryKeyOf(name, e) }),
54
91
  ...(e.key ? { key: [...e.key].sort() } : {}),
55
92
  ...(e.erasable ? { erasable: [...e.erasable].sort() } : {}),
56
93
  };
package/dist/model.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"model.js","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAoDxB;;;;;;;;;GASG;AACH,MAAM,UAAU,cAAc,CAiB5B,QAAW;IACX,OAAO,QAAQ,CAAC;AAClB,CAAC;AA8BD;;;;GAIG;AACH,MAAM,UAAU,SAAS,CAAsC,QAAW;IACxE,MAAM,GAAG,GAAkC,EAAE,CAAC;IAC9C,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;QAChD,MAAM,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;QACzB,IAAI,CAAC,CAAC;YAAE,SAAS;QACjB,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,MAAM,EAAE,GAAG,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,eAAe,EAAE,CAGvG,CAAC;QACF,GAAG,CAAC,IAAI,CAAC,GAAG;YACV,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,MAAM;YACN,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAChE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC5C,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC5D,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC;AAC3B,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB,CAC/B,QAAW;IAEX,OAAO,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC;SACzB,IAAI,EAAE;SACN,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;QAChB,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;QACxC,IAAI,CAAC,OAAO,EAAE,MAAM;YAAE,OAAO,EAAE,CAAC;QAChC,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC;IACrF,CAAC,CAAC,CAAC;AACP,CAAC;AAuED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,gBAAgB,CAI9B,QAAW,EACX,IAAO;IAOP,OAAO;QACL,iBAAiB,EAAE,CAAC,IAAI,CAAC,iBAAiB,IAAI,EAAE,CAA6C;QAC7F,WAAW,EAAE,IAAI,CAAC,WAA+B;QACjD,+DAA+D;QAC/D,4EAA4E;QAC5E,uEAAuE;QACvE,eAAe,EAAE,CAAC,GAAG,iBAAiB,CAAC,QAAQ,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC;QAC5E,EAAE,EAAE,EAAE,WAAW,EAAE,IAAI,CAAC,WAA+B,EAAE;KAC1D,CAAC;AACJ,CAAC;AAuBD,6EAA6E;AAC7E,MAAM,CAAC,MAAM,WAAW,GAAG,gBAAgB,CAAC;AAE5C;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,UAAU,CAAC,OAAe;IACxC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,6DAA6D,CAAC,CAAC;IACpG,OAAO,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,GAAG,WAAW,GAAG,OAAO,EAAE,CAAC,CAAC;AAC1D,CAAC"}
1
+ {"version":3,"file":"model.js","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@substrat-run/contracts",
3
- "version": "0.76.0",
3
+ "version": "0.77.0",
4
4
  "description": "Substrat kernel contract schemas — Zod is the source of truth (master plan D-22); OAS/JSON Schema are emitted artifacts",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {