Skip to content

Commit df371c3

Browse files
KyleAMathewsclaude
andcommitted
fix: reject startAfter on multi-source (join) effects
Cursor gate state is global to the effect, so a cursor from one source collection could incorrectly open the gate for another. Validate at construction time that startAfter is only used with single-source effects until per-source cursor tracking is implemented. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 653eceb commit df371c3

File tree

2 files changed

+28
-0
lines changed

2 files changed

+28
-0
lines changed

packages/db/src/query/effect.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,16 @@ class EffectPipelineRunner<TRow extends object, TKey extends string | number> {
410410
this.collections = extractCollectionsFromQuery(this.query)
411411
const aliasesById = extractCollectionAliases(this.query)
412412

413+
if (
414+
config.startAfter !== undefined &&
415+
Object.keys(this.collections).length > 1
416+
) {
417+
throw new Error(
418+
`startAfter is only supported for single-source effects. ` +
419+
`This effect queries ${Object.keys(this.collections).length} collections.`,
420+
)
421+
}
422+
413423
// Build alias → collection map
414424
this.collectionByAlias = {}
415425
for (const [collectionId, aliases] of aliasesById.entries()) {

packages/db/tests/effect.test.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -568,6 +568,24 @@ describe(`createEffect`, () => {
568568

569569
await effect.dispose()
570570
})
571+
572+
it(`should throw when startAfter is used with multi-source effects`, () => {
573+
const users = createUsersCollection()
574+
const issues = createIssuesCollection()
575+
576+
expect(() => {
577+
createEffect({
578+
query: (q) =>
579+
q
580+
.from({ issue: issues })
581+
.join({ user: users }, ({ issue, user }) =>
582+
eq(issue.userId, user.id),
583+
),
584+
onBatch: () => {},
585+
startAfter: 1,
586+
})
587+
}).toThrow(/single-source/)
588+
})
571589
})
572590

573591
describe(`filtered queries`, () => {

0 commit comments

Comments
 (0)