@tanstack/db 0.0.14 → 0.0.15
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 +117 -104
- package/dist/cjs/collection.cjs.map +1 -1
- package/dist/cjs/collection.d.cts +18 -21
- package/dist/cjs/index.cjs +35 -13
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +0 -1
- package/dist/cjs/query/builder/functions.cjs +107 -0
- package/dist/cjs/query/builder/functions.cjs.map +1 -0
- package/dist/cjs/query/builder/functions.d.cts +38 -0
- package/dist/cjs/query/builder/index.cjs +499 -0
- package/dist/cjs/query/builder/index.cjs.map +1 -0
- package/dist/cjs/query/builder/index.d.cts +324 -0
- package/dist/cjs/query/builder/ref-proxy.cjs +96 -0
- package/dist/cjs/query/builder/ref-proxy.cjs.map +1 -0
- package/dist/cjs/query/builder/ref-proxy.d.cts +28 -0
- package/dist/cjs/query/builder/types.d.cts +80 -0
- package/dist/cjs/query/compiler/evaluators.cjs +261 -0
- package/dist/cjs/query/compiler/evaluators.cjs.map +1 -0
- package/dist/cjs/query/compiler/evaluators.d.cts +11 -0
- package/dist/cjs/query/compiler/group-by.cjs +271 -0
- package/dist/cjs/query/compiler/group-by.cjs.map +1 -0
- package/dist/cjs/query/compiler/group-by.d.cts +7 -0
- package/dist/cjs/query/compiler/index.cjs +181 -0
- package/dist/cjs/query/compiler/index.cjs.map +1 -0
- package/dist/cjs/query/compiler/index.d.cts +15 -0
- package/dist/cjs/query/compiler/joins.cjs +116 -0
- package/dist/cjs/query/compiler/joins.cjs.map +1 -0
- package/dist/cjs/query/compiler/joins.d.cts +11 -0
- package/dist/cjs/query/compiler/order-by.cjs +89 -0
- package/dist/cjs/query/compiler/order-by.cjs.map +1 -0
- package/dist/cjs/query/compiler/order-by.d.cts +9 -0
- package/dist/cjs/query/compiler/select.cjs +57 -0
- package/dist/cjs/query/compiler/select.cjs.map +1 -0
- package/dist/cjs/query/compiler/select.d.cts +15 -0
- package/dist/cjs/query/index.d.cts +6 -5
- package/dist/cjs/query/ir.cjs +57 -0
- package/dist/cjs/query/ir.cjs.map +1 -0
- package/dist/cjs/query/ir.d.cts +81 -0
- package/dist/cjs/query/live-query-collection.cjs +224 -0
- package/dist/cjs/query/live-query-collection.cjs.map +1 -0
- package/dist/cjs/query/live-query-collection.d.cts +124 -0
- package/dist/cjs/transactions.cjs +20 -13
- package/dist/cjs/transactions.cjs.map +1 -1
- package/dist/cjs/transactions.d.cts +10 -1
- package/dist/cjs/types.d.cts +13 -0
- package/dist/esm/collection.d.ts +18 -21
- package/dist/esm/collection.js +118 -105
- package/dist/esm/collection.js.map +1 -1
- package/dist/esm/index.d.ts +0 -1
- package/dist/esm/index.js +34 -12
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/query/builder/functions.d.ts +38 -0
- package/dist/esm/query/builder/functions.js +107 -0
- package/dist/esm/query/builder/functions.js.map +1 -0
- package/dist/esm/query/builder/index.d.ts +324 -0
- package/dist/esm/query/builder/index.js +499 -0
- package/dist/esm/query/builder/index.js.map +1 -0
- package/dist/esm/query/builder/ref-proxy.d.ts +28 -0
- package/dist/esm/query/builder/ref-proxy.js +96 -0
- package/dist/esm/query/builder/ref-proxy.js.map +1 -0
- package/dist/esm/query/builder/types.d.ts +80 -0
- package/dist/esm/query/compiler/evaluators.d.ts +11 -0
- package/dist/esm/query/compiler/evaluators.js +261 -0
- package/dist/esm/query/compiler/evaluators.js.map +1 -0
- package/dist/esm/query/compiler/group-by.d.ts +7 -0
- package/dist/esm/query/compiler/group-by.js +271 -0
- package/dist/esm/query/compiler/group-by.js.map +1 -0
- package/dist/esm/query/compiler/index.d.ts +15 -0
- package/dist/esm/query/compiler/index.js +181 -0
- package/dist/esm/query/compiler/index.js.map +1 -0
- package/dist/esm/query/compiler/joins.d.ts +11 -0
- package/dist/esm/query/compiler/joins.js +116 -0
- package/dist/esm/query/compiler/joins.js.map +1 -0
- package/dist/esm/query/compiler/order-by.d.ts +9 -0
- package/dist/esm/query/compiler/order-by.js +89 -0
- package/dist/esm/query/compiler/order-by.js.map +1 -0
- package/dist/esm/query/compiler/select.d.ts +15 -0
- package/dist/esm/query/compiler/select.js +57 -0
- package/dist/esm/query/compiler/select.js.map +1 -0
- package/dist/esm/query/index.d.ts +6 -5
- package/dist/esm/query/ir.d.ts +81 -0
- package/dist/esm/query/ir.js +57 -0
- package/dist/esm/query/ir.js.map +1 -0
- package/dist/esm/query/live-query-collection.d.ts +124 -0
- package/dist/esm/query/live-query-collection.js +224 -0
- package/dist/esm/query/live-query-collection.js.map +1 -0
- package/dist/esm/transactions.d.ts +10 -1
- package/dist/esm/transactions.js +20 -13
- package/dist/esm/transactions.js.map +1 -1
- package/dist/esm/types.d.ts +13 -0
- package/package.json +3 -4
- package/src/collection.ts +152 -129
- package/src/index.ts +0 -1
- package/src/query/builder/functions.ts +267 -0
- package/src/query/builder/index.ts +648 -0
- package/src/query/builder/ref-proxy.ts +156 -0
- package/src/query/builder/types.ts +278 -0
- package/src/query/compiler/evaluators.ts +315 -0
- package/src/query/compiler/group-by.ts +428 -0
- package/src/query/compiler/index.ts +276 -0
- package/src/query/compiler/joins.ts +228 -0
- package/src/query/compiler/order-by.ts +139 -0
- package/src/query/compiler/select.ts +173 -0
- package/src/query/index.ts +64 -5
- package/src/query/ir.ts +128 -0
- package/src/query/live-query-collection.ts +509 -0
- package/src/transactions.ts +27 -16
- package/src/types.ts +15 -0
- package/dist/cjs/query/compiled-query.cjs +0 -160
- package/dist/cjs/query/compiled-query.cjs.map +0 -1
- package/dist/cjs/query/compiled-query.d.cts +0 -20
- package/dist/cjs/query/evaluators.cjs +0 -161
- package/dist/cjs/query/evaluators.cjs.map +0 -1
- package/dist/cjs/query/evaluators.d.cts +0 -14
- package/dist/cjs/query/extractors.cjs +0 -122
- package/dist/cjs/query/extractors.cjs.map +0 -1
- package/dist/cjs/query/extractors.d.cts +0 -22
- package/dist/cjs/query/functions.cjs +0 -152
- package/dist/cjs/query/functions.cjs.map +0 -1
- package/dist/cjs/query/functions.d.cts +0 -21
- package/dist/cjs/query/group-by.cjs +0 -88
- package/dist/cjs/query/group-by.cjs.map +0 -1
- package/dist/cjs/query/group-by.d.cts +0 -40
- package/dist/cjs/query/joins.cjs +0 -141
- package/dist/cjs/query/joins.cjs.map +0 -1
- package/dist/cjs/query/joins.d.cts +0 -14
- package/dist/cjs/query/order-by.cjs +0 -185
- package/dist/cjs/query/order-by.cjs.map +0 -1
- package/dist/cjs/query/order-by.d.cts +0 -3
- package/dist/cjs/query/pipeline-compiler.cjs +0 -89
- package/dist/cjs/query/pipeline-compiler.cjs.map +0 -1
- package/dist/cjs/query/pipeline-compiler.d.cts +0 -10
- package/dist/cjs/query/query-builder.cjs +0 -307
- package/dist/cjs/query/query-builder.cjs.map +0 -1
- package/dist/cjs/query/query-builder.d.cts +0 -225
- package/dist/cjs/query/schema.d.cts +0 -100
- package/dist/cjs/query/select.cjs +0 -130
- package/dist/cjs/query/select.cjs.map +0 -1
- package/dist/cjs/query/select.d.cts +0 -3
- package/dist/cjs/query/types.d.cts +0 -189
- package/dist/cjs/query/utils.cjs +0 -154
- package/dist/cjs/query/utils.cjs.map +0 -1
- package/dist/cjs/query/utils.d.cts +0 -37
- package/dist/cjs/utils.cjs +0 -17
- package/dist/cjs/utils.cjs.map +0 -1
- package/dist/cjs/utils.d.cts +0 -3
- package/dist/esm/query/compiled-query.d.ts +0 -20
- package/dist/esm/query/compiled-query.js +0 -160
- package/dist/esm/query/compiled-query.js.map +0 -1
- package/dist/esm/query/evaluators.d.ts +0 -14
- package/dist/esm/query/evaluators.js +0 -161
- package/dist/esm/query/evaluators.js.map +0 -1
- package/dist/esm/query/extractors.d.ts +0 -22
- package/dist/esm/query/extractors.js +0 -122
- package/dist/esm/query/extractors.js.map +0 -1
- package/dist/esm/query/functions.d.ts +0 -21
- package/dist/esm/query/functions.js +0 -152
- package/dist/esm/query/functions.js.map +0 -1
- package/dist/esm/query/group-by.d.ts +0 -40
- package/dist/esm/query/group-by.js +0 -88
- package/dist/esm/query/group-by.js.map +0 -1
- package/dist/esm/query/joins.d.ts +0 -14
- package/dist/esm/query/joins.js +0 -141
- package/dist/esm/query/joins.js.map +0 -1
- package/dist/esm/query/order-by.d.ts +0 -3
- package/dist/esm/query/order-by.js +0 -185
- package/dist/esm/query/order-by.js.map +0 -1
- package/dist/esm/query/pipeline-compiler.d.ts +0 -10
- package/dist/esm/query/pipeline-compiler.js +0 -89
- package/dist/esm/query/pipeline-compiler.js.map +0 -1
- package/dist/esm/query/query-builder.d.ts +0 -225
- package/dist/esm/query/query-builder.js +0 -307
- package/dist/esm/query/query-builder.js.map +0 -1
- package/dist/esm/query/schema.d.ts +0 -100
- package/dist/esm/query/select.d.ts +0 -3
- package/dist/esm/query/select.js +0 -130
- package/dist/esm/query/select.js.map +0 -1
- package/dist/esm/query/types.d.ts +0 -189
- package/dist/esm/query/utils.d.ts +0 -37
- package/dist/esm/query/utils.js +0 -154
- package/dist/esm/query/utils.js.map +0 -1
- package/dist/esm/utils.d.ts +0 -3
- package/dist/esm/utils.js +0 -17
- package/dist/esm/utils.js.map +0 -1
- package/src/query/compiled-query.ts +0 -234
- package/src/query/evaluators.ts +0 -250
- package/src/query/extractors.ts +0 -214
- package/src/query/functions.ts +0 -297
- package/src/query/group-by.ts +0 -139
- package/src/query/joins.ts +0 -260
- package/src/query/order-by.ts +0 -264
- package/src/query/pipeline-compiler.ts +0 -149
- package/src/query/query-builder.ts +0 -902
- package/src/query/schema.ts +0 -268
- package/src/query/select.ts +0 -208
- package/src/query/types.ts +0 -418
- package/src/query/utils.ts +0 -245
- package/src/utils.ts +0 -15
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transactions.js","sources":["../../src/transactions.ts"],"sourcesContent":["import { createDeferred } from \"./deferred\"\nimport type { Deferred } from \"./deferred\"\nimport type {\n MutationFn,\n OperationType,\n PendingMutation,\n TransactionConfig,\n TransactionState,\n TransactionWithMutations,\n} from \"./types\"\n\nconst transactions: Array<Transaction<any>> = []\nlet transactionStack: Array<Transaction<any>> = []\n\nexport function createTransaction<\n TData extends object = Record<string, unknown>,\n>(config: TransactionConfig<TData>): Transaction<TData> {\n
|
|
1
|
+
{"version":3,"file":"transactions.js","sources":["../../src/transactions.ts"],"sourcesContent":["import { createDeferred } from \"./deferred\"\nimport type { Deferred } from \"./deferred\"\nimport type {\n MutationFn,\n OperationType,\n PendingMutation,\n TransactionConfig,\n TransactionState,\n TransactionWithMutations,\n} from \"./types\"\n\nconst transactions: Array<Transaction<any>> = []\nlet transactionStack: Array<Transaction<any>> = []\n\nlet sequenceNumber = 0\n\nexport function createTransaction<\n TData extends object = Record<string, unknown>,\n>(config: TransactionConfig<TData>): Transaction<TData> {\n const newTransaction = new Transaction<TData>(config)\n transactions.push(newTransaction)\n return newTransaction\n}\n\nexport function getActiveTransaction(): Transaction | undefined {\n if (transactionStack.length > 0) {\n return transactionStack.slice(-1)[0]\n } else {\n return undefined\n }\n}\n\nfunction registerTransaction(tx: Transaction<any>) {\n transactionStack.push(tx)\n}\n\nfunction unregisterTransaction(tx: Transaction<any>) {\n transactionStack = transactionStack.filter((t) => t.id !== tx.id)\n}\n\nfunction removeFromPendingList(tx: Transaction<any>) {\n const index = transactions.findIndex((t) => t.id === tx.id)\n if (index !== -1) {\n transactions.splice(index, 1)\n }\n}\n\nclass Transaction<\n T extends object = Record<string, unknown>,\n TOperation extends OperationType = OperationType,\n> {\n public id: string\n public state: TransactionState\n public mutationFn: MutationFn<T>\n public mutations: Array<PendingMutation<T, TOperation>>\n public isPersisted: Deferred<Transaction<T, TOperation>>\n public autoCommit: boolean\n public createdAt: Date\n public sequenceNumber: number\n public metadata: Record<string, unknown>\n public error?: {\n message: string\n error: Error\n }\n\n constructor(config: TransactionConfig<T>) {\n if (typeof config.mutationFn === `undefined`) {\n throw `mutationFn is required when creating a transaction`\n }\n this.id = config.id ?? crypto.randomUUID()\n this.mutationFn = config.mutationFn\n this.state = `pending`\n this.mutations = []\n this.isPersisted = createDeferred<Transaction<T, TOperation>>()\n this.autoCommit = config.autoCommit ?? true\n this.createdAt = new Date()\n this.sequenceNumber = sequenceNumber++\n this.metadata = config.metadata ?? {}\n }\n\n setState(newState: TransactionState) {\n this.state = newState\n\n if (newState === `completed` || newState === `failed`) {\n removeFromPendingList(this)\n }\n }\n\n mutate(callback: () => void): Transaction<T> {\n if (this.state !== `pending`) {\n throw `You can no longer call .mutate() as the transaction is no longer pending`\n }\n\n registerTransaction(this)\n try {\n callback()\n } finally {\n unregisterTransaction(this)\n }\n\n if (this.autoCommit) {\n this.commit()\n }\n\n return this\n }\n\n applyMutations(mutations: Array<PendingMutation<any>>): void {\n for (const newMutation of mutations) {\n const existingIndex = this.mutations.findIndex(\n (m) => m.globalKey === newMutation.globalKey\n )\n\n if (existingIndex >= 0) {\n // Replace existing mutation\n this.mutations[existingIndex] = newMutation\n } else {\n // Insert new mutation\n this.mutations.push(newMutation)\n }\n }\n }\n\n rollback(config?: { isSecondaryRollback?: boolean }): Transaction<T> {\n const isSecondaryRollback = config?.isSecondaryRollback ?? false\n if (this.state === `completed`) {\n throw `You can no longer call .rollback() as the transaction is already completed`\n }\n\n this.setState(`failed`)\n\n // See if there's any other transactions w/ mutations on the same ids\n // and roll them back as well.\n if (!isSecondaryRollback) {\n const mutationIds = new Set()\n this.mutations.forEach((m) => mutationIds.add(m.globalKey))\n for (const t of transactions) {\n t.state === `pending` &&\n t.mutations.some((m) => mutationIds.has(m.globalKey)) &&\n t.rollback({ isSecondaryRollback: true })\n }\n }\n\n // Reject the promise\n this.isPersisted.reject(this.error?.error)\n this.touchCollection()\n\n return this\n }\n\n // Tell collection that something has changed with the transaction\n touchCollection(): void {\n const hasCalled = new Set()\n for (const mutation of this.mutations) {\n if (!hasCalled.has(mutation.collection.id)) {\n mutation.collection.onTransactionStateChange()\n\n // Only call commitPendingTransactions if there are pending sync transactions\n if (mutation.collection.pendingSyncedTransactions.length > 0) {\n mutation.collection.commitPendingTransactions()\n }\n\n hasCalled.add(mutation.collection.id)\n }\n }\n }\n\n async commit(): Promise<Transaction<T>> {\n if (this.state !== `pending`) {\n throw `You can no longer call .commit() as the transaction is no longer pending`\n }\n\n this.setState(`persisting`)\n\n if (this.mutations.length === 0) {\n this.setState(`completed`)\n\n return this\n }\n\n // Run mutationFn\n try {\n // At this point we know there's at least one mutation\n // We've already verified mutations is non-empty, so this cast is safe\n // Use a direct type assertion instead of object spreading to preserve the original type\n await this.mutationFn({\n transaction: this as unknown as TransactionWithMutations<T>,\n })\n\n this.setState(`completed`)\n this.touchCollection()\n\n this.isPersisted.resolve(this)\n } catch (error) {\n // Update transaction with error information\n this.error = {\n message: error instanceof Error ? error.message : String(error),\n error: error instanceof Error ? error : new Error(String(error)),\n }\n\n // rollback the transaction\n return this.rollback()\n }\n\n return this\n }\n\n /**\n * Compare two transactions by their createdAt time and sequence number in order\n * to sort them in the order they were created.\n * @param other - The other transaction to compare to\n * @returns -1 if this transaction was created before the other, 1 if it was created after, 0 if they were created at the same time\n */\n compareCreatedAt(other: Transaction<any>): number {\n const createdAtComparison =\n this.createdAt.getTime() - other.createdAt.getTime()\n if (createdAtComparison !== 0) {\n return createdAtComparison\n }\n return this.sequenceNumber - other.sequenceNumber\n }\n}\n\nexport type { Transaction }\n"],"names":[],"mappings":"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"}
|
package/dist/esm/types.d.ts
CHANGED
|
@@ -99,6 +99,14 @@ export interface SyncConfig<T extends object = Record<string, unknown>, TKey ext
|
|
|
99
99
|
* @returns Record containing relation information
|
|
100
100
|
*/
|
|
101
101
|
getSyncMetadata?: () => Record<string, unknown>;
|
|
102
|
+
/**
|
|
103
|
+
* The row update mode used to sync to the collection.
|
|
104
|
+
* @default `partial`
|
|
105
|
+
* @description
|
|
106
|
+
* - `partial`: Updates contain only the changes to the row.
|
|
107
|
+
* - `full`: Updates contain the entire row.
|
|
108
|
+
*/
|
|
109
|
+
rowUpdateMode?: `partial` | `full`;
|
|
102
110
|
}
|
|
103
111
|
export interface ChangeMessage<T extends object = Record<string, unknown>, TKey extends string | number = string | number> {
|
|
104
112
|
key: TKey;
|
|
@@ -222,6 +230,11 @@ export type InputRow = [unknown, Record<string, unknown>];
|
|
|
222
230
|
* This is used as the inputs from a collection to a query
|
|
223
231
|
*/
|
|
224
232
|
export type KeyedStream = IStreamBuilder<InputRow>;
|
|
233
|
+
/**
|
|
234
|
+
* Result stream type representing the output of compiled queries
|
|
235
|
+
* Always returns [key, [result, orderByIndex]] where orderByIndex is undefined for unordered queries
|
|
236
|
+
*/
|
|
237
|
+
export type ResultStream = IStreamBuilder<[unknown, [any, string | undefined]]>;
|
|
225
238
|
/**
|
|
226
239
|
* A namespaced row is a row withing a pipeline that had each table wrapped in its alias
|
|
227
240
|
*/
|
package/package.json
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/db",
|
|
3
3
|
"description": "A reactive client store for building super fast apps on sync",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.15",
|
|
5
5
|
"dependencies": {
|
|
6
|
-
"@electric-sql/d2mini": "^0.1.
|
|
7
|
-
"@standard-schema/spec": "^1.0.0"
|
|
8
|
-
"@tanstack/store": "^0.7.0"
|
|
6
|
+
"@electric-sql/d2mini": "^0.1.4",
|
|
7
|
+
"@standard-schema/spec": "^1.0.0"
|
|
9
8
|
},
|
|
10
9
|
"devDependencies": {
|
|
11
10
|
"@vitest/coverage-istanbul": "^3.0.9"
|
package/src/collection.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Store } from "@tanstack/store"
|
|
2
1
|
import { withArrayChangeTracking, withChangeTracking } from "./proxy"
|
|
3
|
-
import {
|
|
2
|
+
import { createTransaction, getActiveTransaction } from "./transactions"
|
|
4
3
|
import { SortedMap } from "./SortedMap"
|
|
4
|
+
import type { Transaction } from "./transactions"
|
|
5
5
|
import type {
|
|
6
6
|
ChangeListener,
|
|
7
7
|
ChangeMessage,
|
|
@@ -148,8 +148,8 @@ export class CollectionImpl<
|
|
|
148
148
|
public syncedMetadata = new Map<TKey, unknown>()
|
|
149
149
|
|
|
150
150
|
// Optimistic state tracking - make public for testing
|
|
151
|
-
public
|
|
152
|
-
public
|
|
151
|
+
public optimisticUpserts = new Map<TKey, T>()
|
|
152
|
+
public optimisticDeletes = new Set<TKey>()
|
|
153
153
|
|
|
154
154
|
// Cached size for performance
|
|
155
155
|
private _size = 0
|
|
@@ -172,6 +172,10 @@ export class CollectionImpl<
|
|
|
172
172
|
// Array to store one-time commit listeners
|
|
173
173
|
private onFirstCommitCallbacks: Array<() => void> = []
|
|
174
174
|
|
|
175
|
+
// Event batching for preventing duplicate emissions during transaction flows
|
|
176
|
+
private batchedEvents: Array<ChangeMessage<T, TKey>> = []
|
|
177
|
+
private shouldBatchEvents = false
|
|
178
|
+
|
|
175
179
|
// Lifecycle management
|
|
176
180
|
private _status: CollectionStatus = `idle`
|
|
177
181
|
private activeSubscribersCount = 0
|
|
@@ -277,8 +281,8 @@ export class CollectionImpl<
|
|
|
277
281
|
throw new Error(`Collection requires a sync config`)
|
|
278
282
|
}
|
|
279
283
|
|
|
280
|
-
this.transactions = new SortedMap<string, Transaction<any>>(
|
|
281
|
-
|
|
284
|
+
this.transactions = new SortedMap<string, Transaction<any>>((a, b) =>
|
|
285
|
+
a.compareCreatedAt(b)
|
|
282
286
|
)
|
|
283
287
|
|
|
284
288
|
this.config = config
|
|
@@ -377,12 +381,15 @@ export class CollectionImpl<
|
|
|
377
381
|
}
|
|
378
382
|
|
|
379
383
|
pendingTransaction.committed = true
|
|
380
|
-
this.commitPendingTransactions()
|
|
381
384
|
|
|
382
|
-
// Update status to ready
|
|
385
|
+
// Update status to ready
|
|
386
|
+
// We do this before committing as we want the events from the changes to
|
|
387
|
+
// be from a "ready" state.
|
|
383
388
|
if (this._status === `loading`) {
|
|
384
389
|
this.setStatus(`ready`)
|
|
385
390
|
}
|
|
391
|
+
|
|
392
|
+
this.commitPendingTransactions()
|
|
386
393
|
},
|
|
387
394
|
})
|
|
388
395
|
|
|
@@ -472,14 +479,16 @@ export class CollectionImpl<
|
|
|
472
479
|
// Clear data
|
|
473
480
|
this.syncedData.clear()
|
|
474
481
|
this.syncedMetadata.clear()
|
|
475
|
-
this.
|
|
476
|
-
this.
|
|
482
|
+
this.optimisticUpserts.clear()
|
|
483
|
+
this.optimisticDeletes.clear()
|
|
477
484
|
this._size = 0
|
|
478
485
|
this.pendingSyncedTransactions = []
|
|
479
486
|
this.syncedKeys.clear()
|
|
480
487
|
this.hasReceivedFirstCommit = false
|
|
481
488
|
this.onFirstCommitCallbacks = []
|
|
482
489
|
this.preloadPromise = null
|
|
490
|
+
this.batchedEvents = []
|
|
491
|
+
this.shouldBatchEvents = false
|
|
483
492
|
|
|
484
493
|
// Update status
|
|
485
494
|
this.setStatus(`cleaned-up`)
|
|
@@ -553,12 +562,12 @@ export class CollectionImpl<
|
|
|
553
562
|
return
|
|
554
563
|
}
|
|
555
564
|
|
|
556
|
-
const previousState = new Map(this.
|
|
557
|
-
const previousDeletes = new Set(this.
|
|
565
|
+
const previousState = new Map(this.optimisticUpserts)
|
|
566
|
+
const previousDeletes = new Set(this.optimisticDeletes)
|
|
558
567
|
|
|
559
568
|
// Clear current optimistic state
|
|
560
|
-
this.
|
|
561
|
-
this.
|
|
569
|
+
this.optimisticUpserts.clear()
|
|
570
|
+
this.optimisticDeletes.clear()
|
|
562
571
|
|
|
563
572
|
const activeTransactions: Array<Transaction<any>> = []
|
|
564
573
|
const completedTransactions: Array<Transaction<any>> = []
|
|
@@ -578,12 +587,12 @@ export class CollectionImpl<
|
|
|
578
587
|
switch (mutation.type) {
|
|
579
588
|
case `insert`:
|
|
580
589
|
case `update`:
|
|
581
|
-
this.
|
|
582
|
-
this.
|
|
590
|
+
this.optimisticUpserts.set(mutation.key, mutation.modified as T)
|
|
591
|
+
this.optimisticDeletes.delete(mutation.key)
|
|
583
592
|
break
|
|
584
593
|
case `delete`:
|
|
585
|
-
this.
|
|
586
|
-
this.
|
|
594
|
+
this.optimisticUpserts.delete(mutation.key)
|
|
595
|
+
this.optimisticDeletes.add(mutation.key)
|
|
587
596
|
break
|
|
588
597
|
}
|
|
589
598
|
}
|
|
@@ -656,10 +665,10 @@ export class CollectionImpl<
|
|
|
656
665
|
*/
|
|
657
666
|
private calculateSize(): number {
|
|
658
667
|
const syncedSize = this.syncedData.size
|
|
659
|
-
const deletesFromSynced = Array.from(this.
|
|
660
|
-
(key) => this.syncedData.has(key) && !this.
|
|
668
|
+
const deletesFromSynced = Array.from(this.optimisticDeletes).filter(
|
|
669
|
+
(key) => this.syncedData.has(key) && !this.optimisticUpserts.has(key)
|
|
661
670
|
).length
|
|
662
|
-
const upsertsNotInSynced = Array.from(this.
|
|
671
|
+
const upsertsNotInSynced = Array.from(this.optimisticUpserts.keys()).filter(
|
|
663
672
|
(key) => !this.syncedData.has(key)
|
|
664
673
|
).length
|
|
665
674
|
|
|
@@ -676,9 +685,9 @@ export class CollectionImpl<
|
|
|
676
685
|
): void {
|
|
677
686
|
const allKeys = new Set([
|
|
678
687
|
...previousUpserts.keys(),
|
|
679
|
-
...this.
|
|
688
|
+
...this.optimisticUpserts.keys(),
|
|
680
689
|
...previousDeletes,
|
|
681
|
-
...this.
|
|
690
|
+
...this.optimisticDeletes,
|
|
682
691
|
])
|
|
683
692
|
|
|
684
693
|
for (const key of allKeys) {
|
|
@@ -726,34 +735,55 @@ export class CollectionImpl<
|
|
|
726
735
|
}
|
|
727
736
|
|
|
728
737
|
/**
|
|
729
|
-
* Emit
|
|
738
|
+
* Emit events either immediately or batch them for later emission
|
|
730
739
|
*/
|
|
731
|
-
private emitEvents(
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
740
|
+
private emitEvents(
|
|
741
|
+
changes: Array<ChangeMessage<T, TKey>>,
|
|
742
|
+
endBatching = false
|
|
743
|
+
): void {
|
|
744
|
+
if (this.shouldBatchEvents && !endBatching) {
|
|
745
|
+
// Add events to the batch
|
|
746
|
+
this.batchedEvents.push(...changes)
|
|
747
|
+
return
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
// Either we're not batching, or we're ending the batching cycle
|
|
751
|
+
let eventsToEmit = changes
|
|
752
|
+
|
|
753
|
+
if (endBatching) {
|
|
754
|
+
// End batching: combine any batched events with new events and clean up state
|
|
755
|
+
if (this.batchedEvents.length > 0) {
|
|
756
|
+
eventsToEmit = [...this.batchedEvents, ...changes]
|
|
736
757
|
}
|
|
758
|
+
this.batchedEvents = []
|
|
759
|
+
this.shouldBatchEvents = false
|
|
760
|
+
}
|
|
737
761
|
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
762
|
+
if (eventsToEmit.length === 0) return
|
|
763
|
+
|
|
764
|
+
// Emit to all listeners
|
|
765
|
+
for (const listener of this.changeListeners) {
|
|
766
|
+
listener(eventsToEmit)
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
// Emit to key-specific listeners
|
|
770
|
+
if (this.changeKeyListeners.size > 0) {
|
|
771
|
+
// Group changes by key, but only for keys that have listeners
|
|
772
|
+
const changesByKey = new Map<TKey, Array<ChangeMessage<T, TKey>>>()
|
|
773
|
+
for (const change of eventsToEmit) {
|
|
774
|
+
if (this.changeKeyListeners.has(change.key)) {
|
|
775
|
+
if (!changesByKey.has(change.key)) {
|
|
776
|
+
changesByKey.set(change.key, [])
|
|
748
777
|
}
|
|
778
|
+
changesByKey.get(change.key)!.push(change)
|
|
749
779
|
}
|
|
780
|
+
}
|
|
750
781
|
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
}
|
|
782
|
+
// Emit batched changes to each key's listeners
|
|
783
|
+
for (const [key, keyChanges] of changesByKey) {
|
|
784
|
+
const keyListeners = this.changeKeyListeners.get(key)!
|
|
785
|
+
for (const listener of keyListeners) {
|
|
786
|
+
listener(keyChanges)
|
|
757
787
|
}
|
|
758
788
|
}
|
|
759
789
|
}
|
|
@@ -764,13 +794,13 @@ export class CollectionImpl<
|
|
|
764
794
|
*/
|
|
765
795
|
public get(key: TKey): T | undefined {
|
|
766
796
|
// Check if optimistically deleted
|
|
767
|
-
if (this.
|
|
797
|
+
if (this.optimisticDeletes.has(key)) {
|
|
768
798
|
return undefined
|
|
769
799
|
}
|
|
770
800
|
|
|
771
801
|
// Check optimistic upserts first
|
|
772
|
-
if (this.
|
|
773
|
-
return this.
|
|
802
|
+
if (this.optimisticUpserts.has(key)) {
|
|
803
|
+
return this.optimisticUpserts.get(key)
|
|
774
804
|
}
|
|
775
805
|
|
|
776
806
|
// Fall back to synced data
|
|
@@ -782,12 +812,12 @@ export class CollectionImpl<
|
|
|
782
812
|
*/
|
|
783
813
|
public has(key: TKey): boolean {
|
|
784
814
|
// Check if optimistically deleted
|
|
785
|
-
if (this.
|
|
815
|
+
if (this.optimisticDeletes.has(key)) {
|
|
786
816
|
return false
|
|
787
817
|
}
|
|
788
818
|
|
|
789
819
|
// Check optimistic upserts first
|
|
790
|
-
if (this.
|
|
820
|
+
if (this.optimisticUpserts.has(key)) {
|
|
791
821
|
return true
|
|
792
822
|
}
|
|
793
823
|
|
|
@@ -808,14 +838,14 @@ export class CollectionImpl<
|
|
|
808
838
|
public *keys(): IterableIterator<TKey> {
|
|
809
839
|
// Yield keys from synced data, skipping any that are deleted.
|
|
810
840
|
for (const key of this.syncedData.keys()) {
|
|
811
|
-
if (!this.
|
|
841
|
+
if (!this.optimisticDeletes.has(key)) {
|
|
812
842
|
yield key
|
|
813
843
|
}
|
|
814
844
|
}
|
|
815
845
|
// Yield keys from upserts that were not already in synced data.
|
|
816
|
-
for (const key of this.
|
|
817
|
-
if (!this.syncedData.has(key) && !this.
|
|
818
|
-
// The
|
|
846
|
+
for (const key of this.optimisticUpserts.keys()) {
|
|
847
|
+
if (!this.syncedData.has(key) && !this.optimisticDeletes.has(key)) {
|
|
848
|
+
// The optimisticDeletes check is technically redundant if inserts/updates always remove from deletes,
|
|
819
849
|
// but it's safer to keep it.
|
|
820
850
|
yield key
|
|
821
851
|
}
|
|
@@ -829,10 +859,7 @@ export class CollectionImpl<
|
|
|
829
859
|
for (const key of this.keys()) {
|
|
830
860
|
const value = this.get(key)
|
|
831
861
|
if (value !== undefined) {
|
|
832
|
-
|
|
833
|
-
_orderByIndex?: number | string
|
|
834
|
-
}
|
|
835
|
-
yield copy as T
|
|
862
|
+
yield value
|
|
836
863
|
}
|
|
837
864
|
}
|
|
838
865
|
}
|
|
@@ -844,14 +871,46 @@ export class CollectionImpl<
|
|
|
844
871
|
for (const key of this.keys()) {
|
|
845
872
|
const value = this.get(key)
|
|
846
873
|
if (value !== undefined) {
|
|
847
|
-
|
|
848
|
-
_orderByIndex?: number | string
|
|
849
|
-
}
|
|
850
|
-
yield [key, copy as T]
|
|
874
|
+
yield [key, value]
|
|
851
875
|
}
|
|
852
876
|
}
|
|
853
877
|
}
|
|
854
878
|
|
|
879
|
+
/**
|
|
880
|
+
* Get all entries (virtual derived state)
|
|
881
|
+
*/
|
|
882
|
+
public *[Symbol.iterator](): IterableIterator<[TKey, T]> {
|
|
883
|
+
for (const [key, value] of this.entries()) {
|
|
884
|
+
yield [key, value]
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
/**
|
|
889
|
+
* Execute a callback for each entry in the collection
|
|
890
|
+
*/
|
|
891
|
+
public forEach(
|
|
892
|
+
callbackfn: (value: T, key: TKey, index: number) => void
|
|
893
|
+
): void {
|
|
894
|
+
let index = 0
|
|
895
|
+
for (const [key, value] of this.entries()) {
|
|
896
|
+
callbackfn(value, key, index++)
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
/**
|
|
901
|
+
* Create a new array with the results of calling a function for each entry in the collection
|
|
902
|
+
*/
|
|
903
|
+
public map<U>(
|
|
904
|
+
callbackfn: (value: T, key: TKey, index: number) => U
|
|
905
|
+
): Array<U> {
|
|
906
|
+
const result: Array<U> = []
|
|
907
|
+
let index = 0
|
|
908
|
+
for (const [key, value] of this.entries()) {
|
|
909
|
+
result.push(callbackfn(value, key, index++))
|
|
910
|
+
}
|
|
911
|
+
return result
|
|
912
|
+
}
|
|
913
|
+
|
|
855
914
|
/**
|
|
856
915
|
* Attempts to commit pending synced transactions if there are no active transactions
|
|
857
916
|
* This method processes operations from pending transactions and applies them to the synced data
|
|
@@ -893,6 +952,7 @@ export class CollectionImpl<
|
|
|
893
952
|
}
|
|
894
953
|
|
|
895
954
|
const events: Array<ChangeMessage<T, TKey>> = []
|
|
955
|
+
const rowUpdateMode = this.config.sync.rowUpdateMode || `partial`
|
|
896
956
|
|
|
897
957
|
for (const transaction of this.pendingSyncedTransactions) {
|
|
898
958
|
for (const operation of transaction.operations) {
|
|
@@ -925,12 +985,16 @@ export class CollectionImpl<
|
|
|
925
985
|
this.syncedData.set(key, operation.value)
|
|
926
986
|
break
|
|
927
987
|
case `update`: {
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
988
|
+
if (rowUpdateMode === `partial`) {
|
|
989
|
+
const updatedValue = Object.assign(
|
|
990
|
+
{},
|
|
991
|
+
this.syncedData.get(key),
|
|
992
|
+
operation.value
|
|
993
|
+
)
|
|
994
|
+
this.syncedData.set(key, updatedValue)
|
|
995
|
+
} else {
|
|
996
|
+
this.syncedData.set(key, operation.value)
|
|
997
|
+
}
|
|
934
998
|
break
|
|
935
999
|
}
|
|
936
1000
|
case `delete`:
|
|
@@ -941,8 +1005,8 @@ export class CollectionImpl<
|
|
|
941
1005
|
}
|
|
942
1006
|
|
|
943
1007
|
// Clear optimistic state since sync operations will now provide the authoritative data
|
|
944
|
-
this.
|
|
945
|
-
this.
|
|
1008
|
+
this.optimisticUpserts.clear()
|
|
1009
|
+
this.optimisticDeletes.clear()
|
|
946
1010
|
|
|
947
1011
|
// Reset flag and recompute optimistic state for any remaining active transactions
|
|
948
1012
|
this.isCommittingSyncTransactions = false
|
|
@@ -953,12 +1017,15 @@ export class CollectionImpl<
|
|
|
953
1017
|
switch (mutation.type) {
|
|
954
1018
|
case `insert`:
|
|
955
1019
|
case `update`:
|
|
956
|
-
this.
|
|
957
|
-
|
|
1020
|
+
this.optimisticUpserts.set(
|
|
1021
|
+
mutation.key,
|
|
1022
|
+
mutation.modified as T
|
|
1023
|
+
)
|
|
1024
|
+
this.optimisticDeletes.delete(mutation.key)
|
|
958
1025
|
break
|
|
959
1026
|
case `delete`:
|
|
960
|
-
this.
|
|
961
|
-
this.
|
|
1027
|
+
this.optimisticUpserts.delete(mutation.key)
|
|
1028
|
+
this.optimisticDeletes.add(mutation.key)
|
|
962
1029
|
break
|
|
963
1030
|
}
|
|
964
1031
|
}
|
|
@@ -1031,8 +1098,8 @@ export class CollectionImpl<
|
|
|
1031
1098
|
// Update cached size after synced data changes
|
|
1032
1099
|
this._size = this.calculateSize()
|
|
1033
1100
|
|
|
1034
|
-
//
|
|
1035
|
-
this.emitEvents(events)
|
|
1101
|
+
// End batching and emit all events (combines any batched events with sync events)
|
|
1102
|
+
this.emitEvents(events, true)
|
|
1036
1103
|
|
|
1037
1104
|
this.pendingSyncedTransactions = []
|
|
1038
1105
|
|
|
@@ -1242,7 +1309,7 @@ export class CollectionImpl<
|
|
|
1242
1309
|
return ambientTransaction
|
|
1243
1310
|
} else {
|
|
1244
1311
|
// Create a new transaction with a mutation function that calls the onInsert handler
|
|
1245
|
-
const directOpTransaction =
|
|
1312
|
+
const directOpTransaction = createTransaction<T>({
|
|
1246
1313
|
mutationFn: async (params) => {
|
|
1247
1314
|
// Call the onInsert handler with the transaction
|
|
1248
1315
|
return this.config.onInsert!(params)
|
|
@@ -1444,7 +1511,7 @@ export class CollectionImpl<
|
|
|
1444
1511
|
|
|
1445
1512
|
// If no changes were made, return an empty transaction early
|
|
1446
1513
|
if (mutations.length === 0) {
|
|
1447
|
-
const emptyTransaction =
|
|
1514
|
+
const emptyTransaction = createTransaction({
|
|
1448
1515
|
mutationFn: async () => {},
|
|
1449
1516
|
})
|
|
1450
1517
|
emptyTransaction.commit()
|
|
@@ -1464,7 +1531,7 @@ export class CollectionImpl<
|
|
|
1464
1531
|
// No need to check for onUpdate handler here as we've already checked at the beginning
|
|
1465
1532
|
|
|
1466
1533
|
// Create a new transaction with a mutation function that calls the onUpdate handler
|
|
1467
|
-
const directOpTransaction =
|
|
1534
|
+
const directOpTransaction = createTransaction<T>({
|
|
1468
1535
|
mutationFn: async (params) => {
|
|
1469
1536
|
// Call the onUpdate handler with the transaction
|
|
1470
1537
|
return this.config.onUpdate!(params)
|
|
@@ -1559,7 +1626,7 @@ export class CollectionImpl<
|
|
|
1559
1626
|
}
|
|
1560
1627
|
|
|
1561
1628
|
// Create a new transaction with a mutation function that calls the onDelete handler
|
|
1562
|
-
const directOpTransaction =
|
|
1629
|
+
const directOpTransaction = createTransaction<T>({
|
|
1563
1630
|
autoCommit: true,
|
|
1564
1631
|
mutationFn: async (params) => {
|
|
1565
1632
|
// Call the onDelete handler with the transaction
|
|
@@ -1616,19 +1683,7 @@ export class CollectionImpl<
|
|
|
1616
1683
|
* @returns An Array containing all items in the collection
|
|
1617
1684
|
*/
|
|
1618
1685
|
get toArray() {
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
// Currently a query with an orderBy will add a _orderByIndex to the items
|
|
1622
|
-
// so for now we need to sort the array by _orderByIndex if it exists
|
|
1623
|
-
// TODO: in the future it would be much better is the keys are sorted - this
|
|
1624
|
-
// should be done by the query engine.
|
|
1625
|
-
if (array[0] && (array[0] as { _orderByIndex?: number })._orderByIndex) {
|
|
1626
|
-
return (array as Array<{ _orderByIndex: number }>).sort(
|
|
1627
|
-
(a, b) => a._orderByIndex - b._orderByIndex
|
|
1628
|
-
) as Array<T>
|
|
1629
|
-
}
|
|
1630
|
-
|
|
1631
|
-
return array
|
|
1686
|
+
return Array.from(this.values())
|
|
1632
1687
|
}
|
|
1633
1688
|
|
|
1634
1689
|
/**
|
|
@@ -1767,45 +1822,13 @@ export class CollectionImpl<
|
|
|
1767
1822
|
* This method should be called by the Transaction class when state changes
|
|
1768
1823
|
*/
|
|
1769
1824
|
public onTransactionStateChange(): void {
|
|
1825
|
+
// Check if commitPendingTransactions will be called after this
|
|
1826
|
+
// by checking if there are pending sync transactions (same logic as in transactions.ts)
|
|
1827
|
+
this.shouldBatchEvents = this.pendingSyncedTransactions.length > 0
|
|
1828
|
+
|
|
1770
1829
|
// CRITICAL: Capture visible state BEFORE clearing optimistic state
|
|
1771
1830
|
this.capturePreSyncVisibleState()
|
|
1772
1831
|
|
|
1773
1832
|
this.recomputeOptimisticState()
|
|
1774
1833
|
}
|
|
1775
|
-
|
|
1776
|
-
private _storeMap: Store<Map<TKey, T>> | undefined
|
|
1777
|
-
|
|
1778
|
-
/**
|
|
1779
|
-
* Returns a Tanstack Store Map that is updated when the collection changes
|
|
1780
|
-
* This is a temporary solution to enable the existing framework hooks to work
|
|
1781
|
-
* with the new internals of Collection until they are rewritten.
|
|
1782
|
-
* TODO: Remove this once the framework hooks are rewritten.
|
|
1783
|
-
*/
|
|
1784
|
-
public asStoreMap(): Store<Map<TKey, T>> {
|
|
1785
|
-
if (!this._storeMap) {
|
|
1786
|
-
this._storeMap = new Store(new Map(this.entries()))
|
|
1787
|
-
this.changeListeners.add(() => {
|
|
1788
|
-
this._storeMap!.setState(() => new Map(this.entries()))
|
|
1789
|
-
})
|
|
1790
|
-
}
|
|
1791
|
-
return this._storeMap
|
|
1792
|
-
}
|
|
1793
|
-
|
|
1794
|
-
private _storeArray: Store<Array<T>> | undefined
|
|
1795
|
-
|
|
1796
|
-
/**
|
|
1797
|
-
* Returns a Tanstack Store Array that is updated when the collection changes
|
|
1798
|
-
* This is a temporary solution to enable the existing framework hooks to work
|
|
1799
|
-
* with the new internals of Collection until they are rewritten.
|
|
1800
|
-
* TODO: Remove this once the framework hooks are rewritten.
|
|
1801
|
-
*/
|
|
1802
|
-
public asStoreArray(): Store<Array<T>> {
|
|
1803
|
-
if (!this._storeArray) {
|
|
1804
|
-
this._storeArray = new Store(this.toArray)
|
|
1805
|
-
this.changeListeners.add(() => {
|
|
1806
|
-
this._storeArray!.setState(() => this.toArray)
|
|
1807
|
-
})
|
|
1808
|
-
}
|
|
1809
|
-
return this._storeArray
|
|
1810
|
-
}
|
|
1811
1834
|
}
|