@tanstack/db 0.1.3 → 0.1.4
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/cjs/collection.cjs +112 -6
- package/dist/cjs/collection.cjs.map +1 -1
- package/dist/cjs/collection.d.cts +3 -2
- package/dist/cjs/errors.cjs +6 -0
- package/dist/cjs/errors.cjs.map +1 -1
- package/dist/cjs/errors.d.cts +3 -0
- package/dist/cjs/index.cjs +1 -0
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/indexes/auto-index.cjs +30 -19
- package/dist/cjs/indexes/auto-index.cjs.map +1 -1
- package/dist/cjs/indexes/auto-index.d.cts +1 -0
- package/dist/cjs/indexes/base-index.cjs.map +1 -1
- package/dist/cjs/indexes/base-index.d.cts +2 -1
- package/dist/cjs/indexes/btree-index.cjs +26 -0
- package/dist/cjs/indexes/btree-index.cjs.map +1 -1
- package/dist/cjs/indexes/btree-index.d.cts +7 -0
- package/dist/cjs/indexes/index-options.d.cts +1 -1
- package/dist/cjs/query/compiler/evaluators.cjs +2 -2
- package/dist/cjs/query/compiler/evaluators.cjs.map +1 -1
- package/dist/cjs/query/compiler/evaluators.d.cts +1 -1
- package/dist/cjs/query/compiler/group-by.cjs +3 -1
- package/dist/cjs/query/compiler/group-by.cjs.map +1 -1
- package/dist/cjs/query/compiler/index.cjs +72 -6
- package/dist/cjs/query/compiler/index.cjs.map +1 -1
- package/dist/cjs/query/compiler/index.d.cts +16 -2
- package/dist/cjs/query/compiler/joins.cjs +111 -12
- package/dist/cjs/query/compiler/joins.cjs.map +1 -1
- package/dist/cjs/query/compiler/joins.d.cts +9 -2
- package/dist/cjs/query/compiler/order-by.cjs +62 -3
- package/dist/cjs/query/compiler/order-by.cjs.map +1 -1
- package/dist/cjs/query/compiler/order-by.d.cts +12 -2
- package/dist/cjs/query/live-query-collection.cjs +196 -23
- package/dist/cjs/query/live-query-collection.cjs.map +1 -1
- package/dist/cjs/types.d.cts +1 -0
- package/dist/cjs/utils/btree.cjs +15 -0
- package/dist/cjs/utils/btree.cjs.map +1 -1
- package/dist/cjs/utils/btree.d.cts +8 -0
- package/dist/esm/collection.d.ts +3 -2
- package/dist/esm/collection.js +113 -7
- package/dist/esm/collection.js.map +1 -1
- package/dist/esm/errors.d.ts +3 -0
- package/dist/esm/errors.js +6 -0
- package/dist/esm/errors.js.map +1 -1
- package/dist/esm/index.js +2 -1
- package/dist/esm/indexes/auto-index.d.ts +1 -0
- package/dist/esm/indexes/auto-index.js +31 -20
- package/dist/esm/indexes/auto-index.js.map +1 -1
- package/dist/esm/indexes/base-index.d.ts +2 -1
- package/dist/esm/indexes/base-index.js.map +1 -1
- package/dist/esm/indexes/btree-index.d.ts +7 -0
- package/dist/esm/indexes/btree-index.js +26 -0
- package/dist/esm/indexes/btree-index.js.map +1 -1
- package/dist/esm/indexes/index-options.d.ts +1 -1
- package/dist/esm/query/compiler/evaluators.d.ts +1 -1
- package/dist/esm/query/compiler/evaluators.js +2 -2
- package/dist/esm/query/compiler/evaluators.js.map +1 -1
- package/dist/esm/query/compiler/group-by.js +3 -1
- package/dist/esm/query/compiler/group-by.js.map +1 -1
- package/dist/esm/query/compiler/index.d.ts +16 -2
- package/dist/esm/query/compiler/index.js +73 -7
- package/dist/esm/query/compiler/index.js.map +1 -1
- package/dist/esm/query/compiler/joins.d.ts +9 -2
- package/dist/esm/query/compiler/joins.js +114 -15
- package/dist/esm/query/compiler/joins.js.map +1 -1
- package/dist/esm/query/compiler/order-by.d.ts +12 -2
- package/dist/esm/query/compiler/order-by.js +62 -3
- package/dist/esm/query/compiler/order-by.js.map +1 -1
- package/dist/esm/query/live-query-collection.js +196 -23
- package/dist/esm/query/live-query-collection.js.map +1 -1
- package/dist/esm/types.d.ts +1 -0
- package/dist/esm/utils/btree.d.ts +8 -0
- package/dist/esm/utils/btree.js +15 -0
- package/dist/esm/utils/btree.js.map +1 -1
- package/package.json +2 -2
- package/src/collection.ts +163 -10
- package/src/errors.ts +6 -0
- package/src/indexes/auto-index.ts +53 -31
- package/src/indexes/base-index.ts +6 -1
- package/src/indexes/btree-index.ts +29 -0
- package/src/indexes/index-options.ts +2 -2
- package/src/query/compiler/evaluators.ts +6 -3
- package/src/query/compiler/group-by.ts +3 -1
- package/src/query/compiler/index.ts +112 -5
- package/src/query/compiler/joins.ts +216 -20
- package/src/query/compiler/order-by.ts +98 -3
- package/src/query/live-query-collection.ts +352 -24
- package/src/types.ts +1 -0
- package/src/utils/btree.ts +17 -0
package/dist/esm/collection.js
CHANGED
|
@@ -5,7 +5,7 @@ import { BTreeIndex } from "./indexes/btree-index.js";
|
|
|
5
5
|
import { LazyIndexWrapper, IndexProxy } from "./indexes/lazy-index.js";
|
|
6
6
|
import { ensureIndexForExpression } from "./indexes/auto-index.js";
|
|
7
7
|
import { getActiveTransaction, createTransaction } from "./transactions.js";
|
|
8
|
-
import { MissingInsertHandlerError, DuplicateKeyError, MissingDeleteHandlerError, NoKeysPassedToDeleteError, DeleteKeyNotFoundError, CollectionRequiresConfigError, CollectionRequiresSyncConfigError, CollectionInErrorStateError, InvalidCollectionStatusTransitionError,
|
|
8
|
+
import { MissingInsertHandlerError, DuplicateKeyError, MissingDeleteHandlerError, NoKeysPassedToDeleteError, DeleteKeyNotFoundError, CollectionRequiresConfigError, CollectionRequiresSyncConfigError, CollectionInErrorStateError, InvalidCollectionStatusTransitionError, NoPendingSyncTransactionWriteError, SyncTransactionAlreadyCommittedWriteError, NoPendingSyncTransactionCommitError, SyncTransactionAlreadyCommittedError, DuplicateKeySyncError, CollectionIsInErrorStateError, SyncCleanupError, NegativeActiveSubscribersError, InvalidSchemaError, UndefinedKeyError, SchemaMustBeSynchronousError, SchemaValidationError, MissingUpdateArgumentError, MissingUpdateHandlerError, NoKeysPassedToUpdateError, UpdateKeyNotFoundError, KeyUpdateNotAllowedError } from "./errors.js";
|
|
9
9
|
import { currentStateAsChanges, createFilteredCallback } from "./change-events.js";
|
|
10
10
|
function createCollection(options) {
|
|
11
11
|
const collection = new CollectionImpl(options);
|
|
@@ -59,7 +59,10 @@ class CollectionImpl {
|
|
|
59
59
|
break;
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
|
-
|
|
62
|
+
const hasTruncateSync = this.pendingSyncedTransactions.some(
|
|
63
|
+
(t) => t.truncate === true
|
|
64
|
+
);
|
|
65
|
+
if (!hasPersistingTransaction || hasTruncateSync) {
|
|
63
66
|
this.isCommittingSyncTransactions = true;
|
|
64
67
|
const changedKeys = /* @__PURE__ */ new Set();
|
|
65
68
|
for (const transaction of this.pendingSyncedTransactions) {
|
|
@@ -80,6 +83,18 @@ class CollectionImpl {
|
|
|
80
83
|
const events = [];
|
|
81
84
|
const rowUpdateMode = this.config.sync.rowUpdateMode || `partial`;
|
|
82
85
|
for (const transaction of this.pendingSyncedTransactions) {
|
|
86
|
+
if (transaction.truncate) {
|
|
87
|
+
for (const key of this.syncedData.keys()) {
|
|
88
|
+
if (this.optimisticDeletes.has(key)) continue;
|
|
89
|
+
const previousValue = this.optimisticUpserts.get(key) || this.syncedData.get(key);
|
|
90
|
+
if (previousValue !== void 0) {
|
|
91
|
+
events.push({ type: `delete`, key, value: previousValue });
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
this.syncedData.clear();
|
|
95
|
+
this.syncedMetadata.clear();
|
|
96
|
+
this.syncedKeys.clear();
|
|
97
|
+
}
|
|
83
98
|
for (const operation of transaction.operations) {
|
|
84
99
|
const key = operation.key;
|
|
85
100
|
this.syncedKeys.add(key);
|
|
@@ -124,6 +139,78 @@ class CollectionImpl {
|
|
|
124
139
|
}
|
|
125
140
|
}
|
|
126
141
|
}
|
|
142
|
+
const hadTruncate = this.pendingSyncedTransactions.some(
|
|
143
|
+
(t) => t.truncate === true
|
|
144
|
+
);
|
|
145
|
+
if (hadTruncate) {
|
|
146
|
+
const syncedInsertedOrUpdatedKeys = /* @__PURE__ */ new Set();
|
|
147
|
+
for (const t of this.pendingSyncedTransactions) {
|
|
148
|
+
for (const op of t.operations) {
|
|
149
|
+
if (op.type === `insert` || op.type === `update`) {
|
|
150
|
+
syncedInsertedOrUpdatedKeys.add(op.key);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
const reapplyUpserts = /* @__PURE__ */ new Map();
|
|
155
|
+
const reapplyDeletes = /* @__PURE__ */ new Set();
|
|
156
|
+
for (const tx of this.transactions.values()) {
|
|
157
|
+
if ([`completed`, `failed`].includes(tx.state)) continue;
|
|
158
|
+
for (const mutation of tx.mutations) {
|
|
159
|
+
if (mutation.collection !== this || !mutation.optimistic) continue;
|
|
160
|
+
const key = mutation.key;
|
|
161
|
+
switch (mutation.type) {
|
|
162
|
+
case `insert`:
|
|
163
|
+
reapplyUpserts.set(key, mutation.modified);
|
|
164
|
+
reapplyDeletes.delete(key);
|
|
165
|
+
break;
|
|
166
|
+
case `update`: {
|
|
167
|
+
const base = this.syncedData.get(key);
|
|
168
|
+
const next = base ? Object.assign({}, base, mutation.changes) : mutation.modified;
|
|
169
|
+
reapplyUpserts.set(key, next);
|
|
170
|
+
reapplyDeletes.delete(key);
|
|
171
|
+
break;
|
|
172
|
+
}
|
|
173
|
+
case `delete`:
|
|
174
|
+
reapplyUpserts.delete(key);
|
|
175
|
+
reapplyDeletes.add(key);
|
|
176
|
+
break;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
for (const [key, value] of reapplyUpserts) {
|
|
181
|
+
if (reapplyDeletes.has(key)) continue;
|
|
182
|
+
if (syncedInsertedOrUpdatedKeys.has(key)) {
|
|
183
|
+
let foundInsert = false;
|
|
184
|
+
for (let i = events.length - 1; i >= 0; i--) {
|
|
185
|
+
const evt = events[i];
|
|
186
|
+
if (evt.key === key && evt.type === `insert`) {
|
|
187
|
+
evt.value = value;
|
|
188
|
+
foundInsert = true;
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
if (!foundInsert) {
|
|
193
|
+
events.push({ type: `insert`, key, value });
|
|
194
|
+
}
|
|
195
|
+
} else {
|
|
196
|
+
events.push({ type: `insert`, key, value });
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
if (events.length > 0 && reapplyDeletes.size > 0) {
|
|
200
|
+
const filtered = [];
|
|
201
|
+
for (const evt of events) {
|
|
202
|
+
if (evt.type === `insert` && reapplyDeletes.has(evt.key)) {
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
filtered.push(evt);
|
|
206
|
+
}
|
|
207
|
+
events.length = 0;
|
|
208
|
+
events.push(...filtered);
|
|
209
|
+
}
|
|
210
|
+
if (!this.isReady()) {
|
|
211
|
+
this.setStatus(`ready`);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
127
214
|
this.optimisticUpserts.clear();
|
|
128
215
|
this.optimisticDeletes.clear();
|
|
129
216
|
this.isCommittingSyncTransactions = false;
|
|
@@ -404,7 +491,7 @@ class CollectionImpl {
|
|
|
404
491
|
const callbacks = [...this.onFirstReadyCallbacks];
|
|
405
492
|
this.onFirstReadyCallbacks = [];
|
|
406
493
|
callbacks.forEach((callback) => callback());
|
|
407
|
-
if (this.
|
|
494
|
+
if (this.changeListeners.size > 0) {
|
|
408
495
|
this.emitEmptyReadyEvent();
|
|
409
496
|
}
|
|
410
497
|
}
|
|
@@ -497,9 +584,12 @@ class CollectionImpl {
|
|
|
497
584
|
}
|
|
498
585
|
const key = this.getKeyFromItem(messageWithoutKey.value);
|
|
499
586
|
if (messageWithoutKey.type === `insert`) {
|
|
500
|
-
|
|
587
|
+
const insertingIntoExistingSynced = this.syncedData.has(key);
|
|
588
|
+
const hasPendingDeleteForKey = pendingTransaction.operations.some(
|
|
501
589
|
(op) => op.key === key && op.type === `delete`
|
|
502
|
-
)
|
|
590
|
+
);
|
|
591
|
+
const isTruncateTransaction = pendingTransaction.truncate === true;
|
|
592
|
+
if (insertingIntoExistingSynced && !hasPendingDeleteForKey && !isTruncateTransaction) {
|
|
503
593
|
throw new DuplicateKeySyncError(key, this.id);
|
|
504
594
|
}
|
|
505
595
|
}
|
|
@@ -525,6 +615,17 @@ class CollectionImpl {
|
|
|
525
615
|
},
|
|
526
616
|
markReady: () => {
|
|
527
617
|
this.markReady();
|
|
618
|
+
},
|
|
619
|
+
truncate: () => {
|
|
620
|
+
const pendingTransaction = this.pendingSyncedTransactions[this.pendingSyncedTransactions.length - 1];
|
|
621
|
+
if (!pendingTransaction) {
|
|
622
|
+
throw new NoPendingSyncTransactionWriteError();
|
|
623
|
+
}
|
|
624
|
+
if (pendingTransaction.committed) {
|
|
625
|
+
throw new SyncTransactionAlreadyCommittedWriteError();
|
|
626
|
+
}
|
|
627
|
+
pendingTransaction.operations = [];
|
|
628
|
+
pendingTransaction.truncate = true;
|
|
528
629
|
}
|
|
529
630
|
});
|
|
530
631
|
this.syncCleanupFn = typeof cleanupFn === `function` ? cleanupFn : null;
|
|
@@ -794,6 +895,11 @@ class CollectionImpl {
|
|
|
794
895
|
for (const listener of this.changeListeners) {
|
|
795
896
|
listener([]);
|
|
796
897
|
}
|
|
898
|
+
for (const [_key, keyListeners] of this.changeKeyListeners) {
|
|
899
|
+
for (const listener of keyListeners) {
|
|
900
|
+
listener([]);
|
|
901
|
+
}
|
|
902
|
+
}
|
|
797
903
|
}
|
|
798
904
|
/**
|
|
799
905
|
* Emit events either immediately or batch them for later emission
|
|
@@ -957,8 +1063,8 @@ class CollectionImpl {
|
|
|
957
1063
|
}
|
|
958
1064
|
/**
|
|
959
1065
|
* Creates an index on a collection for faster queries.
|
|
960
|
-
* Indexes significantly improve query performance by allowing
|
|
961
|
-
* and range queries instead of full scans.
|
|
1066
|
+
* Indexes significantly improve query performance by allowing constant time lookups
|
|
1067
|
+
* and logarithmic time range queries instead of full scans.
|
|
962
1068
|
*
|
|
963
1069
|
* @template TResolver - The type of the index resolver (constructor or async loader)
|
|
964
1070
|
* @param indexCallback - Function that extracts the indexed value from each item
|