litedbmodel 2.0.1 → 2.0.2

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 (52) hide show
  1. package/dist/scp/catalog.d.ts +4 -1
  2. package/dist/scp/catalog.d.ts.map +1 -1
  3. package/dist/scp/catalog.js +5 -1
  4. package/dist/scp/catalog.js.map +1 -1
  5. package/dist/scp/codegen.d.ts +118 -24
  6. package/dist/scp/codegen.d.ts.map +1 -1
  7. package/dist/scp/codegen.js +360 -33
  8. package/dist/scp/codegen.js.map +1 -1
  9. package/dist/scp/coltype.d.ts +41 -0
  10. package/dist/scp/coltype.d.ts.map +1 -0
  11. package/dist/scp/coltype.js +188 -0
  12. package/dist/scp/coltype.js.map +1 -0
  13. package/dist/scp/dialect.d.ts +12 -3
  14. package/dist/scp/dialect.d.ts.map +1 -1
  15. package/dist/scp/dialect.js +12 -3
  16. package/dist/scp/dialect.js.map +1 -1
  17. package/dist/scp/fragment/assemble.d.ts.map +1 -1
  18. package/dist/scp/fragment/assemble.js +10 -2
  19. package/dist/scp/fragment/assemble.js.map +1 -1
  20. package/dist/scp/fragment/compile-pg.js +4 -4
  21. package/dist/scp/index.cjs +8132 -816
  22. package/dist/scp/index.d.ts +3 -1
  23. package/dist/scp/index.d.ts.map +1 -1
  24. package/dist/scp/index.js +17 -6
  25. package/dist/scp/index.js.map +1 -1
  26. package/dist/scp/index.mjs +660 -81
  27. package/dist/scp/makesql/compile-select.d.ts +8 -1
  28. package/dist/scp/makesql/compile-select.d.ts.map +1 -1
  29. package/dist/scp/makesql/compile-select.js +1 -1
  30. package/dist/scp/makesql/compile-select.js.map +1 -1
  31. package/dist/scp/makesql/outtype.d.ts +44 -0
  32. package/dist/scp/makesql/outtype.d.ts.map +1 -0
  33. package/dist/scp/makesql/outtype.js +197 -0
  34. package/dist/scp/makesql/outtype.js.map +1 -0
  35. package/dist/scp/makesql/static-bundle.d.ts +3 -1
  36. package/dist/scp/makesql/static-bundle.d.ts.map +1 -1
  37. package/dist/scp/makesql/static-bundle.js +95 -6
  38. package/dist/scp/makesql/static-bundle.js.map +1 -1
  39. package/dist/scp/makesql/tx.d.ts +1 -1
  40. package/dist/scp/makesql/tx.d.ts.map +1 -1
  41. package/dist/scp/makesql/tx.js +48 -3
  42. package/dist/scp/makesql/tx.js.map +1 -1
  43. package/dist/scp/makesql/writeouttype.d.ts +66 -0
  44. package/dist/scp/makesql/writeouttype.d.ts.map +1 -0
  45. package/dist/scp/makesql/writeouttype.js +195 -0
  46. package/dist/scp/makesql/writeouttype.js.map +1 -0
  47. package/dist/scp/runtime.d.ts +14 -3
  48. package/dist/scp/runtime.d.ts.map +1 -1
  49. package/dist/scp/runtime.js +28 -9
  50. package/dist/scp/runtime.js.map +1 -1
  51. package/docs/proposal/litedbmodel-v2-scp-architecture.md +51 -0
  52. package/package.json +2 -2
