Skip to content

Commit 9abb4bf

Browse files
authored
Remove the idea of ordered/serialized transactions (#38)
1 parent c198819 commit 9abb4bf

File tree

6 files changed

+89
-329
lines changed

6 files changed

+89
-329
lines changed

packages/optimistic/src/TransactionManager.ts

Lines changed: 12 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,7 @@ import { SortedMap } from "./SortedMap"
33
import { createDeferred } from "./deferred"
44
import type { TransactionStore } from "./TransactionStore"
55
import type { Collection } from "./collection"
6-
import type {
7-
MutationStrategy,
8-
PendingMutation,
9-
Transaction,
10-
TransactionState,
11-
} from "./types"
6+
import type { PendingMutation, Transaction, TransactionState } from "./types"
127

138
// Singleton instance of TransactionManager with type map
149

@@ -141,23 +136,20 @@ export class TransactionManager<T extends object = Record<string, unknown>> {
141136
}
142137

143138
/**
144-
* Applies a transaction with the given mutations using the specified strategy
139+
* Applies mutations to the current transaction. A given transaction accumulates mutations
140+
* within a single event loop.
145141
*
146142
* @param mutations - Array of pending mutations to apply
147-
* @param strategy - Strategy to use when applying the transaction
148143
* @returns A live reference to the created or updated transaction
149144
*/
150-
applyTransaction(
151-
mutations: Array<PendingMutation>,
152-
strategy: MutationStrategy
153-
): Transaction {
154-
// See if there's an existing overlapping queued mutation.
145+
applyTransaction(mutations: Array<PendingMutation>): Transaction {
146+
// See if there's an existing transaction with overlapping queued mutation.
155147
const mutationKeys = mutations.map((m) => m.key)
156148
let transaction: Transaction | undefined = Array.from(
157149
this.transactions.state.values()
158150
).filter(
159151
(t) =>
160-
t.state === `queued` &&
152+
t.state === `pending` &&
161153
t.mutations.some((m) => mutationKeys.includes(m.key))
162154
)[0]
163155

@@ -186,37 +178,21 @@ export class TransactionManager<T extends object = Record<string, unknown>> {
186178
updatedAt: new Date(),
187179
mutations,
188180
metadata: {},
189-
strategy,
190181
isSynced: createDeferred(),
191182
isPersisted: createDeferred(),
192183
} as Transaction
193184
}
194185

195-
// For ordered transactions, check if we need to queue behind another transaction
196-
if (strategy.type === `ordered`) {
197-
const activeTransactions = this.getActiveTransactions()
198-
const orderedTransactions = activeTransactions.filter(
199-
(tx) => tx.strategy.type === `ordered` && tx.state !== `queued`
200-
)
201-
202-
// Find any active transaction that has overlapping mutations
203-
const conflictingTransaction = orderedTransactions.find((tx) =>
204-
this.hasOverlappingMutations(tx.mutations, mutations)
205-
)
206-
207-
if (conflictingTransaction) {
208-
transaction.state = `queued`
209-
transaction.queuedBehind = conflictingTransaction.id
210-
} else {
211-
this.setTransaction(transaction)
212-
this.processTransaction(transaction.id)
213-
}
214-
}
215-
216186
this.setTransaction(transaction)
187+
217188
// Persist async
218189
this.store.putTransaction(transaction)
219190

191+
// Start processing in the next event loop tick.
192+
setTimeout(() => {
193+
this.processTransaction(transaction.id)
194+
}, 0)
195+
220196
// Return a live reference to the transaction
221197
return this.createLiveTransactionReference(transaction.id)
222198
}
@@ -348,29 +324,6 @@ export class TransactionManager<T extends object = Record<string, unknown>> {
348324
// Persist async only if not in terminal state
349325
this.store.putTransaction(updatedTransaction)
350326
}
351-
352-
// If this transaction is completing, check if any are queued behind it
353-
if (
354-
(newState === `completed` || newState === `failed`) &&
355-
transaction.strategy.type === `ordered`
356-
) {
357-
// Get all ordered transactions that are queued behind this one
358-
const queuedTransactions = Array.from(
359-
this.transactions.state.values()
360-
).filter(
361-
(tx) =>
362-
tx.state === `queued` &&
363-
tx.strategy.type === `ordered` &&
364-
tx.queuedBehind === transaction.id
365-
)
366-
367-
// Process each queued transaction
368-
for (const queuedTransaction of queuedTransactions) {
369-
queuedTransaction.queuedBehind = undefined
370-
this.setTransaction(queuedTransaction)
371-
this.processTransaction(queuedTransaction.id)
372-
}
373-
}
374327
}
375328

376329
/**

packages/optimistic/src/collection.ts

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -548,9 +548,7 @@ export class Collection<T extends object = Record<string, unknown>> {
548548
mutations.push(mutation)
549549
})
550550

551-
return this.transactionManager.applyTransaction(mutations, {
552-
type: `ordered`,
553-
})
551+
return this.transactionManager.applyTransaction(mutations)
554552
}
555553

556554
/**
@@ -678,9 +676,7 @@ export class Collection<T extends object = Record<string, unknown>> {
678676
throw new Error(`No changes were made to any of the objects`)
679677
}
680678

681-
return this.transactionManager.applyTransaction(mutations, {
682-
type: `ordered`,
683-
})
679+
return this.transactionManager.applyTransaction(mutations)
684680
}
685681

686682
/**
@@ -758,9 +754,7 @@ export class Collection<T extends object = Record<string, unknown>> {
758754
}
759755
})
760756

761-
return this.transactionManager.applyTransaction(mutations, {
762-
type: `ordered`,
763-
})
757+
return this.transactionManager.applyTransaction(mutations)
764758
}
765759

766760
/**

packages/optimistic/src/types.ts

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import type { Deferred } from "../src/deferred"
33
import type { StandardSchemaV1 } from "@standard-schema/spec"
44

55
export type TransactionState =
6-
| `queued`
76
| `pending`
87
| `persisting`
98
| `persisted_awaiting_sync`
@@ -29,9 +28,7 @@ export interface Transaction {
2928
createdAt: Date
3029
updatedAt: Date
3130
mutations: Array<PendingMutation>
32-
strategy: MutationStrategy
3331
metadata: Record<string, unknown>
34-
queuedBehind?: string
3532
isSynced?: Deferred<boolean>
3633
isPersisted?: Deferred<boolean>
3734
error?: {
@@ -107,14 +104,6 @@ export interface MutationFn<T extends object = Record<string, unknown>> {
107104
}) => Promise<void>
108105
}
109106

110-
export interface MutationStrategy {
111-
type: `ordered` | `parallel`
112-
merge?: (
113-
syncedData: Record<string, unknown>,
114-
pendingMutations: Array<PendingMutation>
115-
) => Record<string, unknown>
116-
}
117-
118107
/**
119108
* The Standard Schema interface.
120109
* This follows the standard-schema specification: https://github.com/standard-schema/standard-schema

0 commit comments

Comments
 (0)