@tanstack/vue-db 0.0.128 → 0.1.0
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/README.md +17 -0
- package/dist/cjs/index.cjs +2 -0
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +1 -0
- package/dist/cjs/useLiveInfiniteQuery.cjs +116 -0
- package/dist/cjs/useLiveInfiniteQuery.cjs.map +1 -0
- package/dist/cjs/useLiveInfiniteQuery.d.cts +55 -0
- package/dist/cjs/useLiveQuery.cjs +32 -46
- package/dist/cjs/useLiveQuery.cjs.map +1 -1
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +2 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/useLiveInfiniteQuery.d.ts +55 -0
- package/dist/esm/useLiveInfiniteQuery.js +116 -0
- package/dist/esm/useLiveInfiniteQuery.js.map +1 -0
- package/dist/esm/useLiveQuery.js +34 -48
- package/dist/esm/useLiveQuery.js.map +1 -1
- package/package.json +2 -2
- package/src/index.ts +1 -0
- package/src/useLiveInfiniteQuery.ts +267 -0
- package/src/useLiveQuery.ts +47 -67
package/src/useLiveQuery.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
computed,
|
|
3
3
|
getCurrentInstance,
|
|
4
|
-
nextTick,
|
|
5
4
|
onUnmounted,
|
|
6
5
|
reactive,
|
|
7
6
|
ref,
|
|
@@ -10,6 +9,7 @@ import {
|
|
|
10
9
|
} from 'vue'
|
|
11
10
|
import {
|
|
12
11
|
createLiveQueryCollection,
|
|
12
|
+
createLiveQueryObserver,
|
|
13
13
|
isCollection,
|
|
14
14
|
isSingleResultCollection,
|
|
15
15
|
} from '@tanstack/db'
|
|
@@ -22,6 +22,7 @@ import type {
|
|
|
22
22
|
InferResultType,
|
|
23
23
|
InitialQueryBuilder,
|
|
24
24
|
LiveQueryCollectionConfig,
|
|
25
|
+
LiveQueryObserver,
|
|
25
26
|
NonSingleResult,
|
|
26
27
|
QueryBuilder,
|
|
27
28
|
SingleResult,
|
|
@@ -363,101 +364,80 @@ export function useLiveQuery(
|
|
|
363
364
|
internalData.push(...Array.from(currentCollection.values()))
|
|
364
365
|
}
|
|
365
366
|
|
|
366
|
-
//
|
|
367
|
-
|
|
367
|
+
// The shared observer owns subscription, the ready-race, and status; Vue
|
|
368
|
+
// materializes into its own reactive map (granular) + ordered array.
|
|
369
|
+
let currentObserver: LiveQueryObserver<any, any> | null = null
|
|
370
|
+
|
|
371
|
+
const syncFromObserver = (
|
|
372
|
+
observer: LiveQueryObserver<any, any>,
|
|
373
|
+
currentCollection: Collection<any, any, any>,
|
|
374
|
+
) => {
|
|
375
|
+
status.value = observer.getSnapshot().status as CollectionStatus
|
|
376
|
+
syncDataFromCollection(currentCollection)
|
|
377
|
+
}
|
|
368
378
|
|
|
369
379
|
// Watch for collection changes and subscribe to updates
|
|
370
380
|
watchEffect((onInvalidate) => {
|
|
371
381
|
const currentCollection = collection.value
|
|
372
382
|
|
|
383
|
+
// Tear down any previous observer.
|
|
384
|
+
currentObserver?.dispose()
|
|
385
|
+
currentObserver = null
|
|
386
|
+
|
|
373
387
|
// Handle null collection (disabled query)
|
|
374
388
|
if (!currentCollection) {
|
|
375
389
|
status.value = `disabled` as const
|
|
376
390
|
state.clear()
|
|
377
391
|
internalData.length = 0
|
|
378
|
-
if (currentUnsubscribe) {
|
|
379
|
-
currentUnsubscribe()
|
|
380
|
-
currentUnsubscribe = null
|
|
381
|
-
}
|
|
382
392
|
return
|
|
383
393
|
}
|
|
384
394
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
// Clean up previous subscription
|
|
389
|
-
if (currentUnsubscribe) {
|
|
390
|
-
currentUnsubscribe()
|
|
391
|
-
}
|
|
395
|
+
const observer = createLiveQueryObserver(currentCollection)
|
|
396
|
+
currentObserver = observer
|
|
392
397
|
|
|
393
|
-
//
|
|
398
|
+
// Initial rows arrive as the observer's first delta (includeInitialState);
|
|
399
|
+
// apply them and every subsequent delta granularly to the reactive map.
|
|
394
400
|
state.clear()
|
|
395
|
-
for (const [key, value] of currentCollection.entries()) {
|
|
396
|
-
state.set(key, value)
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
// Initialize data array in correct order
|
|
400
|
-
syncDataFromCollection(currentCollection)
|
|
401
401
|
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
state.delete(change.key)
|
|
423
|
-
break
|
|
402
|
+
const unsubscribe = observer.subscribe(
|
|
403
|
+
(changes: Array<ChangeMessage<any>> | undefined) => {
|
|
404
|
+
if (changes) {
|
|
405
|
+
for (const change of changes) {
|
|
406
|
+
switch (change.type) {
|
|
407
|
+
case `insert`:
|
|
408
|
+
case `update`:
|
|
409
|
+
state.set(change.key, change.value)
|
|
410
|
+
break
|
|
411
|
+
case `delete`:
|
|
412
|
+
state.delete(change.key)
|
|
413
|
+
break
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
} else {
|
|
417
|
+
// Cleanup and other status-only publications carry no row deltas.
|
|
418
|
+
// Rebuild the keyed view so it cannot diverge from ordered data.
|
|
419
|
+
state.clear()
|
|
420
|
+
for (const [key, value] of observer.getSnapshot().state ?? []) {
|
|
421
|
+
state.set(key, value)
|
|
424
422
|
}
|
|
425
423
|
}
|
|
426
|
-
|
|
427
|
-
// Update the data array to maintain sorted order
|
|
428
|
-
syncDataFromCollection(currentCollection)
|
|
429
|
-
// Update status ref on every change
|
|
430
|
-
status.value = currentCollection.status
|
|
431
|
-
},
|
|
432
|
-
{
|
|
433
|
-
includeInitialState: true,
|
|
424
|
+
syncFromObserver(observer, currentCollection)
|
|
434
425
|
},
|
|
435
426
|
)
|
|
436
|
-
|
|
437
|
-
currentUnsubscribe = subscription.unsubscribe.bind(subscription)
|
|
438
|
-
|
|
439
|
-
// Preload collection data if not already started
|
|
440
|
-
if (currentCollection.status === `idle`) {
|
|
441
|
-
currentCollection.preload().catch(console.error)
|
|
442
|
-
}
|
|
427
|
+
syncFromObserver(observer, currentCollection)
|
|
443
428
|
|
|
444
429
|
// Cleanup when effect is invalidated
|
|
445
430
|
onInvalidate(() => {
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
}
|
|
431
|
+
unsubscribe()
|
|
432
|
+
observer.dispose()
|
|
433
|
+
currentObserver = null
|
|
450
434
|
})
|
|
451
435
|
})
|
|
452
436
|
|
|
453
437
|
// Cleanup on unmount (only if we're in a component context)
|
|
454
438
|
const instance = getCurrentInstance()
|
|
455
439
|
if (instance) {
|
|
456
|
-
onUnmounted(() =>
|
|
457
|
-
if (currentUnsubscribe) {
|
|
458
|
-
currentUnsubscribe()
|
|
459
|
-
}
|
|
460
|
-
})
|
|
440
|
+
onUnmounted(() => currentObserver?.dispose())
|
|
461
441
|
}
|
|
462
442
|
|
|
463
443
|
return {
|