@minnowdb/core 0.3.0 → 0.4.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/README.md +4 -2
- package/dist/block-format/block.d.ts +32 -13
- package/dist/block-format/block.js +179 -55
- package/dist/block-format/checksum.d.ts +2 -1
- package/dist/block-format/checksum.js +5 -2
- package/dist/block-format/codecs.d.ts +7 -2
- package/dist/block-format/codecs.js +53 -12
- package/dist/block-format/column.d.ts +3 -2
- package/dist/block-format/column.js +96 -30
- package/dist/block-format/index.d.ts +2 -2
- package/dist/block-format/index.js +2 -2
- package/dist/block-format/physical.d.ts +8 -2
- package/dist/block-format/physical.js +14 -6
- package/dist/block-format/types.d.ts +7 -3
- package/dist/block-format/types.js +0 -1
- package/dist/block-format/unicode.d.ts +11 -0
- package/dist/block-format/unicode.js +46 -0
- package/dist/date-value.d.ts +15 -0
- package/dist/date-value.js +64 -0
- package/dist/engine/artifact-cache.d.ts +0 -1
- package/dist/engine/artifact-cache.js +0 -1
- package/dist/engine/batch.d.ts +5 -2
- package/dist/engine/batch.js +0 -1
- package/dist/engine/buffered-writer.d.ts +2 -1
- package/dist/engine/buffered-writer.js +34 -9
- package/dist/engine/cache-limits.d.ts +25 -0
- package/dist/engine/cache-limits.js +25 -0
- package/dist/engine/catalog.d.ts +5 -6
- package/dist/engine/catalog.js +5 -5
- package/dist/engine/client.d.ts +27 -7
- package/dist/engine/client.js +197 -31
- package/dist/engine/database.d.ts +161 -38
- package/dist/engine/database.js +4326 -1523
- package/dist/engine/defaults.d.ts +0 -1
- package/dist/engine/defaults.js +2 -4
- package/dist/engine/errors.d.ts +19 -1
- package/dist/engine/errors.js +32 -2
- package/dist/engine/fts.d.ts +0 -6
- package/dist/engine/fts.js +39 -14
- package/dist/engine/group-index.d.ts +0 -1
- package/dist/engine/group-index.js +6 -11
- package/dist/engine/index.d.ts +16 -11
- package/dist/engine/index.js +12 -10
- package/dist/engine/join-index.d.ts +0 -1
- package/dist/engine/join-index.js +2 -2
- package/dist/engine/keyed-live.d.ts +57 -0
- package/dist/engine/keyed-live.js +226 -0
- package/dist/engine/live-api.d.ts +4 -0
- package/dist/engine/live-api.js +4 -0
- package/dist/engine/live.d.ts +43 -26
- package/dist/engine/live.js +499 -129
- package/dist/engine/memory.d.ts +2 -1
- package/dist/engine/memory.js +3 -2
- package/dist/engine/optimizer.d.ts +0 -1
- package/dist/engine/optimizer.js +4 -4
- package/dist/engine/query-api.d.ts +3 -0
- package/dist/engine/query-api.js +3 -0
- package/dist/engine/query-cache.d.ts +0 -1
- package/dist/engine/query-cache.js +4 -4
- package/dist/engine/query.d.ts +4 -7
- package/dist/engine/query.js +348 -155
- package/dist/engine/result-wire.d.ts +0 -1
- package/dist/engine/result-wire.js +2 -2
- package/dist/engine/schema-wire.d.ts +1 -2
- package/dist/engine/schema-wire.js +0 -1
- package/dist/engine/schema.d.ts +3 -8
- package/dist/engine/schema.js +41 -24
- package/dist/engine/sort-keys.d.ts +0 -1
- package/dist/engine/sort-keys.js +2 -2
- package/dist/engine/sql-domains.d.ts +6 -1
- package/dist/engine/sql-domains.js +209 -45
- package/dist/engine/sql-driver.d.ts +2 -2
- package/dist/engine/sql-driver.js +0 -1
- package/dist/engine/sql-json.d.ts +0 -1
- package/dist/engine/sql-json.js +53 -7
- package/dist/engine/sql-semantics.d.ts +8 -5
- package/dist/engine/sql-semantics.js +427 -65
- package/dist/engine/typed-live.d.ts +67 -0
- package/dist/engine/typed-live.js +349 -0
- package/dist/engine/vector.d.ts +7 -1
- package/dist/engine/vector.js +202 -58
- package/dist/engine/worker-host.d.ts +8 -2
- package/dist/engine/worker-host.js +616 -152
- package/dist/engine/worker.d.ts +0 -1
- package/dist/engine/worker.js +3 -3
- package/dist/engine/write-block-planner.d.ts +18 -0
- package/dist/engine/write-block-planner.js +112 -0
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/plan/index.d.ts +0 -1
- package/dist/plan/index.js +0 -1
- package/dist/storage/index.d.ts +1 -1
- package/dist/storage/index.js +1 -1
- package/dist/storage/indexeddb.d.ts +74 -65
- package/dist/storage/indexeddb.js +12301 -2076
- package/dist/storage/memory.d.ts +56 -66
- package/dist/storage/memory.js +1004 -139
- package/dist/storage/opfs/files.d.ts +18 -7
- package/dist/storage/opfs/files.js +115 -28
- package/dist/storage/opfs/index.d.ts +1 -1
- package/dist/storage/opfs/index.js +1 -1
- package/dist/storage/opfs/leader.d.ts +403 -91
- package/dist/storage/opfs/leader.js +4318 -602
- package/dist/storage/opfs/rpc.d.ts +15 -3
- package/dist/storage/opfs/rpc.js +223 -2
- package/dist/storage/opfs/snapshot-ledger.d.ts +40 -0
- package/dist/storage/opfs/snapshot-ledger.js +281 -0
- package/dist/storage/opfs/store.d.ts +26 -121
- package/dist/storage/opfs/store.js +436 -388
- package/dist/storage/persistence.d.ts +37 -0
- package/dist/storage/persistence.js +78 -0
- package/dist/storage/snapshot-stream.d.ts +24 -0
- package/dist/storage/snapshot-stream.js +897 -0
- package/dist/storage/snapshot.d.ts +9 -99
- package/dist/storage/snapshot.js +33 -309
- package/dist/storage/toolkit/extents.d.ts +41 -7
- package/dist/storage/toolkit/extents.js +402 -39
- package/dist/storage/toolkit/index.d.ts +3 -4
- package/dist/storage/toolkit/index.js +27 -3
- package/dist/storage/toolkit/record-core.d.ts +174 -61
- package/dist/storage/toolkit/record-core.js +5401 -849
- package/dist/storage/toolkit/sync-file.d.ts +10 -1
- package/dist/storage/toolkit/sync-file.js +50 -2
- package/dist/storage/toolkit/wal.d.ts +23 -5
- package/dist/storage/toolkit/wal.js +89 -27
- package/dist/storage/toolkit/wire.d.ts +4 -6
- package/dist/storage/toolkit/wire.js +80 -25
- package/dist/storage/types.d.ts +1271 -218
- package/dist/storage/types.js +1471 -138
- package/dist/testing/block-store-conformance.d.ts +0 -1
- package/dist/testing/block-store-conformance.js +877 -138
- package/dist/testing/index.d.ts +42 -31
- package/dist/testing/index.js +100 -68
- package/dist/testing/opfs-shim.d.ts +13 -3
- package/dist/testing/opfs-shim.js +40 -6
- package/dist/testing/simulator.d.ts +0 -1
- package/dist/testing/simulator.js +43 -12
- package/dist/testing/sqllogictest.d.ts +0 -1
- package/dist/testing/sqllogictest.js +0 -1
- package/dist/transactions/index.d.ts +81 -20
- package/dist/transactions/index.js +1050 -268
- package/dist/worker-protocol/index.d.ts +3 -2
- package/dist/worker-protocol/index.js +2 -5
- package/package.json +49 -1
- package/dist/block-format/block.d.ts.map +0 -1
- package/dist/block-format/block.js.map +0 -1
- package/dist/block-format/checksum.d.ts.map +0 -1
- package/dist/block-format/checksum.js.map +0 -1
- package/dist/block-format/codecs.d.ts.map +0 -1
- package/dist/block-format/codecs.js.map +0 -1
- package/dist/block-format/column.d.ts.map +0 -1
- package/dist/block-format/column.js.map +0 -1
- package/dist/block-format/index.d.ts.map +0 -1
- package/dist/block-format/index.js.map +0 -1
- package/dist/block-format/physical.d.ts.map +0 -1
- package/dist/block-format/physical.js.map +0 -1
- package/dist/block-format/types.d.ts.map +0 -1
- package/dist/block-format/types.js.map +0 -1
- package/dist/engine/artifact-cache.d.ts.map +0 -1
- package/dist/engine/artifact-cache.js.map +0 -1
- package/dist/engine/batch.d.ts.map +0 -1
- package/dist/engine/batch.js.map +0 -1
- package/dist/engine/buffered-writer.d.ts.map +0 -1
- package/dist/engine/buffered-writer.js.map +0 -1
- package/dist/engine/catalog.d.ts.map +0 -1
- package/dist/engine/catalog.js.map +0 -1
- package/dist/engine/client.d.ts.map +0 -1
- package/dist/engine/client.js.map +0 -1
- package/dist/engine/coordinator.d.ts +0 -17
- package/dist/engine/coordinator.d.ts.map +0 -1
- package/dist/engine/coordinator.js +0 -60
- package/dist/engine/coordinator.js.map +0 -1
- package/dist/engine/database.d.ts.map +0 -1
- package/dist/engine/database.js.map +0 -1
- package/dist/engine/defaults.d.ts.map +0 -1
- package/dist/engine/defaults.js.map +0 -1
- package/dist/engine/errors.d.ts.map +0 -1
- package/dist/engine/errors.js.map +0 -1
- package/dist/engine/fts.d.ts.map +0 -1
- package/dist/engine/fts.js.map +0 -1
- package/dist/engine/group-index.d.ts.map +0 -1
- package/dist/engine/group-index.js.map +0 -1
- package/dist/engine/index.d.ts.map +0 -1
- package/dist/engine/index.js.map +0 -1
- package/dist/engine/join-index.d.ts.map +0 -1
- package/dist/engine/join-index.js.map +0 -1
- package/dist/engine/live.d.ts.map +0 -1
- package/dist/engine/live.js.map +0 -1
- package/dist/engine/memory.d.ts.map +0 -1
- package/dist/engine/memory.js.map +0 -1
- package/dist/engine/optimizer.d.ts.map +0 -1
- package/dist/engine/optimizer.js.map +0 -1
- package/dist/engine/query-cache.d.ts.map +0 -1
- package/dist/engine/query-cache.js.map +0 -1
- package/dist/engine/query.d.ts.map +0 -1
- package/dist/engine/query.js.map +0 -1
- package/dist/engine/result-wire.d.ts.map +0 -1
- package/dist/engine/result-wire.js.map +0 -1
- package/dist/engine/schema-wire.d.ts.map +0 -1
- package/dist/engine/schema-wire.js.map +0 -1
- package/dist/engine/schema.d.ts.map +0 -1
- package/dist/engine/schema.js.map +0 -1
- package/dist/engine/sort-keys.d.ts.map +0 -1
- package/dist/engine/sort-keys.js.map +0 -1
- package/dist/engine/sql-domains.d.ts.map +0 -1
- package/dist/engine/sql-domains.js.map +0 -1
- package/dist/engine/sql-driver.d.ts.map +0 -1
- package/dist/engine/sql-driver.js.map +0 -1
- package/dist/engine/sql-json.d.ts.map +0 -1
- package/dist/engine/sql-json.js.map +0 -1
- package/dist/engine/sql-semantics.d.ts.map +0 -1
- package/dist/engine/sql-semantics.js.map +0 -1
- package/dist/engine/vector.d.ts.map +0 -1
- package/dist/engine/vector.js.map +0 -1
- package/dist/engine/worker-host.d.ts.map +0 -1
- package/dist/engine/worker-host.js.map +0 -1
- package/dist/engine/worker.d.ts.map +0 -1
- package/dist/engine/worker.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/plan/index.d.ts.map +0 -1
- package/dist/plan/index.js.map +0 -1
- package/dist/storage/fixture-shape.d.ts +0 -42
- package/dist/storage/fixture-shape.d.ts.map +0 -1
- package/dist/storage/fixture-shape.js +0 -146
- package/dist/storage/fixture-shape.js.map +0 -1
- package/dist/storage/index.d.ts.map +0 -1
- package/dist/storage/index.js.map +0 -1
- package/dist/storage/indexeddb.d.ts.map +0 -1
- package/dist/storage/indexeddb.js.map +0 -1
- package/dist/storage/memory.d.ts.map +0 -1
- package/dist/storage/memory.js.map +0 -1
- package/dist/storage/opfs/files.d.ts.map +0 -1
- package/dist/storage/opfs/files.js.map +0 -1
- package/dist/storage/opfs/index.d.ts.map +0 -1
- package/dist/storage/opfs/index.js.map +0 -1
- package/dist/storage/opfs/leader.d.ts.map +0 -1
- package/dist/storage/opfs/leader.js.map +0 -1
- package/dist/storage/opfs/rpc.d.ts.map +0 -1
- package/dist/storage/opfs/rpc.js.map +0 -1
- package/dist/storage/opfs/store.d.ts.map +0 -1
- package/dist/storage/opfs/store.js.map +0 -1
- package/dist/storage/snapshot.d.ts.map +0 -1
- package/dist/storage/snapshot.js.map +0 -1
- package/dist/storage/toolkit/extents.d.ts.map +0 -1
- package/dist/storage/toolkit/extents.js.map +0 -1
- package/dist/storage/toolkit/index.d.ts.map +0 -1
- package/dist/storage/toolkit/index.js.map +0 -1
- package/dist/storage/toolkit/record-core.d.ts.map +0 -1
- package/dist/storage/toolkit/record-core.js.map +0 -1
- package/dist/storage/toolkit/sync-file.d.ts.map +0 -1
- package/dist/storage/toolkit/sync-file.js.map +0 -1
- package/dist/storage/toolkit/wal.d.ts.map +0 -1
- package/dist/storage/toolkit/wal.js.map +0 -1
- package/dist/storage/toolkit/wire.d.ts.map +0 -1
- package/dist/storage/toolkit/wire.js.map +0 -1
- package/dist/storage/types.d.ts.map +0 -1
- package/dist/storage/types.js.map +0 -1
- package/dist/testing/block-store-conformance.d.ts.map +0 -1
- package/dist/testing/block-store-conformance.js.map +0 -1
- package/dist/testing/index.d.ts.map +0 -1
- package/dist/testing/index.js.map +0 -1
- package/dist/testing/opfs-shim.d.ts.map +0 -1
- package/dist/testing/opfs-shim.js.map +0 -1
- package/dist/testing/seeds.d.ts +0 -11
- package/dist/testing/seeds.d.ts.map +0 -1
- package/dist/testing/seeds.js +0 -50
- package/dist/testing/seeds.js.map +0 -1
- package/dist/testing/simulator.d.ts.map +0 -1
- package/dist/testing/simulator.js.map +0 -1
- package/dist/testing/sqllogictest.d.ts.map +0 -1
- package/dist/testing/sqllogictest.js.map +0 -1
- package/dist/transactions/index.d.ts.map +0 -1
- package/dist/transactions/index.js.map +0 -1
- package/dist/worker-protocol/index.d.ts.map +0 -1
- package/dist/worker-protocol/index.js.map +0 -1
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { dateMilliseconds } from "../date-value.js";
|
|
2
|
+
import { physicalColumnByteLength, validatePhysicalColumn } from "./physical.js";
|
|
3
|
+
import { wellFormedUtf8ByteLength } from "./unicode.js";
|
|
1
4
|
const textEncoder = new TextEncoder();
|
|
2
5
|
const textDecoder = new TextDecoder("utf-8", { fatal: true });
|
|
3
6
|
// The on-disk format is little-endian; bulk Float64 writes use platform order when they match.
|
|
@@ -17,37 +20,74 @@ export function encodeColumn(input) {
|
|
|
17
20
|
// the validity bitmap from the value payload and persist a corrupt block. A hole reads as
|
|
18
21
|
// undefined and is rejected like any other non-value.
|
|
19
22
|
const rowCount = input.values.length;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
23
|
+
// Validate the fixed portion before allocation. Its format-level row cap bounds the largest
|
|
24
|
+
// fixed-width allocation to about 8 MiB, so boolean, number, and datetime columns validate and
|
|
25
|
+
// encode each accessor value in one pass. Reading them twice would both waste a full scan and
|
|
26
|
+
// introduce a needless time-of-check/time-of-use boundary for accessor-backed inputs.
|
|
27
|
+
physicalColumnByteLength(input.type, rowCount);
|
|
28
|
+
let stringContentByteLength = 0;
|
|
29
|
+
if (input.type === "string") {
|
|
30
|
+
// Variable-width output still needs an exact sizing pass before allocation. The encode pass
|
|
31
|
+
// below revalidates the local value it writes, so a changing accessor cannot smuggle invalid
|
|
32
|
+
// UTF-16 or make offsets disagree with the content buffer.
|
|
33
|
+
for (let index = 0; index < rowCount; index += 1) {
|
|
34
|
+
const value = input.values[index];
|
|
35
|
+
if (value === undefined)
|
|
36
|
+
throw new TypeError("Column values cannot be undefined");
|
|
37
|
+
if (value !== null) {
|
|
38
|
+
if (typeof value !== "string") {
|
|
39
|
+
throw new TypeError("String columns accept only strings or null");
|
|
40
|
+
}
|
|
41
|
+
stringContentByteLength += wellFormedUtf8ByteLength(value);
|
|
42
|
+
if (!Number.isSafeInteger(stringContentByteLength)) {
|
|
43
|
+
throw new RangeError("Invalid string content byte length");
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
30
47
|
}
|
|
48
|
+
physicalColumnByteLength(input.type, rowCount, stringContentByteLength);
|
|
49
|
+
const validity = new Uint8Array(bitmapLength(rowCount));
|
|
31
50
|
switch (input.type) {
|
|
32
51
|
case "boolean": {
|
|
33
52
|
const values = new Uint8Array(bitmapLength(rowCount));
|
|
53
|
+
let nullCount = 0;
|
|
34
54
|
for (let index = 0; index < rowCount; index += 1) {
|
|
35
|
-
|
|
36
|
-
|
|
55
|
+
const value = input.values[index];
|
|
56
|
+
if (value === undefined)
|
|
57
|
+
throw new TypeError("Column values cannot be undefined");
|
|
58
|
+
if (value !== null && typeof value !== "boolean") {
|
|
59
|
+
throw new TypeError("Boolean columns accept only booleans or null");
|
|
60
|
+
}
|
|
61
|
+
if (value === null)
|
|
62
|
+
nullCount += 1;
|
|
63
|
+
else {
|
|
64
|
+
setBit(validity, index);
|
|
65
|
+
if (value)
|
|
66
|
+
setBit(values, index);
|
|
67
|
+
}
|
|
37
68
|
}
|
|
38
69
|
return { bytes: join(validity, values), metadata: {}, nullCount };
|
|
39
70
|
}
|
|
40
71
|
case "number": {
|
|
41
72
|
const values = new Float64Array(rowCount);
|
|
42
73
|
const view = PLATFORM_LITTLE_ENDIAN ? undefined : new DataView(values.buffer);
|
|
74
|
+
let nullCount = 0;
|
|
43
75
|
let min = Number.POSITIVE_INFINITY;
|
|
44
76
|
let max = Number.NEGATIVE_INFINITY;
|
|
45
77
|
for (let index = 0; index < rowCount; index += 1) {
|
|
46
78
|
const value = input.values[index];
|
|
47
|
-
if (value ===
|
|
79
|
+
if (value === undefined)
|
|
80
|
+
throw new TypeError("Column values cannot be undefined");
|
|
81
|
+
if (value === null) {
|
|
82
|
+
nullCount += 1;
|
|
48
83
|
continue;
|
|
84
|
+
}
|
|
85
|
+
if (typeof value !== "number") {
|
|
86
|
+
throw new TypeError("Number columns accept only numbers or null");
|
|
87
|
+
}
|
|
49
88
|
if (!Number.isFinite(value))
|
|
50
89
|
throw new TypeError("Number values must be finite");
|
|
90
|
+
setBit(validity, index);
|
|
51
91
|
if (view === undefined)
|
|
52
92
|
values[index] = value;
|
|
53
93
|
else
|
|
@@ -61,15 +101,24 @@ export function encodeColumn(input) {
|
|
|
61
101
|
case "datetime": {
|
|
62
102
|
const values = new Float64Array(rowCount);
|
|
63
103
|
const view = PLATFORM_LITTLE_ENDIAN ? undefined : new DataView(values.buffer);
|
|
104
|
+
let nullCount = 0;
|
|
64
105
|
let min = Number.POSITIVE_INFINITY;
|
|
65
106
|
let max = Number.NEGATIVE_INFINITY;
|
|
66
107
|
for (let index = 0; index < rowCount; index += 1) {
|
|
67
108
|
const value = input.values[index];
|
|
68
|
-
if (value ===
|
|
109
|
+
if (value === undefined)
|
|
110
|
+
throw new TypeError("Column values cannot be undefined");
|
|
111
|
+
if (value === null) {
|
|
112
|
+
nullCount += 1;
|
|
69
113
|
continue;
|
|
70
|
-
|
|
114
|
+
}
|
|
115
|
+
if (!(value instanceof Date)) {
|
|
116
|
+
throw new TypeError("Datetime columns accept only Date objects or null");
|
|
117
|
+
}
|
|
118
|
+
const milliseconds = dateMilliseconds(value);
|
|
71
119
|
if (!Number.isFinite(milliseconds))
|
|
72
120
|
throw new TypeError("Datetime values must be valid Dates");
|
|
121
|
+
setBit(validity, index);
|
|
73
122
|
if (view === undefined)
|
|
74
123
|
values[index] = milliseconds;
|
|
75
124
|
else
|
|
@@ -81,25 +130,40 @@ export function encodeColumn(input) {
|
|
|
81
130
|
return { bytes: join(validity, new Uint8Array(values.buffer)), metadata, nullCount };
|
|
82
131
|
}
|
|
83
132
|
case "string": {
|
|
84
|
-
//
|
|
85
|
-
//
|
|
86
|
-
//
|
|
87
|
-
let capacity = 0;
|
|
88
|
-
for (let index = 0; index < rowCount; index += 1) {
|
|
89
|
-
const value = input.values[index];
|
|
90
|
-
if (value !== null && value !== undefined)
|
|
91
|
-
capacity += value.length * 3;
|
|
92
|
-
}
|
|
133
|
+
// Measure exactly without allocating, both to reject lossy unpaired surrogates and to avoid
|
|
134
|
+
// the former 3x worst-case scratch for ASCII-heavy data. The complete 64 MiB format bound is
|
|
135
|
+
// checked before the content or offset arrays are allocated.
|
|
93
136
|
const offsets = new Uint32Array(rowCount + 1);
|
|
94
|
-
|
|
137
|
+
// Some native encodeInto implementations stop at an internal chunk boundary when the
|
|
138
|
+
// destination has exactly two or three bytes left, even though the final code point fits.
|
|
139
|
+
// Three bytes of non-persisted tail room keeps the native fast path reliable; the returned
|
|
140
|
+
// physical payload still contains exactly `contentByteLength` content bytes.
|
|
141
|
+
const content = new Uint8Array(stringContentByteLength + 3);
|
|
95
142
|
let offset = 0;
|
|
143
|
+
let nullCount = 0;
|
|
96
144
|
for (let index = 0; index < rowCount; index += 1) {
|
|
97
145
|
const value = input.values[index];
|
|
98
|
-
if (value
|
|
99
|
-
|
|
146
|
+
if (value === undefined)
|
|
147
|
+
throw new TypeError("Column values cannot be undefined");
|
|
148
|
+
if (value === null)
|
|
149
|
+
nullCount += 1;
|
|
150
|
+
else {
|
|
151
|
+
if (typeof value !== "string") {
|
|
152
|
+
throw new TypeError("String columns accept only strings or null");
|
|
153
|
+
}
|
|
154
|
+
const localByteLength = wellFormedUtf8ByteLength(value);
|
|
155
|
+
setBit(validity, index);
|
|
156
|
+
const result = textEncoder.encodeInto(value, content.subarray(offset));
|
|
157
|
+
if (result.read !== value.length)
|
|
158
|
+
throw new Error("UTF-8 output sizing mismatch");
|
|
159
|
+
if (result.written !== localByteLength)
|
|
160
|
+
throw new Error("UTF-8 output sizing mismatch");
|
|
161
|
+
offset += result.written;
|
|
100
162
|
}
|
|
101
163
|
offsets[index + 1] = offset;
|
|
102
164
|
}
|
|
165
|
+
if (offset !== stringContentByteLength)
|
|
166
|
+
throw new Error("UTF-8 output sizing mismatch");
|
|
103
167
|
return {
|
|
104
168
|
bytes: join(validity, new Uint8Array(offsets.buffer), content.subarray(0, offset)),
|
|
105
169
|
metadata: {},
|
|
@@ -109,9 +173,12 @@ export function encodeColumn(input) {
|
|
|
109
173
|
}
|
|
110
174
|
}
|
|
111
175
|
export function decodeColumn(type, bytes, rowCount) {
|
|
176
|
+
return decodeValidatedColumn(validatePhysicalColumn({ type, bytes, rowCount }));
|
|
177
|
+
}
|
|
178
|
+
/** Package-internal row materialization after the physical payload was already validated. */
|
|
179
|
+
export function decodeValidatedColumn(column) {
|
|
180
|
+
const { type, bytes, rowCount } = column;
|
|
112
181
|
const validityLength = bitmapLength(rowCount);
|
|
113
|
-
if (bytes.byteLength < validityLength)
|
|
114
|
-
throw new Error("Truncated validity bitmap");
|
|
115
182
|
const validity = bytes.subarray(0, validityLength);
|
|
116
183
|
const payload = bytes.subarray(validityLength);
|
|
117
184
|
const values = [];
|
|
@@ -163,4 +230,3 @@ function join(...parts) {
|
|
|
163
230
|
}
|
|
164
231
|
return output;
|
|
165
232
|
}
|
|
166
|
-
//# sourceMappingURL=column.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export * from "./block.js";
|
|
2
2
|
export * from "./checksum.js";
|
|
3
3
|
export * from "./codecs.js";
|
|
4
|
-
export
|
|
4
|
+
export { decodeColumn, encodeColumn } from "./column.js";
|
|
5
5
|
export * from "./physical.js";
|
|
6
6
|
export * from "./types.js";
|
|
7
|
-
|
|
7
|
+
export * from "./unicode.js";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export * from "./block.js";
|
|
2
2
|
export * from "./checksum.js";
|
|
3
3
|
export * from "./codecs.js";
|
|
4
|
-
export
|
|
4
|
+
export { decodeColumn, encodeColumn } from "./column.js";
|
|
5
5
|
export * from "./physical.js";
|
|
6
6
|
export * from "./types.js";
|
|
7
|
-
|
|
7
|
+
export * from "./unicode.js";
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import type { LogicalType, PhysicalColumnMeasurement, PhysicalColumnPayload, PhysicalColumnRange, ValidatedPhysicalColumn } from "./types.js";
|
|
2
2
|
export declare const MAX_PHYSICAL_COLUMN_BYTE_LENGTH: number;
|
|
3
|
+
/**
|
|
4
|
+
* Hard row ceiling for one physical block. Bitmap columns otherwise fit 268 million rows under
|
|
5
|
+
* the byte limit, which would require an unsafe decoded JS array even for a valid block.
|
|
6
|
+
*/
|
|
7
|
+
export declare const MAX_BLOCK_ROW_COUNT = 1048576;
|
|
3
8
|
export declare function physicalBitmapByteLength(rowCount: number): number;
|
|
4
|
-
/** Returns the exact encoded byte length for
|
|
9
|
+
/** Returns the exact encoded byte length for the canonical v2 physical column. */
|
|
5
10
|
export declare function physicalColumnByteLength(type: LogicalType, rowCount: number, stringContentByteLength?: number): number;
|
|
6
11
|
/**
|
|
7
12
|
* Validates a physical payload without copying its bytes or materializing row
|
|
@@ -17,4 +22,5 @@ export declare function measurePhysicalColumnRanges<T extends LogicalType>(type:
|
|
|
17
22
|
export declare function buildPhysicalColumnFromRanges<T extends LogicalType>(type: T, ranges: ReadonlyArray<PhysicalColumnRange<T>>): ValidatedPhysicalColumn<T>;
|
|
18
23
|
export declare function slicePhysicalColumn<T extends LogicalType>(column: PhysicalColumnPayload<T>, start: number, end: number): ValidatedPhysicalColumn<T>;
|
|
19
24
|
export declare function concatenatePhysicalColumns<T extends LogicalType>(type: T, columns: ReadonlyArray<PhysicalColumnPayload<T>>): ValidatedPhysicalColumn<T>;
|
|
20
|
-
|
|
25
|
+
/** Validates the shared persisted-block row ceiling without allocating a physical payload. */
|
|
26
|
+
export declare function assertBlockRowCount(rowCount: number): void;
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
export const MAX_PHYSICAL_COLUMN_BYTE_LENGTH = 64 * 1024 * 1024;
|
|
2
|
+
/**
|
|
3
|
+
* Hard row ceiling for one physical block. Bitmap columns otherwise fit 268 million rows under
|
|
4
|
+
* the byte limit, which would require an unsafe decoded JS array even for a valid block.
|
|
5
|
+
*/
|
|
6
|
+
export const MAX_BLOCK_ROW_COUNT = 1_048_576;
|
|
2
7
|
const MAX_DATETIME_MILLISECONDS = 8_640_000_000_000_000;
|
|
3
8
|
export function physicalBitmapByteLength(rowCount) {
|
|
4
9
|
assertRowCount(rowCount);
|
|
5
10
|
return Math.ceil(rowCount / 8);
|
|
6
11
|
}
|
|
7
|
-
/** Returns the exact encoded byte length for
|
|
12
|
+
/** Returns the exact encoded byte length for the canonical v2 physical column. */
|
|
8
13
|
export function physicalColumnByteLength(type, rowCount, stringContentByteLength = 0) {
|
|
9
14
|
assertLogicalType(type);
|
|
10
15
|
const validityByteLength = physicalBitmapByteLength(rowCount);
|
|
@@ -254,8 +259,7 @@ function preparePhysicalColumn(type, ranges) {
|
|
|
254
259
|
}
|
|
255
260
|
const rangeRowCount = range.end - range.start;
|
|
256
261
|
rowCount = checkedAdd(rowCount, rangeRowCount, "row count");
|
|
257
|
-
|
|
258
|
-
throw new RangeError("Too many rows in one physical column");
|
|
262
|
+
assertBlockRowCount(rowCount);
|
|
259
263
|
const sourceValidityLength = physicalBitmapByteLength(column.rowCount);
|
|
260
264
|
const sourceValidity = column.bytes.subarray(0, sourceValidityLength);
|
|
261
265
|
if (type === "string") {
|
|
@@ -404,8 +408,13 @@ function assertContinuation(bytes, index, end) {
|
|
|
404
408
|
}
|
|
405
409
|
function assertRowCount(rowCount) {
|
|
406
410
|
assertNonnegativeSafeInteger(rowCount, "row count");
|
|
407
|
-
if (rowCount >
|
|
408
|
-
throw new RangeError("
|
|
411
|
+
if (rowCount > MAX_BLOCK_ROW_COUNT) {
|
|
412
|
+
throw new RangeError("Physical column exceeds maximum row count");
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
/** Validates the shared persisted-block row ceiling without allocating a physical payload. */
|
|
416
|
+
export function assertBlockRowCount(rowCount) {
|
|
417
|
+
assertRowCount(rowCount);
|
|
409
418
|
}
|
|
410
419
|
function assertLogicalType(type) {
|
|
411
420
|
if (type !== "boolean" && type !== "number" && type !== "string" && type !== "datetime") {
|
|
@@ -436,4 +445,3 @@ function checkedMultiply(left, right, name) {
|
|
|
436
445
|
}
|
|
437
446
|
return left * right;
|
|
438
447
|
}
|
|
439
|
-
//# sourceMappingURL=physical.js.map
|
|
@@ -30,13 +30,18 @@ export interface BlockMetadata {
|
|
|
30
30
|
}
|
|
31
31
|
export interface BlockDescription {
|
|
32
32
|
formatVersion: number;
|
|
33
|
+
headerLength: number;
|
|
34
|
+
metadataLength: number;
|
|
33
35
|
type: LogicalType;
|
|
34
36
|
compression: Compression;
|
|
35
37
|
rowCount: number;
|
|
36
38
|
nullCount: number;
|
|
37
39
|
encodedLength: number;
|
|
38
40
|
storedLength: number;
|
|
41
|
+
/** CRC32 of the uncompressed physical column bytes. */
|
|
39
42
|
checksum: number;
|
|
43
|
+
/** CRC32 of the stored payload bytes, independently verifiable without decompression. */
|
|
44
|
+
storedChecksum: number;
|
|
40
45
|
metadata: BlockMetadata;
|
|
41
46
|
}
|
|
42
47
|
export interface DecodedBlock<T extends LogicalType = LogicalType> {
|
|
@@ -46,8 +51,8 @@ export interface DecodedBlock<T extends LogicalType = LogicalType> {
|
|
|
46
51
|
column: DecodedColumn<T>;
|
|
47
52
|
}
|
|
48
53
|
/**
|
|
49
|
-
* An uncompressed physical column payload. `bytes` uses the
|
|
50
|
-
*
|
|
54
|
+
* An uncompressed physical column payload. `bytes` uses the canonical v2 column encoding
|
|
55
|
+
* documented in `apps/site/content/docs/reference/architecture.mdx`.
|
|
51
56
|
*/
|
|
52
57
|
export interface PhysicalColumnPayload<T extends LogicalType = LogicalType> {
|
|
53
58
|
type: T;
|
|
@@ -90,4 +95,3 @@ export interface DecodedPhysicalBlock<T extends LogicalType = LogicalType> {
|
|
|
90
95
|
column: ValidatedPhysicalColumn<T>;
|
|
91
96
|
}
|
|
92
97
|
export {};
|
|
93
|
-
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns the exact UTF-8 byte length of a well-formed JavaScript string without allocating.
|
|
3
|
+
*
|
|
4
|
+
* UTF-8 cannot represent isolated UTF-16 surrogate code units. `TextEncoder` silently replaces
|
|
5
|
+
* them with U+FFFD, which would make persistence lossy and can collapse distinct index keys.
|
|
6
|
+
* Minnow rejects those strings instead, so every accepted string has one exact UTF-8 encoding
|
|
7
|
+
* and round-trips byte-for-byte through the block format.
|
|
8
|
+
*/
|
|
9
|
+
export declare function wellFormedUtf8ByteLength(value: string, context?: string): number;
|
|
10
|
+
/** Rejects strings that cannot round-trip exactly through UTF-8 persistence. */
|
|
11
|
+
export declare function assertWellFormedString(value: string, context?: string): void;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns the exact UTF-8 byte length of a well-formed JavaScript string without allocating.
|
|
3
|
+
*
|
|
4
|
+
* UTF-8 cannot represent isolated UTF-16 surrogate code units. `TextEncoder` silently replaces
|
|
5
|
+
* them with U+FFFD, which would make persistence lossy and can collapse distinct index keys.
|
|
6
|
+
* Minnow rejects those strings instead, so every accepted string has one exact UTF-8 encoding
|
|
7
|
+
* and round-trips byte-for-byte through the block format.
|
|
8
|
+
*/
|
|
9
|
+
export function wellFormedUtf8ByteLength(value, context = "String value") {
|
|
10
|
+
return measureWellFormedUtf8(value, context);
|
|
11
|
+
}
|
|
12
|
+
/** Rejects strings that cannot round-trip exactly through UTF-8 persistence. */
|
|
13
|
+
export function assertWellFormedString(value, context = "String value") {
|
|
14
|
+
wellFormedUtf8ByteLength(value, context);
|
|
15
|
+
}
|
|
16
|
+
function measureWellFormedUtf8(value, context) {
|
|
17
|
+
if (typeof value !== "string")
|
|
18
|
+
throw new TypeError(`${context} must be a string`);
|
|
19
|
+
let byteLength = 0;
|
|
20
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
21
|
+
const code = value.charCodeAt(index);
|
|
22
|
+
if (code <= 0x7f) {
|
|
23
|
+
byteLength += 1;
|
|
24
|
+
}
|
|
25
|
+
else if (code <= 0x7ff) {
|
|
26
|
+
byteLength += 2;
|
|
27
|
+
}
|
|
28
|
+
else if (code >= 0xd800 && code <= 0xdbff) {
|
|
29
|
+
const low = index + 1 < value.length ? value.charCodeAt(index + 1) : 0;
|
|
30
|
+
if (low < 0xdc00 || low > 0xdfff)
|
|
31
|
+
throw unpairedSurrogate(context, index);
|
|
32
|
+
byteLength += 4;
|
|
33
|
+
index += 1;
|
|
34
|
+
}
|
|
35
|
+
else if (code >= 0xdc00 && code <= 0xdfff) {
|
|
36
|
+
throw unpairedSurrogate(context, index);
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
byteLength += 3;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return byteLength;
|
|
43
|
+
}
|
|
44
|
+
function unpairedSurrogate(context, index) {
|
|
45
|
+
return new TypeError(`${context} contains an unpaired surrogate at UTF-16 index ${String(index)}`);
|
|
46
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** Returns a Date's internal millisecond value without invoking an instance override. */
|
|
2
|
+
export declare function dateMilliseconds(value: Date): number;
|
|
3
|
+
/** Copies a Date by its internal value without invoking instance methods. */
|
|
4
|
+
export declare function copyDate(value: Date): Date;
|
|
5
|
+
/** Formats a Date's internal value without invoking an instance override. */
|
|
6
|
+
export declare function dateIsoString(value: Date): string;
|
|
7
|
+
export declare function dateUtcFullYear(value: Date): number;
|
|
8
|
+
export declare function dateUtcMonth(value: Date): number;
|
|
9
|
+
export declare function dateUtcDate(value: Date): number;
|
|
10
|
+
export declare function dateUtcDay(value: Date): number;
|
|
11
|
+
export declare function dateUtcHours(value: Date): number;
|
|
12
|
+
export declare function dateUtcMinutes(value: Date): number;
|
|
13
|
+
export declare function dateUtcSeconds(value: Date): number;
|
|
14
|
+
export declare function setDateUtcDate(value: Date, day: number): number;
|
|
15
|
+
export declare function setDateUtcMonth(value: Date, month: number): number;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// Capture the intrinsic once. A Date instance may shadow `getTime`; persistence, indexes, and
|
|
2
|
+
// comparisons must all observe its internal [[DateValue]], not caller-controlled method code.
|
|
3
|
+
// Capturing the intrinsic is the point: later Date.prototype mutations must not change values.
|
|
4
|
+
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
5
|
+
const intrinsicDateGetTime = Date.prototype.getTime;
|
|
6
|
+
// eslint-disable-next-line @typescript-eslint/unbound-method -- See the getTime capture above.
|
|
7
|
+
const intrinsicDateToISOString = Date.prototype.toISOString;
|
|
8
|
+
// eslint-disable-next-line @typescript-eslint/unbound-method -- Captured for the same reason.
|
|
9
|
+
const intrinsicDateGetUtcFullYear = Date.prototype.getUTCFullYear;
|
|
10
|
+
// eslint-disable-next-line @typescript-eslint/unbound-method -- Captured for the same reason.
|
|
11
|
+
const intrinsicDateGetUtcMonth = Date.prototype.getUTCMonth;
|
|
12
|
+
// eslint-disable-next-line @typescript-eslint/unbound-method -- Captured for the same reason.
|
|
13
|
+
const intrinsicDateGetUtcDate = Date.prototype.getUTCDate;
|
|
14
|
+
// eslint-disable-next-line @typescript-eslint/unbound-method -- Captured for the same reason.
|
|
15
|
+
const intrinsicDateGetUtcDay = Date.prototype.getUTCDay;
|
|
16
|
+
// eslint-disable-next-line @typescript-eslint/unbound-method -- Captured for the same reason.
|
|
17
|
+
const intrinsicDateGetUtcHours = Date.prototype.getUTCHours;
|
|
18
|
+
// eslint-disable-next-line @typescript-eslint/unbound-method -- Captured for the same reason.
|
|
19
|
+
const intrinsicDateGetUtcMinutes = Date.prototype.getUTCMinutes;
|
|
20
|
+
// eslint-disable-next-line @typescript-eslint/unbound-method -- Captured for the same reason.
|
|
21
|
+
const intrinsicDateGetUtcSeconds = Date.prototype.getUTCSeconds;
|
|
22
|
+
// eslint-disable-next-line @typescript-eslint/unbound-method -- Captured for the same reason.
|
|
23
|
+
const intrinsicDateSetUtcDate = Date.prototype.setUTCDate;
|
|
24
|
+
// eslint-disable-next-line @typescript-eslint/unbound-method -- Captured for the same reason.
|
|
25
|
+
const intrinsicDateSetUtcMonth = Date.prototype.setUTCMonth;
|
|
26
|
+
/** Returns a Date's internal millisecond value without invoking an instance override. */
|
|
27
|
+
export function dateMilliseconds(value) {
|
|
28
|
+
return intrinsicDateGetTime.call(value);
|
|
29
|
+
}
|
|
30
|
+
/** Copies a Date by its internal value without invoking instance methods. */
|
|
31
|
+
export function copyDate(value) {
|
|
32
|
+
return new Date(dateMilliseconds(value));
|
|
33
|
+
}
|
|
34
|
+
/** Formats a Date's internal value without invoking an instance override. */
|
|
35
|
+
export function dateIsoString(value) {
|
|
36
|
+
return intrinsicDateToISOString.call(value);
|
|
37
|
+
}
|
|
38
|
+
export function dateUtcFullYear(value) {
|
|
39
|
+
return intrinsicDateGetUtcFullYear.call(value);
|
|
40
|
+
}
|
|
41
|
+
export function dateUtcMonth(value) {
|
|
42
|
+
return intrinsicDateGetUtcMonth.call(value);
|
|
43
|
+
}
|
|
44
|
+
export function dateUtcDate(value) {
|
|
45
|
+
return intrinsicDateGetUtcDate.call(value);
|
|
46
|
+
}
|
|
47
|
+
export function dateUtcDay(value) {
|
|
48
|
+
return intrinsicDateGetUtcDay.call(value);
|
|
49
|
+
}
|
|
50
|
+
export function dateUtcHours(value) {
|
|
51
|
+
return intrinsicDateGetUtcHours.call(value);
|
|
52
|
+
}
|
|
53
|
+
export function dateUtcMinutes(value) {
|
|
54
|
+
return intrinsicDateGetUtcMinutes.call(value);
|
|
55
|
+
}
|
|
56
|
+
export function dateUtcSeconds(value) {
|
|
57
|
+
return intrinsicDateGetUtcSeconds.call(value);
|
|
58
|
+
}
|
|
59
|
+
export function setDateUtcDate(value, day) {
|
|
60
|
+
return intrinsicDateSetUtcDate.call(value, day);
|
|
61
|
+
}
|
|
62
|
+
export function setDateUtcMonth(value, month) {
|
|
63
|
+
return intrinsicDateSetUtcMonth.call(value, month);
|
|
64
|
+
}
|
package/dist/engine/batch.d.ts
CHANGED
|
@@ -10,7 +10,11 @@
|
|
|
10
10
|
export type BatchValue = boolean | number | string | Date | null;
|
|
11
11
|
/** One row. A missing property is SQL omission; an explicit `null` remains SQL NULL. */
|
|
12
12
|
export type BatchRow = Readonly<Record<string, BatchValue>>;
|
|
13
|
-
/**
|
|
13
|
+
/**
|
|
14
|
+
* The columnar form: one ordinary readonly array per column, all of the same length and aligned by
|
|
15
|
+
* index. The engine reads these arrays without copying while the asynchronous write is active;
|
|
16
|
+
* callers must not mutate them or use changing accessor/proxy values until the write settles.
|
|
17
|
+
*/
|
|
14
18
|
export interface ColumnarBatch {
|
|
15
19
|
columns: Readonly<Record<string, readonly BatchValue[]>>;
|
|
16
20
|
/**
|
|
@@ -30,4 +34,3 @@ export type InsertBatchInput = readonly BatchRow[] | ColumnarBatch;
|
|
|
30
34
|
export declare function isColumnarBatch(input: InsertBatchInput): input is ColumnarBatch;
|
|
31
35
|
/** Pivots rows into the engine's columnar form; a columnar batch passes straight through. */
|
|
32
36
|
export declare function toColumnarBatch(input: InsertBatchInput): ColumnarBatch;
|
|
33
|
-
//# sourceMappingURL=batch.d.ts.map
|
package/dist/engine/batch.js
CHANGED
|
@@ -24,6 +24,8 @@ export interface LifecycleFlushOptions {
|
|
|
24
24
|
document?: LifecycleDocumentTarget;
|
|
25
25
|
page?: LifecyclePageTarget;
|
|
26
26
|
}
|
|
27
|
+
/** Maximum accepted `add()` calls that have not completed. Callers must await for backpressure. */
|
|
28
|
+
export declare const MAX_BUFFERED_WRITER_PENDING_ADDS = 64;
|
|
27
29
|
/** Batches row-oriented writes by row count, estimated bytes, or age. */
|
|
28
30
|
export declare class BufferedTableWriter {
|
|
29
31
|
#private;
|
|
@@ -40,4 +42,3 @@ export declare class BufferedTableWriter {
|
|
|
40
42
|
}
|
|
41
43
|
/** Requests a non-blocking flush when the browser hides or unloads the page. */
|
|
42
44
|
export declare function attachLifecycleFlush(requester: LifecycleFlushRequester, options?: LifecycleFlushOptions): () => void;
|
|
43
|
-
//# sourceMappingURL=buffered-writer.d.ts.map
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { copyDate } from "../date-value.js";
|
|
2
|
+
/** Maximum accepted `add()` calls that have not completed. Callers must await for backpressure. */
|
|
3
|
+
export const MAX_BUFFERED_WRITER_PENDING_ADDS = 64;
|
|
1
4
|
/** Batches row-oriented writes by row count, estimated bytes, or age. */
|
|
2
5
|
export class BufferedTableWriter {
|
|
3
6
|
database;
|
|
@@ -11,6 +14,9 @@ export class BufferedTableWriter {
|
|
|
11
14
|
#estimatedBytes = 0;
|
|
12
15
|
#timer;
|
|
13
16
|
#inFlight;
|
|
17
|
+
#addTail = Promise.resolve();
|
|
18
|
+
#pendingAddCount = 0;
|
|
19
|
+
#acceptingAdds = true;
|
|
14
20
|
#closed = false;
|
|
15
21
|
constructor(database, tableName, options = {}) {
|
|
16
22
|
this.database = database;
|
|
@@ -29,14 +35,17 @@ export class BufferedTableWriter {
|
|
|
29
35
|
}
|
|
30
36
|
async add(row) {
|
|
31
37
|
this.#assertOpen();
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
this.#
|
|
35
|
-
|
|
36
|
-
if (this.#rows.length >= this.#maxRows || this.#estimatedBytes >= this.#maxBytes) {
|
|
37
|
-
return this.flush();
|
|
38
|
+
if (!this.#acceptingAdds)
|
|
39
|
+
return Promise.reject(new Error("Buffered writer is closing"));
|
|
40
|
+
if (this.#pendingAddCount >= MAX_BUFFERED_WRITER_PENDING_ADDS) {
|
|
41
|
+
return Promise.reject(new RangeError(`Buffered writer cannot queue more than ${String(MAX_BUFFERED_WRITER_PENDING_ADDS)} adds; await add() for backpressure`));
|
|
38
42
|
}
|
|
39
|
-
|
|
43
|
+
this.#pendingAddCount += 1;
|
|
44
|
+
const operation = this.#addTail.then(() => this.#addSerial(row));
|
|
45
|
+
this.#addTail = operation.then(() => undefined, () => undefined);
|
|
46
|
+
return operation.finally(() => {
|
|
47
|
+
this.#pendingAddCount -= 1;
|
|
48
|
+
});
|
|
40
49
|
}
|
|
41
50
|
async flush() {
|
|
42
51
|
if (this.#inFlight !== undefined)
|
|
@@ -70,6 +79,8 @@ export class BufferedTableWriter {
|
|
|
70
79
|
async close() {
|
|
71
80
|
if (this.#closed)
|
|
72
81
|
return undefined;
|
|
82
|
+
this.#acceptingAdds = false;
|
|
83
|
+
await this.#addTail;
|
|
73
84
|
let result;
|
|
74
85
|
while (this.#inFlight !== undefined || this.#rows.length > 0) {
|
|
75
86
|
result = await this.flush();
|
|
@@ -82,6 +93,9 @@ export class BufferedTableWriter {
|
|
|
82
93
|
}
|
|
83
94
|
discard() {
|
|
84
95
|
this.#assertOpen();
|
|
96
|
+
if (this.#pendingAddCount > 0) {
|
|
97
|
+
throw new Error("Cannot discard while buffered adds are pending");
|
|
98
|
+
}
|
|
85
99
|
const discarded = this.#rows.length;
|
|
86
100
|
this.#rows.length = 0;
|
|
87
101
|
this.#estimatedBytes = 0;
|
|
@@ -96,6 +110,18 @@ export class BufferedTableWriter {
|
|
|
96
110
|
await this.flush();
|
|
97
111
|
}
|
|
98
112
|
}
|
|
113
|
+
async #addSerial(row) {
|
|
114
|
+
const copy = cloneRow(row);
|
|
115
|
+
this.#rows.push(copy);
|
|
116
|
+
this.#estimatedBytes += estimateRowBytes(copy);
|
|
117
|
+
this.#scheduleAgeFlush();
|
|
118
|
+
if (this.#rows.length < this.#maxRows && this.#estimatedBytes < this.#maxBytes) {
|
|
119
|
+
return undefined;
|
|
120
|
+
}
|
|
121
|
+
if (this.#inFlight !== undefined)
|
|
122
|
+
await this.#inFlight;
|
|
123
|
+
return this.flush();
|
|
124
|
+
}
|
|
99
125
|
#scheduleAgeFlush() {
|
|
100
126
|
if (this.#timer !== undefined || this.#rows.length === 0 || this.#closed)
|
|
101
127
|
return;
|
|
@@ -140,7 +166,7 @@ function positiveWholeNumber(value, name) {
|
|
|
140
166
|
function cloneRow(row) {
|
|
141
167
|
return Object.fromEntries(Object.entries(row).map(([name, value]) => [
|
|
142
168
|
name,
|
|
143
|
-
value instanceof Date ?
|
|
169
|
+
value instanceof Date ? copyDate(value) : value,
|
|
144
170
|
]));
|
|
145
171
|
}
|
|
146
172
|
function estimateRowBytes(row) {
|
|
@@ -155,4 +181,3 @@ function estimateRowBytes(row) {
|
|
|
155
181
|
}
|
|
156
182
|
return bytes;
|
|
157
183
|
}
|
|
158
|
-
//# sourceMappingURL=buffered-writer.js.map
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** Valid inputs beyond this length execute normally but are not retained in process-wide caches. */
|
|
2
|
+
export declare const MAX_CACHEABLE_TEXT_CHARACTERS: number;
|
|
3
|
+
/**
|
|
4
|
+
* Compilation happens before a query memory context exists. These limits therefore bound parser
|
|
5
|
+
* allocations and recursion independently of the execution budget. They are intentionally much
|
|
6
|
+
* larger than ordinary application SQL while remaining small enough for deterministic refusal.
|
|
7
|
+
*/
|
|
8
|
+
export declare const MAX_SQL_TEXT_CHARACTERS: number;
|
|
9
|
+
export declare const MAX_SQL_TOKENS = 4096;
|
|
10
|
+
export declare const MAX_SQL_NESTING_DEPTH = 128;
|
|
11
|
+
export declare const MAX_SQL_PARAMETERS = 4096;
|
|
12
|
+
/**
|
|
13
|
+
* Scalar functions that create a new string must not allocate an attacker-selected result before
|
|
14
|
+
* query memory accounting can observe it. Plain projection does not use this limit: a stored wide
|
|
15
|
+
* value can still be selected or streamed without asking a scalar function to expand it.
|
|
16
|
+
*/
|
|
17
|
+
export declare const MAX_SQL_SCALAR_RESULT_CHARACTERS: number;
|
|
18
|
+
/** Bounds object/array walks performed before an execution memory context exists. */
|
|
19
|
+
export declare const MAX_SQL_STRUCTURED_VALUE_ITEMS = 65536;
|
|
20
|
+
export declare const MAX_SQL_STRUCTURED_VALUE_DEPTH = 128;
|
|
21
|
+
/** SQL patterns compile outside the execution memory budget and may be retained in small caches. */
|
|
22
|
+
export declare const MAX_SQL_PATTERN_CHARACTERS: number;
|
|
23
|
+
/** Deterministic CPU ceiling for one non-trivial LIKE or SIMILAR TO match. */
|
|
24
|
+
export declare const MAX_SQL_PATTERN_MATCH_STEPS: number;
|
|
25
|
+
export declare const MAX_SQL_NUMERIC_DIGITS = 100000;
|