@minnowdb/core 0.0.1 → 0.1.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 +21 -0
- package/README.md +38 -1
- package/dist/block-format/block.d.ts +46 -0
- package/dist/block-format/block.d.ts.map +1 -0
- package/dist/block-format/block.js +244 -0
- package/dist/block-format/block.js.map +1 -0
- package/dist/block-format/checksum.d.ts +7 -0
- package/dist/block-format/checksum.d.ts.map +1 -0
- package/dist/block-format/checksum.js +56 -0
- package/dist/block-format/checksum.js.map +1 -0
- package/dist/block-format/codecs.d.ts +24 -0
- package/dist/block-format/codecs.d.ts.map +1 -0
- package/dist/block-format/codecs.js +102 -0
- package/dist/block-format/codecs.js.map +1 -0
- package/dist/block-format/column.d.ts +8 -0
- package/dist/block-format/column.d.ts.map +1 -0
- package/dist/block-format/column.js +166 -0
- package/dist/block-format/column.js.map +1 -0
- package/dist/block-format/index.d.ts +7 -0
- package/dist/block-format/index.d.ts.map +1 -0
- package/dist/block-format/index.js +7 -0
- package/dist/block-format/index.js.map +1 -0
- package/dist/block-format/physical.d.ts +20 -0
- package/dist/block-format/physical.d.ts.map +1 -0
- package/dist/block-format/physical.js +439 -0
- package/dist/block-format/physical.js.map +1 -0
- package/dist/block-format/types.d.ts +93 -0
- package/dist/block-format/types.d.ts.map +1 -0
- package/dist/block-format/types.js +2 -0
- package/dist/block-format/types.js.map +1 -0
- package/dist/engine/artifact-cache.d.ts +22 -0
- package/dist/engine/artifact-cache.d.ts.map +1 -0
- package/dist/engine/artifact-cache.js +68 -0
- package/dist/engine/artifact-cache.js.map +1 -0
- package/dist/engine/batch.d.ts +28 -0
- package/dist/engine/batch.d.ts.map +1 -0
- package/dist/engine/batch.js +38 -0
- package/dist/engine/batch.js.map +1 -0
- package/dist/engine/buffered-writer.d.ts +43 -0
- package/dist/engine/buffered-writer.d.ts.map +1 -0
- package/dist/engine/buffered-writer.js +158 -0
- package/dist/engine/buffered-writer.js.map +1 -0
- package/dist/engine/catalog.d.ts +82 -0
- package/dist/engine/catalog.d.ts.map +1 -0
- package/dist/engine/catalog.js +47 -0
- package/dist/engine/catalog.js.map +1 -0
- package/dist/engine/client.d.ts +211 -0
- package/dist/engine/client.d.ts.map +1 -0
- package/dist/engine/client.js +538 -0
- package/dist/engine/client.js.map +1 -0
- package/dist/engine/coordinator.d.ts +17 -0
- package/dist/engine/coordinator.d.ts.map +1 -0
- package/dist/engine/coordinator.js +60 -0
- package/dist/engine/coordinator.js.map +1 -0
- package/dist/engine/database.d.ts +661 -0
- package/dist/engine/database.d.ts.map +1 -0
- package/dist/engine/database.js +10313 -0
- package/dist/engine/database.js.map +1 -0
- package/dist/engine/defaults.d.ts +33 -0
- package/dist/engine/defaults.d.ts.map +1 -0
- package/dist/engine/defaults.js +87 -0
- package/dist/engine/defaults.js.map +1 -0
- package/dist/engine/errors.d.ts +55 -0
- package/dist/engine/errors.d.ts.map +1 -0
- package/dist/engine/errors.js +81 -0
- package/dist/engine/errors.js.map +1 -0
- package/dist/engine/fts.d.ts +93 -0
- package/dist/engine/fts.d.ts.map +1 -0
- package/dist/engine/fts.js +273 -0
- package/dist/engine/fts.js.map +1 -0
- package/dist/engine/group-index.d.ts +32 -0
- package/dist/engine/group-index.d.ts.map +1 -0
- package/dist/engine/group-index.js +366 -0
- package/dist/engine/group-index.js.map +1 -0
- package/dist/engine/index.d.ts +13 -0
- package/dist/engine/index.d.ts.map +1 -0
- package/dist/engine/index.js +12 -0
- package/dist/engine/index.js.map +1 -0
- package/dist/engine/join-index.d.ts +12 -0
- package/dist/engine/join-index.d.ts.map +1 -0
- package/dist/engine/join-index.js +217 -0
- package/dist/engine/join-index.js.map +1 -0
- package/dist/engine/live.d.ts +86 -0
- package/dist/engine/live.d.ts.map +1 -0
- package/dist/engine/live.js +289 -0
- package/dist/engine/live.js.map +1 -0
- package/dist/engine/memory.d.ts +37 -0
- package/dist/engine/memory.d.ts.map +1 -0
- package/dist/engine/memory.js +119 -0
- package/dist/engine/memory.js.map +1 -0
- package/dist/engine/optimizer.d.ts +20 -0
- package/dist/engine/optimizer.d.ts.map +1 -0
- package/dist/engine/optimizer.js +1170 -0
- package/dist/engine/optimizer.js.map +1 -0
- package/dist/engine/query-cache.d.ts +10 -0
- package/dist/engine/query-cache.d.ts.map +1 -0
- package/dist/engine/query-cache.js +58 -0
- package/dist/engine/query-cache.js.map +1 -0
- package/dist/engine/query.d.ts +844 -0
- package/dist/engine/query.d.ts.map +1 -0
- package/dist/engine/query.js +7450 -0
- package/dist/engine/query.js.map +1 -0
- package/dist/engine/schema-wire.d.ts +92 -0
- package/dist/engine/schema-wire.d.ts.map +1 -0
- package/dist/engine/schema-wire.js +115 -0
- package/dist/engine/schema-wire.js.map +1 -0
- package/dist/engine/schema.d.ts +394 -0
- package/dist/engine/schema.d.ts.map +1 -0
- package/dist/engine/schema.js +709 -0
- package/dist/engine/schema.js.map +1 -0
- package/dist/engine/sort-keys.d.ts +36 -0
- package/dist/engine/sort-keys.d.ts.map +1 -0
- package/dist/engine/sort-keys.js +60 -0
- package/dist/engine/sort-keys.js.map +1 -0
- package/dist/engine/sql-json.d.ts +30 -0
- package/dist/engine/sql-json.d.ts.map +1 -0
- package/dist/engine/sql-json.js +120 -0
- package/dist/engine/sql-json.js.map +1 -0
- package/dist/engine/sql-semantics.d.ts +31 -0
- package/dist/engine/sql-semantics.d.ts.map +1 -0
- package/dist/engine/sql-semantics.js +121 -0
- package/dist/engine/sql-semantics.js.map +1 -0
- package/dist/engine/vector.d.ts +87 -0
- package/dist/engine/vector.d.ts.map +1 -0
- package/dist/engine/vector.js +4227 -0
- package/dist/engine/vector.js.map +1 -0
- package/dist/engine/worker-host.d.ts +48 -0
- package/dist/engine/worker-host.d.ts.map +1 -0
- package/dist/engine/worker-host.js +501 -0
- package/dist/engine/worker-host.js.map +1 -0
- package/dist/engine/worker.d.ts +2 -0
- package/dist/engine/worker.d.ts.map +1 -0
- package/dist/engine/worker.js +14 -0
- package/dist/engine/worker.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/plan/index.d.ts +17 -0
- package/dist/plan/index.d.ts.map +1 -0
- package/dist/plan/index.js +17 -0
- package/dist/plan/index.js.map +1 -0
- package/dist/storage/fixture-shape.d.ts +42 -0
- package/dist/storage/fixture-shape.d.ts.map +1 -0
- package/dist/storage/fixture-shape.js +146 -0
- package/dist/storage/fixture-shape.js.map +1 -0
- package/dist/storage/index.d.ts +5 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +5 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/indexeddb.d.ts +139 -0
- package/dist/storage/indexeddb.d.ts.map +1 -0
- package/dist/storage/indexeddb.js +3161 -0
- package/dist/storage/indexeddb.js.map +1 -0
- package/dist/storage/memory.d.ts +121 -0
- package/dist/storage/memory.d.ts.map +1 -0
- package/dist/storage/memory.js +1455 -0
- package/dist/storage/memory.js.map +1 -0
- package/dist/storage/snapshot.d.ts +108 -0
- package/dist/storage/snapshot.d.ts.map +1 -0
- package/dist/storage/snapshot.js +276 -0
- package/dist/storage/snapshot.js.map +1 -0
- package/dist/storage/types.d.ts +895 -0
- package/dist/storage/types.d.ts.map +1 -0
- package/dist/storage/types.js +1549 -0
- package/dist/storage/types.js.map +1 -0
- package/dist/testing/index.d.ts +76 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +233 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/seeds.d.ts +11 -0
- package/dist/testing/seeds.d.ts.map +1 -0
- package/dist/testing/seeds.js +50 -0
- package/dist/testing/seeds.js.map +1 -0
- package/dist/transactions/index.d.ts +148 -0
- package/dist/transactions/index.d.ts.map +1 -0
- package/dist/transactions/index.js +662 -0
- package/dist/transactions/index.js.map +1 -0
- package/dist/worker-protocol/index.d.ts +84 -0
- package/dist/worker-protocol/index.d.ts.map +1 -0
- package/dist/worker-protocol/index.js +117 -0
- package/dist/worker-protocol/index.js.map +1 -0
- package/package.json +66 -16
- package/sql-feature-matrix.json +1275 -0
- package/index.d.ts +0 -1
- package/index.js +0 -1
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Byte-bounded LRU for decoded blocks, vectors, derived results, and memoized query results.
|
|
3
|
+
* Payloads are immutable by convention; callers own the byte estimates for their artifact type.
|
|
4
|
+
*/
|
|
5
|
+
export class ArtifactCache {
|
|
6
|
+
#limitBytes;
|
|
7
|
+
#entries = new Map();
|
|
8
|
+
#usedBytes = 0;
|
|
9
|
+
#hits = 0;
|
|
10
|
+
#misses = 0;
|
|
11
|
+
#evictions = 0;
|
|
12
|
+
constructor(limitBytes) {
|
|
13
|
+
if (!Number.isSafeInteger(limitBytes) || limitBytes < 0) {
|
|
14
|
+
throw new RangeError("Prepare cache bytes must be a non-negative whole number");
|
|
15
|
+
}
|
|
16
|
+
this.#limitBytes = limitBytes;
|
|
17
|
+
}
|
|
18
|
+
get enabled() {
|
|
19
|
+
return this.#limitBytes > 0;
|
|
20
|
+
}
|
|
21
|
+
get(key) {
|
|
22
|
+
if (!this.enabled)
|
|
23
|
+
return undefined;
|
|
24
|
+
const entry = this.#entries.get(key);
|
|
25
|
+
if (entry === undefined) {
|
|
26
|
+
this.#misses += 1;
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
this.#hits += 1;
|
|
30
|
+
this.#entries.delete(key);
|
|
31
|
+
this.#entries.set(key, entry);
|
|
32
|
+
return entry.payload;
|
|
33
|
+
}
|
|
34
|
+
put(key, payload, bytes) {
|
|
35
|
+
if (!this.enabled || bytes > this.#limitBytes)
|
|
36
|
+
return;
|
|
37
|
+
if (!Number.isSafeInteger(bytes) || bytes < 0) {
|
|
38
|
+
throw new RangeError("Artifact cache entry bytes must be a non-negative whole number");
|
|
39
|
+
}
|
|
40
|
+
const existing = this.#entries.get(key);
|
|
41
|
+
if (existing !== undefined) {
|
|
42
|
+
this.#entries.delete(key);
|
|
43
|
+
this.#usedBytes -= existing.bytes;
|
|
44
|
+
}
|
|
45
|
+
this.#entries.set(key, { payload, bytes });
|
|
46
|
+
this.#usedBytes += bytes;
|
|
47
|
+
for (const [oldestKey, entry] of this.#entries) {
|
|
48
|
+
if (this.#usedBytes <= this.#limitBytes)
|
|
49
|
+
break;
|
|
50
|
+
if (oldestKey === key)
|
|
51
|
+
continue;
|
|
52
|
+
this.#entries.delete(oldestKey);
|
|
53
|
+
this.#usedBytes -= entry.bytes;
|
|
54
|
+
this.#evictions += 1;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
stats() {
|
|
58
|
+
return {
|
|
59
|
+
limitBytes: this.#limitBytes,
|
|
60
|
+
usedBytes: this.#usedBytes,
|
|
61
|
+
entries: this.#entries.size,
|
|
62
|
+
hits: this.#hits,
|
|
63
|
+
misses: this.#misses,
|
|
64
|
+
evictions: this.#evictions,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=artifact-cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"artifact-cache.js","sourceRoot":"","sources":["../../src/engine/artifact-cache.ts"],"names":[],"mappings":"AAUA;;;GAGG;AACH,MAAM,OAAO,aAAa;IACf,WAAW,CAAS;IACpB,QAAQ,GAAG,IAAI,GAAG,EAA+C,CAAC;IAC3E,UAAU,GAAG,CAAC,CAAC;IACf,KAAK,GAAG,CAAC,CAAC;IACV,OAAO,GAAG,CAAC,CAAC;IACZ,UAAU,GAAG,CAAC,CAAC;IAEf,YAAY,UAAkB;QAC5B,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,UAAU,CAAC,IAAI,UAAU,GAAG,CAAC,EAAE,CAAC;YACxD,MAAM,IAAI,UAAU,CAAC,yDAAyD,CAAC,CAAC;QAClF,CAAC;QACD,IAAI,CAAC,WAAW,GAAG,UAAU,CAAC;IAChC,CAAC;IAED,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC;IAC9B,CAAC;IAED,GAAG,CAAC,GAAW;QACb,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO,SAAS,CAAC;QACpC,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACrC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC;YAClB,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC;QAChB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC1B,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC9B,OAAO,KAAK,CAAC,OAAO,CAAC;IACvB,CAAC;IAED,GAAG,CAAC,GAAW,EAAE,OAAgB,EAAE,KAAa;QAC9C,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,KAAK,GAAG,IAAI,CAAC,WAAW;YAAE,OAAO;QACtD,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;YAC9C,MAAM,IAAI,UAAU,CAAC,gEAAgE,CAAC,CAAC;QACzF,CAAC;QACD,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACxC,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC3B,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC1B,IAAI,CAAC,UAAU,IAAI,QAAQ,CAAC,KAAK,CAAC;QACpC,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;QAC3C,IAAI,CAAC,UAAU,IAAI,KAAK,CAAC;QACzB,KAAK,MAAM,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC/C,IAAI,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,WAAW;gBAAE,MAAM;YAC/C,IAAI,SAAS,KAAK,GAAG;gBAAE,SAAS;YAChC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;YAChC,IAAI,CAAC,UAAU,IAAI,KAAK,CAAC,KAAK,CAAC;YAC/B,IAAI,CAAC,UAAU,IAAI,CAAC,CAAC;QACvB,CAAC;IACH,CAAC;IAED,KAAK;QACH,OAAO;YACL,UAAU,EAAE,IAAI,CAAC,WAAW;YAC5B,SAAS,EAAE,IAAI,CAAC,UAAU;YAC1B,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI;YAC3B,IAAI,EAAE,IAAI,CAAC,KAAK;YAChB,MAAM,EAAE,IAAI,CAAC,OAAO;YACpB,SAAS,EAAE,IAAI,CAAC,UAAU;SAC3B,CAAC;IACJ,CAAC;CACF"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The input shapes the batch writes accept. Rows are the ordinary form — one object per row, the
|
|
3
|
+
* same shape queries return. The columnar form (one array per column) is what the engine encodes,
|
|
4
|
+
* so it stays available for bulk loads that already hold columns and want to skip the pivot.
|
|
5
|
+
*
|
|
6
|
+
* This module deliberately has no imports: the main-thread client normalizes here too, and must
|
|
7
|
+
* not pull the engine in behind it.
|
|
8
|
+
*/
|
|
9
|
+
/** A value a column can hold. */
|
|
10
|
+
export type BatchValue = boolean | number | string | Date | null;
|
|
11
|
+
/** One row. Columns left out are written as null, so nullable columns can be omitted. */
|
|
12
|
+
export type BatchRow = Readonly<Record<string, BatchValue>>;
|
|
13
|
+
/** The columnar form: one array per column, all of the same length, aligned by index. */
|
|
14
|
+
export interface ColumnarBatch {
|
|
15
|
+
columns: Readonly<Record<string, readonly BatchValue[]>>;
|
|
16
|
+
/**
|
|
17
|
+
* The batch's row count when no column carries it — a pivot of rows whose every column is
|
|
18
|
+
* default-generated produces an empty column map, and the count would otherwise be lost
|
|
19
|
+
* across the worker boundary.
|
|
20
|
+
*/
|
|
21
|
+
rowCount?: number;
|
|
22
|
+
}
|
|
23
|
+
/** What `insertBatch` and `upsertBatch` take: rows, or columns for a bulk load. */
|
|
24
|
+
export type InsertBatchInput = readonly BatchRow[] | ColumnarBatch;
|
|
25
|
+
export declare function isColumnarBatch(input: InsertBatchInput): input is ColumnarBatch;
|
|
26
|
+
/** Pivots rows into the engine's columnar form; a columnar batch passes straight through. */
|
|
27
|
+
export declare function toColumnarBatch(input: InsertBatchInput): ColumnarBatch;
|
|
28
|
+
//# sourceMappingURL=batch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"batch.d.ts","sourceRoot":"","sources":["../../src/engine/batch.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,iCAAiC;AACjC,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC;AAEjE,yFAAyF;AACzF,MAAM,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;AAE5D,yFAAyF;AACzF,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,UAAU,EAAE,CAAC,CAAC,CAAC;IACzD;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,mFAAmF;AACnF,MAAM,MAAM,gBAAgB,GAAG,SAAS,QAAQ,EAAE,GAAG,aAAa,CAAC;AAEnE,wBAAgB,eAAe,CAAC,KAAK,EAAE,gBAAgB,GAAG,KAAK,IAAI,aAAa,CAE/E;AAED,6FAA6F;AAC7F,wBAAgB,eAAe,CAAC,KAAK,EAAE,gBAAgB,GAAG,aAAa,CAqBtE"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The input shapes the batch writes accept. Rows are the ordinary form — one object per row, the
|
|
3
|
+
* same shape queries return. The columnar form (one array per column) is what the engine encodes,
|
|
4
|
+
* so it stays available for bulk loads that already hold columns and want to skip the pivot.
|
|
5
|
+
*
|
|
6
|
+
* This module deliberately has no imports: the main-thread client normalizes here too, and must
|
|
7
|
+
* not pull the engine in behind it.
|
|
8
|
+
*/
|
|
9
|
+
export function isColumnarBatch(input) {
|
|
10
|
+
return !Array.isArray(input);
|
|
11
|
+
}
|
|
12
|
+
/** Pivots rows into the engine's columnar form; a columnar batch passes straight through. */
|
|
13
|
+
export function toColumnarBatch(input) {
|
|
14
|
+
if (isColumnarBatch(input))
|
|
15
|
+
return input;
|
|
16
|
+
if (input.length === 0)
|
|
17
|
+
throw new TypeError("A batch needs at least one row");
|
|
18
|
+
// One pass over the rows, discovering columns in first-seen order. A column no row mentions
|
|
19
|
+
// stays absent, so the write still fails with "Missing column"; a column only some rows
|
|
20
|
+
// mention keeps its pre-filled nulls, which the per-column nullability check then accepts or
|
|
21
|
+
// rejects. Reading each row object once beats one full re-walk of every row per column.
|
|
22
|
+
const columnsByName = new Map();
|
|
23
|
+
for (let index = 0; index < input.length; index += 1) {
|
|
24
|
+
const row = input[index];
|
|
25
|
+
if (row === undefined)
|
|
26
|
+
continue;
|
|
27
|
+
for (const name of Object.keys(row)) {
|
|
28
|
+
let values = columnsByName.get(name);
|
|
29
|
+
if (values === undefined) {
|
|
30
|
+
values = new Array(input.length).fill(null);
|
|
31
|
+
columnsByName.set(name, values);
|
|
32
|
+
}
|
|
33
|
+
values[index] = row[name] ?? null;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return { columns: Object.fromEntries(columnsByName), rowCount: input.length };
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=batch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"batch.js","sourceRoot":"","sources":["../../src/engine/batch.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAsBH,MAAM,UAAU,eAAe,CAAC,KAAuB;IACrD,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC/B,CAAC;AAED,6FAA6F;AAC7F,MAAM,UAAU,eAAe,CAAC,KAAuB;IACrD,IAAI,eAAe,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACzC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,MAAM,IAAI,SAAS,CAAC,gCAAgC,CAAC,CAAC;IAC9E,4FAA4F;IAC5F,wFAAwF;IACxF,6FAA6F;IAC7F,wFAAwF;IACxF,MAAM,aAAa,GAAG,IAAI,GAAG,EAAwB,CAAC;IACtD,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACrD,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;QACzB,IAAI,GAAG,KAAK,SAAS;YAAE,SAAS;QAChC,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YACpC,IAAI,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACrC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;gBACzB,MAAM,GAAG,IAAI,KAAK,CAAa,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACxD,aAAa,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YAClC,CAAC;YACD,MAAM,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC;QACpC,CAAC;IACH,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,WAAW,CAAC,aAAa,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC;AAChF,CAAC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { BatchValue } from "./batch.js";
|
|
2
|
+
import type { InsertBatchResult, MinnowDatabase, UpsertBatchResult } from "./database.js";
|
|
3
|
+
export interface BufferedWriterOptions {
|
|
4
|
+
mode?: "insert" | "upsert";
|
|
5
|
+
maxRows?: number;
|
|
6
|
+
maxBytes?: number;
|
|
7
|
+
maxAgeMs?: number;
|
|
8
|
+
onError?: (error: unknown) => void;
|
|
9
|
+
}
|
|
10
|
+
export type BufferedFlushResult = InsertBatchResult | UpsertBatchResult;
|
|
11
|
+
export interface LifecycleFlushRequester {
|
|
12
|
+
requestFlush(): void;
|
|
13
|
+
}
|
|
14
|
+
export interface LifecycleDocumentTarget {
|
|
15
|
+
readonly visibilityState: string;
|
|
16
|
+
addEventListener(type: "visibilitychange", listener: () => void): void;
|
|
17
|
+
removeEventListener(type: "visibilitychange", listener: () => void): void;
|
|
18
|
+
}
|
|
19
|
+
export interface LifecyclePageTarget {
|
|
20
|
+
addEventListener(type: "pagehide", listener: () => void): void;
|
|
21
|
+
removeEventListener(type: "pagehide", listener: () => void): void;
|
|
22
|
+
}
|
|
23
|
+
export interface LifecycleFlushOptions {
|
|
24
|
+
document?: LifecycleDocumentTarget;
|
|
25
|
+
page?: LifecyclePageTarget;
|
|
26
|
+
}
|
|
27
|
+
/** Batches row-oriented writes by row count, estimated bytes, or age. */
|
|
28
|
+
export declare class BufferedTableWriter {
|
|
29
|
+
#private;
|
|
30
|
+
private readonly database;
|
|
31
|
+
private readonly tableName;
|
|
32
|
+
constructor(database: MinnowDatabase, tableName: string, options?: BufferedWriterOptions);
|
|
33
|
+
get pendingRowCount(): number;
|
|
34
|
+
get estimatedBytes(): number;
|
|
35
|
+
add(row: Readonly<Record<string, BatchValue>>): Promise<BufferedFlushResult | undefined>;
|
|
36
|
+
flush(): Promise<BufferedFlushResult | undefined>;
|
|
37
|
+
requestFlush(): void;
|
|
38
|
+
close(): Promise<BufferedFlushResult | undefined>;
|
|
39
|
+
discard(): number;
|
|
40
|
+
}
|
|
41
|
+
/** Requests a non-blocking flush when the browser hides or unloads the page. */
|
|
42
|
+
export declare function attachLifecycleFlush(requester: LifecycleFlushRequester, options?: LifecycleFlushOptions): () => void;
|
|
43
|
+
//# sourceMappingURL=buffered-writer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buffered-writer.d.ts","sourceRoot":"","sources":["../../src/engine/buffered-writer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAE1F,MAAM,WAAW,qBAAqB;IACpC,IAAI,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CACpC;AAED,MAAM,MAAM,mBAAmB,GAAG,iBAAiB,GAAG,iBAAiB,CAAC;AAExE,MAAM,WAAW,uBAAuB;IACtC,YAAY,IAAI,IAAI,CAAC;CACtB;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,gBAAgB,CAAC,IAAI,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;IACvE,mBAAmB,CAAC,IAAI,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;CAC3E;AAED,MAAM,WAAW,mBAAmB;IAClC,gBAAgB,CAAC,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;IAC/D,mBAAmB,CAAC,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;CACnE;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,EAAE,uBAAuB,CAAC;IACnC,IAAI,CAAC,EAAE,mBAAmB,CAAC;CAC5B;AAED,yEAAyE;AACzE,qBAAa,mBAAmB;;IAa5B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,SAAS;gBADT,QAAQ,EAAE,cAAc,EACxB,SAAS,EAAE,MAAM,EAClC,OAAO,GAAE,qBAA0B;IASrC,IAAI,eAAe,IAAI,MAAM,CAE5B;IAED,IAAI,cAAc,IAAI,MAAM,CAE3B;IAEK,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,GAAG,OAAO,CAAC,mBAAmB,GAAG,SAAS,CAAC;IAYxF,KAAK,IAAI,OAAO,CAAC,mBAAmB,GAAG,SAAS,CAAC;IAsBvD,YAAY,IAAI,IAAI;IAKd,KAAK,IAAI,OAAO,CAAC,mBAAmB,GAAG,SAAS,CAAC;IAYvD,OAAO,IAAI,MAAM;CAiClB;AAED,gFAAgF;AAChF,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,uBAAuB,EAClC,OAAO,GAAE,qBAA0B,GAClC,MAAM,IAAI,CAcZ"}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/** Batches row-oriented writes by row count, estimated bytes, or age. */
|
|
2
|
+
export class BufferedTableWriter {
|
|
3
|
+
database;
|
|
4
|
+
tableName;
|
|
5
|
+
#mode;
|
|
6
|
+
#maxRows;
|
|
7
|
+
#maxBytes;
|
|
8
|
+
#maxAgeMs;
|
|
9
|
+
#onError;
|
|
10
|
+
#rows = [];
|
|
11
|
+
#estimatedBytes = 0;
|
|
12
|
+
#timer;
|
|
13
|
+
#inFlight;
|
|
14
|
+
#closed = false;
|
|
15
|
+
constructor(database, tableName, options = {}) {
|
|
16
|
+
this.database = database;
|
|
17
|
+
this.tableName = tableName;
|
|
18
|
+
this.#mode = options.mode ?? "insert";
|
|
19
|
+
this.#maxRows = positiveWholeNumber(options.maxRows ?? 1_000, "Buffered row limit");
|
|
20
|
+
this.#maxBytes = positiveWholeNumber(options.maxBytes ?? 1024 * 1024, "Buffered byte limit");
|
|
21
|
+
this.#maxAgeMs = positiveWholeNumber(options.maxAgeMs ?? 1_000, "Buffered age limit");
|
|
22
|
+
this.#onError = options.onError;
|
|
23
|
+
}
|
|
24
|
+
get pendingRowCount() {
|
|
25
|
+
return this.#rows.length;
|
|
26
|
+
}
|
|
27
|
+
get estimatedBytes() {
|
|
28
|
+
return this.#estimatedBytes;
|
|
29
|
+
}
|
|
30
|
+
async add(row) {
|
|
31
|
+
this.#assertOpen();
|
|
32
|
+
const copy = cloneRow(row);
|
|
33
|
+
this.#rows.push(copy);
|
|
34
|
+
this.#estimatedBytes += estimateRowBytes(copy);
|
|
35
|
+
this.#scheduleAgeFlush();
|
|
36
|
+
if (this.#rows.length >= this.#maxRows || this.#estimatedBytes >= this.#maxBytes) {
|
|
37
|
+
return this.flush();
|
|
38
|
+
}
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
async flush() {
|
|
42
|
+
if (this.#inFlight !== undefined)
|
|
43
|
+
return this.#inFlight;
|
|
44
|
+
if (this.#rows.length === 0)
|
|
45
|
+
return undefined;
|
|
46
|
+
this.#clearTimer();
|
|
47
|
+
const rows = this.#rows.splice(0);
|
|
48
|
+
this.#estimatedBytes = 0;
|
|
49
|
+
const operation = this.#mode === "upsert"
|
|
50
|
+
? this.database.upsertBatch(this.tableName, rows)
|
|
51
|
+
: this.database.insertBatch(this.tableName, rows);
|
|
52
|
+
this.#inFlight = operation;
|
|
53
|
+
try {
|
|
54
|
+
return await operation;
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
this.#rows.unshift(...rows);
|
|
58
|
+
this.#estimatedBytes = this.#rows.reduce((total, row) => total + estimateRowBytes(row), 0);
|
|
59
|
+
throw error;
|
|
60
|
+
}
|
|
61
|
+
finally {
|
|
62
|
+
this.#inFlight = undefined;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
requestFlush() {
|
|
66
|
+
if (this.#closed)
|
|
67
|
+
return;
|
|
68
|
+
void this.#flushPending().catch((error) => this.#onError?.(error));
|
|
69
|
+
}
|
|
70
|
+
async close() {
|
|
71
|
+
if (this.#closed)
|
|
72
|
+
return undefined;
|
|
73
|
+
let result;
|
|
74
|
+
while (this.#inFlight !== undefined || this.#rows.length > 0) {
|
|
75
|
+
result = await this.flush();
|
|
76
|
+
if (this.#inFlight !== undefined)
|
|
77
|
+
await this.#inFlight;
|
|
78
|
+
}
|
|
79
|
+
this.#closed = true;
|
|
80
|
+
this.#clearTimer();
|
|
81
|
+
return result;
|
|
82
|
+
}
|
|
83
|
+
discard() {
|
|
84
|
+
this.#assertOpen();
|
|
85
|
+
const discarded = this.#rows.length;
|
|
86
|
+
this.#rows.length = 0;
|
|
87
|
+
this.#estimatedBytes = 0;
|
|
88
|
+
this.#clearTimer();
|
|
89
|
+
return discarded;
|
|
90
|
+
}
|
|
91
|
+
async #flushPending() {
|
|
92
|
+
while (this.#inFlight !== undefined || this.#rows.length > 0) {
|
|
93
|
+
if (this.#inFlight !== undefined)
|
|
94
|
+
await this.#inFlight;
|
|
95
|
+
else
|
|
96
|
+
await this.flush();
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
#scheduleAgeFlush() {
|
|
100
|
+
if (this.#timer !== undefined || this.#rows.length === 0 || this.#closed)
|
|
101
|
+
return;
|
|
102
|
+
this.#timer = setTimeout(() => {
|
|
103
|
+
this.#timer = undefined;
|
|
104
|
+
void this.#flushPending().catch((error) => this.#onError?.(error));
|
|
105
|
+
}, this.#maxAgeMs);
|
|
106
|
+
}
|
|
107
|
+
#clearTimer() {
|
|
108
|
+
if (this.#timer === undefined)
|
|
109
|
+
return;
|
|
110
|
+
clearTimeout(this.#timer);
|
|
111
|
+
this.#timer = undefined;
|
|
112
|
+
}
|
|
113
|
+
#assertOpen() {
|
|
114
|
+
if (this.#closed)
|
|
115
|
+
throw new Error("Buffered writer is closed");
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/** Requests a non-blocking flush when the browser hides or unloads the page. */
|
|
119
|
+
export function attachLifecycleFlush(requester, options = {}) {
|
|
120
|
+
const documentTarget = options.document ?? (typeof document === "undefined" ? undefined : document);
|
|
121
|
+
const pageTarget = options.page ?? (typeof window === "undefined" ? undefined : window);
|
|
122
|
+
const onVisibilityChange = () => {
|
|
123
|
+
if (documentTarget?.visibilityState === "hidden")
|
|
124
|
+
requester.requestFlush();
|
|
125
|
+
};
|
|
126
|
+
const onPageHide = () => requester.requestFlush();
|
|
127
|
+
documentTarget?.addEventListener("visibilitychange", onVisibilityChange);
|
|
128
|
+
pageTarget?.addEventListener("pagehide", onPageHide);
|
|
129
|
+
return () => {
|
|
130
|
+
documentTarget?.removeEventListener("visibilitychange", onVisibilityChange);
|
|
131
|
+
pageTarget?.removeEventListener("pagehide", onPageHide);
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
function positiveWholeNumber(value, name) {
|
|
135
|
+
if (!Number.isSafeInteger(value) || value <= 0) {
|
|
136
|
+
throw new RangeError(`${name} must be a positive whole number`);
|
|
137
|
+
}
|
|
138
|
+
return value;
|
|
139
|
+
}
|
|
140
|
+
function cloneRow(row) {
|
|
141
|
+
return Object.fromEntries(Object.entries(row).map(([name, value]) => [
|
|
142
|
+
name,
|
|
143
|
+
value instanceof Date ? new Date(value.getTime()) : value,
|
|
144
|
+
]));
|
|
145
|
+
}
|
|
146
|
+
function estimateRowBytes(row) {
|
|
147
|
+
let bytes = 0;
|
|
148
|
+
for (const value of Object.values(row)) {
|
|
149
|
+
if (typeof value === "string")
|
|
150
|
+
bytes += 4 + value.length;
|
|
151
|
+
else if (typeof value === "number" || value instanceof Date)
|
|
152
|
+
bytes += 8;
|
|
153
|
+
else
|
|
154
|
+
bytes += 1;
|
|
155
|
+
}
|
|
156
|
+
return bytes;
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=buffered-writer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buffered-writer.js","sourceRoot":"","sources":["../../src/engine/buffered-writer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import type { ColumnDefault, SimpleDataType, TableRecord } from "../storage/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* The published shape of the catalog: everything a schema tool needs to diff a live database
|
|
4
|
+
* against a desired schema, without reading engine internals.
|
|
5
|
+
*
|
|
6
|
+
* The distinction from `listTables()` is identity. `TableDefinition` answers "what can I select,
|
|
7
|
+
* and of what type", which is enough to render a table and not enough to plan a migration: a
|
|
8
|
+
* rename is only expressible because a column keeps a stable ID across it, and a constraint can
|
|
9
|
+
* only be diffed if it is visible in the first place. This carries both, plus the derived facts
|
|
10
|
+
* (auto-increment, view bodies) that a planner would otherwise have to reverse-engineer.
|
|
11
|
+
*/
|
|
12
|
+
export interface CatalogColumn {
|
|
13
|
+
/** Stable across renames. Diffing a rename is not expressible without it. */
|
|
14
|
+
readonly id: string;
|
|
15
|
+
readonly name: string;
|
|
16
|
+
readonly type: SimpleDataType;
|
|
17
|
+
readonly nullable: boolean;
|
|
18
|
+
/** Filled at insert time for null-or-absent slots; never applied at read time. */
|
|
19
|
+
readonly defaultValue?: ColumnDefault;
|
|
20
|
+
/** String columns only: the closed set of values writes may draw from. */
|
|
21
|
+
readonly enumValues?: readonly string[];
|
|
22
|
+
/** Derived from the default spec, because a planner should not have to decode one. */
|
|
23
|
+
readonly isAutoIncrementing: boolean;
|
|
24
|
+
/** What rows written before this column existed read as, instead of NULL. */
|
|
25
|
+
readonly backfill?: boolean | number | string | Date;
|
|
26
|
+
}
|
|
27
|
+
export interface CatalogForeignKey {
|
|
28
|
+
readonly name: string;
|
|
29
|
+
readonly column: string;
|
|
30
|
+
readonly parentTable: string;
|
|
31
|
+
readonly parentColumn: string;
|
|
32
|
+
readonly onDelete: "restrict" | "cascade" | "set null";
|
|
33
|
+
}
|
|
34
|
+
export interface CatalogCheck {
|
|
35
|
+
readonly name: string;
|
|
36
|
+
/** The boolean expression's text, as declared. */
|
|
37
|
+
readonly sql: string;
|
|
38
|
+
}
|
|
39
|
+
export interface CatalogTrigger {
|
|
40
|
+
readonly name: string;
|
|
41
|
+
readonly event: "insert" | "update" | "delete";
|
|
42
|
+
readonly timing: "before" | "after";
|
|
43
|
+
}
|
|
44
|
+
export interface CatalogTable {
|
|
45
|
+
readonly name: string;
|
|
46
|
+
/**
|
|
47
|
+
* True when a migration created this table. The schema is then authoritative over it and may
|
|
48
|
+
* drop it; a table created with `CREATE TABLE` belongs to no schema and is never removed by
|
|
49
|
+
* one. See `CatalogView.managed`, which follows the same rule.
|
|
50
|
+
*/
|
|
51
|
+
readonly managed: boolean;
|
|
52
|
+
readonly columns: readonly CatalogColumn[];
|
|
53
|
+
/** The unique key's column ID, absent on a table declared without one. */
|
|
54
|
+
readonly uniqueKeyColumnId?: string;
|
|
55
|
+
readonly foreignKeys: readonly CatalogForeignKey[];
|
|
56
|
+
readonly checks: readonly CatalogCheck[];
|
|
57
|
+
/**
|
|
58
|
+
* Reported but not declarable through the schema DSL: a trigger's body is a statement, not a
|
|
59
|
+
* column, so it stays SQL-only. A tool that rewrites triggers still needs to see them.
|
|
60
|
+
*/
|
|
61
|
+
readonly triggers: readonly CatalogTrigger[];
|
|
62
|
+
}
|
|
63
|
+
export interface CatalogView {
|
|
64
|
+
readonly name: string;
|
|
65
|
+
/** The query text the view stands for. */
|
|
66
|
+
readonly sql: string;
|
|
67
|
+
/** The query's inferred output schema, so a view answers the same questions a table does. */
|
|
68
|
+
readonly columns: readonly CatalogColumn[];
|
|
69
|
+
/**
|
|
70
|
+
* True when a migration created this view from a schema declaration. The schema is then
|
|
71
|
+
* authoritative over it and may drop it; a view created with `CREATE VIEW` — or one written
|
|
72
|
+
* before this was recorded — is not owned by any schema and no migration removes it.
|
|
73
|
+
*/
|
|
74
|
+
readonly managed: boolean;
|
|
75
|
+
}
|
|
76
|
+
export interface Catalog {
|
|
77
|
+
readonly tables: readonly CatalogTable[];
|
|
78
|
+
readonly views: readonly CatalogView[];
|
|
79
|
+
}
|
|
80
|
+
/** Projects storage's table records into the published catalog, sorted by name for stable diffs. */
|
|
81
|
+
export declare function toCatalog(records: readonly TableRecord[]): Catalog;
|
|
82
|
+
//# sourceMappingURL=catalog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../../src/engine/catalog.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEtF;;;;;;;;;GASG;AAEH,MAAM,WAAW,aAAa;IAC5B,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,kFAAkF;IAClF,QAAQ,CAAC,YAAY,CAAC,EAAE,aAAa,CAAC;IACtC,0EAA0E;IAC1E,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,sFAAsF;IACtF,QAAQ,CAAC,kBAAkB,EAAE,OAAO,CAAC;IACrC,6EAA6E;IAC7E,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;CACtD;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,UAAU,GAAG,SAAS,GAAG,UAAU,CAAC;CACxD;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,kDAAkD;IAClD,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAC/C,QAAQ,CAAC,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAC;CACrC;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,SAAS,aAAa,EAAE,CAAC;IAC3C,0EAA0E;IAC1E,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,WAAW,EAAE,SAAS,iBAAiB,EAAE,CAAC;IACnD,QAAQ,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,CAAC;IACzC;;;OAGG;IACH,QAAQ,CAAC,QAAQ,EAAE,SAAS,cAAc,EAAE,CAAC;CAC9C;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,0CAA0C;IAC1C,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,6FAA6F;IAC7F,QAAQ,CAAC,OAAO,EAAE,SAAS,aAAa,EAAE,CAAC;IAC3C;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,CAAC;IACzC,QAAQ,CAAC,KAAK,EAAE,SAAS,WAAW,EAAE,CAAC;CACxC;AAeD,oGAAoG;AACpG,wBAAgB,SAAS,CAAC,OAAO,EAAE,SAAS,WAAW,EAAE,GAAG,OAAO,CAgClE"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
function toCatalogColumn(column) {
|
|
2
|
+
return {
|
|
3
|
+
id: column.id,
|
|
4
|
+
name: column.name,
|
|
5
|
+
type: column.type,
|
|
6
|
+
nullable: column.nullable,
|
|
7
|
+
...(column.defaultValue === undefined ? {} : { defaultValue: column.defaultValue }),
|
|
8
|
+
...(column.enumValues === undefined ? {} : { enumValues: [...column.enumValues] }),
|
|
9
|
+
...(column.backfill === undefined ? {} : { backfill: column.backfill }),
|
|
10
|
+
isAutoIncrementing: column.defaultValue?.kind === "autoincrement",
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
/** Projects storage's table records into the published catalog, sorted by name for stable diffs. */
|
|
14
|
+
export function toCatalog(records) {
|
|
15
|
+
const byName = [...records].sort((left, right) => left.name.localeCompare(right.name));
|
|
16
|
+
const tables = [];
|
|
17
|
+
const views = [];
|
|
18
|
+
for (const record of byName) {
|
|
19
|
+
const columns = record.columns.map(toCatalogColumn);
|
|
20
|
+
if (record.view !== undefined) {
|
|
21
|
+
views.push({
|
|
22
|
+
name: record.name,
|
|
23
|
+
sql: record.view.sql,
|
|
24
|
+
columns,
|
|
25
|
+
managed: record.view.managed === true,
|
|
26
|
+
});
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
tables.push({
|
|
30
|
+
name: record.name,
|
|
31
|
+
managed: record.managed === true,
|
|
32
|
+
columns,
|
|
33
|
+
...(record.uniqueKeyColumnId === undefined
|
|
34
|
+
? {}
|
|
35
|
+
: { uniqueKeyColumnId: record.uniqueKeyColumnId }),
|
|
36
|
+
foreignKeys: (record.foreignKeys ?? []).map((key) => ({ ...key })),
|
|
37
|
+
checks: (record.checks ?? []).map((check) => ({ ...check })),
|
|
38
|
+
triggers: (record.triggers ?? []).map(({ name, event, timing }) => ({
|
|
39
|
+
name,
|
|
40
|
+
event,
|
|
41
|
+
timing,
|
|
42
|
+
})),
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
return { tables, views };
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=catalog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../src/engine/catalog.ts"],"names":[],"mappings":"AAwFA,SAAS,eAAe,CAAC,MAAsC;IAC7D,OAAO;QACL,EAAE,EAAE,MAAM,CAAC,EAAE;QACb,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,GAAG,CAAC,MAAM,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,MAAM,CAAC,YAAY,EAAE,CAAC;QACnF,GAAG,CAAC,MAAM,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,GAAG,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC;QAClF,GAAG,CAAC,MAAM,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC;QACvE,kBAAkB,EAAE,MAAM,CAAC,YAAY,EAAE,IAAI,KAAK,eAAe;KAClE,CAAC;AACJ,CAAC;AAED,oGAAoG;AACpG,MAAM,UAAU,SAAS,CAAC,OAA+B;IACvD,MAAM,MAAM,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;IACvF,MAAM,MAAM,GAAmB,EAAE,CAAC;IAClC,MAAM,KAAK,GAAkB,EAAE,CAAC;IAChC,KAAK,MAAM,MAAM,IAAI,MAAM,EAAE,CAAC;QAC5B,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;QACpD,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC9B,KAAK,CAAC,IAAI,CAAC;gBACT,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,GAAG,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG;gBACpB,OAAO;gBACP,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,KAAK,IAAI;aACtC,CAAC,CAAC;YACH,SAAS;QACX,CAAC;QACD,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,OAAO,EAAE,MAAM,CAAC,OAAO,KAAK,IAAI;YAChC,OAAO;YACP,GAAG,CAAC,MAAM,CAAC,iBAAiB,KAAK,SAAS;gBACxC,CAAC,CAAC,EAAE;gBACJ,CAAC,CAAC,EAAE,iBAAiB,EAAE,MAAM,CAAC,iBAAiB,EAAE,CAAC;YACpD,WAAW,EAAE,CAAC,MAAM,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,GAAG,EAAE,CAAC,CAAC;YAClE,MAAM,EAAE,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC;YAC5D,QAAQ,EAAE,CAAC,MAAM,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC;gBAClE,IAAI;gBACJ,KAAK;gBACL,MAAM;aACP,CAAC,CAAC;SACJ,CAAC,CAAC;IACL,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;AAC3B,CAAC"}
|