Skip to content

Commit defc2c2

Browse files
committed
Fix #109 jsonGroupArray emitting redundant primary key check if specified in filter argument
1 parent 53dd31b commit defc2c2

File tree

2 files changed

+60
-3
lines changed

2 files changed

+60
-3
lines changed

Sources/StructuredQueriesCore/SQLite/JSONFunctions.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -180,11 +180,12 @@ extension PrimaryKeyedTableDefinition where QueryValue: _OptionalProtocol & Coda
180180
filter: (some QueryExpression<Bool>)? = Bool?.none
181181
) -> some QueryExpression<[Wrapped].JSONRepresentation>
182182
where QueryValue == Wrapped? {
183+
let primaryKeyCheck = self.primaryKey.isNot(nil)
183184
let filterQueryFragment =
184-
if let filter {
185-
self.primaryKey.isNot(nil).and(filter).queryFragment
185+
if let filter, filter.queryFragment != primaryKeyCheck.queryFragment {
186+
primaryKeyCheck.and(filter).queryFragment
186187
} else {
187-
self.primaryKey.isNot(nil).queryFragment
188+
primaryKeyCheck.queryFragment
188189
}
189190
return AggregateFunction(
190191
"json_group_array",

Tests/StructuredQueriesTests/JSONFunctionsTests.swift

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import Dependencies
22
import Foundation
33
import InlineSnapshotTesting
44
import StructuredQueries
5+
import StructuredQueriesTestSupport
56
import StructuredQueriesSQLite
67
import Testing
78

@@ -212,6 +213,61 @@ extension SnapshotTests {
212213
}
213214
}
214215

216+
@Test func jsonAssociation_Filtering() throws {
217+
let noFilterSpecified = Reminder
218+
.group(by: \.id)
219+
.leftJoin(ReminderTag.all) { $0.id.eq($1.reminderID) }
220+
.leftJoin(Tag.all) { $1.tagID.eq($2.id) }
221+
.leftJoin(User.all) { $0.assignedUserID.eq($3.id) }
222+
.select { reminder, _, tag, user in
223+
ReminderRow.Columns(
224+
assignedUser: user,
225+
reminder: reminder,
226+
tags: tag.jsonGroupArray()
227+
)
228+
}
229+
230+
let tagIdNotNilFilterSpecified = Reminder
231+
.group(by: \.id)
232+
.leftJoin(ReminderTag.all) { $0.id.eq($1.reminderID) }
233+
.leftJoin(Tag.all) { $1.tagID.eq($2.id) }
234+
.leftJoin(User.all) { $0.assignedUserID.eq($3.id) }
235+
.select { reminder, _, tag, user in
236+
ReminderRow.Columns(
237+
assignedUser: user,
238+
reminder: reminder,
239+
tags: tag.jsonGroupArray(filter: tag.id.isNot(nil))
240+
)
241+
}
242+
243+
#expect(noFilterSpecified.query == tagIdNotNilFilterSpecified.query)
244+
245+
let otherFilterSpecified = Reminder
246+
.group(by: \.id)
247+
.leftJoin(ReminderTag.all) { $0.id.eq($1.reminderID) }
248+
.leftJoin(Tag.all) { $1.tagID.eq($2.id) }
249+
.leftJoin(User.all) { $0.assignedUserID.eq($3.id) }
250+
.select { reminder, _, tag, user in
251+
ReminderRow.Columns(
252+
assignedUser: user,
253+
reminder: reminder,
254+
tags: tag.jsonGroupArray(filter: tag.id.eq(4))
255+
)
256+
}
257+
258+
assertInlineSnapshot(of: otherFilterSpecified, as: .sql) {
259+
"""
260+
SELECT "users"."id", "users"."name" AS "assignedUser", "reminders"."id", "reminders"."assignedUserID", "reminders"."dueDate", "reminders"."isCompleted", "reminders"."isFlagged", "reminders"."notes", "reminders"."priority", "reminders"."remindersListID", "reminders"."title", "reminders"."updatedAt" AS "reminder", json_group_array(CASE WHEN ("tags"."id" IS NOT NULL) THEN json_object('id', json_quote("tags"."id"), 'title', json_quote("tags"."title")) END) FILTER (WHERE (("tags"."id" IS NOT NULL) AND ("tags"."id" = 4))) AS "tags"
261+
FROM "reminders"
262+
LEFT JOIN "remindersTags" ON ("reminders"."id" = "remindersTags"."reminderID")
263+
LEFT JOIN "tags" ON ("remindersTags"."tagID" = "tags"."id")
264+
LEFT JOIN "users" ON ("reminders"."assignedUserID" = "users"."id")
265+
GROUP BY "reminders"."id"
266+
"""
267+
}
268+
269+
}
270+
215271
@Test func jsonAssociation_RemindersList() throws {
216272
assertQuery(
217273
RemindersList

0 commit comments

Comments
 (0)