@minnowdb/core 0.6.9 → 0.7.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.
Files changed (103) hide show
  1. package/dist/block-format/block.js +254 -325
  2. package/dist/block-format/checksum.js +30 -52
  3. package/dist/block-format/codecs.js +112 -125
  4. package/dist/block-format/column.js +187 -205
  5. package/dist/block-format/index.js +5 -1
  6. package/dist/block-format/physical.js +371 -387
  7. package/dist/block-format/types.js +4 -1
  8. package/dist/block-format/unicode.js +30 -39
  9. package/dist/date-value.d.ts +5 -0
  10. package/dist/date-value.js +71 -41
  11. package/dist/engine/artifact-cache.js +106 -116
  12. package/dist/engine/batch.js +36 -44
  13. package/dist/engine/buffered-writer.js +156 -158
  14. package/dist/engine/byte-estimates.js +20 -22
  15. package/dist/engine/cache-limits.js +24 -25
  16. package/dist/engine/cancellation.js +5 -3
  17. package/dist/engine/catalog.js +64 -73
  18. package/dist/engine/client.js +715 -780
  19. package/dist/engine/database.js +15952 -18465
  20. package/dist/engine/defaults.js +104 -111
  21. package/dist/engine/errors.js +113 -128
  22. package/dist/engine/fts.js +233 -280
  23. package/dist/engine/group-index.js +287 -321
  24. package/dist/engine/index.js +23 -12
  25. package/dist/engine/join-index.js +177 -186
  26. package/dist/engine/keyed-live.js +168 -173
  27. package/dist/engine/live-api.js +0 -1
  28. package/dist/engine/live-equal.js +32 -37
  29. package/dist/engine/live.js +603 -647
  30. package/dist/engine/memory.js +109 -111
  31. package/dist/engine/optimizer.d.ts +19 -1
  32. package/dist/engine/optimizer.js +2642 -2515
  33. package/dist/engine/point-read.d.ts +4 -2
  34. package/dist/engine/point-read.js +121 -171
  35. package/dist/engine/query-api.js +12 -3
  36. package/dist/engine/query-cache.js +61 -69
  37. package/dist/engine/query.d.ts +45 -0
  38. package/dist/engine/query.js +8506 -9375
  39. package/dist/engine/result-wire.js +221 -252
  40. package/dist/engine/schema-wire.js +97 -112
  41. package/dist/engine/schema.js +1099 -1254
  42. package/dist/engine/sort-keys.js +315 -389
  43. package/dist/engine/sql-domains.d.ts +7 -1
  44. package/dist/engine/sql-domains.js +648 -734
  45. package/dist/engine/sql-driver.js +0 -1
  46. package/dist/engine/sql-functions.d.ts +11 -0
  47. package/dist/engine/sql-functions.js +1092 -0
  48. package/dist/engine/sql-json.js +199 -218
  49. package/dist/engine/sql-semantics.d.ts +25 -4
  50. package/dist/engine/sql-semantics.js +579 -513
  51. package/dist/engine/typed-live.js +271 -293
  52. package/dist/engine/vector.d.ts +7 -1
  53. package/dist/engine/vector.js +4513 -4580
  54. package/dist/engine/worker-host.d.ts +8 -63
  55. package/dist/engine/worker-host.js +28 -1130
  56. package/dist/engine/worker-indexeddb.d.ts +1 -0
  57. package/dist/engine/worker-indexeddb.js +3 -0
  58. package/dist/engine/worker-memory.d.ts +1 -0
  59. package/dist/engine/worker-memory.js +3 -0
  60. package/dist/engine/worker-opfs.d.ts +1 -0
  61. package/dist/engine/worker-opfs.js +3 -0
  62. package/dist/engine/worker-server.d.ts +93 -0
  63. package/dist/engine/worker-server.js +999 -0
  64. package/dist/engine/worker-store-indexeddb.d.ts +2 -0
  65. package/dist/engine/worker-store-indexeddb.js +11 -0
  66. package/dist/engine/worker-store-memory.d.ts +2 -0
  67. package/dist/engine/worker-store-memory.js +6 -0
  68. package/dist/engine/worker-store-opfs.d.ts +2 -0
  69. package/dist/engine/worker-store-opfs.js +9 -0
  70. package/dist/engine/worker.js +0 -12
  71. package/dist/engine/write-block-planner.js +93 -100
  72. package/dist/plan/index.js +15 -16
  73. package/dist/plan/model.d.ts +9 -1
  74. package/dist/plan/model.js +20 -27
  75. package/dist/storage/index.js +0 -12
  76. package/dist/storage/indexeddb.js +11776 -13171
  77. package/dist/storage/memory.js +1198 -1241
  78. package/dist/storage/opfs/files.js +238 -295
  79. package/dist/storage/opfs/index.js +9 -3
  80. package/dist/storage/opfs/leader.js +4386 -4856
  81. package/dist/storage/opfs/rpc.js +223 -259
  82. package/dist/storage/opfs/snapshot-ledger.js +219 -260
  83. package/dist/storage/opfs/store.js +884 -1003
  84. package/dist/storage/persistence.js +59 -74
  85. package/dist/storage/snapshot-stream.js +788 -826
  86. package/dist/storage/snapshot.js +36 -37
  87. package/dist/storage/toolkit/extents.js +444 -520
  88. package/dist/storage/toolkit/index.js +28 -29
  89. package/dist/storage/toolkit/record-core.js +5792 -6377
  90. package/dist/storage/toolkit/sync-file.js +34 -42
  91. package/dist/storage/toolkit/wal.js +92 -127
  92. package/dist/storage/toolkit/wire.js +232 -256
  93. package/dist/storage/types.js +2952 -3228
  94. package/dist/testing/block-store-conformance.js +1556 -1629
  95. package/dist/testing/index.js +310 -291
  96. package/dist/testing/opfs-shim.js +280 -312
  97. package/dist/testing/simulator.js +496 -534
  98. package/dist/testing/sqllogictest.js +425 -365
  99. package/dist/transactions/index.js +1464 -1712
  100. package/dist/worker-protocol/index.js +70 -69
  101. package/package.json +20 -2
  102. package/postgres-feature-profile.json +15 -5
  103. package/sql-feature-matrix.json +252 -2
