Skip to content

Commit 0a0bbb0

Browse files
committed
address review
1 parent 9ad1169 commit 0a0bbb0

9 files changed

Lines changed: 105 additions & 115 deletions

File tree

packages/db/src/collection/events.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,17 +35,18 @@ export interface CollectionSubscribersChangeEvent {
3535
/**
3636
* Event emitted when the collection's loading more state changes
3737
*/
38-
export interface CollectionLoadingMoreChangeEvent {
39-
type: `loadingMore:change`
38+
export interface CollectionLoadingSubsetChangeEvent {
39+
type: `loadingSubset:change`
4040
collection: Collection<any, any, any, any, any>
41-
isLoadingMore: boolean
42-
previousIsLoadingMore: boolean
41+
isLoadingSubset: boolean
42+
previousIsLoadingSubset: boolean
43+
loadingSubsetTransition: `start` | `end`
4344
}
4445

4546
export type AllCollectionEvents = {
4647
"status:change": CollectionStatusChangeEvent
4748
"subscribers:change": CollectionSubscribersChangeEvent
48-
"loadingMore:change": CollectionLoadingMoreChangeEvent
49+
"loadingSubset:change": CollectionLoadingSubsetChangeEvent
4950
} & {
5051
[K in CollectionStatus as `status:${K}`]: CollectionStatusEvent<K>
5152
}
@@ -54,7 +55,7 @@ export type CollectionEvent =
5455
| AllCollectionEvents[keyof AllCollectionEvents]
5556
| CollectionStatusChangeEvent
5657
| CollectionSubscribersChangeEvent
57-
| CollectionLoadingMoreChangeEvent
58+
| CollectionLoadingSubsetChangeEvent
5859

5960
export type CollectionEventHandler<T extends keyof AllCollectionEvents> = (
6061
event: AllCollectionEvents[T]

packages/db/src/collection/index.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -359,8 +359,8 @@ export class CollectionImpl<
359359
* Check if the collection is currently loading more data
360360
* @returns true if the collection has pending load more operations, false otherwise
361361
*/
362-
public get isLoadingMore(): boolean {
363-
return this._sync.isLoadingMore
362+
public get isLoadingSubset(): boolean {
363+
return this._sync.isLoadingSubset
364364
}
365365

366366
/**
@@ -372,7 +372,7 @@ export class CollectionImpl<
372372
}
373373

374374
/**
375-
* Tracks a load promise for isLoadingMore state.
375+
* Tracks a load promise for isLoadingSubset state.
376376
* @internal This is for internal coordination (e.g., live-query glue code), not for general use.
377377
*/
378378
public trackLoadPromise(promise: Promise<void>): void {

packages/db/src/collection/subscription.ts

Lines changed: 20 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,24 @@ export class CollectionSubscription
124124
} as SubscriptionEvents[typeof eventKey])
125125
}
126126

127+
/**
128+
* Track a loadSubset promise and manage loading status
129+
*/
130+
private trackLoadSubsetPromise(syncResult: Promise<void> | true) {
131+
// Track the promise if it's actually a promise (async work)
132+
if (syncResult instanceof Promise) {
133+
this.pendingLoadSubsetPromises.add(syncResult)
134+
this.setStatus(`loadingSubset`)
135+
136+
syncResult.finally(() => {
137+
this.pendingLoadSubsetPromises.delete(syncResult)
138+
if (this.pendingLoadSubsetPromises.size === 0) {
139+
this.setStatus(`ready`)
140+
}
141+
})
142+
}
143+
}
144+
127145
hasLoadedInitialState() {
128146
return this.loadedInitialState
129147
}
@@ -179,18 +197,7 @@ export class CollectionSubscription
179197
subscription: this,
180198
})
181199

182-
// Track the promise if it's actually a promise (async work)
183-
if (syncResult instanceof Promise) {
184-
this.pendingLoadSubsetPromises.add(syncResult)
185-
this.setStatus(`loadingMore`)
186-
187-
syncResult.finally(() => {
188-
this.pendingLoadSubsetPromises.delete(syncResult)
189-
if (this.pendingLoadSubsetPromises.size === 0) {
190-
this.setStatus(`ready`)
191-
}
192-
})
193-
}
200+
this.trackLoadSubsetPromise(syncResult)
194201

195202
// Also load data immediately from the collection
196203
const snapshot = this.collection.currentStateAsChanges(stateOpts)
@@ -289,18 +296,7 @@ export class CollectionSubscription
289296
subscription: this,
290297
})
291298

