Skip to content

Commit 0f28a47

Browse files
committed
tweaks
1 parent f1b24c2 commit 0f28a47

File tree

9 files changed

+222
-30
lines changed

9 files changed

+222
-30
lines changed

packages/db/src/collection.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -957,6 +957,12 @@ export class CollectionImpl<
957957
for (const listener of this.changeListeners) {
958958
listener([])
959959
}
960+
// Emit to key-specific listeners
961+
for (const [_key, keyListeners] of this.changeKeyListeners) {
962+
for (const listener of keyListeners) {
963+
listener([])
964+
}
965+
}
960966
}
961967

962968
/**

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

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,13 @@ export function liveQueryCollectionOptions<
168168
)
169169
}
170170

171+
const allCollectionsReadyOrInitialCommit = () => {
172+
return Object.values(collections).every(
173+
(collection) =>
174+
collection.status === `ready` || collection.status === `initialCommit`
175+
)
176+
}
177+
171178
let graphCache: D2 | undefined
172179
let inputsCache: Record<string, RootStreamBuilder<unknown>> | undefined
173180
let pipelineCache: ResultStream | undefined
@@ -293,7 +300,7 @@ export function liveQueryCollectionOptions<
293300

294301
const maybeRunGraph = () => {
295302
// We only run the graph if all the collections are ready
296-
if (allCollectionsReady()) {
303+
if (allCollectionsReadyOrInitialCommit()) {
297304
graph.run()
298305
// On the initial run, we may need to do an empty commit to ensure that
299306
// the collection is initialized
@@ -302,7 +309,9 @@ export function liveQueryCollectionOptions<
302309
commit()
303310
}
304311
// Mark the collection as ready after the first successful run
305-
markReady()
312+
if (allCollectionsReady()) {
313+
markReady()
314+
}
306315
}
307316
}
308317

packages/db/tests/query/live-query-collection.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ describe(`createLiveQueryCollection`, () => {
171171
expect(liveQuery.size).toBe(0)
172172
})
173173

174-
it(`shouldn't call markReady when source collection sync doesn't call markReady`, async () => {
174+
it(`shouldn't call markReady when source collection sync doesn't call markReady`, () => {
175175
const collection = createCollection<{ id: string }>({
176176
sync: {
177177
sync({ begin, commit }) {

packages/react-db/tests/useLiveQuery.test.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1077,15 +1077,17 @@ describe(`Query Collections`, () => {
10771077
it(`should update isLoading when collection status changes`, async () => {
10781078
let beginFn: (() => void) | undefined
10791079
let commitFn: (() => void) | undefined
1080+
let markReadyFn: (() => void) | undefined
10801081

10811082
const collection = createCollection<Person>({
10821083
id: `status-change-has-loaded-test`,
10831084
getKey: (person: Person) => person.id,
10841085
startSync: false,
10851086
sync: {
1086-
sync: ({ begin, commit }) => {
1087+
sync: ({ begin, commit, markReady }) => {
10871088
beginFn = begin
10881089
commitFn = commit
1090+
markReadyFn = markReady
10891091
// Don't sync immediately
10901092
},
10911093
},
@@ -1116,9 +1118,10 @@ describe(`Query Collections`, () => {
11161118

11171119
// Trigger the first commit to make collection ready
11181120
act(() => {
1119-
if (beginFn && commitFn) {
1121+
if (beginFn && commitFn && markReadyFn) {
11201122
beginFn()
11211123
commitFn()
1124+
markReadyFn()
11221125
}
11231126
})
11241127

packages/solid-db/tests/useLiveQuery.test.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1053,15 +1053,17 @@ describe(`Query Collections`, () => {
10531053
it(`should update isLoading when collection status changes`, async () => {
10541054
let beginFn: (() => void) | undefined
10551055
let commitFn: (() => void) | undefined
1056+
let markReadyFn: (() => void) | undefined
10561057

10571058
const collection = createCollection<Person>({
10581059
id: `status-change-has-loaded-test`,
10591060
getKey: (person: Person) => person.id,
10601061
startSync: false,
10611062
sync: {
1062-
sync: ({ begin, commit }) => {
1063+
sync: ({ begin, commit, markReady }) => {
10631064
beginFn = begin
10641065
commitFn = commit
1066+
markReadyFn = markReady
10651067
// Don't sync immediately
10661068
},
10671069
},
@@ -1089,9 +1091,10 @@ describe(`Query Collections`, () => {
10891091
collection.preload()
10901092

10911093
// Trigger the first commit to make collection ready
1092-
if (beginFn && commitFn) {
1094+
if (beginFn && commitFn && markReadyFn) {
10931095
beginFn()
10941096
commitFn()
1097+
markReadyFn()
10951098
}
10961099

10971100
// Insert data

packages/svelte-db/src/useLiveQuery.svelte.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,10 @@ export function useLiveQuery(
246246

247247
if (isCollection) {
248248
// It's already a collection, ensure sync is started for Svelte helpers
249-
unwrappedParam.startSyncImmediate()
249+
// Only start sync if the collection is in idle state
250+
if (unwrappedParam.status === `idle`) {
251+
unwrappedParam.startSyncImmediate()
252+
}
250253
return unwrappedParam
251254
}
252255

packages/svelte-db/tests/useLiveQuery.svelte.test.ts

Lines changed: 94 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -751,16 +751,18 @@ describe(`Query Collections`, () => {
751751
it(`should be false initially and true after collection is ready`, () => {
752752
let beginFn: (() => void) | undefined
753753
let commitFn: (() => void) | undefined
754+
let markReadyFn: (() => void) | undefined
754755

755756
// Create a collection that doesn't start sync immediately
756757
const collection = createCollection<Person>({
757758
id: `is-ready-test`,
758759
getKey: (person: Person) => person.id,
759760
startSync: false, // Don't start sync immediately
760761
sync: {
761-
sync: ({ begin, commit }) => {
762+
sync: ({ begin, commit, markReady }) => {
762763
beginFn = begin
763764
commitFn = commit
765+
markReadyFn = markReady
764766
// Don't call begin/commit immediately
765767
},
766768
},
@@ -787,9 +789,10 @@ describe(`Query Collections`, () => {
787789
collection.preload()
788790

789791
// Trigger the first commit to make collection ready
790-
if (beginFn && commitFn) {
792+
if (beginFn && commitFn && markReadyFn) {
791793
beginFn()
792794
commitFn()
795+
markReadyFn()
793796
}
794797

795798
// Insert data
@@ -874,15 +877,17 @@ describe(`Query Collections`, () => {
874877
it(`should update isReady when collection status changes`, () => {
875878
let beginFn: (() => void) | undefined
876879
let commitFn: (() => void) | undefined
880+
let markReadyFn: (() => void) | undefined
877881

878882
const collection = createCollection<Person>({
879883
id: `status-change-is-ready-test`,
880884
getKey: (person: Person) => person.id,
881885
startSync: false,
882886
sync: {
883-
sync: ({ begin, commit }) => {
887+
sync: ({ begin, commit, markReady }) => {
884888
beginFn = begin
885889
commitFn = commit
890+
markReadyFn = markReady
886891
// Don't sync immediately
887892
},
888893
},
@@ -904,10 +909,71 @@ describe(`Query Collections`, () => {
904909

905910
expect(query.isReady).toBe(false)
906911
collection.preload()
907-
if (beginFn && commitFn) {
912+
if (beginFn && commitFn && markReadyFn) {
913+
beginFn()
914+
commitFn()
915+
markReadyFn()
916+
}
917+
collection.insert({
918+
id: `1`,
919+
name: `John Doe`,
920+
age: 35,
921+
922+
isActive: true,
923+
team: `team1`,
924+
})
925+
flushSync()
926+
expect(query.isReady).toBe(true)
927+
})
928+
})
929+
930+
it(`should update isLoading when collection status changes`, () => {
931+
let beginFn: (() => void) | undefined
932+
let commitFn: (() => void) | undefined
933+
let markReadyFn: (() => void) | undefined
934+
935+
const collection = createCollection<Person>({
936+
id: `status-change-is-loading-test`,
937+
getKey: (person: Person) => person.id,
938+
startSync: false,
939+
sync: {
940+
sync: ({ begin, commit, markReady }) => {
941+
beginFn = begin
942+
commitFn = commit
943+
markReadyFn = markReady
944+
// Don't sync immediately
945+
},
946+
},
947+
onInsert: () => Promise.resolve(),
948+
onUpdate: () => Promise.resolve(),
949+
onDelete: () => Promise.resolve(),
950+
})
951+
952+
cleanup = $effect.root(() => {
953+
const query = useLiveQuery((q) =>
954+
q
955+
.from({ persons: collection })
956+
.where(({ persons }) => gt(persons.age, 30))
957+
.select(({ persons }) => ({
958+
id: persons.id,
959+
name: persons.name,
960+
}))
961+
)
962+
963+
// Initially should be true
964+
expect(query.isLoading).toBe(true)
965+
966+
// Start sync manually
967+
collection.preload()
968+
969+
// Trigger the first commit to make collection ready
970+
if (beginFn && commitFn && markReadyFn) {
908971
beginFn()
909972
commitFn()
973+
markReadyFn()
910974
}
975+
976+
// Insert data
911977
collection.insert({
912978
id: `1`,
913979
name: `John Doe`,
@@ -916,8 +982,16 @@ describe(`Query Collections`, () => {
916982
isActive: true,
917983
team: `team1`,
918984
})
985+
919986
flushSync()
987+
988+
expect(query.isLoading).toBe(false)
920989
expect(query.isReady).toBe(true)
990+
991+
// Wait for collection to become ready
992+
flushSync()
993+
expect(query.isLoading).toBe(false)
994+
expect(query.status).toBe(`ready`)
921995
})
922996
})
923997

@@ -973,9 +1047,12 @@ describe(`Query Collections`, () => {
9731047
getKey: (person: Person) => person.id,
9741048
startSync: false,
9751049
sync: {
976-
sync: ({ begin, commit }) => {
1050+
sync: ({ begin, commit, markReady }) => {
9771051
personBeginFn = begin
978-
personCommitFn = commit
1052+
personCommitFn = () => {
1053+
commit()
1054+
markReady()
1055+
}
9791056
// Don't sync immediately
9801057
},
9811058
},
@@ -990,9 +1067,12 @@ describe(`Query Collections`, () => {
9901067
getKey: (issue: Issue) => issue.id,
9911068
startSync: false,
9921069
sync: {
993-
sync: ({ begin, commit }) => {
1070+
sync: ({ begin, commit, markReady }) => {
9941071
issueBeginFn = begin
995-
issueCommitFn = commit
1072+
issueCommitFn = () => {
1073+
commit()
1074+
markReady()
1075+
}
9961076
// Don't sync immediately
9971077
},
9981078
},
@@ -1044,7 +1124,7 @@ describe(`Query Collections`, () => {
10441124
})
10451125
})
10461126

1047-
it(`should handle isReady with parameterized queries`, async () => {
1127+
it(`should handle isReady with parameterized queries`, () => {
10481128
let beginFn: (() => void) | undefined
10491129
let commitFn: (() => void) | undefined
10501130

@@ -1053,9 +1133,12 @@ describe(`Query Collections`, () => {
10531133
getKey: (person: Person) => person.id,
10541134
startSync: false,
10551135
sync: {
1056-
sync: ({ begin, commit }) => {
1136+
sync: ({ begin, commit, markReady }) => {
10571137
beginFn = begin
1058-
commitFn = commit
1138+
commitFn = () => {
1139+
commit()
1140+
markReady()
1141+
}
10591142
// Don't sync immediately
10601143
},
10611144
},

packages/vue-db/src/useLiveQuery.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,10 @@ export function useLiveQuery(
230230

231231
if (isCollection) {
232232
// It's already a collection, ensure sync is started for Vue hooks
233-
unwrappedParam.startSyncImmediate()
233+
// Only start sync if the collection is in idle state
234+
if (unwrappedParam.status === `idle`) {
235+
unwrappedParam.startSyncImmediate()
236+
}
234237
return unwrappedParam
235238
}
236239

0 commit comments

Comments
 (0)