@@ -20,8 +20,15 @@ import type { Dialect } from './handler';
20
20
  export interface SelectDesc {
21
21
  dialect: Dialect;
22
22
  tableName: string;
23
- /** SELECT column list (default `*`). */
23
+ /** SELECT column list (an explicit `options.select`). Empty/absent → falls back to {@link selectColumn}. */
24
24
  select?: string;
25
+ /**
26
+ * The model's `SELECT_COLUMN` (v1 `DBModel.SELECT_COLUMN`) — the fallback projection when no explicit
27
+ * `select` is given. v1 derives the SELECT list as `options.select || this.SELECT_COLUMN`
28
+ * (`DBModel._buildSelectSQL`:572), so a subclass that overrides `SELECT_COLUMN` must flow through here
29
+ * rather than being hardcoded to `'*'`. Absent → the base-class default `'*'` (`DBModel.SELECT_COLUMN`).
30
+ */
31
+ selectColumn?: string;
25
32
  conditions?: ConditionObject;
26
33
  join?: string;
27
34
  joinParams?: unknown[];
@@ -1 +1 @@
1
- {"version":3,"file":"compile-select.d.ts","sourceRoot":"","sources":["../../../src/scp/makesql/compile-select.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAE1D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGzC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,2FAA2F;AAC3F,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,wCAAwC;IACxC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,eAAe,CAAC;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,OAAO,EAAE,CAAC;IACvB,GAAG,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,OAAO,EAAE,CAAA;KAAE,CAAC;IACvD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CA6BvD"}
1
+ {"version":3,"file":"compile-select.d.ts","sourceRoot":"","sources":["../../../src/scp/makesql/compile-select.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAE1D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGzC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,2FAA2F;AAC3F,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,4GAA4G;IAC5G,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,eAAe,CAAC;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,OAAO,EAAE,CAAC;IACvB,GAAG,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,OAAO,EAAE,CAAA;KAAE,CAAC;IACvD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CA6BvD"}
@@ -24,7 +24,7 @@ const json_array_1 = require("./json-array");
24
24
  */
25
25
  function compileSelect(desc) {
26
26
  const params = [];
27
- const selectCols = desc.select ?? '*';
27
+ const selectCols = desc.select || (desc.selectColumn ?? '*');
28
28
  const formatter = (0, compile_1.formatterFor)(desc.dialect);
29
29
  // Param order (matches SQL order): CTE params → JOIN params → WHERE params.
30
30
  if (desc.cte?.params && desc.cte.params.length > 0)
@@ -1 +1 @@
1
- {"version":3,"file":"compile-select.js","sourceRoot":"","sources":["../../../src/scp/makesql/compile-select.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;GAaG;;AAgCH,sCA6BC;AA1DD,yCAA6C;AAG7C,uCAAyC;AACzC,6CAA6C;AAqB7C;;;GAGG;AACH,SAAgB,aAAa,CAAC,IAAgB;IAC5C,MAAM,MAAM,GAAc,EAAE,CAAC;IAC7B,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,IAAI,GAAG,CAAC;IACtC,MAAM,SAAS,GAAG,IAAA,sBAAY,EAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAE7C,4EAA4E;IAC5E,IAAI,IAAI,CAAC,GAAG,EAAE,MAAM,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC;QAAE,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACpF,IAAI,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC;QAAE,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC;IAEnF,MAAM,WAAW,GAAG,IAAA,0BAAa,EAAC,IAAI,CAAC,UAAU,IAAI,EAAE,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAElG,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,IAAI,IAAI,CAAC,GAAG;QAAE,GAAG,GAAG,QAAQ,IAAI,CAAC,GAAG,CAAC,IAAI,QAAQ,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;IAElE,GAAG,IAAI,UAAU,UAAU,SAAS,IAAI,CAAC,SAAS,EAAE,CAAC;IACrD,IAAI,IAAI,CAAC,IAAI;QAAE,GAAG,IAAI,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;IACtC,IAAI,WAAW;QAAE,GAAG,IAAI,UAAU,WAAW,EAAE,CAAC;IAChD,IAAI,IAAI,CAAC,KAAK;QAAE,GAAG,IAAI,aAAa,IAAI,CAAC,KAAK,EAAE,CAAC;IAEjD,MAAM,WAAW,GACf,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAA,sBAAa,EAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC1E,IAAI,WAAW;QAAE,GAAG,IAAI,aAAa,WAAW,EAAE,CAAC;IAEnD,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS;QAAE,GAAG,IAAI,UAAU,IAAI,CAAC,KAAK,EAAE,CAAC;IAC5D,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS;QAAE,GAAG,IAAI,WAAW,IAAI,CAAC,MAAM,EAAE,CAAC;IAC/D,IAAI,IAAI,CAAC,SAAS;QAAE,GAAG,IAAI,aAAa,CAAC;IACzC,IAAI,IAAI,CAAC,MAAM;QAAE,GAAG,IAAI,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;IAE1C,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC;AACzB,CAAC"}
1
+ {"version":3,"file":"compile-select.js","sourceRoot":"","sources":["../../../src/scp/makesql/compile-select.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;GAaG;;AAuCH,sCA6BC;AAjED,yCAA6C;AAG7C,uCAAyC;AACzC,6CAA6C;AA4B7C;;;GAGG;AACH,SAAgB,aAAa,CAAC,IAAgB;IAC5C,MAAM,MAAM,GAAc,EAAE,CAAC;IAC7B,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,YAAY,IAAI,GAAG,CAAC,CAAC;IAC7D,MAAM,SAAS,GAAG,IAAA,sBAAY,EAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAE7C,4EAA4E;IAC5E,IAAI,IAAI,CAAC,GAAG,EAAE,MAAM,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC;QAAE,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACpF,IAAI,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC;QAAE,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC;IAEnF,MAAM,WAAW,GAAG,IAAA,0BAAa,EAAC,IAAI,CAAC,UAAU,IAAI,EAAE,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAElG,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,IAAI,IAAI,CAAC,GAAG;QAAE,GAAG,GAAG,QAAQ,IAAI,CAAC,GAAG,CAAC,IAAI,QAAQ,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;IAElE,GAAG,IAAI,UAAU,UAAU,SAAS,IAAI,CAAC,SAAS,EAAE,CAAC;IACrD,IAAI,IAAI,CAAC,IAAI;QAAE,GAAG,IAAI,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;IACtC,IAAI,WAAW;QAAE,GAAG,IAAI,UAAU,WAAW,EAAE,CAAC;IAChD,IAAI,IAAI,CAAC,KAAK;QAAE,GAAG,IAAI,aAAa,IAAI,CAAC,KAAK,EAAE,CAAC;IAEjD,MAAM,WAAW,GACf,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAA,sBAAa,EAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC1E,IAAI,WAAW;QAAE,GAAG,IAAI,aAAa,WAAW,EAAE,CAAC;IAEnD,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS;QAAE,GAAG,IAAI,UAAU,IAAI,CAAC,KAAK,EAAE,CAAC;IAC5D,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS;QAAE,GAAG,IAAI,WAAW,IAAI,CAAC,MAAM,EAAE,CAAC;IAC/D,IAAI,IAAI,CAAC,SAAS;QAAE,GAAG,IAAI,aAAa,CAAC;IACzC,IAAI,IAAI,CAAC,MAAM;QAAE,GAAG,IAAI,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;IAE1C,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC;AACzB,CAAC"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * litedbmodel v2 SCP — codegen `outType` derivation (spec §4.1; issues #58/#56).
3
+ *
4
+ * bc's TYPED-RAW de-box emitters (`rust-typed-raw` / `go-typed-raw` / `typescript-typed`) require
5
+ * each read node to carry an `outType` and the component an `outputType` (bc portable type
6
+ * notation). WITHOUT them the emitter hard-fails ("nothing to de-box") — the correct fail-closed
7
+ * behavior. This module derives those annotations for a READ component from:
8
+ *
9
+ * 1. the per-node SELECT projection (`table` + `select` ports) → a row `obj` type, each column's
10
+ * bc scalar resolved from its SQL type (the schema/DDL SoT) via {@link sqlTypeToBcScalar};
11
+ * 2. the node cardinality (a Select node returns a row LIST → `{arr:rowObj}`; a Count → `int`; a
12
+ * `.map` node wraps its per-element handler result → `{arr:<elem>}`);
13
+ * 3. the component `output` Φ-expression, walked to compose the `outputType` from the node types
14
+ * (`{ref:[nodeId]}` → that node's outType; `{obj:{…}}`/`{arr:…}`/`{opt:…}` recurse).
15
+ *
16
+ * Spec §4.1 discipline: an ambiguous/unmappable projection is a HARD ERROR (no-assume,
17
+ * no-fallback) — a `*` projection, a computed/aliased column, or a column with no schema type
18
+ * THROWS. It is NEVER degraded to a boxed/untyped output; that would silently defeat the de-box.
19
+ */
20
+ import type { PortableType } from 'behavior-contracts';
21
+ import type { Component, ComponentRefNode, MapNode } from '../authoring';
22
+ import { type ColumnTypeResolver } from '../coltype';
23
+ /** A body node that is a component ref or a map (a cond node has no SELECT projection). */
24
+ type RefLike = ComponentRefNode | MapNode;
25
+ /**
26
+ * The `outType` of ONE read body node. A `Select` returns a ROW LIST → `{arr:rowObj}`. A `Count`
27
+ * returns a single `int`. A `.map` node runs its inner component PER element of the iterated list,
28
+ * so its result is `{arr:<per-element outType>}` (the per-element type being the inner node's own
29
+ * outType — for a `.map` over a Select-per-element that is `{arr:{arr:rowObj}}`). An unrecognized
30
+ * component throws (typed codegen covers only the SQL read catalog).
31
+ */
32
+ export declare function nodeOutType(node: RefLike, resolveColumnType: ColumnTypeResolver): PortableType;
33
+ /**
34
+ * Per-node `outType` (keyed by body node id) + the component `outputType`, derived for a READ
35
+ * component (spec §4.1). `cond` nodes are skipped for the per-node map but a `cond` at the OUTPUT
36
+ * position (a shared-branch merge) would be handled by {@link outputType} if reached — the bench's
37
+ * read outputs are ref / obj compositions of Select nodes. Any ambiguity throws (fail-closed).
38
+ */
39
+ export declare function deriveReadOutTypes(component: Component, resolveColumnType: ColumnTypeResolver): {
40
+ byNode: Map<string, PortableType>;
41
+ outputType: PortableType;
42
+ };
43
+ export {};
44
+ //# sourceMappingURL=outtype.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"outtype.d.ts","sourceRoot":"","sources":["../../../src/scp/makesql/outtype.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAsB,MAAM,oBAAoB,CAAC;AAC3E,OAAO,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACzE,OAAO,EAAoC,KAAK,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAcvF,2FAA2F;AAC3F,KAAK,OAAO,GAAG,gBAAgB,GAAG,OAAO,CAAC;AAwE1C;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,GAAG,YAAY,CAmB9F;AAwDD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,SAAS,EACpB,iBAAiB,EAAE,kBAAkB,GACpC;IAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAAC,UAAU,EAAE,YAAY,CAAA;CAAE,CAOjE"}
@@ -0,0 +1,197 @@
1
+ "use strict";
2
+ /**
3
+ * litedbmodel v2 SCP — codegen `outType` derivation (spec §4.1; issues #58/#56).
4
+ *
5
+ * bc's TYPED-RAW de-box emitters (`rust-typed-raw` / `go-typed-raw` / `typescript-typed`) require
6
+ * each read node to carry an `outType` and the component an `outputType` (bc portable type
7
+ * notation). WITHOUT them the emitter hard-fails ("nothing to de-box") — the correct fail-closed
8
+ * behavior. This module derives those annotations for a READ component from:
9
+ *
10
+ * 1. the per-node SELECT projection (`table` + `select` ports) → a row `obj` type, each column's
11
+ * bc scalar resolved from its SQL type (the schema/DDL SoT) via {@link sqlTypeToBcScalar};
12
+ * 2. the node cardinality (a Select node returns a row LIST → `{arr:rowObj}`; a Count → `int`; a
13
+ * `.map` node wraps its per-element handler result → `{arr:<elem>}`);
14
+ * 3. the component `output` Φ-expression, walked to compose the `outputType` from the node types
15
+ * (`{ref:[nodeId]}` → that node's outType; `{obj:{…}}`/`{arr:…}`/`{opt:…}` recurse).
16
+ *
17
+ * Spec §4.1 discipline: an ambiguous/unmappable projection is a HARD ERROR (no-assume,
18
+ * no-fallback) — a `*` projection, a computed/aliased column, or a column with no schema type
19
+ * THROWS. It is NEVER degraded to a boxed/untyped output; that would silently defeat the de-box.
20
+ */
21
+ Object.defineProperty(exports, "__esModule", { value: true });
22
+ exports.nodeOutType = nodeOutType;
23
+ exports.deriveReadOutTypes = deriveReadOutTypes;
24
+ const coltype_1 = require("../coltype");
25
+ const tx_1 = require("./tx");
26
+ /**
27
+ * Narrow a {@link BcScalar} to a bc {@link PortableScalarType}. `BcScalar`'s members
28
+ * (`string|int|float|bool|null`) are exactly bc 0.3.0's portable scalar notation, so this is an
29
+ * identity narrow. DATE/TIMESTAMP columns map to `string` at the `sqlTypeToBcScalar` layer (spec
30
+ * §4.1 owner decision; bc has no `date` scalar — behavior-contracts#84 deferred), so no `date`
31
+ * scalar ever reaches here.
32
+ */
33
+ function toPortableScalar(scalar, _table, _column) {
34
+ return scalar;
35
+ }
36
+ function isMap(n) {
37
+ return 'map' in n;
38
+ }
39
+ /** The `{component, ports}` of a body node (unwrapping a `.map`). */
40
+ function nodeRef(n) {
41
+ return isMap(n) ? { component: n.map.component, ports: n.map.ports } : { component: n.component, ports: n.ports };
42
+ }
43
+ function opKey(node) {
44
+ if (node === null || typeof node !== 'object' || Array.isArray(node))
45
+ return undefined;
46
+ const keys = Object.keys(node);
47
+ return keys.length === 1 ? keys[0] : undefined;
48
+ }
49
+ /** Read a required literal string port, or throw (the projection SoT must be a literal in the IR). */
50
+ function stringPort(ports, name) {
51
+ const v = ports[name];
52
+ if (v === undefined)
53
+ return undefined;
54
+ if (typeof v !== 'string') {
55
+ throw new Error(`outtype: port '${name}' must be a literal string in the IR (got ${JSON.stringify(v)})`);
56
+ }
57
+ return v;
58
+ }
59
+ /** Read a literal `{arr:[str,…]}` string-list port (the SELECT projection). */
60
+ function stringArrayPort(ports, name) {
61
+ const v = ports[name];
62
+ if (v === undefined)
63
+ return undefined;
64
+ if (typeof v === 'object' && v !== null && 'arr' in v && Array.isArray(v.arr)) {
65
+ return v.arr.map((e) => {
66
+ if (typeof e !== 'string')
67
+ throw new Error(`outtype: '${name}' entries must be literal strings (got ${JSON.stringify(e)})`);
68
+ return e;
69
+ });
70
+ }
71
+ throw new Error(`outtype: port '${name}' must be an {arr:[…]} literal in the IR (got ${JSON.stringify(v)})`);
72
+ }
73
+ /**
74
+ * The row `obj` type of a SELECT projection: `{obj:{col: <bcScalar>, …}}`. Each column is typed by
75
+ * resolving its SQL type from the schema SoT and mapping via {@link sqlTypeToBcScalar}. A `*` or
76
+ * absent projection, a computed/aliased/qualified column, or a duplicate column is a HARD ERROR —
77
+ * such a projection cannot be de-boxed into a concrete struct (no-assume, no-fallback).
78
+ */
79
+ function rowObjType(table, projection, resolveColumnType, at) {
80
+ if (projection === undefined || projection.length === 0) {
81
+ throw new Error(`outtype: ${at}: SELECT on '${table}' has no explicit column projection ('*' / empty). A typed ` +
82
+ `de-box needs the concrete column list to build the row struct — spec §4.1 is column-typed. ` +
83
+ `Project explicit columns (no-assume, no-fallback).`);
84
+ }
85
+ const obj = {};
86
+ for (const col of projection) {
87
+ // Reject anything that is not a bare column name — an alias (`x AS y`), a qualified name
88
+ // (`t.c`), or a computed expression cannot be typed from the schema alone.
89
+ if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(col)) {
90
+ throw new Error(`outtype: ${at}: projected column '${col}' on '${table}' is not a bare column name (alias / ` +
91
+ `qualified / computed). Typed de-box (spec §4.1) requires bare schema columns so each maps ` +
92
+ `to a SQL type. No-assume, no-fallback.`);
93
+ }
94
+ if (col in obj)
95
+ throw new Error(`outtype: ${at}: duplicate projected column '${col}' on '${table}'`);
96
+ // sqlTypeToBcScalar throws on an unknown/ambiguous SQL type — fail-closed by construction.
97
+ obj[col] = toPortableScalar((0, coltype_1.sqlTypeToBcScalar)(resolveColumnType(table, col)), table, col);
98
+ }
99
+ return { obj };
100
+ }
101
+ /**
102
+ * The `outType` of ONE read body node. A `Select` returns a ROW LIST → `{arr:rowObj}`. A `Count`
103
+ * returns a single `int`. A `.map` node runs its inner component PER element of the iterated list,
104
+ * so its result is `{arr:<per-element outType>}` (the per-element type being the inner node's own
105
+ * outType — for a `.map` over a Select-per-element that is `{arr:{arr:rowObj}}`). An unrecognized
106
+ * component throws (typed codegen covers only the SQL read catalog).
107
+ */
108
+ function nodeOutType(node, resolveColumnType) {
109
+ const { component, ports } = nodeRef(node);
110
+ const at = `node '${node.id}'`;
111
+ if (component === 'Count')
112
+ return 'int';
113
+ if (component === 'Select') {
114
+ const table = stringPort(ports, 'table');
115
+ if (table === undefined)
116
+ throw new Error(`outtype: ${at}: Select node requires a literal 'table' port`);
117
+ const projection = stringArrayPort(ports, 'select');
118
+ const row = rowObjType(table, projection, resolveColumnType, at);
119
+ // A `.map` node iterates a list and invokes the inner component per element; the node result is
120
+ // the list of per-element results. Here the inner is a Select → per element a row LIST, so the
121
+ // map node's outType is `{arr:{arr:rowObj}}`. A non-map Select node returns the row list `{arr:rowObj}`.
122
+ if (isMap(node))
123
+ return { arr: { arr: row } };
124
+ return { arr: row };
125
+ }
126
+ throw new Error(`outtype: ${at}: component '${component}' has no typed outType (typed read codegen covers Select/Count only). ` +
127
+ `A write / unknown node cannot be de-boxed here — no-assume, no-fallback.`);
128
+ }
129
+ /**
130
+ * Derive the component `outputType` by walking the `output` Φ-expression against a `nodeId →
131
+ * outType` map. `{ref:[id]}` resolves to that node's outType; `{obj:{k:expr,…}}` /
132
+ * `{arr:expr}` / `{opt:expr}` recurse structurally. A `ref` to an unknown id, or an operator the
133
+ * typed output path does not cover, is a HARD ERROR (no-assume, no-fallback) — the output must be
134
+ * a pure composition of typed node results, never a boxed dynamic tree.
135
+ */
136
+ function outputType(output, byNode, at) {
137
+ const op = opKey(output);
138
+ if (op === 'ref' || op === 'refOpt') {
139
+ const path = output[op];
140
+ if (!Array.isArray(path) || path.length === 0 || typeof path[0] !== 'string') {
141
+ throw new Error(`outtype: ${at}: a '${op}' output must reference a node id`);
142
+ }
143
+ // A node-result ref is a single-segment path `[nodeId]`. A deeper path (field access on a node
144
+ // result) cannot be typed here without walking into the row struct — out of the bench's scope.
145
+ if (path.length !== 1 || path[0].startsWith('$') || path[0] === tx_1.IN_SENTINEL) {
146
+ throw new Error(`outtype: ${at}: output ref path ${JSON.stringify(path)} is not a bare node-result reference; ` +
147
+ `field access / input refs at the output position are not supported by the typed de-box path. No-assume, no-fallback.`);
148
+ }
149
+ const t = byNode.get(path[0]);
150
+ if (t === undefined)
151
+ throw new Error(`outtype: ${at}: output references node '${path[0]}' which has no derived outType`);
152
+ return t;
153
+ }
154
+ if (op === 'obj') {
155
+ const obj = output.obj;
156
+ if (obj === null || typeof obj !== 'object' || Array.isArray(obj))
157
+ throw new Error(`outtype: ${at}: 'obj' output must be a record`);
158
+ const out = {};
159
+ for (const [k, expr] of Object.entries(obj)) {
160
+ if (k === '__proto__')
161
+ throw new Error(`outtype: ${at}: '__proto__' key forbidden in output obj`);
162
+ out[k] = outputType(expr, byNode, `${at}.obj.${k}`);
163
+ }
164
+ return { obj: out };
165
+ }
166
+ if (op === 'arr') {
167
+ const arr = output.arr;
168
+ // An `{arr:<expr>}` output whose single element expr types the element (the typed corpus uses
169
+ // homogeneous arrays). An `{arr:[…]}` literal list is not a typed homogeneous array here.
170
+ if (Array.isArray(arr))
171
+ throw new Error(`outtype: ${at}: an '{arr:[…]}' literal list output cannot be typed as a homogeneous array. No-assume, no-fallback.`);
172
+ return { arr: outputType(arr, byNode, `${at}.arr`) };
173
+ }
174
+ if (op === 'opt') {
175
+ const inner = output.opt;
176
+ return { opt: outputType(inner, byNode, `${at}.opt`) };
177
+ }
178
+ throw new Error(`outtype: ${at}: output expression ${JSON.stringify(output)} is not a typed composition ` +
179
+ `(ref / obj / arr / opt of node results). The typed de-box path does not build a dynamic ` +
180
+ `Value output tree — no-assume, no-fallback.`);
181
+ }
182
+ /**
183
+ * Per-node `outType` (keyed by body node id) + the component `outputType`, derived for a READ
184
+ * component (spec §4.1). `cond` nodes are skipped for the per-node map but a `cond` at the OUTPUT
185
+ * position (a shared-branch merge) would be handled by {@link outputType} if reached — the bench's
186
+ * read outputs are ref / obj compositions of Select nodes. Any ambiguity throws (fail-closed).
187
+ */
188
+ function deriveReadOutTypes(component, resolveColumnType) {
189
+ const byNode = new Map();
190
+ for (const n of component.body) {
191
+ if ('cond' in n)
192
+ continue; // a cond node carries no SELECT projection; it is typed by its branch
193
+ byNode.set(n.id, nodeOutType(n, resolveColumnType));
194
+ }
195
+ return { byNode, outputType: outputType(component.output, byNode, `component '${component.name}' output`) };
196
+ }
197
+ //# sourceMappingURL=outtype.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"outtype.js","sourceRoot":"","sources":["../../../src/scp/makesql/outtype.ts"],"names":[],"mappings":"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"}
@@ -36,6 +36,8 @@
36
36
  import { type Scope, type Value, type ComponentGraphIR } from 'behavior-contracts';
37
37
  import type { ComponentRefNode, MapNode, BehaviorModelContract } from '../authoring';
38
38
  import { type Dialect } from './handler';
39
+ import { type FindFilterSource } from '../find-filter-guard';
40
+ import type { ColumnTypeResolver } from '../coltype';
39
41
  /** A closed-set bc Expression IR node used as a deferred value-spec or a skip expression. */
40
42
  export type ValueSpec = unknown;
41
43
  /**
@@ -139,7 +141,7 @@ export interface ReadGraph {
139
141
  * and compile each node's static statements ONCE. SYMBOLIC — no concrete input. bc will own map
140
142
  * iteration / wire binding / Φ output at execute time; the handler renders each node's statements.
141
143
  */
142
- export declare function compileReadGraph(contract: BehaviorModelContract, dialect: Dialect, entry?: string): ReadGraph;
144
+ export declare function compileReadGraph(contract: BehaviorModelContract, dialect: Dialect, entry?: string, findFilterModel?: FindFilterSource, resolveColumnType?: ColumnTypeResolver): ReadGraph;
143
145
  /**
144
146
  * Execute a compiled {@link ReadGraph} via bc `runBehavior` + a makeSQL handler: bc drives map
145
147
  * iteration / wire binding / Φ output; the handler renders each node's static statements against
@@ -1 +1 @@
1
- {"version":3,"file":"static-bundle.d.ts","sourceRoot":"","sources":["../../../src/scp/makesql/static-bundle.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"static-bundle.d.ts","sourceRoot":"","sources":["../../../src/scp/makesql/static-bundle.ts"],"names":[],"mappings":"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"}
@@ -49,6 +49,8 @@ const tx_1 = require("./tx");
49
49
  const makesql_1 = require("./makesql");
50
50
  const handler_1 = require("./handler");
51
51
  const tx_2 = require("./tx");
52
+ const find_filter_guard_1 = require("../find-filter-guard");
53
+ const outtype_1 = require("./outtype");
52
54
  const errors_1 = require("../errors");
53
55
  const DBConditions_1 = require("../../DBConditions");
54
56
  const DBValues_1 = require("../../DBValues");
@@ -556,7 +558,7 @@ function compilePrimaryNode(node, dialect) {
556
558
  if (component === 'Select' || component === 'Count')
557
559
  return compileSelectNode(node, dialect);
558
560
  if (component === 'Insert' || component === 'Update' || component === 'Delete') {
559
- const op = (0, tx_2.compileWriteNode)(node);
561
+ const op = (0, tx_2.compileWriteNode)(node, dialect);
560
562
  return [{ sql: op.sql, params: op.params }];
561
563
  }
562
564
  throw new Error(`static-bundle: catalog component '${component}' has no makeSQL compile (SQL CRUD only: Select/Count/Insert/Update/Delete)`);
@@ -673,6 +675,65 @@ function collectRefHeads(node, into) {
673
675
  for (const v of Object.values(node))
674
676
  collectRefHeads(v, into);
675
677
  }
678
+ // ── FIND_FILTER leak guard: authored WHERE column keys (fail-closed model-scope enforcement) ──
679
+ /**
680
+ * Collect the top-level COLUMN names an authored `where` port constrains — the LHS column of each
681
+ * eq/ne/cmp member, the IN-sentinel column, and (recursively) the columns of `and`/`or` groups and
682
+ * SKIP-`cond` members. This is exactly the key set v1 compares against when it folds a model's
683
+ * `FIND_FILTER` into the WHERE (`condsToRecord(FIND_FILTER)` keys vs the compiled predicate), so the
684
+ * {@link assertFindFilterFolded} guard can fail-closed when a FIND_FILTER model is SCP-compiled
685
+ * without its scope predicates folded in. Additive sentinel primitives (immediate/dynamic/exists/…)
686
+ * carry no plain column key and are skipped — a scope key must be an ordinary eq/cmp/in the author
687
+ * expressed, matching how a FIND_FILTER predicate manifests.
688
+ */
689
+ function whereMemberColumns(node, into) {
690
+ const op = opKey(node);
691
+ if (op === undefined)
692
+ return;
693
+ if (op === 'and' || op === 'or') {
694
+ const args = node[op];
695
+ if (Array.isArray(args))
696
+ for (const m of args)
697
+ whereMemberColumns(m, into);
698
+ return;
699
+ }
700
+ if (op === 'cond') {
701
+ const cargs = node.cond;
702
+ if (Array.isArray(cargs) && cargs.length === 3)
703
+ whereMemberColumns(cargs[1], into);
704
+ return;
705
+ }
706
+ if (op === 'eq' || op in CMP_OPS) {
707
+ const args = node[op];
708
+ if (!Array.isArray(args) || args.length !== 2)
709
+ return;
710
+ const inCol = inSentinelColumn(args[0]);
711
+ if (inCol !== undefined) {
712
+ into.add(inCol);
713
+ return;
714
+ }
715
+ // A plain column ref LHS (a bare eq/cmp). An additive sentinel LHS (immediate/dynamic/exists/…)
716
+ // is NOT a plain column — its column key would be encoded in the primitive, so it is skipped
717
+ // (a FIND_FILTER scope key is always an ordinary eq/cmp/IS NULL the author must fold explicitly).
718
+ const lhsOp = opKey(args[0]);
719
+ if (lhsOp === 'ref' || lhsOp === 'refOpt') {
720
+ const path = args[0][lhsOp];
721
+ if (Array.isArray(path) && path.length > 0 && typeof path[path.length - 1] === 'string' && path[0] !== tx_1.IN_SENTINEL) {
722
+ into.add(path[path.length - 1]);
723
+ }
724
+ }
725
+ }
726
+ }
727
+ /** The authored WHERE column-key set of a read node's `where` port (for the FIND_FILTER guard). */
728
+ function authoredWhereKeysOf(ports) {
729
+ const keys = new Set();
730
+ const arr = arrPort(ports, 'where');
731
+ if (arr === undefined)
732
+ return keys;
733
+ for (const m of arr)
734
+ whereMemberColumns(m, keys);
735
+ return keys;
736
+ }
676
737
  // ── Runtime: evaluate value-specs + skip per-input, assemble, render, execute ──
677
738
  /** bc evaluates ints to bigint; convert a rendered param to a driver-bindable value. */
678
739
  function toDriverParam(v) {
@@ -845,7 +906,7 @@ function compileNodeStatements(node, dialect) {
845
906
  const component = 'map' in node ? node.map.component : node.component;
846
907
  if (component === 'Select' || component === 'Count')
847
908
  return compileSelectNode(node, dialect);
848
- const op = (0, tx_2.compileWriteNode)(node);
909
+ const op = (0, tx_2.compileWriteNode)(node, dialect);
849
910
  return [{ sql: op.sql, params: op.params }];
850
911
  }
851
912
  /**
@@ -854,26 +915,54 @@ function compileNodeStatements(node, dialect) {
854
915
  * and compile each node's static statements ONCE. SYMBOLIC — no concrete input. bc will own map
855
916
  * iteration / wire binding / Φ output at execute time; the handler renders each node's statements.
856
917
  */
857
- function compileReadGraph(contract, dialect, entry) {
918
+ function compileReadGraph(contract, dialect, entry, findFilterModel, resolveColumnType) {
858
919
  const component = entry ? contract.components.find((c) => c.name === entry) : contract.components[0];
859
920
  if (component === undefined)
860
921
  throw new Error(`static-bundle: entry component '${entry ?? '<first>'}' not found in contract`);
922
+ // FIND_FILTER fail-closed guard (M2): when a `DBModel`-shaped source that DECLARES a `FIND_FILTER`
923
+ // (soft-delete / tenant scope) is routed through the SCP read compile, its scope predicates MUST be
924
+ // folded into the authored `where` of every read node — the SCP compile has no model context to
925
+ // auto-apply them (see find-filter-guard.ts). If any read node's authored WHERE omits a scope key,
926
+ // `assertFindFilterFolded` throws (never a silent cross-tenant / soft-deleted leak). No model
927
+ // supplied ⇒ nothing to enforce (the guard is a no-op for a model with no FIND_FILTER either way).
928
+ if (findFilterModel !== undefined) {
929
+ for (const n of component.body) {
930
+ if ('cond' in n)
931
+ continue;
932
+ const ref = 'map' in n ? n.map : n;
933
+ if (ref.component !== 'Select' && ref.component !== 'Count')
934
+ continue;
935
+ (0, find_filter_guard_1.assertFindFilterFolded)(findFilterModel, authoredWhereKeysOf(ref.ports));
936
+ }
937
+ }
861
938
  const statementsById = {};
862
939
  for (const n of component.body) {
863
940
  if ('cond' in n)
864
941
  continue;
865
942
  statementsById[n.id] = compileNodeStatements(n, dialect);
866
943
  }
944
+ // Typed-codegen `outType`/`outputType` annotations (spec §4.1; #58/#56). Derived from the ORIGINAL
945
+ // body (real `table`/`select` ports) so bc's typed-raw de-box emitters can materialize concrete
946
+ // row structs instead of hard-failing ("nothing to de-box"). Only when a column-type resolver (the
947
+ // schema/DDL SoT) is supplied — without it the read graph stays un-annotated (interpret path only;
948
+ // typed codegen then fail-closes downstream, never silently boxes). Any ambiguity throws here.
949
+ const outTypes = resolveColumnType !== undefined ? (0, outtype_1.deriveReadOutTypes)(component, resolveColumnType) : undefined;
867
950
  const surrogateBody = component.body.map((n) => {
868
951
  if ('cond' in n)
869
952
  return n;
870
953
  const stmts = statementsById[n.id];
954
+ const outType = outTypes?.byNode.get(n.id);
955
+ const outAnn = outType !== undefined ? { outType } : {};
871
956
  if ('map' in n) {
872
- return { ...n, map: { ...n.map, component: NODE_COMPONENT, ports: { [SCOPE_PORT]: scopePort(stmts) } } };
957
+ return { ...n, ...outAnn, map: { ...n.map, component: NODE_COMPONENT, ports: { [SCOPE_PORT]: scopePort(stmts) } } };
873
958
  }
874
- return { ...n, component: NODE_COMPONENT, ports: { [SCOPE_PORT]: scopePort(stmts) } };
959
+ return { ...n, ...outAnn, component: NODE_COMPONENT, ports: { [SCOPE_PORT]: scopePort(stmts) } };
875
960
  });
876
- const surrogate = { ...component, body: surrogateBody };
961
+ const surrogate = {
962
+ ...component,
963
+ body: surrogateBody,
964
+ ...(outTypes !== undefined ? { outputType: outTypes.outputType } : {}),
965
+ };
877
966
  const ir = { irVersion: 1, exprVersion: 2, components: [surrogate] };
878
967
  return {
879
968
  dialect,