@zmdb/orm 1.0.0-beta.1
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/LICENSE +674 -0
- package/README.md +30 -0
- package/dist/cache/index.d.ts +34 -0
- package/dist/cache/index.d.ts.map +1 -0
- package/dist/cache/index.js +149 -0
- package/dist/cache/index.js.map +1 -0
- package/dist/drivers/transactional.d.ts +6 -0
- package/dist/drivers/transactional.d.ts.map +1 -0
- package/dist/drivers/transactional.js +2 -0
- package/dist/drivers/transactional.js.map +1 -0
- package/dist/dto/index.d.ts +41 -0
- package/dist/dto/index.d.ts.map +1 -0
- package/dist/dto/index.js +334 -0
- package/dist/dto/index.js.map +1 -0
- package/dist/entity-modeling/index.d.ts +18 -0
- package/dist/entity-modeling/index.d.ts.map +1 -0
- package/dist/entity-modeling/index.js +26 -0
- package/dist/entity-modeling/index.js.map +1 -0
- package/dist/filters/index.d.ts +62 -0
- package/dist/filters/index.d.ts.map +1 -0
- package/dist/filters/index.js +163 -0
- package/dist/filters/index.js.map +1 -0
- package/dist/index.d.ts +413 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2003 -0
- package/dist/index.js.map +1 -0
- package/dist/loaders/index.d.ts +38 -0
- package/dist/loaders/index.d.ts.map +1 -0
- package/dist/loaders/index.js +164 -0
- package/dist/loaders/index.js.map +1 -0
- package/dist/outbox/index.d.ts +59 -0
- package/dist/outbox/index.d.ts.map +1 -0
- package/dist/outbox/index.js +323 -0
- package/dist/outbox/index.js.map +1 -0
- package/dist/outbox/sql.d.ts +52 -0
- package/dist/outbox/sql.d.ts.map +1 -0
- package/dist/outbox/sql.js +115 -0
- package/dist/outbox/sql.js.map +1 -0
- package/dist/relations/index.d.ts +38 -0
- package/dist/relations/index.d.ts.map +1 -0
- package/dist/relations/index.js +164 -0
- package/dist/relations/index.js.map +1 -0
- package/dist/replicas/index.d.ts +10 -0
- package/dist/replicas/index.d.ts.map +1 -0
- package/dist/replicas/index.js +42 -0
- package/dist/replicas/index.js.map +1 -0
- package/dist/seeding/index.d.ts +18 -0
- package/dist/seeding/index.d.ts.map +1 -0
- package/dist/seeding/index.js +66 -0
- package/dist/seeding/index.js.map +1 -0
- package/dist/streaming/index.d.ts +7 -0
- package/dist/streaming/index.d.ts.map +1 -0
- package/dist/streaming/index.js +67 -0
- package/dist/streaming/index.js.map +1 -0
- package/dist/testing/official-dialects.fixture.d.ts +16 -0
- package/dist/testing/official-dialects.fixture.d.ts.map +1 -0
- package/dist/testing/official-dialects.fixture.js +21 -0
- package/dist/testing/official-dialects.fixture.js.map +1 -0
- package/dist/testing/repository.fixture.d.ts +11 -0
- package/dist/testing/repository.fixture.d.ts.map +1 -0
- package/dist/testing/repository.fixture.js +33 -0
- package/dist/testing/repository.fixture.js.map +1 -0
- package/dist/transactions/index.d.ts +40 -0
- package/dist/transactions/index.d.ts.map +1 -0
- package/dist/transactions/index.js +249 -0
- package/dist/transactions/index.js.map +1 -0
- package/dist/typed-populate/nested.fixtures.d.ts +34 -0
- package/dist/typed-populate/nested.fixtures.d.ts.map +1 -0
- package/dist/typed-populate/nested.fixtures.js +4 -0
- package/dist/typed-populate/nested.fixtures.js.map +1 -0
- package/package.json +78 -0
- package/src/cache/index.ts +188 -0
- package/src/drivers/transactional.ts +6 -0
- package/src/dto/index.ts +379 -0
- package/src/entity-modeling/index.ts +38 -0
- package/src/filters/index.ts +267 -0
- package/src/index.ts +2757 -0
- package/src/loaders/index.ts +256 -0
- package/src/outbox/index.ts +409 -0
- package/src/outbox/sql.ts +179 -0
- package/src/relations/index.ts +221 -0
- package/src/replicas/index.ts +51 -0
- package/src/seeding/index.ts +72 -0
- package/src/streaming/index.ts +67 -0
- package/src/testing/repository.fixture.ts +44 -0
- package/src/transactions/index.ts +315 -0
- package/src/typed-populate/nested.fixtures.ts +59 -0
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { resolveRelation } from '@zmdb/schema/relations';
|
|
2
|
+
import { dialectName, dialectTraits, formatPlaceholder, quoteIdentifier, renderPredicate, UnsupportedFeatureError, } from '@zmdb/sql';
|
|
3
|
+
function sanitizeKeys(keys) {
|
|
4
|
+
const result = [];
|
|
5
|
+
const seen = new Set();
|
|
6
|
+
for (const k of keys) {
|
|
7
|
+
if (k !== null && k !== undefined && !seen.has(k)) {
|
|
8
|
+
seen.add(k);
|
|
9
|
+
result.push(k);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
return result;
|
|
13
|
+
}
|
|
14
|
+
function sameKeyValue(left, right) {
|
|
15
|
+
if (left instanceof Date && right instanceof Date)
|
|
16
|
+
return left.getTime() === right.getTime();
|
|
17
|
+
return Object.is(left, right);
|
|
18
|
+
}
|
|
19
|
+
function sanitizeCompositeKeys(ir, relationName, keys, arity) {
|
|
20
|
+
const result = [];
|
|
21
|
+
for (const key of keys) {
|
|
22
|
+
if (key === null || key === undefined)
|
|
23
|
+
continue;
|
|
24
|
+
if (!Array.isArray(key)) {
|
|
25
|
+
throw new Error(`${ir.table}.${relationName}: composite-key populate expects a ${String(arity)}-column tuple for every parent`);
|
|
26
|
+
}
|
|
27
|
+
if (key.length !== arity) {
|
|
28
|
+
throw new Error(`${ir.table}.${relationName}: composite-key populate expected ${String(arity)} values, received ${String(key.length)}`);
|
|
29
|
+
}
|
|
30
|
+
if (key.some(value => value === null || value === undefined))
|
|
31
|
+
continue;
|
|
32
|
+
if (result.some(existing => existing.every((value, index) => sameKeyValue(value, key[index]))))
|
|
33
|
+
continue;
|
|
34
|
+
result.push([...key]);
|
|
35
|
+
}
|
|
36
|
+
return result;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Compile a populate hint into SQL: a to-one becomes an `INNER JOIN`, a to-many a batched
|
|
40
|
+
* `IN (…)` select over the parent keys.
|
|
41
|
+
*
|
|
42
|
+
* Takes the declaring table's IR and a relation name rather than a relation object, which is
|
|
43
|
+
* what makes the two spellings one: the columns on either side of the `ON` come out of
|
|
44
|
+
* `resolveRelation`, the same call `@zmdb/orm`'s `populate` makes.
|
|
45
|
+
*/
|
|
46
|
+
export function compilePopulate(ir, relationName, dialect, parentIds = [], targetFilters = [], schemas = []) {
|
|
47
|
+
const rel = resolveRelation(ir, relationName);
|
|
48
|
+
const q = (name) => quoteIdentifier(dialect, name);
|
|
49
|
+
const targetIr = schemas.find(schema => schema.table === rel.targetTable);
|
|
50
|
+
const sourceTable = ir.physicalTable;
|
|
51
|
+
const targetTable = targetIr?.physicalTable ?? rel.targetTable;
|
|
52
|
+
const physicalColumn = (schema, declared) => {
|
|
53
|
+
if (schema === undefined)
|
|
54
|
+
return declared;
|
|
55
|
+
const separator = declared.lastIndexOf('.');
|
|
56
|
+
const property = separator === -1 ? declared : declared.slice(separator + 1);
|
|
57
|
+
const physical = schema.columns.find(column => column.name === property)?.physicalName;
|
|
58
|
+
if (physical === undefined)
|
|
59
|
+
return declared;
|
|
60
|
+
if (separator === -1)
|
|
61
|
+
return physical;
|
|
62
|
+
const qualifier = declared.slice(0, separator);
|
|
63
|
+
return `${qualifier === schema.table ? schema.physicalTable : qualifier}.${physical}`;
|
|
64
|
+
};
|
|
65
|
+
const parentKeys = rel.parentKey.map(column => physicalColumn(ir, column));
|
|
66
|
+
const targetKeys = rel.targetKey.map(column => physicalColumn(targetIr, column));
|
|
67
|
+
const physicalFilters = targetFilters.map(predicate => ({
|
|
68
|
+
...predicate,
|
|
69
|
+
col: physicalColumn(targetIr, predicate.col),
|
|
70
|
+
}));
|
|
71
|
+
const renderFilters = (parameters) => {
|
|
72
|
+
if (physicalFilters.length === 0)
|
|
73
|
+
return '';
|
|
74
|
+
const body = physicalFilters
|
|
75
|
+
.map((predicate, index) => {
|
|
76
|
+
const rendered = renderPredicate(dialect, predicate, parameters);
|
|
77
|
+
return index === 0 ? rendered : `${predicate.connector ?? 'AND'} ${rendered}`;
|
|
78
|
+
})
|
|
79
|
+
.join(' ');
|
|
80
|
+
const grouped = targetFilters.some((predicate, index) => index > 0 && predicate.connector === 'OR');
|
|
81
|
+
return `AND ${grouped ? `(${body})` : body}`;
|
|
82
|
+
};
|
|
83
|
+
if (!rel.toMany) {
|
|
84
|
+
const parameters = [];
|
|
85
|
+
const filtered = physicalFilters.length > 0;
|
|
86
|
+
const onFilters = renderFilters(parameters);
|
|
87
|
+
const conditions = parentKeys.map((parentKey, index) => {
|
|
88
|
+
const targetKey = targetKeys[index];
|
|
89
|
+
if (targetKey === undefined) {
|
|
90
|
+
throw new Error(`${ir.table}.${relationName}: resolved relation keys have different lengths`);
|
|
91
|
+
}
|
|
92
|
+
return `${q(sourceTable)}.${q(parentKey)} = ${q(targetTable)}.${q(targetKey)}`;
|
|
93
|
+
});
|
|
94
|
+
const sql = `SELECT * FROM ${q(sourceTable)} ${filtered ? 'LEFT' : 'INNER'} JOIN ${q(targetTable)} ` +
|
|
95
|
+
`ON ${conditions.join(' AND ')}` +
|
|
96
|
+
(onFilters.length === 0 ? '' : ` ${onFilters}`);
|
|
97
|
+
return { kind: 'join', sql, parameters };
|
|
98
|
+
}
|
|
99
|
+
if (parentIds.length === 0) {
|
|
100
|
+
return { kind: 'batched', sql: `SELECT * FROM ${q(targetTable)} WHERE 1 = 0`, parameters: [] };
|
|
101
|
+
}
|
|
102
|
+
if (targetKeys.length === 1) {
|
|
103
|
+
const sanitized = sanitizeKeys(parentIds);
|
|
104
|
+
if (sanitized.length === 0) {
|
|
105
|
+
return { kind: 'batched', sql: `SELECT * FROM ${q(targetTable)} WHERE 1 = 0`, parameters: [] };
|
|
106
|
+
}
|
|
107
|
+
const [targetKey] = targetKeys;
|
|
108
|
+
if (targetKey === undefined) {
|
|
109
|
+
throw new Error(`${ir.table}.${relationName}: resolved relation has no target key`);
|
|
110
|
+
}
|
|
111
|
+
const inList = sanitized.map((_, i) => formatPlaceholder(dialect, i + 1)).join(', ');
|
|
112
|
+
const parameters = [...sanitized];
|
|
113
|
+
const filters = renderFilters(parameters);
|
|
114
|
+
const sql = `SELECT * FROM ${q(targetTable)} WHERE ${q(targetKey)} IN (${inList})` +
|
|
115
|
+
(filters.length === 0 ? '' : ` ${filters}`);
|
|
116
|
+
return { kind: 'batched', sql, parameters };
|
|
117
|
+
}
|
|
118
|
+
if (!dialectTraits(dialect).rowValueIn) {
|
|
119
|
+
const name = dialectName(dialect);
|
|
120
|
+
throw new UnsupportedFeatureError(`composite-key populate for relation "${relationName}"`, name, `${ir.table}.${relationName}: dialect "${name}" does not support row-value IN for a composite-key populate`);
|
|
121
|
+
}
|
|
122
|
+
const sanitized = sanitizeCompositeKeys(ir, relationName, parentIds, targetKeys.length);
|
|
123
|
+
if (sanitized.length === 0) {
|
|
124
|
+
return { kind: 'batched', sql: `SELECT * FROM ${q(targetTable)} WHERE 1 = 0`, parameters: [] };
|
|
125
|
+
}
|
|
126
|
+
const parameters = [];
|
|
127
|
+
const inList = sanitized
|
|
128
|
+
.map(tuple => {
|
|
129
|
+
const placeholders = tuple.map(value => {
|
|
130
|
+
parameters.push(value);
|
|
131
|
+
return formatPlaceholder(dialect, parameters.length);
|
|
132
|
+
});
|
|
133
|
+
return `(${placeholders.join(', ')})`;
|
|
134
|
+
})
|
|
135
|
+
.join(', ');
|
|
136
|
+
const columns = targetKeys.map(targetKey => q(targetKey)).join(', ');
|
|
137
|
+
const filters = renderFilters(parameters);
|
|
138
|
+
const sql = `SELECT * FROM ${q(targetTable)} WHERE (${columns}) IN (${inList})` + (filters.length === 0 ? '' : ` ${filters}`);
|
|
139
|
+
return { kind: 'batched', sql, parameters };
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Attach a populated relation to a parent row, without mutating it.
|
|
143
|
+
*
|
|
144
|
+
* The type widening is `Populated<T, K>` in `../derive/query.ts`, which reads the declared
|
|
145
|
+
* relation property; this only puts the value there.
|
|
146
|
+
*/
|
|
147
|
+
export function attachPopulated(parent, name, value) {
|
|
148
|
+
// boundary: a computed key in an object literal widens to `string`, so TS types
|
|
149
|
+
// this spread as `P & { [x: string]: V }`. `name` is the literal `N` at the call
|
|
150
|
+
// site, which is what the return type states.
|
|
151
|
+
return { ...parent, [name]: value };
|
|
152
|
+
}
|
|
153
|
+
/** Rename aliased columns per a { alias: outKey } map (stable, non-mutating). */
|
|
154
|
+
export function aliasRow(row, map) {
|
|
155
|
+
const out = { ...row };
|
|
156
|
+
for (const [alias, outKey] of Object.entries(map)) {
|
|
157
|
+
if (alias in out) {
|
|
158
|
+
out[outKey] = out[alias];
|
|
159
|
+
delete out[alias]; // rename: drop the original aliased key
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return out;
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/relations/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type Driver } from '../index.js';
|
|
2
|
+
export interface ReplicaOptions {
|
|
3
|
+
primary: Driver;
|
|
4
|
+
replicas: readonly Driver[];
|
|
5
|
+
pick?: (replicas: readonly Driver[], nextIndex: number) => Driver;
|
|
6
|
+
}
|
|
7
|
+
export declare function isWrite(sql: string): boolean;
|
|
8
|
+
/** Wrap primary+replicas into a single Driver that routes reads to replicas. */
|
|
9
|
+
export declare function withReplicas(opts: ReplicaOptions): Driver;
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/replicas/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5B,IAAI,CAAC,EAAE,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,EAAE,SAAS,EAAE,MAAM,KAAK,MAAM,CAAC;CACnE;AAED,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAG5C;AAED,gFAAgF;AAChF,wBAAgB,YAAY,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM,CAiCzD"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import {} from '@zmdb/sql';
|
|
2
|
+
// Read-replica routing — see ./SPEC.md.
|
|
3
|
+
import {} from '../index.js';
|
|
4
|
+
export function isWrite(sql) {
|
|
5
|
+
const s = sql.trimStart().toUpperCase();
|
|
6
|
+
return s.startsWith('INSERT') || s.startsWith('UPDATE') || s.startsWith('DELETE');
|
|
7
|
+
}
|
|
8
|
+
/** Wrap primary+replicas into a single Driver that routes reads to replicas. */
|
|
9
|
+
export function withReplicas(opts) {
|
|
10
|
+
const { primary, replicas } = opts;
|
|
11
|
+
let rr = 0;
|
|
12
|
+
const pick = (query) => {
|
|
13
|
+
if (isWrite(query.text) || replicas.length === 0)
|
|
14
|
+
return primary;
|
|
15
|
+
const driver = opts.pick ? opts.pick(replicas, rr) : replicas[rr % replicas.length];
|
|
16
|
+
rr = (rr + 1) % replicas.length;
|
|
17
|
+
// `replicas` is non-empty here (checked above), so the modulo index always
|
|
18
|
+
// hits — but a custom `pick` is caller code, so fall back to the primary
|
|
19
|
+
// rather than crashing on a bad index.
|
|
20
|
+
return driver ?? primary;
|
|
21
|
+
};
|
|
22
|
+
const canStream = typeof primary.stream === 'function' && replicas.every(driver => typeof driver.stream === 'function');
|
|
23
|
+
return {
|
|
24
|
+
dialect: primary.dialect,
|
|
25
|
+
execute(query, executeOpts) {
|
|
26
|
+
return pick(query).execute(query, executeOpts);
|
|
27
|
+
},
|
|
28
|
+
...(canStream
|
|
29
|
+
? {
|
|
30
|
+
stream(query, executeOpts) {
|
|
31
|
+
const driver = pick(query);
|
|
32
|
+
const stream = driver.stream;
|
|
33
|
+
if (typeof stream !== 'function') {
|
|
34
|
+
throw new Error('replica routing selected a driver without stream support');
|
|
35
|
+
}
|
|
36
|
+
return stream.call(driver, query, executeOpts);
|
|
37
|
+
},
|
|
38
|
+
}
|
|
39
|
+
: {}),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/replicas/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,MAAM,WAAW,CAAC;AAE/C,wCAAwC;AACxC,OAAO,EAAe,MAAM,aAAa,CAAC;AAQ1C,MAAM,UAAU,OAAO,CAAC,GAAW;IACjC,MAAM,CAAC,GAAG,GAAG,CAAC,SAAS,EAAE,CAAC,WAAW,EAAE,CAAC;IACxC,OAAO,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;AACpF,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,YAAY,CAAC,IAAoB;IAC/C,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC;IACnC,IAAI,EAAE,GAAG,CAAC,CAAC;IACX,MAAM,IAAI,GAAG,CAAC,KAAoB,EAAU,EAAE;QAC5C,IAAI,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,OAAO,CAAC;QACjE,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;QACpF,EAAE,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC;QAChC,2EAA2E;QAC3E,yEAAyE;QACzE,uCAAuC;QACvC,OAAO,MAAM,IAAI,OAAO,CAAC;IAC3B,CAAC,CAAC;IAEF,MAAM,SAAS,GACb,OAAO,OAAO,CAAC,MAAM,KAAK,UAAU,IAAI,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,MAAM,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC;IACxG,OAAO;QACL,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,OAAO,CAAC,KAAK,EAAE,WAAW;YACxB,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;QACjD,CAAC;QACD,GAAG,CAAC,SAAS;YACX,CAAC,CAAC;gBACE,MAAM,CAAC,KAAoB,EAAE,WAA0D;oBACrF,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;oBAC3B,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;oBAC7B,IAAI,OAAO,MAAM,KAAK,UAAU,EAAE,CAAC;wBACjC,MAAM,IAAI,KAAK,CAAC,0DAA0D,CAAC,CAAC;oBAC9E,CAAC;oBACD,OAAO,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC;gBACjD,CAAC;aACF;YACH,CAAC,CAAC,EAAE,CAAC;KACR,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type CreateDTO, type DeclaredTable, type TaggedSchema } from '@zmdb/schema';
|
|
2
|
+
/** Deterministic PRNG (mulberry32). Same seed ⇒ same sequence. */
|
|
3
|
+
export declare function makeRng(seed: number): () => number;
|
|
4
|
+
export interface SeedOptions {
|
|
5
|
+
seed?: number;
|
|
6
|
+
count: number;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* `count` rows shaped like `T`'s create DTO, reproducible from `seed`.
|
|
10
|
+
*
|
|
11
|
+
* Typed as `CreateDTO<T>[]`, which the column-map version could not be: it built its rows
|
|
12
|
+
* from the lossy projection and had no way to tell the compiler what it had made. `random`'s
|
|
13
|
+
* type parameter is inferred from the return type here, so there is no assertion — and no
|
|
14
|
+
* type argument either, which is what keeps the transformer out of a call whose shape is only
|
|
15
|
+
* known at runtime.
|
|
16
|
+
*/
|
|
17
|
+
export declare function seedRows<T extends DeclaredTable>(schema: TaggedSchema<T>, opts: SeedOptions): CreateDTO<T>[];
|
|
18
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/seeding/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,aAAa,EAAE,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AA2BrF,kEAAkE;AAClE,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,MAAM,CASlD;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAcD;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,aAAa,EAAE,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,WAAW,GAAG,SAAS,CAAC,CAAC,CAAC,EAAE,CAM5G"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import {} from '@zmdb/schema';
|
|
2
|
+
import { objectTypeFromIR } from '@zmdb/schema/ir';
|
|
3
|
+
// Deterministic seeding — see ./SPEC.md.
|
|
4
|
+
//
|
|
5
|
+
// This module used to live in `@zmdb/schema/seeding` and generate its values from a
|
|
6
|
+
// walk of its own over `schema.columns`: a `switch` on `col.type` returning a random number
|
|
7
|
+
// for an integer, a random `s…` for anything string-ish, and a member of `flags.enum` for an
|
|
8
|
+
// enum. It was the fifth walker over column metadata, and it had the failure mode all five
|
|
9
|
+
// shared — it read part of what a column says. `Min<18>`, `Max<120>`, `Pattern<…>`,
|
|
10
|
+
// `MinLength`, a `json` payload shape and nullability were all invisible to it, so seeding a
|
|
11
|
+
// table with any of them produced rows the table's own validator rejects.
|
|
12
|
+
//
|
|
13
|
+
// It generates from the IR now, through the same sampler `random<T>()` uses, which reads the
|
|
14
|
+
// whole vocabulary and *refuses* what it cannot satisfy rather than guessing. Two
|
|
15
|
+
// consequences worth stating, because both are visible to a caller:
|
|
16
|
+
//
|
|
17
|
+
// - The rows honour the constraints. A `Min<18>` column is seeded within its bounds.
|
|
18
|
+
// - A `Pattern<…>` column is refused, with the column named. Nothing inverts a regular
|
|
19
|
+
// expression, so the alternative is a value that violates the pattern — which is what
|
|
20
|
+
// used to happen, silently, and surfaced later as a validation failure in a test whose
|
|
21
|
+
// subject was something else.
|
|
22
|
+
//
|
|
23
|
+
// Seeding lives in ORM because its sampler ships in `@zmdb/validator`, which
|
|
24
|
+
// depends on `@zmdb/schema/ir`. The dependencies point inward from ORM. That is also the honest home: a seeded row exists to be handed to
|
|
25
|
+
// `repository.create`, and now it type-checks as one.
|
|
26
|
+
import { random } from '@zmdb/validator';
|
|
27
|
+
/** Deterministic PRNG (mulberry32). Same seed ⇒ same sequence. */
|
|
28
|
+
export function makeRng(seed) {
|
|
29
|
+
let a = seed >>> 0;
|
|
30
|
+
return () => {
|
|
31
|
+
a |= 0;
|
|
32
|
+
a = (a + 0x6d2b79f5) | 0;
|
|
33
|
+
let t = Math.imul(a ^ (a >>> 15), 1 | a);
|
|
34
|
+
t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
|
|
35
|
+
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* The create shape with its optional properties dropped — the columns a caller *must* supply.
|
|
40
|
+
*
|
|
41
|
+
* The sampler fills every property of an object it is given, including the optional ones, and
|
|
42
|
+
* that is right for `random<T>()`: a sample of a type is a value of that type. It is wrong
|
|
43
|
+
* here. A column is optional in `CreateDTO` because the database has a default for it, and
|
|
44
|
+
* seeding a value over the default is how a seeded row stops resembling an inserted one.
|
|
45
|
+
*/
|
|
46
|
+
function requiredColumns(shape) {
|
|
47
|
+
return { ...shape, properties: shape.properties.filter(property => !property.optional) };
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* `count` rows shaped like `T`'s create DTO, reproducible from `seed`.
|
|
51
|
+
*
|
|
52
|
+
* Typed as `CreateDTO<T>[]`, which the column-map version could not be: it built its rows
|
|
53
|
+
* from the lossy projection and had no way to tell the compiler what it had made. `random`'s
|
|
54
|
+
* type parameter is inferred from the return type here, so there is no assertion — and no
|
|
55
|
+
* type argument either, which is what keeps the transformer out of a call whose shape is only
|
|
56
|
+
* known at runtime.
|
|
57
|
+
*/
|
|
58
|
+
export function seedRows(schema, opts) {
|
|
59
|
+
const rng = makeRng(opts.seed ?? 1);
|
|
60
|
+
const shape = requiredColumns(objectTypeFromIR(schema.ir, 'create'));
|
|
61
|
+
const rows = [];
|
|
62
|
+
for (let i = 0; i < opts.count; i++)
|
|
63
|
+
rows.push(random(shape, rng));
|
|
64
|
+
return rows;
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/seeding/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyD,MAAM,cAAc,CAAC;AACrF,OAAO,EAAE,gBAAgB,EAAiB,MAAM,iBAAiB,CAAC;AAClE,yCAAyC;AACzC,EAAE;AACF,oFAAoF;AACpF,4FAA4F;AAC5F,6FAA6F;AAC7F,2FAA2F;AAC3F,oFAAoF;AACpF,6FAA6F;AAC7F,0EAA0E;AAC1E,EAAE;AACF,6FAA6F;AAC7F,kFAAkF;AAClF,oEAAoE;AACpE,EAAE;AACF,uFAAuF;AACvF,yFAAyF;AACzF,0FAA0F;AAC1F,2FAA2F;AAC3F,kCAAkC;AAClC,EAAE;AACF,6EAA6E;AAC7E,0IAA0I;AAC1I,sDAAsD;AACtD,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAEzC,kEAAkE;AAClE,MAAM,UAAU,OAAO,CAAC,IAAY;IAClC,IAAI,CAAC,GAAG,IAAI,KAAK,CAAC,CAAC;IACnB,OAAO,GAAG,EAAE;QACV,CAAC,IAAI,CAAC,CAAC;QACP,CAAC,GAAG,CAAC,CAAC,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;QACzB,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;QACzC,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QAC/C,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,UAAU,CAAC;IAC/C,CAAC,CAAC;AACJ,CAAC;AAOD;;;;;;;GAOG;AACH,SAAS,eAAe,CAAC,KAAe;IACtC,OAAO,EAAE,GAAG,KAAK,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;AAC3F,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,QAAQ,CAA0B,MAAuB,EAAE,IAAiB;IAC1F,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC;IACpC,MAAM,KAAK,GAAG,eAAe,CAAC,gBAAgB,CAAC,MAAM,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC,CAAC;IACrE,MAAM,IAAI,GAAmB,EAAE,CAAC;IAChC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE;QAAE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC;IACnE,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Add repository ergonomics around a driver's deliberately small stream
|
|
3
|
+
* surface. The driver owns its cursor; this wrapper owns single-shot use,
|
|
4
|
+
* per-row mapping, and exactly one cleanup path.
|
|
5
|
+
*/
|
|
6
|
+
export declare function createRepositoryStream<Raw, Row>(open: () => AsyncIterable<Raw>, map: (row: Raw) => Row, signal?: AbortSignal): AsyncIterable<Row> & AsyncDisposable;
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/streaming/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,GAAG,EAC7C,IAAI,EAAE,MAAM,aAAa,CAAC,GAAG,CAAC,EAC9B,GAAG,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,GAAG,EACtB,MAAM,CAAC,EAAE,WAAW,GACnB,aAAa,CAAC,GAAG,CAAC,GAAG,eAAe,CAyDtC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Add repository ergonomics around a driver's deliberately small stream
|
|
3
|
+
* surface. The driver owns its cursor; this wrapper owns single-shot use,
|
|
4
|
+
* per-row mapping, and exactly one cleanup path.
|
|
5
|
+
*/
|
|
6
|
+
export function createRepositoryStream(open, map, signal) {
|
|
7
|
+
let started = false;
|
|
8
|
+
let disposed = false;
|
|
9
|
+
let active;
|
|
10
|
+
let closing;
|
|
11
|
+
const close = () => {
|
|
12
|
+
if (closing !== undefined)
|
|
13
|
+
return closing;
|
|
14
|
+
disposed = true;
|
|
15
|
+
const iterator = active;
|
|
16
|
+
active = undefined;
|
|
17
|
+
closing = (async () => {
|
|
18
|
+
if (iterator?.return !== undefined)
|
|
19
|
+
await iterator.return();
|
|
20
|
+
})();
|
|
21
|
+
return closing;
|
|
22
|
+
};
|
|
23
|
+
return {
|
|
24
|
+
[Symbol.asyncIterator]() {
|
|
25
|
+
if (started)
|
|
26
|
+
throw new Error('repository stream is single-shot');
|
|
27
|
+
if (disposed)
|
|
28
|
+
throw new Error('repository stream has been disposed');
|
|
29
|
+
started = true;
|
|
30
|
+
const iterate = async function* () {
|
|
31
|
+
let completed = false;
|
|
32
|
+
try {
|
|
33
|
+
if (disposed)
|
|
34
|
+
throw new Error('repository stream has been disposed');
|
|
35
|
+
signal?.throwIfAborted();
|
|
36
|
+
active = open()[Symbol.asyncIterator]();
|
|
37
|
+
for (;;) {
|
|
38
|
+
signal?.throwIfAborted();
|
|
39
|
+
const iterator = active;
|
|
40
|
+
if (iterator === undefined)
|
|
41
|
+
return;
|
|
42
|
+
const next = await iterator.next();
|
|
43
|
+
if (disposed)
|
|
44
|
+
return;
|
|
45
|
+
signal?.throwIfAborted();
|
|
46
|
+
if (next.done) {
|
|
47
|
+
completed = true;
|
|
48
|
+
active = undefined;
|
|
49
|
+
disposed = true;
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
yield map(next.value);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
finally {
|
|
56
|
+
if (!completed)
|
|
57
|
+
await close();
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
return iterate();
|
|
61
|
+
},
|
|
62
|
+
[Symbol.asyncDispose]() {
|
|
63
|
+
return close();
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/streaming/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CACpC,IAA8B,EAC9B,GAAsB,EACtB,MAAoB;IAEpB,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,IAAI,MAAsC,CAAC;IAC3C,IAAI,OAAkC,CAAC;IAEvC,MAAM,KAAK,GAAG,GAAkB,EAAE;QAChC,IAAI,OAAO,KAAK,SAAS;YAAE,OAAO,OAAO,CAAC;QAC1C,QAAQ,GAAG,IAAI,CAAC;QAChB,MAAM,QAAQ,GAAG,MAAM,CAAC;QACxB,MAAM,GAAG,SAAS,CAAC;QACnB,OAAO,GAAG,CAAC,KAAK,IAAI,EAAE;YACpB,IAAI,QAAQ,EAAE,MAAM,KAAK,SAAS;gBAAE,MAAM,QAAQ,CAAC,MAAM,EAAE,CAAC;QAC9D,CAAC,CAAC,EAAE,CAAC;QACL,OAAO,OAAO,CAAC;IACjB,CAAC,CAAC;IAEF,OAAO;QACL,CAAC,MAAM,CAAC,aAAa,CAAC;YACpB,IAAI,OAAO;gBAAE,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;YACjE,IAAI,QAAQ;gBAAE,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;YACrE,OAAO,GAAG,IAAI,CAAC;YAEf,MAAM,OAAO,GAAG,KAAK,SAAS,CAAC;gBAC7B,IAAI,SAAS,GAAG,KAAK,CAAC;gBACtB,IAAI,CAAC;oBACH,IAAI,QAAQ;wBAAE,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;oBACrE,MAAM,EAAE,cAAc,EAAE,CAAC;oBACzB,MAAM,GAAG,IAAI,EAAE,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC;oBAExC,SAAS,CAAC;wBACR,MAAM,EAAE,cAAc,EAAE,CAAC;wBACzB,MAAM,QAAQ,GAAG,MAAM,CAAC;wBACxB,IAAI,QAAQ,KAAK,SAAS;4BAAE,OAAO;wBACnC,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;wBACnC,IAAI,QAAQ;4BAAE,OAAO;wBACrB,MAAM,EAAE,cAAc,EAAE,CAAC;wBACzB,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;4BACd,SAAS,GAAG,IAAI,CAAC;4BACjB,MAAM,GAAG,SAAS,CAAC;4BACnB,QAAQ,GAAG,IAAI,CAAC;4BAChB,OAAO;wBACT,CAAC;wBACD,MAAM,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;oBACxB,CAAC;gBACH,CAAC;wBAAS,CAAC;oBACT,IAAI,CAAC,SAAS;wBAAE,MAAM,KAAK,EAAE,CAAC;gBAChC,CAAC;YACH,CAAC,CAAC;YAEF,OAAO,OAAO,EAAE,CAAC;QACnB,CAAC;QAED,CAAC,MAAM,CAAC,YAAY,CAAC;YACnB,OAAO,KAAK,EAAE,CAAC;QACjB,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export declare const cockroachDialect: import("@zmdb/sql").SqlDialect<"cockroach">;
|
|
2
|
+
export declare const mssqlDialect: import("@zmdb/sql").SqlDialect<"mssql">;
|
|
3
|
+
export declare const mysqlDialect: import("@zmdb/sql").SqlDialect<"mysql">;
|
|
4
|
+
export declare const postgresDialect: import("@zmdb/sql").SqlDialect<"postgres">;
|
|
5
|
+
export declare const singlestoreDialect: import("@zmdb/sql").SqlDialect<"singlestore">;
|
|
6
|
+
export declare const sqliteDialect: import("@zmdb/sql").SqlDialect<"sqlite">;
|
|
7
|
+
export declare const officialDialects: Readonly<{
|
|
8
|
+
cockroach: import("@zmdb/sql").SqlDialect<"cockroach">;
|
|
9
|
+
mssql: import("@zmdb/sql").SqlDialect<"mssql">;
|
|
10
|
+
mysql: import("@zmdb/sql").SqlDialect<"mysql">;
|
|
11
|
+
postgres: import("@zmdb/sql").SqlDialect<"postgres">;
|
|
12
|
+
singlestore: import("@zmdb/sql").SqlDialect<"singlestore">;
|
|
13
|
+
sqlite: import("@zmdb/sql").SqlDialect<"sqlite">;
|
|
14
|
+
}>;
|
|
15
|
+
export type OfficialDialectName = keyof typeof officialDialects;
|
|
16
|
+
//# sourceMappingURL=official-dialects.fixture.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"official-dialects.fixture.d.ts","sourceRoot":"","sources":["../../src/testing/official-dialects.fixture.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,gBAAgB,6CAAY,CAAC;AAC1C,eAAO,MAAM,YAAY,yCAAQ,CAAC;AAClC,eAAO,MAAM,YAAY,yCAAQ,CAAC;AAClC,eAAO,MAAM,eAAe,4CAAW,CAAC;AACxC,eAAO,MAAM,kBAAkB,+CAAc,CAAC;AAC9C,eAAO,MAAM,aAAa,0CAAS,CAAC;AAEpC,eAAO,MAAM,gBAAgB;;;;;;;EAO3B,CAAC;AAEH,MAAM,MAAM,mBAAmB,GAAG,MAAM,OAAO,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { cockroach } from '@zmdb/cockroach';
|
|
2
|
+
import { mssql } from '@zmdb/mssql';
|
|
3
|
+
import { mysql } from '@zmdb/mysql';
|
|
4
|
+
import { postgres } from '@zmdb/postgres';
|
|
5
|
+
import { singlestore } from '@zmdb/singlestore';
|
|
6
|
+
import { sqlite } from '@zmdb/sqlite';
|
|
7
|
+
export const cockroachDialect = cockroach;
|
|
8
|
+
export const mssqlDialect = mssql;
|
|
9
|
+
export const mysqlDialect = mysql;
|
|
10
|
+
export const postgresDialect = postgres;
|
|
11
|
+
export const singlestoreDialect = singlestore;
|
|
12
|
+
export const sqliteDialect = sqlite;
|
|
13
|
+
export const officialDialects = Object.freeze({
|
|
14
|
+
cockroach: cockroachDialect,
|
|
15
|
+
mssql: mssqlDialect,
|
|
16
|
+
mysql: mysqlDialect,
|
|
17
|
+
postgres: postgresDialect,
|
|
18
|
+
singlestore: singlestoreDialect,
|
|
19
|
+
sqlite: sqliteDialect,
|
|
20
|
+
});
|
|
21
|
+
//# sourceMappingURL=official-dialects.fixture.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"official-dialects.fixture.js","sourceRoot":"","sources":["../../src/testing/official-dialects.fixture.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAEtC,MAAM,CAAC,MAAM,gBAAgB,GAAG,SAAS,CAAC;AAC1C,MAAM,CAAC,MAAM,YAAY,GAAG,KAAK,CAAC;AAClC,MAAM,CAAC,MAAM,YAAY,GAAG,KAAK,CAAC;AAClC,MAAM,CAAC,MAAM,eAAe,GAAG,QAAQ,CAAC;AACxC,MAAM,CAAC,MAAM,kBAAkB,GAAG,WAAW,CAAC;AAC9C,MAAM,CAAC,MAAM,aAAa,GAAG,MAAM,CAAC;AAEpC,MAAM,CAAC,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,CAAC;IAC5C,SAAS,EAAE,gBAAgB;IAC3B,KAAK,EAAE,YAAY;IACnB,KAAK,EAAE,YAAY;IACnB,QAAQ,EAAE,eAAe;IACzB,WAAW,EAAE,kBAAkB;IAC/B,MAAM,EAAE,aAAa;CACtB,CAAC,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type ColumnIR } from '@zmdb/schema/ir';
|
|
2
|
+
import { type CompiledQuery } from '@zmdb/sql';
|
|
3
|
+
import { type Driver } from '../index.js';
|
|
4
|
+
export declare function column(name: string, sql: ColumnIR['sql'], overrides?: Partial<ColumnIR>): ColumnIR;
|
|
5
|
+
interface RecordingDriver extends Driver {
|
|
6
|
+
readonly calls: CompiledQuery[];
|
|
7
|
+
}
|
|
8
|
+
type DriverAnswer = (query: CompiledQuery, call: number) => readonly Record<string, unknown>[] | Promise<readonly Record<string, unknown>[]>;
|
|
9
|
+
export declare function recordingDriver(answer: DriverAnswer): RecordingDriver;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=repository.fixture.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repository.fixture.d.ts","sourceRoot":"","sources":["../../src/testing/repository.fixture.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,WAAW,CAAC;AAE/C,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AAG1C,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,GAAE,OAAO,CAAC,QAAQ,CAAM,GAAG,QAAQ,CAetG;AAED,UAAU,eAAgB,SAAQ,MAAM;IACtC,QAAQ,CAAC,KAAK,EAAE,aAAa,EAAE,CAAC;CACjC;AAED,KAAK,YAAY,GAAG,CAClB,KAAK,EAAE,aAAa,EACpB,IAAI,EAAE,MAAM,KACT,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,OAAO,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC;AAEtF,wBAAgB,eAAe,CAAC,MAAM,EAAE,YAAY,GAAG,eAAe,CAWrE"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import {} from '@zmdb/schema/ir';
|
|
2
|
+
import {} from '@zmdb/sql';
|
|
3
|
+
import {} from '../index.js';
|
|
4
|
+
import { postgresDialect } from './official-dialects.fixture.js';
|
|
5
|
+
export function column(name, sql, overrides = {}) {
|
|
6
|
+
return {
|
|
7
|
+
name,
|
|
8
|
+
physicalName: name,
|
|
9
|
+
sql,
|
|
10
|
+
nullable: false,
|
|
11
|
+
primaryKey: false,
|
|
12
|
+
serial: false,
|
|
13
|
+
unique: false,
|
|
14
|
+
hasDefault: false,
|
|
15
|
+
sensitive: false,
|
|
16
|
+
constraints: {},
|
|
17
|
+
rules: [],
|
|
18
|
+
...overrides,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export function recordingDriver(answer) {
|
|
22
|
+
const calls = [];
|
|
23
|
+
return {
|
|
24
|
+
dialect: postgresDialect,
|
|
25
|
+
calls,
|
|
26
|
+
async execute(query) {
|
|
27
|
+
const call = calls.length;
|
|
28
|
+
calls.push(query);
|
|
29
|
+
return answer(query, call);
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=repository.fixture.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repository.fixture.js","sourceRoot":"","sources":["../../src/testing/repository.fixture.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAsB,MAAM,WAAW,CAAC;AAE/C,OAAO,EAAe,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAEjE,MAAM,UAAU,MAAM,CAAC,IAAY,EAAE,GAAoB,EAAE,SAAS,GAAsB,EAAE;IAC1F,OAAO;QACL,IAAI;QACJ,YAAY,EAAE,IAAI;QAClB,GAAG;QACH,QAAQ,EAAE,KAAK;QACf,UAAU,EAAE,KAAK;QACjB,MAAM,EAAE,KAAK;QACb,MAAM,EAAE,KAAK;QACb,UAAU,EAAE,KAAK;QACjB,SAAS,EAAE,KAAK;QAChB,WAAW,EAAE,EAAE;QACf,KAAK,EAAE,EAAE;QACT,GAAG,SAAS;KACb,CAAC;AACJ,CAAC;AAWD,MAAM,UAAU,eAAe,CAAC,MAAoB;IAClD,MAAM,KAAK,GAAoB,EAAE,CAAC;IAClC,OAAO;QACL,OAAO,EAAE,eAAe;QACxB,KAAK;QACL,KAAK,CAAC,OAAO,CAAC,KAAK;YACjB,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC;YAC1B,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAClB,OAAO,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QAC7B,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { type CompiledQuery, type DialectTarget } from '@zmdb/sql';
|
|
2
|
+
import { type ExecuteOptions } from '../index.js';
|
|
3
|
+
export type TransactionState = 'active' | 'closed' | 'committed' | 'rolled_back' | string;
|
|
4
|
+
export interface TransactionContext<State extends string = 'active'> {
|
|
5
|
+
readonly _state?: State | undefined;
|
|
6
|
+
readonly dialect?: DialectTarget;
|
|
7
|
+
execute(query: CompiledQuery, opts?: ExecuteOptions): Promise<readonly Record<string, unknown>[]>;
|
|
8
|
+
stream?(query: CompiledQuery, opts?: ExecuteOptions): AsyncIterable<Record<string, unknown>>;
|
|
9
|
+
savepoint<R>(fn: (tx: TransactionContext<State>) => Promise<R>): Promise<R>;
|
|
10
|
+
}
|
|
11
|
+
export type ActiveTransactionContext = TransactionContext<'active'>;
|
|
12
|
+
export type ClosedTransactionContext = TransactionContext<'closed'>;
|
|
13
|
+
export declare function markTransactionClosed<State extends string = 'active'>(tx: TransactionContext<State>): ClosedTransactionContext;
|
|
14
|
+
export interface TxConnection {
|
|
15
|
+
readonly dialect?: DialectTarget;
|
|
16
|
+
raw(sql: string): Promise<void>;
|
|
17
|
+
execute(query: CompiledQuery, opts?: ExecuteOptions): Promise<readonly Record<string, unknown>[]>;
|
|
18
|
+
stream?(query: CompiledQuery, opts?: ExecuteOptions): AsyncIterable<Record<string, unknown>>;
|
|
19
|
+
}
|
|
20
|
+
export interface TransactionalDb {
|
|
21
|
+
transaction<R, State extends string = 'active'>(fn: (tx: TransactionContext<State>) => Promise<R>, options?: TransactionOptions): Promise<R>;
|
|
22
|
+
}
|
|
23
|
+
export interface TransactionRetryPolicy {
|
|
24
|
+
/** Retries after the first failed attempt. The transaction body may run `maxRetries + 1` times. */
|
|
25
|
+
readonly maxRetries: number;
|
|
26
|
+
/** Exponential-backoff starting delay. Defaults to 10 ms. */
|
|
27
|
+
readonly baseDelayMs?: number;
|
|
28
|
+
/** Backoff ceiling. Defaults to 1,000 ms. */
|
|
29
|
+
readonly maxDelayMs?: number;
|
|
30
|
+
}
|
|
31
|
+
export interface TransactionOptions {
|
|
32
|
+
/**
|
|
33
|
+
* Explicit opt-in only: retrying re-runs the callback, including any side effects
|
|
34
|
+
* outside the database. Keep those effects out of a retrying transaction body.
|
|
35
|
+
*/
|
|
36
|
+
readonly retry?: TransactionRetryPolicy;
|
|
37
|
+
}
|
|
38
|
+
export declare function createTransactionalDb(conn: TxConnection): TransactionalDb;
|
|
39
|
+
export declare function batch<R, State extends string = 'active'>(db: TransactionalDb, ops: readonly ((tx: TransactionContext<State>) => Promise<R>)[]): Promise<R[]>;
|
|
40
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/transactions/index.ts"],"names":[],"mappings":"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"}
|