@minnowdb/core 0.8.0 → 0.9.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/dist/engine/artifact-cache.js +3 -2
- package/dist/engine/buffered-writer.js +12 -2
- package/dist/engine/client.d.ts +8 -2
- package/dist/engine/client.js +106 -22
- package/dist/engine/database.d.ts +5 -3
- package/dist/engine/database.js +2044 -1674
- package/dist/engine/errors.d.ts +19 -0
- package/dist/engine/errors.js +29 -0
- package/dist/engine/index.d.ts +1 -0
- package/dist/engine/index.js +4 -0
- package/dist/engine/live-accept.js +13 -0
- package/dist/engine/live-aggregate.js +54 -16
- package/dist/engine/live.d.ts +2 -0
- package/dist/engine/live.js +109 -108
- package/dist/engine/query-cache.js +17 -2
- package/dist/engine/query.d.ts +1 -2
- package/dist/engine/query.js +4 -7
- package/dist/engine/result-state.d.ts +7 -0
- package/dist/engine/result-state.js +15 -0
- package/dist/engine/vector.d.ts +4 -0
- package/dist/engine/vector.js +14 -14
- package/dist/engine/windows.js +15 -14
- package/dist/engine/worker-server.d.ts +1 -1
- package/dist/engine/worker-server.js +28 -15
- package/dist/engine/write-coordinator.js +54 -0
- package/dist/storage/indexeddb.js +134 -89
- package/dist/storage/opfs/index.d.ts +1 -1
- package/dist/storage/opfs/index.js +3 -1
- package/dist/storage/opfs/leader.js +20 -9
- package/dist/storage/opfs/rpc.js +3 -1
- package/dist/storage/opfs/store.d.ts +2 -0
- package/dist/storage/opfs/store.js +128 -40
- package/dist/storage/toolkit/record-core.js +2 -1
- package/dist/storage/types.d.ts +14 -0
- package/dist/storage/types.js +21 -0
- package/dist/transactions/index.d.ts +3 -0
- package/dist/transactions/index.js +4 -1
- package/dist/worker-protocol/index.d.ts +1 -1
- package/dist/worker-protocol/index.js +1 -1
- package/package.json +2 -2
- package/dist/date-value.d.ts +0 -20
- package/dist/engine/artifact-cache.d.ts +0 -29
- package/dist/engine/byte-estimates.d.ts +0 -11
- package/dist/engine/cancellation.d.ts +0 -2
- package/dist/engine/defaults.d.ts +0 -29
- package/dist/engine/group-index.d.ts +0 -33
- package/dist/engine/join-index.d.ts +0 -10
- package/dist/engine/live-aggregate.d.ts +0 -12
- package/dist/engine/live-equal.d.ts +0 -7
- package/dist/engine/point-read.d.ts +0 -59
- package/dist/engine/query-cache.d.ts +0 -21
- package/dist/engine/query-generations.d.ts +0 -8
- package/dist/engine/query-identity.d.ts +0 -3
- package/dist/engine/result-wire.d.ts +0 -70
- package/dist/engine/sort-keys.d.ts +0 -73
- package/dist/engine/sql-domains.d.ts +0 -97
- package/dist/engine/sql-functions.d.ts +0 -11
- package/dist/engine/sql-json.d.ts +0 -40
- package/dist/engine/sql-semantics.d.ts +0 -66
- package/dist/engine/worker-store-indexeddb.d.ts +0 -2
- package/dist/engine/worker-store-memory.d.ts +0 -2
- package/dist/engine/worker-store-opfs.d.ts +0 -2
- package/dist/engine/write-block-planner.d.ts +0 -19
- package/dist/storage/opfs/leader.d.ts +0 -460
- package/dist/storage/opfs/rpc.d.ts +0 -82
- package/dist/storage/opfs/snapshot-ledger.d.ts +0 -41
package/dist/engine/errors.d.ts
CHANGED
|
@@ -3,6 +3,25 @@
|
|
|
3
3
|
* them (name, fields, instanceof) without bundling the executor.
|
|
4
4
|
*/
|
|
5
5
|
type ErrorValue = boolean | number | string | Date;
|
|
6
|
+
/** An idle SQL transaction rolled back; later statements must not become autocommits. */
|
|
7
|
+
export declare class TransactionExpiredError extends Error {
|
|
8
|
+
readonly name = "TransactionExpiredError";
|
|
9
|
+
constructor();
|
|
10
|
+
}
|
|
11
|
+
/** The worker stopped responding within the configured request deadline. */
|
|
12
|
+
export declare class DatabaseWorkerTimeoutError extends Error {
|
|
13
|
+
readonly method: string;
|
|
14
|
+
readonly timeoutMs: number;
|
|
15
|
+
readonly name = "DatabaseWorkerTimeoutError";
|
|
16
|
+
constructor(method: string, timeoutMs: number);
|
|
17
|
+
}
|
|
18
|
+
/** A transport failure cannot prove whether this operation published before its reply was lost. */
|
|
19
|
+
export declare class DatabaseWorkerOutcomeUnknownError extends Error {
|
|
20
|
+
readonly method: string;
|
|
21
|
+
readonly requestId: string;
|
|
22
|
+
readonly name = "DatabaseWorkerOutcomeUnknownError";
|
|
23
|
+
constructor(method: string, requestId: string, options?: ErrorOptions);
|
|
24
|
+
}
|
|
6
25
|
/** A database operation named a table that is not present in the current catalog. */
|
|
7
26
|
export declare class UnknownTableError extends TypeError {
|
|
8
27
|
readonly tableName: string;
|
package/dist/engine/errors.js
CHANGED
|
@@ -1,3 +1,29 @@
|
|
|
1
|
+
class TransactionExpiredError extends Error {
|
|
2
|
+
name = "TransactionExpiredError";
|
|
3
|
+
constructor() {
|
|
4
|
+
super("The SQL transaction expired and rolled back; issue ROLLBACK or BEGIN before continuing");
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
class DatabaseWorkerTimeoutError extends Error {
|
|
8
|
+
method;
|
|
9
|
+
timeoutMs;
|
|
10
|
+
name = "DatabaseWorkerTimeoutError";
|
|
11
|
+
constructor(method, timeoutMs) {
|
|
12
|
+
super(`Database worker ${method} did not respond within ${String(timeoutMs)}ms`);
|
|
13
|
+
this.method = method;
|
|
14
|
+
this.timeoutMs = timeoutMs;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
class DatabaseWorkerOutcomeUnknownError extends Error {
|
|
18
|
+
method;
|
|
19
|
+
requestId;
|
|
20
|
+
name = "DatabaseWorkerOutcomeUnknownError";
|
|
21
|
+
constructor(method, requestId, options) {
|
|
22
|
+
super(`Database worker outcome is unknown for ${method}; reconcile durable application IDs before retrying`, options);
|
|
23
|
+
this.method = method;
|
|
24
|
+
this.requestId = requestId;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
1
27
|
function formatValue(value) {
|
|
2
28
|
return value instanceof Date ? dateIsoString(value) : String(value);
|
|
3
29
|
}
|
|
@@ -117,10 +143,13 @@ export {
|
|
|
117
143
|
CompactionMemoryBudgetError,
|
|
118
144
|
CompactionWriteAmplificationError,
|
|
119
145
|
DatabaseReadBacklogError,
|
|
146
|
+
DatabaseWorkerOutcomeUnknownError,
|
|
147
|
+
DatabaseWorkerTimeoutError,
|
|
120
148
|
LiveQueryLimitError,
|
|
121
149
|
MaintenanceBacklogError,
|
|
122
150
|
MissingKeyError,
|
|
123
151
|
SqlCompileError,
|
|
152
|
+
TransactionExpiredError,
|
|
124
153
|
UniqueConstraintError,
|
|
125
154
|
UnknownTableError,
|
|
126
155
|
VisibleSegmentCursorStaleError
|
package/dist/engine/index.d.ts
CHANGED
|
@@ -17,3 +17,4 @@ export type * from "./schema.js";
|
|
|
17
17
|
export type { InsertValue, CompiledQuery, CompiledStatement, QueryResult, QueryRow, QueryExecutionOptions, QueryValue, SqlColumnSchema, SqlColumnType, } from "./query.js";
|
|
18
18
|
export type { AsyncQueryExecutionOptions, QueryBatchExecutionOptions, QuerySpillStore, } from "./vector.js";
|
|
19
19
|
export type { MinnowSqlDriver, MinnowSqlExecutor } from "./sql-driver.js";
|
|
20
|
+
export { OpfsCoordinationError, OpfsDatabaseInUseError, OpfsUncertainOutcomeError, } from "../storage/types.js";
|
package/dist/engine/index.js
CHANGED
|
@@ -4,6 +4,7 @@ export * from "./errors.js";
|
|
|
4
4
|
import { QueryMemoryBudgetError } from "./memory.js";
|
|
5
5
|
import { MAX_SQL_NESTING_DEPTH, MAX_SQL_NUMERIC_DIGITS, MAX_SQL_PARAMETERS, MAX_SQL_PATTERN_CHARACTERS, MAX_SQL_PATTERN_MATCH_STEPS, MAX_SQL_SCALAR_RESULT_CHARACTERS, MAX_SQL_STRUCTURED_VALUE_DEPTH, MAX_SQL_STRUCTURED_VALUE_ITEMS, MAX_SQL_TEXT_CHARACTERS, MAX_SQL_TOKENS } from "./cache-limits.js";
|
|
6
6
|
import { column, foreignKeyName, isDestructiveStep, planMigration, schema, table, view } from "./schema.js";
|
|
7
|
+
import { OpfsCoordinationError, OpfsDatabaseInUseError, OpfsUncertainOutcomeError } from "../storage/types.js";
|
|
7
8
|
export {
|
|
8
9
|
MAX_SQL_NESTING_DEPTH,
|
|
9
10
|
MAX_SQL_NUMERIC_DIGITS,
|
|
@@ -15,6 +16,9 @@ export {
|
|
|
15
16
|
MAX_SQL_STRUCTURED_VALUE_ITEMS,
|
|
16
17
|
MAX_SQL_TEXT_CHARACTERS,
|
|
17
18
|
MAX_SQL_TOKENS,
|
|
19
|
+
OpfsCoordinationError,
|
|
20
|
+
OpfsDatabaseInUseError,
|
|
21
|
+
OpfsUncertainOutcomeError,
|
|
18
22
|
QueryMemoryBudgetError,
|
|
19
23
|
column,
|
|
20
24
|
foreignKeyName,
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const publications = /* @__PURE__ */ new WeakMap();
|
|
2
|
+
function stageLiveExecution(execution, publish) {
|
|
3
|
+
publications.set(execution, publish);
|
|
4
|
+
return execution;
|
|
5
|
+
}
|
|
6
|
+
function acceptLiveExecution(execution) {
|
|
7
|
+
publications.get(execution)?.();
|
|
8
|
+
publications.delete(execution);
|
|
9
|
+
}
|
|
10
|
+
export {
|
|
11
|
+
acceptLiveExecution,
|
|
12
|
+
stageLiveExecution
|
|
13
|
+
};
|
|
@@ -2,23 +2,35 @@ import { childExpressions, hasAggregate, mapChildExpressions, executeRowQueryInt
|
|
|
2
2
|
import { encodeQueryIdentity } from "./query-identity.js";
|
|
3
3
|
import { exactNumericBinary, exactNumericValue, externalSqlDomainValue, isExactNumeric } from "./sql-domains.js";
|
|
4
4
|
import { encodeSqlEqualityValue } from "./sql-semantics.js";
|
|
5
|
+
function contributionBytes(key, row) {
|
|
6
|
+
return 64 + key.length * 2 + row.group.length * 2 + row.values.reduce((sum, value) => sum + (typeof value === "string" ? value.length * 2 + 16 : 16), 0);
|
|
7
|
+
}
|
|
8
|
+
function groupBytes(key, group) {
|
|
9
|
+
return 96 + key.length * 2 + group.sums.reduce((sum, value) => sum + value.length * 2 + 24, 0);
|
|
10
|
+
}
|
|
5
11
|
class LiveAggregate {
|
|
6
12
|
inputPlan;
|
|
7
13
|
#outputPlan;
|
|
8
14
|
#aggregates;
|
|
9
15
|
#groupAliases;
|
|
10
|
-
#
|
|
16
|
+
#contributions;
|
|
17
|
+
#revision;
|
|
18
|
+
#pending;
|
|
19
|
+
#bytes;
|
|
11
20
|
#groups;
|
|
12
21
|
#domains;
|
|
13
22
|
keyAlias;
|
|
14
23
|
#schema;
|
|
15
|
-
constructor(inputPlan, outputPlan, aggregates, groupAliases, keyAlias,
|
|
24
|
+
constructor(inputPlan, outputPlan, aggregates, groupAliases, keyAlias, contributions = { rows: /* @__PURE__ */ new Map(), revision: 0 }, groups = /* @__PURE__ */ new Map(), domains = [], schema = [], bytes = 256 + encodeQueryIdentity(inputPlan).length * 2 + encodeQueryIdentity(outputPlan).length * 2, pending) {
|
|
16
25
|
this.inputPlan = inputPlan;
|
|
17
26
|
this.#outputPlan = outputPlan;
|
|
18
27
|
this.#aggregates = aggregates;
|
|
19
28
|
this.#groupAliases = groupAliases;
|
|
20
29
|
this.keyAlias = keyAlias;
|
|
21
|
-
this.#
|
|
30
|
+
this.#contributions = contributions;
|
|
31
|
+
this.#revision = contributions.revision;
|
|
32
|
+
this.#pending = pending;
|
|
33
|
+
this.#bytes = bytes;
|
|
22
34
|
this.#groups = groups;
|
|
23
35
|
this.#domains = domains;
|
|
24
36
|
this.#schema = schema;
|
|
@@ -38,7 +50,7 @@ class LiveAggregate {
|
|
|
38
50
|
if (grouped !== void 0)
|
|
39
51
|
return { kind: "column", reference: grouped };
|
|
40
52
|
if (expression.kind === "call" && hasAggregate(expression)) {
|
|
41
|
-
if (!["COUNT", "SUM", "AVG"].includes(expression.name) || expression.arguments.length !== 1)
|
|
53
|
+
if (!["COUNT", "SUM", "AVG"].includes(expression.name) || expression.arguments.length !== 1 || expression.distinct === true)
|
|
42
54
|
throw new TypeError("Not an additive live aggregate");
|
|
43
55
|
const argument = expression.arguments[0];
|
|
44
56
|
if (argument === void 0 || !(rowLocal(argument) || expression.name === "COUNT" && argument.kind === "wildcard"))
|
|
@@ -102,11 +114,17 @@ class LiveAggregate {
|
|
|
102
114
|
}
|
|
103
115
|
}
|
|
104
116
|
patch(result, changed, token) {
|
|
105
|
-
|
|
117
|
+
if (this.#pending !== void 0 || this.#revision !== this.#contributions.revision)
|
|
118
|
+
throw new Error("Unaccepted or stale aggregate");
|
|
119
|
+
const rows = this.#contributions.rows;
|
|
120
|
+
const pending = /* @__PURE__ */ new Map();
|
|
121
|
+
let bytes = this.#bytes;
|
|
106
122
|
const groups = new Map(this.#groups);
|
|
107
123
|
const touched = /* @__PURE__ */ new Set();
|
|
108
124
|
const groupFor = (key, keys = []) => {
|
|
109
125
|
let group = groups.get(key);
|
|
126
|
+
if (group !== void 0 && !touched.has(key))
|
|
127
|
+
bytes -= groupBytes(key, group);
|
|
110
128
|
if (group === void 0) {
|
|
111
129
|
group = {
|
|
112
130
|
keys,
|
|
@@ -158,15 +176,20 @@ class LiveAggregate {
|
|
|
158
176
|
if (old === void 0)
|
|
159
177
|
continue;
|
|
160
178
|
apply(groupFor(old.group), old.values, -1);
|
|
161
|
-
|
|
179
|
+
pending.set(key, void 0);
|
|
180
|
+
bytes -= contributionBytes(key, old);
|
|
162
181
|
}
|
|
163
182
|
for (const row of result.rows) {
|
|
164
183
|
const key = token(row[this.keyAlias] ?? null);
|
|
184
|
+
if (pending.get(key) !== void 0 || rows.has(key) && !changed.has(key))
|
|
185
|
+
throw new TypeError("Duplicate live input key");
|
|
165
186
|
const keys = this.#groupAliases.map((alias) => row[alias] ?? null);
|
|
166
187
|
const group = JSON.stringify(keys.map(encodeSqlEqualityValue));
|
|
167
188
|
const values = this.#aggregates.map(({ alias }) => row[alias] ?? null);
|
|
168
189
|
apply(groupFor(group, keys), values, 1);
|
|
169
|
-
|
|
190
|
+
const contribution = { group, values };
|
|
191
|
+
pending.set(key, contribution);
|
|
192
|
+
bytes += contributionBytes(key, contribution);
|
|
170
193
|
}
|
|
171
194
|
if (this.#groupAliases.length === 0)
|
|
172
195
|
groupFor("[]");
|
|
@@ -174,17 +197,37 @@ class LiveAggregate {
|
|
|
174
197
|
for (const key of touched)
|
|
175
198
|
if (groups.get(key)?.members === 0)
|
|
176
199
|
groups.delete(key);
|
|
200
|
+
for (const key of touched) {
|
|
201
|
+
const group = groups.get(key);
|
|
202
|
+
if (group !== void 0)
|
|
203
|
+
bytes += groupBytes(key, group);
|
|
204
|
+
}
|
|
177
205
|
const domains = this.#aggregates.map(({ alias }, index) => result.columnDomains[result.columns.indexOf(alias)] ?? this.#domains[index] ?? null);
|
|
178
|
-
return new LiveAggregate(this.inputPlan, this.#outputPlan, this.#aggregates, this.#groupAliases, this.keyAlias,
|
|
206
|
+
return new LiveAggregate(this.inputPlan, this.#outputPlan, this.#aggregates, this.#groupAliases, this.keyAlias, this.#contributions, groups, domains, result.columns.map((name, index) => {
|
|
179
207
|
const domain = result.columnDomains[index];
|
|
180
208
|
const value = result.rows.find((row) => row[name] !== null)?.[name];
|
|
181
209
|
const aggregate = this.#aggregates.find((item) => item.alias === name);
|
|
182
210
|
return {
|
|
183
211
|
name,
|
|
184
|
-
type: aggregate?.name === "COUNT" ? "number" : domain !== null && domain !== void 0 ? "string" : typeof value === "number" ? "number" : typeof value === "boolean" ? "boolean" : value instanceof Date ? "datetime" : "string",
|
|
212
|
+
type: aggregate?.name === "COUNT" ? "number" : domain !== null && domain !== void 0 ? "string" : typeof value === "number" ? "number" : typeof value === "boolean" ? "boolean" : value instanceof Date ? "datetime" : value === void 0 || value === null ? this.#schema[index]?.type ?? "string" : "string",
|
|
185
213
|
...domain === null || domain === void 0 || aggregate?.name === "COUNT" ? {} : { sqlDomain: domain }
|
|
186
214
|
};
|
|
187
|
-
}));
|
|
215
|
+
}), bytes, pending);
|
|
216
|
+
}
|
|
217
|
+
accept() {
|
|
218
|
+
const pending = this.#pending;
|
|
219
|
+
if (pending === void 0)
|
|
220
|
+
return;
|
|
221
|
+
if (this.#revision !== this.#contributions.revision)
|
|
222
|
+
throw new Error("Stale aggregate");
|
|
223
|
+
for (const [key, contribution] of pending) {
|
|
224
|
+
if (contribution === void 0)
|
|
225
|
+
this.#contributions.rows.delete(key);
|
|
226
|
+
else
|
|
227
|
+
this.#contributions.rows.set(key, contribution);
|
|
228
|
+
}
|
|
229
|
+
this.#revision = ++this.#contributions.revision;
|
|
230
|
+
this.#pending = void 0;
|
|
188
231
|
}
|
|
189
232
|
result() {
|
|
190
233
|
const rows = [];
|
|
@@ -213,12 +256,7 @@ class LiveAggregate {
|
|
|
213
256
|
return externalizeQueryResult(result);
|
|
214
257
|
}
|
|
215
258
|
get retainedBytes() {
|
|
216
|
-
|
|
217
|
-
for (const [key, row] of this.#rows)
|
|
218
|
-
bytes += 64 + key.length * 2 + row.group.length * 2 + row.values.reduce((sum, value) => sum + (typeof value === "string" ? value.length * 2 + 16 : 16), 0);
|
|
219
|
-
for (const [key, group] of this.#groups)
|
|
220
|
-
bytes += 96 + key.length * 2 + group.sums.reduce((sum, value) => sum + value.length * 2 + 24, 0);
|
|
221
|
-
return bytes;
|
|
259
|
+
return this.#bytes;
|
|
222
260
|
}
|
|
223
261
|
}
|
|
224
262
|
export {
|
package/dist/engine/live.d.ts
CHANGED
|
@@ -169,6 +169,8 @@ export interface LiveQueryHost {
|
|
|
169
169
|
dependencyTableIds(query: LiveQueryInput, probe?: CatalogProbe): Promise<Set<string>>;
|
|
170
170
|
/** Executes the statement; the returned result belongs to the set and is never shared. */
|
|
171
171
|
execute(query: LiveQueryInput, context?: LiveQueryExecuteContext): Promise<QueryResult>;
|
|
172
|
+
/** Optionally publishes an accepted result for adapters that re-execute after invalidation. */
|
|
173
|
+
memoize?(query: LiveQueryInput, result: QueryResult, probe: CatalogProbe): Promise<void>;
|
|
172
174
|
/**
|
|
173
175
|
* Executes a statement the host can later maintain incrementally, or returns undefined when
|
|
174
176
|
* the statement's shape rules that out; the set then executes it in full from then on.
|