Skip to content

Commit ce7e2b2

Browse files
duailibekevin-dp
andauthored
Fix joins using conditions with computed values (#595)
* skip join optimization when joining with a computed value * changeset * Rephrased comment --------- Co-authored-by: Kevin De Porre <[email protected]>
1 parent 59b406e commit ce7e2b2

File tree

3 files changed

+36
-2
lines changed

3 files changed

+36
-2
lines changed

.changeset/five-waves-rule.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@tanstack/db": patch
3+
---
4+
5+
Fix joins using conditions with computed values (such as `concat()`)

packages/db/src/query/compiler/joins.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,12 @@ function processJoin(
204204
lazyFrom.type === `queryRef` &&
205205
(lazyFrom.query.limit || lazyFrom.query.offset)
206206

207-
if (!limitedSubquery) {
207+
// If join expressions contain computed values (like concat functions)
208+
// we don't optimize the join because we don't have an index over the computed values
209+
const hasComputedJoinExpr =
210+
mainExpr.type === `func` || joinedExpr.type === `func`
211+
212+
if (!limitedSubquery && !hasComputedJoinExpr) {
208213
// This join can be optimized by having the active collection
209214
// dynamically load keys into the lazy collection
210215
// based on the value of the joinKey and by looking up

packages/db/tests/query/join.test.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { beforeEach, describe, expect, test } from "vitest"
2-
import { createLiveQueryCollection, eq } from "../../src/query/index.js"
2+
import { concat, createLiveQueryCollection, eq } from "../../src/query/index.js"
33
import { createCollection } from "../../src/collection/index.js"
44
import { mockSyncCollectionOptions } from "../utils.js"
55

@@ -948,6 +948,30 @@ function createJoinTests(autoIndex: `off` | `eager`): void {
948948
const alice = results.find((r) => r.user_name === `Alice`)
949949
expect(alice?.department_name).toBe(`Engineering`)
950950
})
951+
952+
test(`should handle joins with computed expressions`, () => {
953+
const joinQuery = createLiveQueryCollection({
954+
startSync: true,
955+
query: (q) =>
956+
q
957+
.from({ user: usersCollection })
958+
.join(
959+
{ dept: departmentsCollection },
960+
({ user, dept }) =>
961+
eq(
962+
concat(`dept`, user.department_id),
963+
concat(`dept`, dept.id)
964+
),
965+
`inner`
966+
)
967+
.select(({ user, dept }) => ({
968+
user_name: user.name,
969+
department_name: dept.name,
970+
})),
971+
})
972+
973+
expect(joinQuery.size).toBe(3)
974+
})
951975
})
952976

953977
test(`should handle chained joins with incremental updates`, () => {

0 commit comments

Comments
 (0)