litedbmodel 2.0.2 → 2.2.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/README.md +7 -0
- package/dist/DBConditions.d.ts.map +1 -1
- package/dist/DBConditions.js +16 -1
- package/dist/DBConditions.js.map +1 -1
- package/dist/DBHandler.d.ts.map +1 -1
- package/dist/DBHandler.js +6 -0
- package/dist/DBHandler.js.map +1 -1
- package/dist/DBModel.d.ts +84 -2
- package/dist/DBModel.d.ts.map +1 -1
- package/dist/DBModel.js +312 -29
- package/dist/DBModel.js.map +1 -1
- package/dist/decorators.d.ts +52 -0
- package/dist/decorators.d.ts.map +1 -1
- package/dist/decorators.js +127 -24
- package/dist/decorators.js.map +1 -1
- package/dist/drivers/mysql.d.ts.map +1 -1
- package/dist/drivers/mysql.js +12 -2
- package/dist/drivers/mysql.js.map +1 -1
- package/dist/drivers/postgres.d.ts.map +1 -1
- package/dist/drivers/postgres.js +13 -2
- package/dist/drivers/postgres.js.map +1 -1
- package/dist/drivers/sqlite.d.ts +2 -0
- package/dist/drivers/sqlite.d.ts.map +1 -1
- package/dist/drivers/sqlite.js +49 -4
- package/dist/drivers/sqlite.js.map +1 -1
- package/dist/index.cjs +10741 -0
- package/dist/index.d.cts +1 -0
- package/dist/scp/coltype.d.ts +108 -0
- package/dist/scp/coltype.d.ts.map +1 -1
- package/dist/scp/coltype.js +293 -6
- package/dist/scp/coltype.js.map +1 -1
- package/dist/scp/connection-routing.d.ts +312 -0
- package/dist/scp/connection-routing.d.ts.map +1 -0
- package/dist/scp/connection-routing.js +394 -0
- package/dist/scp/connection-routing.js.map +1 -0
- package/dist/scp/dbmodel-runtime.d.ts +101 -0
- package/dist/scp/dbmodel-runtime.d.ts.map +1 -0
- package/dist/scp/dbmodel-runtime.js +174 -0
- package/dist/scp/dbmodel-runtime.js.map +1 -0
- package/dist/scp/decorator-adapter.d.ts +196 -0
- package/dist/scp/decorator-adapter.d.ts.map +1 -0
- package/dist/scp/decorator-adapter.js +286 -0
- package/dist/scp/decorator-adapter.js.map +1 -0
- package/dist/scp/emit/emitter.d.ts +108 -0
- package/dist/scp/emit/emitter.d.ts.map +1 -0
- package/dist/scp/emit/emitter.js +782 -0
- package/dist/scp/emit/emitter.js.map +1 -0
- package/dist/scp/emit/endpoint.d.ts +248 -0
- package/dist/scp/emit/endpoint.d.ts.map +1 -0
- package/dist/scp/emit/endpoint.js +20 -0
- package/dist/scp/emit/endpoint.js.map +1 -0
- package/dist/scp/emit/index.d.ts +11 -0
- package/dist/scp/emit/index.d.ts.map +1 -0
- package/dist/scp/emit/index.js +13 -0
- package/dist/scp/emit/index.js.map +1 -0
- package/dist/scp/errors.d.ts +45 -1
- package/dist/scp/errors.d.ts.map +1 -1
- package/dist/scp/errors.js +47 -1
- package/dist/scp/errors.js.map +1 -1
- package/dist/scp/exec-context.d.ts +390 -0
- package/dist/scp/exec-context.d.ts.map +1 -0
- package/dist/scp/exec-context.js +540 -0
- package/dist/scp/exec-context.js.map +1 -0
- package/dist/scp/grouping.d.ts +32 -0
- package/dist/scp/grouping.d.ts.map +1 -0
- package/dist/scp/grouping.js +0 -0
- package/dist/scp/grouping.js.map +1 -0
- package/dist/scp/index.cjs +6432 -17579
- package/dist/scp/index.d.cts +1 -0
- package/dist/scp/index.d.mts +1 -0
- package/dist/scp/index.d.ts +51 -52
- package/dist/scp/index.d.ts.map +1 -1
- package/dist/scp/index.js +189 -152
- package/dist/scp/index.js.map +1 -1
- package/dist/scp/index.mjs +6067 -3659
- package/dist/scp/leaf-transport.d.ts +50 -0
- package/dist/scp/leaf-transport.d.ts.map +1 -0
- package/dist/scp/leaf-transport.js +92 -0
- package/dist/scp/leaf-transport.js.map +1 -0
- package/dist/scp/leaves.d.ts +174 -0
- package/dist/scp/leaves.d.ts.map +1 -0
- package/dist/scp/leaves.js +287 -0
- package/dist/scp/leaves.js.map +1 -0
- package/dist/scp/limit-config.d.ts +118 -0
- package/dist/scp/limit-config.d.ts.map +1 -0
- package/dist/scp/limit-config.js +126 -0
- package/dist/scp/limit-config.js.map +1 -0
- package/dist/scp/makesql/compile-relation.d.ts +49 -23
- package/dist/scp/makesql/compile-relation.d.ts.map +1 -1
- package/dist/scp/makesql/compile-relation.js +101 -76
- package/dist/scp/makesql/compile-relation.js.map +1 -1
- package/dist/scp/makesql/compile-select.d.ts +45 -10
- package/dist/scp/makesql/compile-select.d.ts.map +1 -1
- package/dist/scp/makesql/compile-select.js +50 -10
- package/dist/scp/makesql/compile-select.js.map +1 -1
- package/dist/scp/makesql/handler.d.ts +1 -1
- package/dist/scp/makesql/handler.d.ts.map +1 -1
- package/dist/scp/makesql/index.d.ts +7 -10
- package/dist/scp/makesql/index.d.ts.map +1 -1
- package/dist/scp/makesql/index.js +19 -30
- package/dist/scp/makesql/index.js.map +1 -1
- package/dist/scp/makesql/json-array.d.ts +65 -0
- package/dist/scp/makesql/json-array.d.ts.map +1 -1
- package/dist/scp/makesql/json-array.js +99 -10
- package/dist/scp/makesql/json-array.js.map +1 -1
- package/dist/scp/makesql/json-batch.d.ts.map +1 -1
- package/dist/scp/makesql/json-batch.js +21 -19
- package/dist/scp/makesql/json-batch.js.map +1 -1
- package/dist/scp/makesql/makesql.d.ts +1 -1
- package/dist/scp/makesql/makesql.d.ts.map +1 -1
- package/dist/scp/makesql/mysql-returning.d.ts +93 -0
- package/dist/scp/makesql/mysql-returning.d.ts.map +1 -0
- package/dist/scp/makesql/mysql-returning.js +215 -0
- package/dist/scp/makesql/mysql-returning.js.map +1 -0
- package/dist/scp/makesql/outtype.d.ts +75 -34
- package/dist/scp/makesql/outtype.d.ts.map +1 -1
- package/dist/scp/makesql/outtype.js +91 -118
- package/dist/scp/makesql/outtype.js.map +1 -1
- package/dist/scp/makesql/pool-executor.d.ts +135 -13
- package/dist/scp/makesql/pool-executor.d.ts.map +1 -1
- package/dist/scp/makesql/pool-executor.js +229 -21
- package/dist/scp/makesql/pool-executor.js.map +1 -1
- package/dist/scp/makesql/tx.d.ts +107 -22
- package/dist/scp/makesql/tx.d.ts.map +1 -1
- package/dist/scp/makesql/tx.js +451 -97
- package/dist/scp/makesql/tx.js.map +1 -1
- package/dist/scp/makesql/writeouttype.d.ts +7 -8
- package/dist/scp/makesql/writeouttype.d.ts.map +1 -1
- package/dist/scp/makesql/writeouttype.js +8 -7
- package/dist/scp/makesql/writeouttype.js.map +1 -1
- package/dist/scp/middleware.d.ts +287 -0
- package/dist/scp/middleware.d.ts.map +1 -0
- package/dist/scp/middleware.js +358 -0
- package/dist/scp/middleware.js.map +1 -0
- package/dist/scp/relation.d.ts +80 -9
- package/dist/scp/relation.d.ts.map +1 -1
- package/dist/scp/relation.js +198 -78
- package/dist/scp/relation.js.map +1 -1
- package/dist/scp/tx-options.d.ts +136 -0
- package/dist/scp/tx-options.d.ts.map +1 -0
- package/dist/scp/tx-options.js +184 -0
- package/dist/scp/tx-options.js.map +1 -0
- package/dist/scp/write-bundle.d.ts +131 -0
- package/dist/scp/write-bundle.d.ts.map +1 -0
- package/dist/scp/write-bundle.js +160 -0
- package/dist/scp/write-bundle.js.map +1 -0
- package/dist/types.d.ts +7 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/docs/BENCHMARK.md +58 -56
- package/docs/benchmark-chart.svg +166 -166
- package/docs/design/phase-a-execution-context.md +139 -0
- package/package.json +16 -9
- package/dist/scp/authoring-sql.d.ts +0 -134
- package/dist/scp/authoring-sql.d.ts.map +0 -1
- package/dist/scp/authoring-sql.js +0 -191
- package/dist/scp/authoring-sql.js.map +0 -1
- package/dist/scp/authoring.d.ts +0 -155
- package/dist/scp/authoring.d.ts.map +0 -1
- package/dist/scp/authoring.js +0 -162
- package/dist/scp/authoring.js.map +0 -1
- package/dist/scp/catalog.d.ts +0 -94
- package/dist/scp/catalog.d.ts.map +0 -1
- package/dist/scp/catalog.js +0 -234
- package/dist/scp/catalog.js.map +0 -1
- package/dist/scp/codegen.d.ts +0 -189
- package/dist/scp/codegen.d.ts.map +0 -1
- package/dist/scp/codegen.js +0 -421
- package/dist/scp/codegen.js.map +0 -1
- package/dist/scp/find-filter-guard.d.ts +0 -68
- package/dist/scp/find-filter-guard.d.ts.map +0 -1
- package/dist/scp/find-filter-guard.js +0 -88
- package/dist/scp/find-filter-guard.js.map +0 -1
- package/dist/scp/guard.d.ts +0 -43
- package/dist/scp/guard.d.ts.map +0 -1
- package/dist/scp/guard.js +0 -134
- package/dist/scp/guard.js.map +0 -1
- package/dist/scp/makesql/authoring-compile.d.ts +0 -90
- package/dist/scp/makesql/authoring-compile.d.ts.map +0 -1
- package/dist/scp/makesql/authoring-compile.js +0 -494
- package/dist/scp/makesql/authoring-compile.js.map +0 -1
- package/dist/scp/makesql/ir.d.ts +0 -42
- package/dist/scp/makesql/ir.d.ts.map +0 -1
- package/dist/scp/makesql/ir.js +0 -66
- package/dist/scp/makesql/ir.js.map +0 -1
- package/dist/scp/makesql/static-bundle.d.ts +0 -187
- package/dist/scp/makesql/static-bundle.d.ts.map +0 -1
- package/dist/scp/makesql/static-bundle.js +0 -1113
- package/dist/scp/makesql/static-bundle.js.map +0 -1
- package/dist/scp/runtime.d.ts +0 -242
- package/dist/scp/runtime.d.ts.map +0 -1
- package/dist/scp/runtime.js +0 -400
- package/dist/scp/runtime.js.map +0 -1
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* litedbmodel v2 SCP — the **middleware layer** (Phase D / #92).
|
|
4
|
+
*
|
|
5
|
+
* This module is the **API REFERENCE** for Phase D — the 4 native ports (rust #93 / go #94 / py #95
|
|
6
|
+
* / php #96) mirror THIS contract exactly: the registration surface (`use` / `createMiddleware`), the
|
|
7
|
+
* SQL-level `execute(next, sql, params)` chain contract + APPLIED ORDER, the method-level hook shape
|
|
8
|
+
* + op-kind dispatch, the standard {@link Logger} middleware, and the raw {@link rawExecute} /
|
|
9
|
+
* {@link rawQuery} API that goes THROUGH the exec-context seam (so middleware + connection routing +
|
|
10
|
+
* transaction all still apply). It builds ON the Phase A {@link import('./exec-context').ExecutionContext}
|
|
11
|
+
* seam (the empty {@link import('./exec-context').MiddlewareChain} hook Phase A reserved) — it does
|
|
12
|
+
* NOT restructure the seam; it makes the reserved hook real.
|
|
13
|
+
*
|
|
14
|
+
* ## The two hook levels (design §4)
|
|
15
|
+
*
|
|
16
|
+
* 1. **SQL-level `execute` hook** — `(sql, params, next) => T`. Wraps EVERY statement that funnels
|
|
17
|
+
* through the central seam ({@link import('./exec-context').execute} / `run` / their async +
|
|
18
|
+
* safeIntegers twins), so read, write, tx-control (BEGIN/COMMIT/ROLLBACK), and relation-batch
|
|
19
|
+
* SQL are ALL intercepted. A middleware can observe / rewrite (`next(sql', params')`) / time /
|
|
20
|
+
* short-circuit (return without calling `next`). This is the seam's `MiddlewareChain` folded
|
|
21
|
+
* around the connection-resolve terminal.
|
|
22
|
+
* 2. **method-level hook** — at the ORM operation boundary, keyed by the operation KIND
|
|
23
|
+
* (`find`/`findOne`/`findById`/`count`/`create`/`createMany`/`update`/`updateMany`/`delete`/
|
|
24
|
+
* `query`). In v2 the "methods" map onto the read (`executeBundle`) / write (`executeTransactionBundle`)
|
|
25
|
+
* operations tagged with their {@link MethodKind}; {@link runMethod} folds the matching method
|
|
26
|
+
* hooks around the operation. A method hook runs before/after (around) the whole operation and
|
|
27
|
+
* can rewrite its args / short-circuit its result.
|
|
28
|
+
*
|
|
29
|
+
* ## Registration + APPLIED ORDER (the 5-language contract — v1 `DBModel.use` parity)
|
|
30
|
+
*
|
|
31
|
+
* `use(mw)` appends to an ordered stack and returns an un-register fn (`DBModel.use` :414). The stack
|
|
32
|
+
* is folded so the FIRST-registered middleware is the OUTERMOST wrapper: given `use(A); use(B)`, a
|
|
33
|
+
* statement runs `A.before → B.before → «execute» → B.after → A.after`. This holds identically for the
|
|
34
|
+
* SQL-level chain ({@link MiddlewareChain.wrap}) and the method-level chain ({@link runMethod}) — the
|
|
35
|
+
* fold walks the stack from LAST to FIRST building `next`, so index 0 ends up outermost. This ORDER is
|
|
36
|
+
* the normative contract the ports reproduce.
|
|
37
|
+
*
|
|
38
|
+
* ## Per-execution-scope isolation (NOT a serializing process global) — design §4 last line
|
|
39
|
+
*
|
|
40
|
+
* A middleware binds to the EXECUTION SCOPE, so concurrent requests/contexts never see each other's
|
|
41
|
+
* middleware or per-request state. TS uses `AsyncLocalStorage` (as v1 does): {@link withMiddlewareScope}
|
|
42
|
+
* runs a callback with an ISOLATED registry copy; every middleware STATE object is likewise ALS-scoped
|
|
43
|
+
* (a fresh per-scope instance via {@link MiddlewareHandle.state}). Two concurrent `withMiddlewareScope`
|
|
44
|
+
* bodies each mutate their OWN registry + state, never a shared global slot — so N concurrent requests
|
|
45
|
+
* do not serialize on one registry (the bug a process-global stack would cause). Absent an explicit
|
|
46
|
+
* scope, `use` mutates a process-global default stack (the app-startup registration path). The native
|
|
47
|
+
* ports translate the ALS: rust = `task_local!`, go = a value on `context.Context`, py = `contextvars`,
|
|
48
|
+
* php = an explicit registry arg (1 request = 1 process ⇒ no concurrency to isolate).
|
|
49
|
+
*
|
|
50
|
+
* NB: native registration (design §4 "native 側でも登録可"): each runtime exposes its own
|
|
51
|
+
* `register_middleware(mw)` appending to its ctx chain; the CHAIN CONTRACT + ORDER above is shared, the
|
|
52
|
+
* middleware BODY is that language's closure/impl. TS is the reference for the shape.
|
|
53
|
+
*/
|
|
54
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
55
|
+
exports.Registry = void 0;
|
|
56
|
+
exports.currentRegistry = currentRegistry;
|
|
57
|
+
exports.withMiddlewareScope = withMiddlewareScope;
|
|
58
|
+
exports.activeSqlMiddlewares = activeSqlMiddlewares;
|
|
59
|
+
exports.register = register;
|
|
60
|
+
exports.use = use;
|
|
61
|
+
exports.createMiddleware = createMiddleware;
|
|
62
|
+
exports.runMethod = runMethod;
|
|
63
|
+
exports.Logger = Logger;
|
|
64
|
+
exports.rawExecute = rawExecute;
|
|
65
|
+
exports.rawExecuteAsync = rawExecuteAsync;
|
|
66
|
+
exports.rawQuery = rawQuery;
|
|
67
|
+
exports.rawQueryAsync = rawQueryAsync;
|
|
68
|
+
exports.clearMiddlewares = clearMiddlewares;
|
|
69
|
+
const node_async_hooks_1 = require("node:async_hooks");
|
|
70
|
+
// ── The middleware registry (the ordered stack + ambient isolation) ────────────
|
|
71
|
+
/**
|
|
72
|
+
* The ordered middleware stack. `use` appends (first-registered = outermost, §order), returning an
|
|
73
|
+
* un-register fn. `sqlHooks()` / `methodHooks(kind)` return the folded-order slices the seam +
|
|
74
|
+
* {@link runMethod} consume. A {@link Registry} is EITHER the process-global default (app-startup
|
|
75
|
+
* registration) OR a per-execution-scope copy pushed by {@link withMiddlewareScope} (concurrent
|
|
76
|
+
* isolation) — the two share this class; only their lifetime differs.
|
|
77
|
+
*/
|
|
78
|
+
class Registry {
|
|
79
|
+
stack = [];
|
|
80
|
+
/**
|
|
81
|
+
* Per-scope STATE instances, keyed by the state-owning token a {@link createMiddleware} descriptor
|
|
82
|
+
* carries. Because the Registry is itself per-execution-scope ({@link withMiddlewareScope} pushes a
|
|
83
|
+
* COPY), the state map is scope-local too — so a middleware's per-request state is isolated across
|
|
84
|
+
* concurrent scopes WITHOUT leaking (the `enterWith`-leak trap). A fresh scope's copy starts with an
|
|
85
|
+
* EMPTY state map (states are NOT copied), so each scope lazily builds its own fresh state instances.
|
|
86
|
+
*/
|
|
87
|
+
states = new Map();
|
|
88
|
+
/** The current scope's state for `token`, lazily created via `fresh` on first access (v1 getCurrentContext). */
|
|
89
|
+
stateFor(token, fresh) {
|
|
90
|
+
let s = this.states.get(token);
|
|
91
|
+
if (s === undefined) {
|
|
92
|
+
s = fresh();
|
|
93
|
+
this.states.set(token, s);
|
|
94
|
+
}
|
|
95
|
+
return s;
|
|
96
|
+
}
|
|
97
|
+
/** Reset `token`'s state in this scope to a fresh instance (testing convenience). */
|
|
98
|
+
resetStateFor(token, fresh) {
|
|
99
|
+
this.states.set(token, fresh());
|
|
100
|
+
}
|
|
101
|
+
/** Register `mw` (appended ⇒ outermost). Returns an idempotent un-register fn. */
|
|
102
|
+
use(mw) {
|
|
103
|
+
this.stack.push(mw);
|
|
104
|
+
return () => {
|
|
105
|
+
const i = this.stack.indexOf(mw);
|
|
106
|
+
if (i !== -1)
|
|
107
|
+
this.stack.splice(i, 1);
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
/** Remove `mw` (v1 `removeMiddleware`). Returns whether it was present. */
|
|
111
|
+
remove(mw) {
|
|
112
|
+
const i = this.stack.indexOf(mw);
|
|
113
|
+
if (i === -1)
|
|
114
|
+
return false;
|
|
115
|
+
this.stack.splice(i, 1);
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
/** Drop every registration (v1 `clearMiddlewares` — testing). */
|
|
119
|
+
clear() {
|
|
120
|
+
this.stack = [];
|
|
121
|
+
}
|
|
122
|
+
/** The registered descriptors, registration order (index 0 = first = outermost). */
|
|
123
|
+
all() {
|
|
124
|
+
return this.stack;
|
|
125
|
+
}
|
|
126
|
+
/** The SQL-level hooks (registration order), for the {@link MiddlewareChain} fold. */
|
|
127
|
+
sqlHooks() {
|
|
128
|
+
const out = [];
|
|
129
|
+
for (const mw of this.stack)
|
|
130
|
+
if (mw.sql !== undefined)
|
|
131
|
+
out.push(mw.sql);
|
|
132
|
+
return out;
|
|
133
|
+
}
|
|
134
|
+
/** The method hooks for `kind` (registration order), for the {@link runMethod} fold. */
|
|
135
|
+
methodHooks(kind) {
|
|
136
|
+
const out = [];
|
|
137
|
+
for (const mw of this.stack) {
|
|
138
|
+
const h = mw.methods?.[kind];
|
|
139
|
+
if (h !== undefined)
|
|
140
|
+
out.push(h);
|
|
141
|
+
}
|
|
142
|
+
return out;
|
|
143
|
+
}
|
|
144
|
+
/** A shallow COPY (used to seed an isolated per-scope registry that starts from the global set). */
|
|
145
|
+
copy() {
|
|
146
|
+
const r = new Registry();
|
|
147
|
+
r.stack = [...this.stack];
|
|
148
|
+
return r;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
exports.Registry = Registry;
|
|
152
|
+
/** The process-global default registry (app-startup `use` with no explicit scope). */
|
|
153
|
+
const globalRegistry = new Registry();
|
|
154
|
+
/** The per-execution-scope registry override (ALS): present ⇒ `use`/reads target THIS scope's copy. */
|
|
155
|
+
const registryScope = new node_async_hooks_1.AsyncLocalStorage();
|
|
156
|
+
/** The registry the current execution scope resolves to: the ALS override, else the global default. */
|
|
157
|
+
function currentRegistry() {
|
|
158
|
+
return registryScope.getStore() ?? globalRegistry;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Run `fn` with an ISOLATED middleware registry (concurrent-request isolation, design §4). The scope
|
|
162
|
+
* seeds a COPY of the currently-visible registry (so app-wide registrations remain in effect), and any
|
|
163
|
+
* `use` / per-request state inside `fn` mutates ONLY this scope — two concurrent `withMiddlewareScope`
|
|
164
|
+
* bodies never see each other's middleware. `seed` lets a caller start from an EMPTY registry instead
|
|
165
|
+
* (`inherit: false`). The native ports run their task-local / contextvar / `context.Context` /
|
|
166
|
+
* explicit-arg equivalent.
|
|
167
|
+
*/
|
|
168
|
+
function withMiddlewareScope(fn, opts = {}) {
|
|
169
|
+
const seed = opts.inherit === false ? new Registry() : currentRegistry().copy();
|
|
170
|
+
return registryScope.run(seed, fn);
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* The LIVE SQL-level middleware stack of the current execution scope — the
|
|
174
|
+
* {@link import('./exec-context').MiddlewareStackSource} the ctx factories give their
|
|
175
|
+
* {@link import('./exec-context').MiddlewareChain}. Resolved at EACH `wrap`, so registration after ctx
|
|
176
|
+
* construction, and per-scope registries, are both honored. Empty ⇒ the seam is a byte-identical
|
|
177
|
+
* passthrough.
|
|
178
|
+
*/
|
|
179
|
+
function activeSqlMiddlewares() {
|
|
180
|
+
return currentRegistry().sqlHooks();
|
|
181
|
+
}
|
|
182
|
+
// ── Registration surface (v1 `DBModel.use` / `createMiddleware` parity) ────────
|
|
183
|
+
/**
|
|
184
|
+
* Register a middleware descriptor on the CURRENT scope's registry (the ambient per-scope one inside
|
|
185
|
+
* {@link withMiddlewareScope}, else the process-global default). Returns an un-register fn (v1
|
|
186
|
+
* `DBModel.use` :414). This is the low-level surface; app code usually registers a
|
|
187
|
+
* {@link createMiddleware} handle via {@link use}.
|
|
188
|
+
*/
|
|
189
|
+
function register(mw) {
|
|
190
|
+
return currentRegistry().use(mw);
|
|
191
|
+
}
|
|
192
|
+
/** Register a {@link createMiddleware} handle (or a raw descriptor) — v1 `DBModel.use`. */
|
|
193
|
+
function use(mw) {
|
|
194
|
+
const descriptor = 'descriptor' in mw ? mw.descriptor : mw;
|
|
195
|
+
return register(descriptor);
|
|
196
|
+
}
|
|
197
|
+
/** The op-kind method-hook config keys (in registration-independent order). */
|
|
198
|
+
const METHOD_KINDS = [
|
|
199
|
+
'find', 'findOne', 'findById', 'count', 'create', 'createMany', 'update', 'updateMany', 'delete', 'query',
|
|
200
|
+
];
|
|
201
|
+
/**
|
|
202
|
+
* Build a {@link MiddlewareHandle} from a v1-shaped {@link MiddlewareConfig} (v1 `createMiddleware`
|
|
203
|
+
* parity). Each hook body's `this` is the CURRENT execution scope's state instance (a fresh
|
|
204
|
+
* `structuredClone` of `config.state` per scope, ALS-isolated). The `execute` hook is adapted from the
|
|
205
|
+
* v1 `(next, sql, params)` order to the seam's `(sql, params, next)` order, so a v1 hook body ports
|
|
206
|
+
* unchanged. Method hooks pass through in the v1 `(model, next, ...args)` shape.
|
|
207
|
+
*/
|
|
208
|
+
function createMiddleware(config) {
|
|
209
|
+
// Per-scope state: keyed on THIS unique token in the CURRENT scope's registry. Because the registry
|
|
210
|
+
// is itself per-execution-scope ({@link withMiddlewareScope} pushes a fresh copy with an empty state
|
|
211
|
+
// map), each scope lazily builds its OWN state instance — isolated across concurrent scopes with no
|
|
212
|
+
// `enterWith` leak (v1's per-subclass AsyncLocalStorage, but scope-tied to the registry). First
|
|
213
|
+
// access in a scope deep-copies the initial state (v1 `structuredClone`).
|
|
214
|
+
const token = {};
|
|
215
|
+
const freshState = () => (config.state !== undefined ? structuredClone(config.state) : {});
|
|
216
|
+
const state = () => currentRegistry().stateFor(token, freshState);
|
|
217
|
+
// SQL-level hook: adapt v1 (next, sql, params) → seam (sql, params, next); bind `this` to the state.
|
|
218
|
+
const sql = config.execute
|
|
219
|
+
? (s, p, next) => config.execute
|
|
220
|
+
.call(state(), (ns, np) => next(ns, np ?? []), s, p)
|
|
221
|
+
: undefined;
|
|
222
|
+
const methods = {};
|
|
223
|
+
for (const kind of METHOD_KINDS) {
|
|
224
|
+
const fn = config[kind];
|
|
225
|
+
if (fn !== undefined) {
|
|
226
|
+
methods[kind] = (model, next, ...args) => fn.call(state(), model, next, ...args);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
const descriptor = {
|
|
230
|
+
...(sql !== undefined ? { sql } : {}),
|
|
231
|
+
...(Object.keys(methods).length > 0 ? { methods } : {}),
|
|
232
|
+
};
|
|
233
|
+
return {
|
|
234
|
+
descriptor,
|
|
235
|
+
state,
|
|
236
|
+
resetState: () => currentRegistry().resetStateFor(token, freshState),
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
// ── Method-level dispatch (design §4 level 2) — the operation boundary fold ─────
|
|
240
|
+
/**
|
|
241
|
+
* Run an ORM operation of KIND `kind` through the current scope's method hooks, then execute `core`.
|
|
242
|
+
* The hooks fold first-registered-outermost (§order), each getting `(model, next, ...args)`; a hook may
|
|
243
|
+
* rewrite `args`, time `next`, or short-circuit. Empty hooks for this kind ⇒ `core(...args)` verbatim
|
|
244
|
+
* (byte-identical — no method registered = the operation runs untouched). This is the v2 equivalent of
|
|
245
|
+
* v1 `DBModel._applyMiddleware`: the runtime calls it at the read (`executeBundle`) / write
|
|
246
|
+
* (`executeTransactionBundle`) boundary with the op tagged by its {@link MethodKind}.
|
|
247
|
+
*
|
|
248
|
+
* @param kind the operation kind (how a method hook distinguishes read vs. write vs. find/create/…).
|
|
249
|
+
* @param model the operation's model/target descriptor (opaque; passed to each hook).
|
|
250
|
+
* @param core the actual operation, taking the (possibly hook-rewritten) args.
|
|
251
|
+
* @param args the operation's arguments.
|
|
252
|
+
*/
|
|
253
|
+
function runMethod(kind, model, core, args) {
|
|
254
|
+
const hooks = currentRegistry().methodHooks(kind);
|
|
255
|
+
if (hooks.length === 0)
|
|
256
|
+
return core(...args); // fast path: no method hook for this kind
|
|
257
|
+
let next = (...a) => core(...a);
|
|
258
|
+
for (let i = hooks.length - 1; i >= 0; i--) {
|
|
259
|
+
const hook = hooks[i];
|
|
260
|
+
const inner = next;
|
|
261
|
+
next = (...a) => hook(model, inner, ...a);
|
|
262
|
+
}
|
|
263
|
+
return next(...args);
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* The standard **Logger middleware** (design §4, v1 `StatisticsMiddleware`/`Logger` parity): a
|
|
267
|
+
* SQL-level {@link SqlHook} that records the SQL, its params, and the wall-clock ms each statement
|
|
268
|
+
* takes. Every statement through the seam — read, write, tx-control, relation-batch — is logged (it is
|
|
269
|
+
* an `execute`-level hook). Register it with {@link use}: `use(Logger({ sink }))`. Timing brackets the
|
|
270
|
+
* `next` call, so it measures the connection execute (chain remainder included), NOT just the log call.
|
|
271
|
+
*
|
|
272
|
+
* The per-scope log history lives on the handle's `state().entries` (v1 `getCurrentContext().getLogs()`),
|
|
273
|
+
* so concurrent requests each collect their OWN entries (ALS-isolated). The port agents build the same
|
|
274
|
+
* shape: a scope-local list + an `execute` hook timing `next`.
|
|
275
|
+
*/
|
|
276
|
+
function Logger(options = {}) {
|
|
277
|
+
const now = options.now ?? Date.now;
|
|
278
|
+
return createMiddleware({
|
|
279
|
+
state: { entries: [] },
|
|
280
|
+
// Works on BOTH the sync (`Rows`/`RunInfo`) and async (`Promise<…>`) seams: `next` may return a
|
|
281
|
+
// value or a thenable, so timing/recording is done in a completion callback that handles either —
|
|
282
|
+
// NOT an `async`/`await` (which would coerce the sync seam's value into a Promise, breaking the
|
|
283
|
+
// synchronous conformance path). `this` is the per-scope state (isolated log history).
|
|
284
|
+
execute: function (next, sql, params) {
|
|
285
|
+
const entries = this.entries;
|
|
286
|
+
const started = now();
|
|
287
|
+
const record = () => {
|
|
288
|
+
const entry = { sql, params, durationMs: now() - started };
|
|
289
|
+
entries.push(entry);
|
|
290
|
+
if (options.sink !== undefined)
|
|
291
|
+
options.sink(entry);
|
|
292
|
+
if (options.console === true) {
|
|
293
|
+
console.log(`[scp] ${sql} (${entry.durationMs}ms) params=${JSON.stringify(params)}`);
|
|
294
|
+
}
|
|
295
|
+
};
|
|
296
|
+
const result = next(sql, params);
|
|
297
|
+
if (result !== null && typeof result === 'object' && typeof result.then === 'function') {
|
|
298
|
+
return result.then((v) => { record(); return v; }, (e) => { record(); throw e; });
|
|
299
|
+
}
|
|
300
|
+
record();
|
|
301
|
+
return result;
|
|
302
|
+
},
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
// ── D3: raw execute / query THROUGH the seam ───────────────────────────────────
|
|
306
|
+
//
|
|
307
|
+
// A public raw statement API that goes through the exec-context seam, so a registered SQL-level
|
|
308
|
+
// middleware sees it AND connection routing / an ambient transaction still apply (design §4 D3). It is
|
|
309
|
+
// a thin front over the seam's `execute`/`run` (sync) or `executeAsync`/`runAsync` (async) — the SAME
|
|
310
|
+
// central point every ORM-generated statement uses. `rawQuery` is `rawExecute` tagged as a `query`
|
|
311
|
+
// operation kind (so a `query` method hook fires), matching v1 `DBModel.query` → `execute`.
|
|
312
|
+
const exec_context_1 = require("./exec-context");
|
|
313
|
+
/** Does `sql` return rows (SELECT / …RETURNING / WITH…SELECT / SHOW / PRAGMA / VALUES)? */
|
|
314
|
+
function returnsRows(sql) {
|
|
315
|
+
return /^\s*(select|with|show|pragma|values|explain|table)\b/i.test(sql) || /\breturning\b/i.test(sql);
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Raw **synchronous** `execute(sql, params)` THROUGH the seam (design §4 D3): a registered SQL-level
|
|
319
|
+
* middleware intercepts it, connection routing resolves the connection, and an ambient transaction (if
|
|
320
|
+
* the ctx is tx-scoped) applies — because it is the SAME `execute`/`run` seam the ORM uses, not a
|
|
321
|
+
* direct driver call. A row-returning statement runs `execute`; a non-returning one runs `run`.
|
|
322
|
+
* `write` forces the write intent (writer routing / tx connection) for a row-returning write.
|
|
323
|
+
*/
|
|
324
|
+
function rawExecute(ctx, sql, params = [], opts = {}) {
|
|
325
|
+
if (returnsRows(sql)) {
|
|
326
|
+
const rows = (0, exec_context_1.execute)(ctx, sql, params, { write: opts.write ?? false });
|
|
327
|
+
return { rows, rowCount: rows.length };
|
|
328
|
+
}
|
|
329
|
+
const info = (0, exec_context_1.run)(ctx, sql, params);
|
|
330
|
+
return { rows: [], rowCount: info.changes };
|
|
331
|
+
}
|
|
332
|
+
/** Raw **async** `execute(sql, params)` THROUGH the async seam — the live PG / MySQL twin of {@link rawExecute}. */
|
|
333
|
+
async function rawExecuteAsync(ctx, sql, params = [], opts = {}) {
|
|
334
|
+
if (returnsRows(sql)) {
|
|
335
|
+
const rows = await (0, exec_context_1.executeAsync)(ctx, sql, params, { write: opts.write ?? false });
|
|
336
|
+
return { rows, rowCount: rows.length };
|
|
337
|
+
}
|
|
338
|
+
const info = await (0, exec_context_1.runAsync)(ctx, sql, params);
|
|
339
|
+
return { rows: [], rowCount: info.changes };
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Raw **synchronous** `query(sql, params)` — {@link rawExecute} tagged as a `query` operation, so a
|
|
343
|
+
* `query` method hook fires (then its SQL flows through the same seam + `execute` hooks, exactly as v1
|
|
344
|
+
* `DBModel.query` calls `DBModel.execute`). Returns the row list.
|
|
345
|
+
*/
|
|
346
|
+
function rawQuery(ctx, sql, params = []) {
|
|
347
|
+
return runMethod('query', undefined, async () => rawExecute(ctx, sql, params).rows, [sql, params]);
|
|
348
|
+
}
|
|
349
|
+
/** Raw **async** `query(sql, params)` — the live PG / MySQL twin of {@link rawQuery}. */
|
|
350
|
+
function rawQueryAsync(ctx, sql, params = []) {
|
|
351
|
+
return runMethod('query', undefined, async () => (await rawExecuteAsync(ctx, sql, params)).rows, [sql, params]);
|
|
352
|
+
}
|
|
353
|
+
// ── Reset / testing helpers ────────────────────────────────────────────────────
|
|
354
|
+
/** Clear the process-global registry (testing; a per-scope registry is dropped when its scope exits). */
|
|
355
|
+
function clearMiddlewares() {
|
|
356
|
+
globalRegistry.clear();
|
|
357
|
+
}
|
|
358
|
+
//# sourceMappingURL=middleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../src/scp/middleware.ts"],"names":[],"mappings":"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"}
|
package/dist/scp/relation.d.ts
CHANGED
|
@@ -26,6 +26,9 @@
|
|
|
26
26
|
* - **Lazy** (`await post.author`): a prototype getter fires the SAME op over the sibling set.
|
|
27
27
|
*/
|
|
28
28
|
import { type Dialect } from './makesql/handler';
|
|
29
|
+
import { type ExecutionContext } from './exec-context';
|
|
30
|
+
import { type MaterializeClass, type ColumnTypeResolver } from './coltype';
|
|
31
|
+
import { type RelationGuard } from './limit-config';
|
|
29
32
|
/** A read relation cardinality (v1 parity). `belongsTo`/`hasOne` are single; `hasMany` many. */
|
|
30
33
|
export type RelationKind = 'belongsTo' | 'hasMany' | 'hasOne';
|
|
31
34
|
/**
|
|
@@ -57,8 +60,26 @@ export interface RelationDecl {
|
|
|
57
60
|
readonly order?: string;
|
|
58
61
|
/** Optional per-parent row limit (`hasMany` only). */
|
|
59
62
|
readonly limit?: number;
|
|
63
|
+
/**
|
|
64
|
+
* Per-relation hard-limit override (Phase E-2, epic #74; v1 `@hasMany({ hardLimit })`): the
|
|
65
|
+
* batch-total cap for THIS relation, winning over the global `hasManyHardLimit`. `null` DISABLES
|
|
66
|
+
* the check for this relation even when the global is set; `undefined` ⇒ use the global. `hasMany`
|
|
67
|
+
* only (a single-cardinality relation fetches at most one child per parent). A relation with an
|
|
68
|
+
* intrinsic per-parent {@link limit} window skips the batch-total check regardless (its fanout is
|
|
69
|
+
* already bounded). See {@link import('./limit-config').resolveHasManyHardLimit}.
|
|
70
|
+
*/
|
|
71
|
+
readonly hardLimit?: number | null;
|
|
60
72
|
/** The target SQL dialect the batch SELECT is compiled for (default `'sqlite'`). */
|
|
61
73
|
readonly dialect?: Dialect;
|
|
74
|
+
/**
|
|
75
|
+
* CHAINED relations (nested `with`, e.g. users→posts→comments): the relations declared ON THIS
|
|
76
|
+
* relation's CHILD rows — a grandchild batch keyed by this relation's own result rows (level ≥ 3).
|
|
77
|
+
* Each is a normal {@link RelationDecl} whose parent is THIS relation's target table. The batch stays
|
|
78
|
+
* N+1-free per level (one query per depth): a per-language codegen lowers the chain as a batched map
|
|
79
|
+
* off the parent relation's node; the runtime resolves the flattened child keys once per level. Absent
|
|
80
|
+
* for a leaf (2-level) relation — additive, so existing single-level relations are byte-unchanged.
|
|
81
|
+
*/
|
|
82
|
+
readonly childRelations?: readonly RelationDecl[];
|
|
62
83
|
/**
|
|
63
84
|
* CROSS-DB relations (V0 R1): the NAME of the connection the batch SELECT must execute against —
|
|
64
85
|
* the TARGET model's DB, which may differ from the parent's (v1 `LazyRelation.ts:236` runs a
|
|
@@ -97,12 +118,46 @@ export interface RelationOp {
|
|
|
97
118
|
*/
|
|
98
119
|
readonly connection?: string;
|
|
99
120
|
/**
|
|
100
|
-
* The batched child SELECT as STATIC makeSQL text.
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
*
|
|
121
|
+
* The batched child SELECT as STATIC makeSQL text. ONE `?` binds the deduped parent-key set on
|
|
122
|
+
* every dialect and arity: single-key as the scalar set (PG `= ANY(?::t[])` / MySQL·SQLite
|
|
123
|
+
* single-JSON), composite as the ONE array-of-tuples JSON param every dialect expands server-side
|
|
124
|
+
* (PG `json_array_elements`, MySQL `JSON_TABLE`, SQLite `json_each`). Value-length-independent, so
|
|
125
|
+
* `sql` is fixed — and the key set is exactly the ONE array the `pluck` leaf yields.
|
|
104
126
|
*/
|
|
105
127
|
readonly sql: string;
|
|
128
|
+
/**
|
|
129
|
+
* The child (target) table + projected columns (issue #59) — carried for diagnostics + as the
|
|
130
|
+
* basis of the baked `materializers` map. Additive/optional.
|
|
131
|
+
*/
|
|
132
|
+
readonly targetTable?: string;
|
|
133
|
+
readonly select?: readonly string[];
|
|
134
|
+
/**
|
|
135
|
+
* CHAINED relations (nested `with`): the COMPILED grandchild relation ops keyed off THIS relation's
|
|
136
|
+
* child rows (level ≥ 3). Present iff the decl carried {@link RelationDecl.childRelations}. A codegen
|
|
137
|
+
* lowering injects each as a batched map off this relation's node (N+1-free per level); the mode-2
|
|
138
|
+
* flat-batch runtime does not recurse into it (single-level). Additive — absent for leaf relations.
|
|
139
|
+
*/
|
|
140
|
+
readonly childRelations?: readonly RelationOp[];
|
|
141
|
+
/**
|
|
142
|
+
* The child columns' STATIC materialize classes (issue #59): `column → MaterializeClass`, baked
|
|
143
|
+
* at compile from the model's DDL resolver (only non-passthrough entries). The relation batch runs
|
|
144
|
+
* these over its child rows so a BIGINT/DATE/BOOLEAN child de-boxes identically to the primary
|
|
145
|
+
* read — with ZERO per-read DB introspection. Absent ⇒ the child rows stay raw (no schema).
|
|
146
|
+
*/
|
|
147
|
+
readonly materializers?: Readonly<Record<string, MaterializeClass>>;
|
|
148
|
+
/**
|
|
149
|
+
* Hard-limit runaway cap (Phase E-2, epic #74; v1 `_selectForRelation` `hasManyHardLimit`): the
|
|
150
|
+
* effective per-batch row cap RESOLVED at compile (per-relation override → global). When the batch
|
|
151
|
+
* fetches MORE than this TOTAL, {@link import('./errors').LimitExceededError} is raised
|
|
152
|
+
* (`context: 'relation'`, EXACT count) — by {@link runRelationOp} on the typed-object / lazy
|
|
153
|
+
* surface, and by the `executeSQL` leaf on the CODEGEN surface, where the emitter bakes this cap
|
|
154
|
+
* into the child fetch's `guard` port (the raw child rows are only visible there, before `group`).
|
|
155
|
+
* BOTH read it through {@link relationGuard} + `assertRelationHardLimit`, so neither the cap nor the
|
|
156
|
+
* error identity can drift between surfaces or languages. Absent ⇒ no check (disabled, or a relation
|
|
157
|
+
* with an intrinsic per-parent `limit` window whose fanout is already bounded).
|
|
158
|
+
* See {@link import('./limit-config').resolveHasManyHardLimit}.
|
|
159
|
+
*/
|
|
160
|
+
readonly hardLimit?: number;
|
|
106
161
|
}
|
|
107
162
|
/** The reserved input head the relation batch query binds its deduped key array to. */
|
|
108
163
|
export declare const RELATION_KEYS_HEAD = "__keys";
|
|
@@ -114,15 +169,30 @@ export declare const RELATION_KEYS_HEAD = "__keys";
|
|
|
114
169
|
* LATERAL (PG) / ROW_NUMBER (MySQL·SQLite) form. The SQL text is FIXED (the array binds as one
|
|
115
170
|
* param regardless of length), so it needs no per-input recompile.
|
|
116
171
|
*/
|
|
117
|
-
export declare function compileRelationOp(decl: RelationDecl): RelationOp;
|
|
172
|
+
export declare function compileRelationOp(decl: RelationDecl, resolveColumnType?: ColumnTypeResolver): RelationOp;
|
|
118
173
|
/** A minimal read-only driver surface (`prepare(sql).all(...params)`), the SQLite `Database`. */
|
|
119
174
|
export interface RelationDriver {
|
|
120
175
|
prepare(sql: string): {
|
|
121
176
|
all(...params: unknown[]): unknown[];
|
|
177
|
+
safeIntegers?(v: boolean): unknown;
|
|
122
178
|
};
|
|
123
179
|
}
|
|
180
|
+
/** A relation batch runs against either a raw {@link RelationDriver} or a full {@link ExecutionContext}. */
|
|
181
|
+
export type RelationTarget = RelationDriver | ExecutionContext;
|
|
124
182
|
/** The child rows grouped for a batch: parent-key value (stringified) → child rows. */
|
|
125
183
|
export type RelationBatch = Map<string, Record<string, unknown>[]>;
|
|
184
|
+
/** The ordered PARENT key columns of an op (single-key → 1-element list; composite → the tuple). */
|
|
185
|
+
export declare function parentKeyCols(op: RelationOp): readonly string[];
|
|
186
|
+
/** The ordered CHILD key columns of an op (single-key → 1-element list; composite → the tuple). */
|
|
187
|
+
export declare function targetKeyCols(op: RelationOp): readonly string[];
|
|
188
|
+
/**
|
|
189
|
+
* The op's RELATION RUNAWAY GUARD, or `null` when it baked none (disabled, or an intrinsic per-parent
|
|
190
|
+
* `limit` window whose fanout is already bounded). The ONE projection of a compiled op onto the
|
|
191
|
+
* {@link RelationGuard} record — read by BOTH consumers of the cap: {@link runRelationOp} (the
|
|
192
|
+
* typed-object / lazy batch) and the emitter, which bakes this record into the generated child fetch's
|
|
193
|
+
* `guard` port so the leaf enforces the SAME resolved cap. Nothing downstream re-derives it.
|
|
194
|
+
*/
|
|
195
|
+
export declare function relationGuard(op: RelationOp): RelationGuard | null;
|
|
126
196
|
/**
|
|
127
197
|
* Run ONE {@link RelationOp} for a set of parent rows: dedup the parent-key tuples, render the
|
|
128
198
|
* STATIC batch SELECT once (dialect placeholder form) resolving the deferred PG array cast(s) from
|
|
@@ -133,16 +203,17 @@ export type RelationBatch = Map<string, Record<string, unknown>[]>;
|
|
|
133
203
|
* Returns `{ sql, keys, batch }` (`keys` = the deduped parent-key tuples). An empty key set issues
|
|
134
204
|
* NO query (the correct empty-set behavior — the membership over no keys selects nothing).
|
|
135
205
|
*/
|
|
136
|
-
export declare function runRelationOp(op: RelationOp, parents: readonly Record<string, unknown>[], db:
|
|
206
|
+
export declare function runRelationOp(op: RelationOp, parents: readonly Record<string, unknown>[], db: RelationTarget): {
|
|
137
207
|
sql: string;
|
|
138
208
|
keys: unknown[][];
|
|
139
209
|
batch: RelationBatch;
|
|
140
210
|
};
|
|
141
211
|
/**
|
|
142
212
|
* Distribute a resolved {@link RelationBatch} onto ONE parent per the relation cardinality:
|
|
143
|
-
* `hasMany` → the child list (`[]` when none); `belongsTo`/`hasOne` → the single child (or
|
|
144
|
-
*
|
|
145
|
-
*
|
|
213
|
+
* `hasMany` → the child list (`[]` when none); `belongsTo`/`hasOne` → the single child (or `null`).
|
|
214
|
+
* A thin consumer over the shared grouping SSoT ({@link attachToParent}) — the SAME core the eager
|
|
215
|
+
* `group` leaf uses (no duplicated grouping). `null`/`[]` is the declared cardinality's empty
|
|
216
|
+
* representation, not an ad-hoc default.
|
|
146
217
|
*/
|
|
147
218
|
export declare function distributeToParent(op: RelationOp, parent: Record<string, unknown>, batch: RelationBatch): Record<string, unknown>[] | Record<string, unknown> | null;
|
|
148
219
|
//# sourceMappingURL=relation.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"relation.d.ts","sourceRoot":"","sources":["../../src/scp/relation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAGH,OAAO,EAAsB,KAAK,OAAO,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"relation.d.ts","sourceRoot":"","sources":["../../src/scp/relation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAGH,OAAO,EAAsB,KAAK,OAAO,EAAE,MAAM,mBAAmB,CAAC;AACrE,OAAO,EACL,KAAK,gBAAgB,EAItB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAA8C,KAAK,gBAAgB,EAAE,KAAK,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAEvH,OAAO,EAAoD,KAAK,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAatG,gGAAgG;AAChG,MAAM,MAAM,YAAY,GAAG,WAAW,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE9D;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,kEAAkE;IAClE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,mBAAmB;IACnB,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,qCAAqC;IACrC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,mEAAmE;IACnE,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,6EAA6E;IAC7E,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,8EAA8E;IAC9E,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B;;;OAGG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,+FAA+F;IAC/F,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,gEAAgE;IAChE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,sDAAsD;IACtD,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;;;OAOG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,oFAAoF;IACpF,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B;;;;;;;OAOG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,SAAS,YAAY,EAAE,CAAC;IAClD;;;;;;OAMG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED;;;;GAIG;AACH,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,uFAAuF;IACvF,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,6FAA6F;IAC7F,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B;;;OAGG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,mGAAmG;IACnG,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,oEAAoE;IACpE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B;;;;;OAKG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B;;;;;;OAMG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC;;;;;OAKG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IAChD;;;;;OAKG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC;IACpE;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,uFAAuF;AACvF,eAAO,MAAM,kBAAkB,WAAW,CAAC;AAE3C;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,YAAY,EAAE,iBAAiB,CAAC,EAAE,kBAAkB,GAAG,UAAU,CAgFxG;AA4GD,iGAAiG;AACjG,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG;QAAE,GAAG,CAAC,GAAG,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,EAAE,CAAC;QAAC,YAAY,CAAC,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAAA;KAAE,CAAC;CACpG;AAED,4GAA4G;AAC5G,MAAM,MAAM,cAAc,GAAG,cAAc,GAAG,gBAAgB,CAAC;AA0B/D,uFAAuF;AACvF,MAAM,MAAM,aAAa,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC;AAEnE,oGAAoG;AACpG,wBAAgB,aAAa,CAAC,EAAE,EAAE,UAAU,GAAG,SAAS,MAAM,EAAE,CAE/D;AAED,mGAAmG;AACnG,wBAAgB,aAAa,CAAC,EAAE,EAAE,UAAU,GAAG,SAAS,MAAM,EAAE,CAE/D;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,EAAE,EAAE,UAAU,GAAG,aAAa,GAAG,IAAI,CAOlE;AAoBD;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAC3B,EAAE,EAAE,UAAU,EACd,OAAO,EAAE,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAC3C,EAAE,EAAE,cAAc,GACjB;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC;IAAC,KAAK,EAAE,aAAa,CAAA;CAAE,CAuC1D;AAsBD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,EAAE,EAAE,UAAU,EACd,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,KAAK,EAAE,aAAa,GACnB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAE5D"}
|