292-
// Track the promise if it's actually a promise (async work)
293-
if (syncResult instanceof Promise) {
294-
this.pendingLoadSubsetPromises.add(syncResult)
295-
this.setStatus(`loadingMore`)
296-
297-
syncResult.finally(() => {
298-
this.pendingLoadSubsetPromises.delete(syncResult)
299-
if (this.pendingLoadSubsetPromises.size === 0) {
300-
this.setStatus(`ready`)
301-
}
302-
})
303-
}
299+
this.trackLoadSubsetPromise(syncResult)
304300
}
305301

306302
/**

packages/db/src/collection/sync.ts

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -259,40 +259,41 @@ export class CollectionSyncManager<
259259
/**
260260
* Gets whether the collection is currently loading more data
261261
*/
262-
public get isLoadingMore(): boolean {
262+
public get isLoadingSubset(): boolean {
263263
return this.pendingLoadSubsetPromises.size > 0
264264
}
265265

266266
/**
267-
* Tracks a load promise for isLoadingMore state.
267+
* Tracks a load promise for isLoadingSubset state.
268268
* @internal This is for internal coordination (e.g., live-query glue code), not for general use.
269269
*/
270270
public trackLoadPromise(promise: Promise<void>): void {
271-
const wasLoading = this.isLoadingMore
271+
const loadingStarting = !this.isLoadingSubset
272272
this.pendingLoadSubsetPromises.add(promise)
273-
const isLoadingNow = this.isLoadingMore
274273

275-
if (!wasLoading && isLoadingNow) {
276-
this._events.emit(`loadingMore:change`, {
277-
type: `loadingMore:change`,
274+
if (loadingStarting) {
275+
this._events.emit(`loadingSubset:change`, {
276+
type: `loadingSubset:change`,
278277
collection: this.collection,
279-
isLoadingMore: true,
280-
previousIsLoadingMore: false,
278+
isLoadingSubset: true,
279+
previousIsLoadingSubset: false,
280+
loadingSubsetTransition: `start`,
281281
})
282282
}
283283

284284
promise.finally(() => {
285-
// Check loading state BEFORE removing the promise
286-
const wasLoadingBeforeRemoval = this.isLoadingMore
285+
const loadingEnding =
286+
this.pendingLoadSubsetPromises.size === 1 &&
287+
this.pendingLoadSubsetPromises.has(promise)
287288
this.pendingLoadSubsetPromises.delete(promise)
288-
const stillLoading = this.isLoadingMore
289289

290-
if (wasLoadingBeforeRemoval && !stillLoading) {
291-
this._events.emit(`loadingMore:change`, {
292-
type: `loadingMore:change`,
290+
if (loadingEnding) {
291+
this._events.emit(`loadingSubset:change`, {
292+
type: `loadingSubset:change`,
293293
collection: this.collection,
294-
isLoadingMore: false,
295-
previousIsLoadingMore: true,
294+
isLoadingSubset: false,
295+
previousIsLoadingSubset: true,
296+
loadingSubsetTransition: `end`,
296297
})
297298
}
298299
})

packages/db/src/query/live/collection-subscriber.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,12 +76,12 @@ export class CollectionSubscriber<
7676
// Subscribe to subscription status changes to propagate loading state
7777
const statusUnsubscribe = subscription.on(`status:change`, (event) => {
7878
// TODO: For now we are setting this loading state whenever the subscription
79-
// status changes to 'loadingMore'. But we have discussed it only happening
79+
// status changes to 'loadingSubset'. But we have discussed it only happening
8080
// when the the live query has it's offset/limit changed, and that triggers the
8181
// subscription to request a snapshot. This will require more work to implement,
8282
// and builds on https://github.com/TanStack/db/pull/663 which this PR
8383
// does not yet depend on.
84-
if (event.status === `loadingMore`) {
84+
if (event.status === `loadingSubset`) {
8585
// Guard against duplicate transitions
8686
if (!this.subscriptionLoadingPromises.has(subscription)) {
8787
let resolve: () => void

packages/db/src/types.ts

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ export type OperationType = `insert` | `update` | `delete`
154154
/**
155155
* Subscription status values
156156
*/
157-
export type SubscriptionStatus = `ready` | `loadingMore`
157+
export type SubscriptionStatus = `ready` | `loadingSubset`
158158

159159
/**
160160
* Event emitted when subscription status changes
@@ -190,7 +190,7 @@ export interface SubscriptionUnsubscribedEvent {
190190
export type SubscriptionEvents = {
191191
"status:change": SubscriptionStatusChangeEvent
192192
"status:ready": SubscriptionStatusEvent<`ready`>
193-
"status:loadingMore": SubscriptionStatusEvent<`loadingMore`>
193+
"status:loadingSubset": SubscriptionStatusEvent<`loadingSubset`>
194194
unsubscribed: SubscriptionUnsubscribedEvent
195195
}
196196

@@ -380,14 +380,6 @@ export type CollectionStatus =
380380
/** Collection has been cleaned up and resources freed */
381381
| `cleaned-up`
382382

383-
/**
384-
* @default `eager`
385-
* @description
386-
* Collections have two modes of sync: eager and on-demand.
387-
* - eager: syncs all data immediately on preload
388-
* - on-demand: syncs data in incremental snapshots when the collection is queried
389-
* The exact implementation of the sync mode is up to the sync implementation.
390-
*/
391383
export type SyncMode = `eager` | `on-demand`
392384

393385
export interface BaseCollectionConfig<

packages/db/tests/collection-subscription.test.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ describe(`CollectionSubscription status tracking`, () => {
2020
subscription.unsubscribe()
2121
})
2222

23-
it(`status changes to 'loadingMore' when requestSnapshot triggers a promise`, async () => {
23+
it(`status changes to 'loadingSubset' when requestSnapshot triggers a promise`, async () => {
2424
let resolveLoadSubset: () => void
2525
const loadSubsetPromise = new Promise<void>((resolve) => {
2626
resolveLoadSubset = resolve
@@ -49,8 +49,8 @@ describe(`CollectionSubscription status tracking`, () => {
4949
// Trigger a snapshot request that will call loadSubset
5050
subscription.requestSnapshot({ optimizedOnly: false })
5151

52-
// Status should now be loadingMore
53-
expect(subscription.status).toBe(`loadingMore`)
52+
// Status should now be loadingSubset
53+
expect(subscription.status).toBe(`loadingSubset`)
5454

5555
// Resolve the load more promise
5656
resolveLoadSubset!()
@@ -87,7 +87,7 @@ describe(`CollectionSubscription status tracking`, () => {
8787
})
8888

8989
subscription.requestSnapshot({ optimizedOnly: false })
90-
expect(subscription.status).toBe(`loadingMore`)
90+
expect(subscription.status).toBe(`loadingSubset`)
9191

9292
resolveLoadSubset!()
9393
await flushPromises()
@@ -96,7 +96,7 @@ describe(`CollectionSubscription status tracking`, () => {
9696
subscription.unsubscribe()
9797
})
9898

99-
it(`concurrent promises keep status as 'loadingMore' until all resolve`, async () => {
99+
it(`concurrent promises keep status as 'loadingSubset' until all resolve`, async () => {
100100
let resolveLoadSubset1: () => void
101101
let resolveLoadSubset2: () => void
102102
let callCount = 0
@@ -132,18 +132,18 @@ describe(`CollectionSubscription status tracking`, () => {
132132

133133
// Trigger first load
134134
subscription.requestSnapshot({ optimizedOnly: false })
135-
expect(subscription.status).toBe(`loadingMore`)
135+
expect(subscription.status).toBe(`loadingSubset`)
136136

137137
// Trigger second load
138138
subscription.requestSnapshot({ optimizedOnly: false })
139-
expect(subscription.status).toBe(`loadingMore`)
139+
expect(subscription.status).toBe(`loadingSubset`)
140140

141141
// Resolve first promise
142142
resolveLoadSubset1!()
143143
await flushPromises()
144144

145145
// Should still be loading because second promise is pending
146-
expect(subscription.status).toBe(`loadingMore`)
146+
expect(subscription.status).toBe(`loadingSubset`)
147147

148148
// Resolve second promise
149149
resolveLoadSubset2!()
@@ -193,15 +193,15 @@ describe(`CollectionSubscription status tracking`, () => {
193193
expect(statusChanges).toHaveLength(1)
194194
expect(statusChanges[0]).toEqual({
195195
previous: `ready`,
196-
current: `loadingMore`,
196+
current: `loadingSubset`,
197197
})
198198

199199
resolveLoadSubset!()
200200
await flushPromises()
201201

202202
expect(statusChanges).toHaveLength(2)
203203
expect(statusChanges[1]).toEqual({
204-
previous: `loadingMore`,
204+
previous: `loadingSubset`,
205205
current: `ready`,
206206
})
207207

@@ -235,7 +235,7 @@ describe(`CollectionSubscription status tracking`, () => {
235235
})
236236

237237
subscription.requestSnapshot({ optimizedOnly: false })
238-
expect(subscription.status).toBe(`loadingMore`)
238+
expect(subscription.status).toBe(`loadingSubset`)
239239

240240
// Reject the promise
241241
rejectLoadSubset!(new Error(`Load failed`))

0 commit comments

Comments
 (0)