@minnowdb/core 0.7.2 → 0.7.7
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/dist/engine/client.d.ts +2 -2
- package/dist/engine/client.js +7 -2
- package/dist/engine/database.d.ts +11 -1
- package/dist/engine/database.js +642 -175
- package/dist/engine/optimizer.js +48 -26
- package/dist/engine/query.d.ts +98 -0
- package/dist/engine/query.js +1452 -165
- package/dist/engine/sql-domains.d.ts +11 -0
- package/dist/engine/sql-domains.js +56 -0
- package/dist/engine/sql-functions.js +129 -3
- package/dist/engine/sql-json.d.ts +2 -0
- package/dist/engine/sql-json.js +4 -0
- package/dist/engine/sql-semantics.d.ts +9 -1
- package/dist/engine/sql-semantics.js +19 -3
- package/dist/engine/vector.js +29 -13
- package/dist/engine/worker-server.js +4 -1
- package/dist/plan/model.d.ts +14 -2
- package/dist/storage/indexeddb.js +13 -8
- package/dist/storage/memory.d.ts +2 -1
- package/dist/storage/memory.js +29 -4
- package/dist/storage/toolkit/record-core.js +11 -6
- package/dist/storage/types.d.ts +11 -0
- package/dist/testing/sqllogictest.js +3 -1
- package/package.json +1 -1
- package/postgres-feature-profile.json +9 -4
- package/sql-feature-matrix.json +541 -4
package/dist/storage/memory.js
CHANGED
|
@@ -3,6 +3,27 @@ import { verifyStoredBlock } from "../block-format/index.js";
|
|
|
3
3
|
import { crc32 } from "../block-format/checksum.js";
|
|
4
4
|
import { decodeSnapshotMetadataItems, encodeSnapshotFrameStreamFooter, encodeSnapshotFrameStreamHeader, encodeSnapshotMetadataPage, extendSnapshotFrameStreamChecksum, prepareSnapshotFrameStreamHeader, snapshotFrameEnvelopeParts, snapshotFrameStreamHeaderIdentity } from "./snapshot-stream.js";
|
|
5
5
|
import { RecordCore, validateFtsPostingChunks, validateId, validateTempRunPage, validateTempRunPageIdentity } from "./toolkit/record-core.js";
|
|
6
|
+
const commitTurn = (() => {
|
|
7
|
+
const immediate = globalThis.setImmediate;
|
|
8
|
+
if (immediate !== void 0 && !Reflect.has(immediate, "clock")) {
|
|
9
|
+
return () => new Promise((resolve) => {
|
|
10
|
+
immediate(resolve);
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
if (typeof MessageChannel === "undefined") {
|
|
14
|
+
return () => new Promise((resolve) => setTimeout(resolve, 0));
|
|
15
|
+
}
|
|
16
|
+
let channel;
|
|
17
|
+
const waiting = [];
|
|
18
|
+
return () => new Promise((resolve) => {
|
|
19
|
+
if (channel === void 0) {
|
|
20
|
+
channel = new MessageChannel();
|
|
21
|
+
channel.port1.onmessage = () => waiting.shift()?.();
|
|
22
|
+
}
|
|
23
|
+
waiting.push(resolve);
|
|
24
|
+
channel.port2.postMessage(void 0);
|
|
25
|
+
});
|
|
26
|
+
})();
|
|
6
27
|
class MemoryBlockStore {
|
|
7
28
|
#blocks = /* @__PURE__ */ new Map();
|
|
8
29
|
#blockChecksums = /* @__PURE__ */ new Map();
|
|
@@ -549,15 +570,19 @@ class MemoryBlockStore {
|
|
|
549
570
|
});
|
|
550
571
|
}
|
|
551
572
|
async commitTransaction(input) {
|
|
552
|
-
|
|
573
|
+
const summary = await this.#runAtomic(() => this.#core.commitTransaction(input));
|
|
574
|
+
await commitTurn();
|
|
575
|
+
return summary;
|
|
553
576
|
}
|
|
554
577
|
async writeTransaction(input) {
|
|
555
|
-
|
|
556
|
-
const
|
|
578
|
+
const summary = await this.#runAtomic(() => {
|
|
579
|
+
const summary2 = this.#core.writeTransaction(input);
|
|
557
580
|
for (const block of input.blocks)
|
|
558
581
|
this.#putBlock(block.id, block.bytes);
|
|
559
|
-
return
|
|
582
|
+
return summary2;
|
|
560
583
|
});
|
|
584
|
+
await commitTurn();
|
|
585
|
+
return summary;
|
|
561
586
|
}
|
|
562
587
|
async createLease(record) {
|
|
563
588
|
return this.#runAtomic(() => {
|
|
@@ -3567,7 +3567,12 @@ class RecordCore {
|
|
|
3567
3567
|
throw new GarbageCollectionJobConflictError(input.jobId, input.expectedRevision, current?.revision ?? null);
|
|
3568
3568
|
}
|
|
3569
3569
|
const updated = updateGarbageCollectionPlanningRecord(current, input);
|
|
3570
|
-
assertGarbageCollectionCandidateProvenance(
|
|
3570
|
+
assertGarbageCollectionCandidateProvenance({
|
|
3571
|
+
candidateManifestVersions: input.candidateManifestVersions ?? [],
|
|
3572
|
+
candidateSegmentIds: input.candidateSegmentIds ?? [],
|
|
3573
|
+
candidateBlockIds: input.candidateBlockIds ?? [],
|
|
3574
|
+
candidateTransactionIds: input.candidateTransactionIds ?? []
|
|
3575
|
+
}, this.#manifests, this.#manifestBlocks, this.#segments, this.#transactions, this.#roots);
|
|
3571
3576
|
this.#garbageCollectionJobs.set(updated.id, updated);
|
|
3572
3577
|
return cloneRecord(updated);
|
|
3573
3578
|
}
|
|
@@ -5661,23 +5666,23 @@ function assertPendingArtifactsAvailable(transaction, physical, segments, valida
|
|
|
5661
5666
|
}
|
|
5662
5667
|
}
|
|
5663
5668
|
}
|
|
5664
|
-
function assertGarbageCollectionCandidateProvenance(
|
|
5665
|
-
for (const version of
|
|
5669
|
+
function assertGarbageCollectionCandidateProvenance(candidates, manifests, manifestBlocks, segments, transactions, roots) {
|
|
5670
|
+
for (const version of candidates.candidateManifestVersions) {
|
|
5666
5671
|
if (!manifests.has(version)) {
|
|
5667
5672
|
throw new Error(`Garbage collection candidate manifest is missing: ${String(version)}`);
|
|
5668
5673
|
}
|
|
5669
5674
|
}
|
|
5670
|
-
for (const id of
|
|
5675
|
+
for (const id of candidates.candidateTransactionIds) {
|
|
5671
5676
|
const transaction = transactions.get(id);
|
|
5672
5677
|
if (transaction === void 0 || transaction.status !== "aborted" && (transaction.status !== "committed" || transaction.committedVersion === null)) {
|
|
5673
5678
|
throw new Error(`Garbage collection transaction candidate is not terminal: ${id}`);
|
|
5674
5679
|
}
|
|
5675
5680
|
}
|
|
5676
|
-
const unprovenBlockId =
|
|
5681
|
+
const unprovenBlockId = candidates.candidateBlockIds.find((id) => !manifestBlocks.has(id) && roots.abortedTransactionBlockCount(id) === 0 && roots.terminalJobBlockCount(id) === 0);
|
|
5677
5682
|
if (unprovenBlockId !== void 0) {
|
|
5678
5683
|
throw new Error(`Garbage collection block candidate has no persisted provenance: ${unprovenBlockId}`);
|
|
5679
5684
|
}
|
|
5680
|
-
const unprovenSegmentId =
|
|
5685
|
+
const unprovenSegmentId = candidates.candidateSegmentIds.find((id) => {
|
|
5681
5686
|
return !segments.has(id);
|
|
5682
5687
|
});
|
|
5683
5688
|
if (unprovenSegmentId !== void 0) {
|
package/dist/storage/types.d.ts
CHANGED
|
@@ -815,6 +815,17 @@ export interface UpdateGarbageCollectionPlanningInput {
|
|
|
815
815
|
discovery: GarbageCollectionDiscovery;
|
|
816
816
|
updatedAt: string;
|
|
817
817
|
}
|
|
818
|
+
/**
|
|
819
|
+
* One page's (or one job's full) proposed garbage-collection candidates, checked for persisted
|
|
820
|
+
* provenance before being accepted. Shared by every adapter's provenance assertion so a candidate
|
|
821
|
+
* kind added to one cannot be forgotten in another.
|
|
822
|
+
*/
|
|
823
|
+
export interface GarbageCollectionCandidateSet {
|
|
824
|
+
readonly candidateManifestVersions: readonly number[];
|
|
825
|
+
readonly candidateSegmentIds: readonly string[];
|
|
826
|
+
readonly candidateBlockIds: readonly string[];
|
|
827
|
+
readonly candidateTransactionIds: readonly string[];
|
|
828
|
+
}
|
|
818
829
|
export interface GarbageCollectionJobRecord {
|
|
819
830
|
id: string;
|
|
820
831
|
candidateManifestVersions: number[];
|
|
@@ -166,7 +166,9 @@ function parseExpected(lines, file, line) {
|
|
|
166
166
|
return { kind: "hash", valueCount, hash: (match[2] ?? "").toLowerCase() };
|
|
167
167
|
}
|
|
168
168
|
function tokenizeDirective(line) {
|
|
169
|
-
|
|
169
|
+
const hash = line.indexOf("#");
|
|
170
|
+
const directive = hash === -1 ? line : line.slice(0, hash);
|
|
171
|
+
return directive.trim().split(/\s+/u);
|
|
170
172
|
}
|
|
171
173
|
function sqlLines(lines) {
|
|
172
174
|
return lines.map((line) => line.text).join("\n");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@minnowdb/core",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.7",
|
|
4
4
|
"description": "A columnar SQL database for the browser: PostgreSQL-style SQL over durable IndexedDB or OPFS data, with no server or WebAssembly module.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Eric Wilhite",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
{
|
|
32
32
|
"id": "expression.arithmetic",
|
|
33
33
|
"classification": "different",
|
|
34
|
-
"reason": "
|
|
34
|
+
"reason": "Division by zero returns NULL instead of raising PostgreSQL's error. Integer division itself follows PostgreSQL: two integer operands truncate toward zero."
|
|
35
35
|
},
|
|
36
36
|
{
|
|
37
37
|
"id": "expression.round",
|
|
@@ -43,6 +43,11 @@
|
|
|
43
43
|
"classification": "extension",
|
|
44
44
|
"reason": "PostgreSQL uses $n parameters. Minnow also accepts ? as adapter-friendly shorthand."
|
|
45
45
|
},
|
|
46
|
+
{
|
|
47
|
+
"id": "mutation.truncate",
|
|
48
|
+
"classification": "different",
|
|
49
|
+
"reason": "TRUNCATE reports the number of rows it removed, where PostgreSQL's command tag carries no count. The resulting table state is identical."
|
|
50
|
+
},
|
|
46
51
|
{
|
|
47
52
|
"id": "mutation.upsert-replace",
|
|
48
53
|
"classification": "extension",
|
|
@@ -91,7 +96,7 @@
|
|
|
91
96
|
{
|
|
92
97
|
"id": "expression.modulo",
|
|
93
98
|
"classification": "different",
|
|
94
|
-
"reason": "Minnow permits % on
|
|
99
|
+
"reason": "Minnow permits % on double precision values; PostgreSQL has no % operator for double precision."
|
|
95
100
|
},
|
|
96
101
|
{
|
|
97
102
|
"id": "expression.date-trunc",
|
|
@@ -101,7 +106,7 @@
|
|
|
101
106
|
{
|
|
102
107
|
"id": "function.numeric-core",
|
|
103
108
|
"classification": "different",
|
|
104
|
-
"reason": "Minnow's
|
|
109
|
+
"reason": "Minnow's numeric functions accept integer, exact, and double-precision arguments interchangeably, where PostgreSQL's distinct integer, numeric, and double-precision overloads do not."
|
|
105
110
|
},
|
|
106
111
|
{
|
|
107
112
|
"id": "function.string-extended",
|
|
@@ -247,7 +252,7 @@
|
|
|
247
252
|
{
|
|
248
253
|
"id": "transaction.isolation-level",
|
|
249
254
|
"classification": "inapplicable",
|
|
250
|
-
"reason": "
|
|
255
|
+
"reason": "Every transaction reads one snapshot and commits atomically, which satisfies READ UNCOMMITTED, READ COMMITTED, and REPEATABLE READ, so those levels are accepted and ignored. SERIALIZABLE promises more than one snapshot can, and is refused rather than silently downgraded."
|
|
251
256
|
},
|
|
252
257
|
{
|
|
253
258
|
"id": "privileges.grant",
|