@@ -1,311 +1,289 @@
1
1
  import { sameLiveValue } from "./live-equal.js";
2
2
  function immutableRows(rows) {
3
- // Adapters own their values. Copy the array so mutating the returned builder result cannot
4
- // change the snapshot identity retained for exact suppression.
5
- return Object.freeze([...rows]);
3
+ return Object.freeze([...rows]);
6
4
  }
7
- /**
8
- * One typed live SELECT. It is also a framework-neutral external store: getSnapshot is stable
9
- * until state changes and subscribe returns synchronous cleanup. Slow consumers coalesce to the
10
- * newest invalidation; errors retain the last good rows.
11
- */
12
- export class LiveQuery {
13
- #listeners = new Set();
14
- #source;
15
- #backend;
16
- #onClose;
17
- #snapshot = { status: "loading", rows: [] };
18
- #subscription;
19
- #observationGeneration = 0;
20
- #queued;
21
- #execution;
22
- #executionAbort;
23
- #invalidationSequence = 0;
24
- #closed = false;
25
- constructor(backend, source, onClose) {
26
- this.#backend = backend;
27
- this.#source = source;
28
- this.#onClose = onClose;
29
- }
30
- getSnapshot = () => this.#snapshot;
31
- subscribe = (listener) => {
32
- if (this.#closed)
33
- throw new Error("Live query is closed");
34
- // A subscription is a lease, even when a framework reuses the same callback function.
35
- const registered = () => listener();
36
- this.#listeners.add(registered);
37
- if (this.#listeners.size === 1)
38
- this.#startObservation();
39
- let subscribed = true;
40
- return () => {
41
- if (!subscribed)
42
- return;
43
- subscribed = false;
44
- this.#listeners.delete(registered);
45
- if (this.#listeners.size === 0)
46
- this.#stopObservation();
47
- };
5
+ class LiveQuery {
6
+ #listeners = /* @__PURE__ */ new Set();
7
+ #source;
8
+ #backend;
9
+ #onClose;
10
+ #snapshot = { status: "loading", rows: [] };
11
+ #subscription;
12
+ #observationGeneration = 0;
13
+ #queued;
14
+ #execution;
15
+ #executionAbort;
16
+ #invalidationSequence = 0;
17
+ #closed = false;
18
+ constructor(backend, source, onClose) {
19
+ this.#backend = backend;
20
+ this.#source = source;
21
+ this.#onClose = onClose;
22
+ }
23
+ getSnapshot = () => this.#snapshot;
24
+ subscribe = (listener) => {
25
+ if (this.#closed)
26
+ throw new Error("Live query is closed");
27
+ const registered = () => listener();
28
+ this.#listeners.add(registered);
29
+ if (this.#listeners.size === 1)
30
+ this.#startObservation();
31
+ let subscribed = true;
32
+ return () => {
33
+ if (!subscribed)
34
+ return;
35
+ subscribed = false;
36
+ this.#listeners.delete(registered);
37
+ if (this.#listeners.size === 0)
38
+ this.#stopObservation();
48
39
  };
49
- async refresh() {
50
- if (this.#closed)
51
- throw new Error("Live query is closed");
52
- const sequence = this.#invalidationSequence;
53
- if (this.#listeners.size > 0) {
54
- // A transient dependency/observer setup failure must not strand existing subscribers.
55
- // Re-open first so this refresh and future commits reach the query again.
56
- if (this.#subscription === undefined)
57
- this.#startObservation();
58
- const opening = this.#subscription;
59
- if (opening !== undefined)
60
- await opening.catch(() => undefined);
61
- await this.#backend.refresh();
62
- }
63
- // A backend refresh normally invalidates observers itself. Only synthesize an execution
64
- // when it did not, which preserves manual retry without running every refreshed query twice.
65
- if (this.#invalidationSequence === sequence) {
66
- const version = this.#snapshot.status === "loading" ? null : this.#snapshot.version;
67
- this.#schedule({ manifestVersion: version, catalogEpoch: 0, initial: false });
68
- }
69
- await this.#waitForIdle();
40
+ };
41
+ async refresh() {
42
+ if (this.#closed)
43
+ throw new Error("Live query is closed");
44
+ const sequence = this.#invalidationSequence;
45
+ if (this.#listeners.size > 0) {
46
+ if (this.#subscription === void 0)
47
+ this.#startObservation();
48
+ const opening = this.#subscription;
49
+ if (opening !== void 0)
50
+ await opening.catch(() => void 0);
51
+ await this.#backend.refresh();
70
52
  }
71
- close() {
72
- if (this.#closed)
73
- return;
74
- this.#closed = true;
75
- this.#observationGeneration += 1;
76
- this.#executionAbort?.abort(new Error("Live query is closed"));
77
- const subscription = this.#subscription;
78
- this.#subscription = undefined;
79
- if (subscription !== undefined) {
80
- void subscription.then((handle) => handle.close()).catch(() => undefined);
81
- }
82
- // Wake iterators before removing their listeners so a parked next() terminates.
83
- this.#emit();
84
- this.#listeners.clear();
85
- this.#onClose?.();
53
+ if (this.#invalidationSequence === sequence) {
54
+ const version = this.#snapshot.status === "loading" ? null : this.#snapshot.version;
55
+ this.#schedule({ manifestVersion: version, catalogEpoch: 0, initial: false });
86
56
  }
87
- #startObservation() {
88
- if (this.#subscription !== undefined || this.#closed)
89
- return;
90
- const generation = (this.#observationGeneration += 1);
91
- const subscription = this.#backend.observe(this.#source.query, {
92
- onInvalidate: (invalidation) => {
93
- if (generation !== this.#observationGeneration || this.#closed)
94
- return;
95
- this.#schedule(invalidation);
96
- },
97
- onError: (error) => {
98
- if (generation !== this.#observationGeneration || this.#closed)
99
- return;
100
- this.#setError(error, this.#currentVersion());
101
- },
102
- onComplete: () => {
103
- if (generation !== this.#observationGeneration)
104
- return;
105
- this.#subscription = undefined;
106
- },
107
- });
108
- this.#subscription = subscription;
109
- subscription.catch((error) => {
110
- if (generation !== this.#observationGeneration || this.#closed)
111
- return;
112
- this.#subscription = undefined;
113
- this.#setError(error, this.#currentVersion());
114
- });
57
+ await this.#waitForIdle();
58
+ }
59
+ close() {
60
+ if (this.#closed)
61
+ return;
62
+ this.#closed = true;
63
+ this.#observationGeneration += 1;
64
+ this.#executionAbort?.abort(new Error("Live query is closed"));
65
+ const subscription = this.#subscription;
66
+ this.#subscription = void 0;
67
+ if (subscription !== void 0) {
68
+ void subscription.then((handle) => handle.close()).catch(() => void 0);
115
69
  }
116
- #stopObservation() {
117
- this.#observationGeneration += 1;
118
- this.#executionAbort?.abort(new Error("Live query has no subscribers"));
119
- const subscription = this.#subscription;
120
- this.#subscription = undefined;
121
- if (subscription !== undefined) {
122
- void subscription.then((handle) => handle.close()).catch(() => undefined);
123
- }
124
- }
125
- #schedule(invalidation) {
126
- this.#invalidationSequence += 1;
127
- this.#queued = invalidation;
128
- if (this.#execution !== undefined)
129
- return;
130
- const execution = this.#drain();
131
- this.#execution = execution;
132
- void execution.finally(() => {
133
- if (this.#execution === execution)
134
- this.#execution = undefined;
135
- if (this.#queued !== undefined && !this.#closed)
136
- this.#schedule(this.#queued);
137
- });
70
+ this.#emit();
71
+ this.#listeners.clear();
72
+ this.#onClose?.();
73
+ }
74
+ #startObservation() {
75
+ if (this.#subscription !== void 0 || this.#closed)
76
+ return;
77
+ const generation = this.#observationGeneration += 1;
78
+ const subscription = this.#backend.observe(this.#source.query, {
79
+ onInvalidate: (invalidation) => {
80
+ if (generation !== this.#observationGeneration || this.#closed)
81
+ return;
82
+ this.#schedule(invalidation);
83
+ },
84
+ onError: (error) => {
85
+ if (generation !== this.#observationGeneration || this.#closed)
86
+ return;
87
+ this.#setError(error, this.#currentVersion());
88
+ },
89
+ onComplete: () => {
90
+ if (generation !== this.#observationGeneration)
91
+ return;
92
+ this.#subscription = void 0;
93
+ }
94
+ });
95
+ this.#subscription = subscription;
96
+ subscription.catch((error) => {
97
+ if (generation !== this.#observationGeneration || this.#closed)
98
+ return;
99
+ this.#subscription = void 0;
100
+ this.#setError(error, this.#currentVersion());
101
+ });
102
+ }
103
+ #stopObservation() {
104
+ this.#observationGeneration += 1;
105
+ this.#executionAbort?.abort(new Error("Live query has no subscribers"));
106
+ const subscription = this.#subscription;
107
+ this.#subscription = void 0;
108
+ if (subscription !== void 0) {
109
+ void subscription.then((handle) => handle.close()).catch(() => void 0);
138
110
  }
139
- async #drain() {
140
- while (this.#queued !== undefined && !this.#closed) {
141
- const invalidation = this.#queued;
142
- this.#queued = undefined;
143
- const abort = new AbortController();
144
- this.#executionAbort = abort;
145
- try {
146
- const rows = immutableRows(await this.#source.execute(abort.signal));
147
- if (this.#executionWasCancelled(abort))
148
- continue;
149
- // A newer invalidation arrived while this ran. Skip the intermediate snapshot and let
150
- // the loop execute once more against the newest durable state.
151
- if (this.#hasQueuedInvalidation())
152
- continue;
153
- const previous = this.#snapshot.rows;
154
- if (this.#snapshot.status === "ready" &&
155
- this.#snapshot.version === invalidation.manifestVersion &&
156
- sameLiveValue(previous, rows)) {
157
- continue;
158
- }
159
- if (sameLiveValue(previous, rows) && this.#snapshot.status !== "loading") {
160
- // Advance the version without replacing the immutable row array.
161
- this.#snapshot = {
162
- status: "ready",
163
- rows: previous,
164
- version: invalidation.manifestVersion,
165
- };
166
- }
167
- else {
168
- this.#snapshot = {
169
- status: "ready",
170
- rows,
171
- version: invalidation.manifestVersion,
172
- };
173
- }
174
- this.#emit();
175
- }
176
- catch (error) {
177
- if (this.#executionWasCancelled(abort) || this.#hasQueuedInvalidation())
178
- continue;
179
- this.#setError(error, invalidation.manifestVersion);
180
- }
181
- finally {
182
- if (this.#executionAbort === abort)
183
- this.#executionAbort = undefined;
184
- }
111
+ }
112
+ #schedule(invalidation) {
113
+ this.#invalidationSequence += 1;
114
+ this.#queued = invalidation;
115
+ if (this.#execution !== void 0)
116
+ return;
117
+ const execution = this.#drain();
118
+ this.#execution = execution;
119
+ void execution.finally(() => {
120
+ if (this.#execution === execution)
121
+ this.#execution = void 0;
122
+ if (this.#queued !== void 0 && !this.#closed)
123
+ this.#schedule(this.#queued);
124
+ });
125
+ }
126
+ async #drain() {
127
+ while (this.#queued !== void 0 && !this.#closed) {
128
+ const invalidation = this.#queued;
129
+ this.#queued = void 0;
130
+ const abort = new AbortController();
131
+ this.#executionAbort = abort;
132
+ try {
133
+ const rows = immutableRows(await this.#source.execute(abort.signal));
134
+ if (this.#executionWasCancelled(abort))
135
+ continue;
136
+ if (this.#hasQueuedInvalidation())
137
+ continue;
138
+ const previous = this.#snapshot.rows;
139
+ if (this.#snapshot.status === "ready" && this.#snapshot.version === invalidation.manifestVersion && sameLiveValue(previous, rows)) {
140
+ continue;
185
141
  }
186
- }
187
- #executionWasCancelled(abort) {
188
- return abort.signal.aborted || this.#closed;
189
- }
190
- #hasQueuedInvalidation() {
191
- return this.#queued !== undefined;
192
- }
193
- async #waitForIdle() {
194
- for (;;) {
195
- const execution = this.#execution;
196
- if (execution === undefined)
197
- return;
198
- await execution;
199
- if (this.#execution === undefined && this.#queued === undefined)
200
- return;
142
+ if (sameLiveValue(previous, rows) && this.#snapshot.status !== "loading") {
143
+ this.#snapshot = {
144
+ status: "ready",
145
+ rows: previous,
146
+ version: invalidation.manifestVersion
147
+ };
148
+ } else {
149
+ this.#snapshot = {
150
+ status: "ready",
151
+ rows,
152
+ version: invalidation.manifestVersion
153
+ };
201
154
  }
155
+ this.#emit();
156
+ } catch (error) {
157
+ if (this.#executionWasCancelled(abort) || this.#hasQueuedInvalidation())
158
+ continue;
159
+ this.#setError(error, invalidation.manifestVersion);
160
+ } finally {
161
+ if (this.#executionAbort === abort)
162
+ this.#executionAbort = void 0;
163
+ }
202
164
  }
203
- #currentVersion() {
204
- return this.#snapshot.status === "loading" ? null : this.#snapshot.version;
165
+ }
166
+ #executionWasCancelled(abort) {
167
+ return abort.signal.aborted || this.#closed;
168
+ }
169
+ #hasQueuedInvalidation() {
170
+ return this.#queued !== void 0;
171
+ }
172
+ async #waitForIdle() {
173
+ for (; ; ) {
174
+ const execution = this.#execution;
175
+ if (execution === void 0)
176
+ return;
177
+ await execution;
178
+ if (this.#execution === void 0 && this.#queued === void 0)
179
+ return;
205
180
  }
206
- #setError(error, version) {
207
- this.#snapshot = { status: "error", rows: this.#snapshot.rows, error, version };
208
- this.#emit();
181
+ }
182
+ #currentVersion() {
183
+ return this.#snapshot.status === "loading" ? null : this.#snapshot.version;
184
+ }
185
+ #setError(error, version) {
186
+ this.#snapshot = { status: "error", rows: this.#snapshot.rows, error, version };
187
+ this.#emit();
188
+ }
189
+ #emit() {
190
+ for (const listener of [...this.#listeners]) {
191
+ try {
192
+ listener();
193
+ } catch {
194
+ }
209
195
  }
210
- #emit() {
211
- for (const listener of [...this.#listeners]) {
212
- try {
213
- listener();
214
- }
215
- catch {
216
- // One framework listener must not prevent the others from observing the same snapshot.
217
- }
196
+ }
197
+ [Symbol.asyncIterator]() {
198
+ const inbox = {
199
+ latest: this.#snapshot,
200
+ hasLatest: true,
201
+ stopped: false,
202
+ notify: void 0
203
+ };
204
+ const wake = () => {
205
+ const notify = inbox.notify;
206
+ inbox.notify = void 0;
207
+ notify?.();
208
+ };
209
+ const unsubscribe = this.subscribe(() => {
210
+ inbox.latest = this.#snapshot;
211
+ inbox.hasLatest = true;
212
+ wake();
213
+ });
214
+ const done = { done: true, value: void 0 };
215
+ const read = async () => {
216
+ for (; ; ) {
217
+ if (inbox.stopped || this.#closed)
218
+ return done;
219
+ if (inbox.hasLatest) {
220
+ inbox.hasLatest = false;
221
+ return { done: false, value: inbox.latest };
218
222
  }
219
- }
220
- [Symbol.asyncIterator]() {
221
- const inbox = {
222
- latest: this.#snapshot,
223
- hasLatest: true,
224
- stopped: false,
225
- notify: undefined,
226
- };
227
- const wake = () => {
228
- const notify = inbox.notify;
229
- inbox.notify = undefined;
230
- notify?.();
231
- };
232
- const unsubscribe = this.subscribe(() => {
233
- inbox.latest = this.#snapshot;
234
- inbox.hasLatest = true;
235
- wake();
223
+ await new Promise((resolve) => {
224
+ inbox.notify = resolve;
236
225
  });
237
- const done = { done: true, value: undefined };
238
- const read = async () => {
239
- for (;;) {
240
- if (inbox.stopped || this.#closed)
241
- return done;
242
- if (inbox.hasLatest) {
243
- inbox.hasLatest = false;
244
- return { done: false, value: inbox.latest };
245
- }
246
- await new Promise((resolve) => {
247
- inbox.notify = resolve;
248
- });
249
- }
250
- };
251
- let queue = Promise.resolve();
252
- return {
253
- next: () => {
254
- const result = queue.then(read, read);
255
- queue = result.then(() => undefined, () => undefined);
256
- return result;
257
- },
258
- return: async () => {
259
- inbox.stopped = true;
260
- wake();
261
- unsubscribe();
262
- return done;
263
- },
264
- throw: async (error) => {
265
- inbox.stopped = true;
266
- wake();
267
- unsubscribe();
268
- throw error;
269
- },
270
- };
271
- }
226
+ }
227
+ };
228
+ let queue = Promise.resolve();
229
+ return {
230
+ next: () => {
231
+ const result = queue.then(read, read);
232
+ queue = result.then(() => void 0, () => void 0);
233
+ return result;
234
+ },
235
+ return: async () => {
236
+ inbox.stopped = true;
237
+ wake();
238
+ unsubscribe();
239
+ return done;
240
+ },
241
+ throw: async (error) => {
242
+ inbox.stopped = true;
243
+ wake();
244
+ unsubscribe();
245
+ throw error;
246
+ }
247
+ };
248
+ }
272
249
  }
273
- /** Owns one shared low-level set and every typed query created from it. */
274
- export class LiveQueryManager {
275
- #backend;
276
- #queries = new Set();
277
- #closed = false;
278
- constructor(driver, options = {}) {
279
- this.#backend = driver.liveQueries(options);
280
- }
281
- watch(source) {
282
- if (this.#closed)
283
- throw new Error("Live query manager is closed");
284
- const query = new LiveQuery(this.#backend, source, () => {
285
- this.#queries.delete(query);
286
- });
287
- this.#queries.add(query);
288
- return query;
289
- }
290
- async refresh() {
291
- if (this.#closed)
292
- throw new Error("Live query manager is closed");
293
- // The shared backend sweep remains selective. Queries that were already in an adapter-level
294
- // error also run their local retry path; concurrent backend refresh calls collapse into the
295
- // same low-level sweep, so this does not multiply durable probes.
296
- const failed = [...this.#queries].filter((query) => query.getSnapshot().status === "error");
297
- await Promise.all([this.#backend.refresh(), ...failed.map((query) => query.refresh())]);
298
- }
299
- async close() {
300
- if (this.#closed)
301
- return;
302
- this.#closed = true;
303
- for (const query of [...this.#queries])
304
- query.close();
305
- this.#queries.clear();
306
- await this.#backend.close();
307
- }
250
+ class LiveQueryManager {
251
+ #backend;
252
+ #queries = /* @__PURE__ */ new Set();
253
+ #closed = false;
254
+ constructor(driver, options = {}) {
255
+ this.#backend = driver.liveQueries(options);
256
+ }
257
+ watch(source) {
258
+ if (this.#closed)
259
+ throw new Error("Live query manager is closed");
260
+ const query = new LiveQuery(this.#backend, source, () => {
261
+ this.#queries.delete(query);
262
+ });
263
+ this.#queries.add(query);
264
+ return query;
265
+ }
266
+ async refresh() {
267
+ if (this.#closed)
268
+ throw new Error("Live query manager is closed");
269
+ const failed = [...this.#queries].filter((query) => query.getSnapshot().status === "error");
270
+ await Promise.all([this.#backend.refresh(), ...failed.map((query) => query.refresh())]);
271
+ }
272
+ async close() {
273
+ if (this.#closed)
274
+ return;
275
+ this.#closed = true;
276
+ for (const query of [...this.#queries])
277
+ query.close();
278
+ this.#queries.clear();
279
+ await this.#backend.close();
280
+ }
308
281
  }
309
- export function createLiveQueryManager(driver, options = {}) {
310
- return new LiveQueryManager(driver, options);
282
+ function createLiveQueryManager(driver, options = {}) {
283
+ return new LiveQueryManager(driver, options);
311
284
  }
285
+ export {
286
+ LiveQuery,
287
+ LiveQueryManager,
288
+ createLiveQueryManager
289
+ };
@@ -34,7 +34,7 @@ interface StringVector extends VectorBase {
34
34
  readonly dictionary: readonly string[];
35
35
  }
36
36
  export type ColumnVector = BooleanVector | NumberVector | DateTimeVector | StringVector;
37
- interface ColumnarColumnInput {
37
+ export interface ColumnarColumnInput {
38
38
  readonly type: VectorType;
39
39
  readonly values: readonly QueryValue[];
40
40
  }
@@ -86,6 +86,12 @@ export interface AsyncQueryExecutionOptions {
86
86
  * reference instead of stitching copies.
87
87
  */
88
88
  readonly loadScanWindow?: (start: number, length: number) => number | Promise<number>;
89
+ /**
90
+ * Ascending scan row positions an index has already narrowed the plan to. The predicates
91
+ * still run on every visited row, so the selection is a pure skip list: rows outside it are
92
+ * never loaded or evaluated. Only the streamed scan honors it.
93
+ */
94
+ readonly scanRows?: readonly number[];
89
95
  }
90
96
  export interface QueryBatchExecutionOptions extends AsyncQueryExecutionOptions {
91
97
  /** Maximum result rows handed to the consumer at once. */