Skip to content

Commit f1cf5e4

Browse files
committed
Where.{and,or,not}() fixes
When called with a predicate-less `Where` it could lead to invalid SQL.
1 parent 2d9f1d9 commit f1cf5e4

File tree

2 files changed

+82
-1
lines changed

2 files changed

+82
-1
lines changed

Sources/StructuredQueriesCore/Statements/Where.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,8 @@ extension Where: SelectStatement {
357357
/// - Parameter other: Another where clause.
358358
/// - Returns: A where clause that `AND`s the given where clauses together.
359359
public func and(_ other: Self) -> Self {
360+
guard !predicates.isEmpty else { return other }
361+
guard !other.predicates.isEmpty else { return self }
360362
var `where` = self
361363
`where`.predicates = [
362364
"""
@@ -373,6 +375,8 @@ extension Where: SelectStatement {
373375
/// - Parameter other: Another where clause.
374376
/// - Returns: A where clause that `OR`s the given where clauses together.
375377
public func or(_ other: Self) -> Self {
378+
guard !predicates.isEmpty else { return other }
379+
guard !other.predicates.isEmpty else { return self }
376380
var `where` = self
377381
`where`.predicates = [
378382
"""
@@ -389,7 +393,9 @@ extension Where: SelectStatement {
389393
/// - Returns: A where clause that `NOT`s this where clause.
390394
public func not() -> Self {
391395
var `where` = self
392-
`where`.predicates = ["NOT (\(`where`.predicates.joined(separator: " AND ")))"]
396+
`where`.predicates = [
397+
"NOT (\(predicates.isEmpty ? "1" : predicates.joined(separator: " AND ")))"
398+
]
393399
return `where`
394400
}
395401

Tests/StructuredQueriesTests/WhereTests.swift

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,36 @@ extension SnapshotTests {
4040
└───┘
4141
"""
4242
}
43+
assertQuery(
44+
Reminder.all.and(Reminder.where(\.isFlagged)).count()
45+
) {
46+
"""
47+
SELECT count(*)
48+
FROM "reminders"
49+
WHERE "reminders"."isFlagged"
50+
"""
51+
} results: {
52+
"""
53+
┌───┐
54+
│ 2 │
55+
└───┘
56+
"""
57+
}
58+
assertQuery(
59+
Reminder.where(\.isFlagged).and(Reminder.all).count()
60+
) {
61+
"""
62+
SELECT count(*)
63+
FROM "reminders"
64+
WHERE "reminders"."isFlagged"
65+
"""
66+
} results: {
67+
"""
68+
┌───┐
69+
│ 2 │
70+
└───┘
71+
"""
72+
}
4373
}
4474

4575
@Test(.snapshots(record: .never)) func emptyResults() {
@@ -93,6 +123,36 @@ extension SnapshotTests {
93123
└───┘
94124
"""
95125
}
126+
assertQuery(
127+
Reminder.all.or(Reminder.where(\.isFlagged)).count()
128+
) {
129+
"""
130+
SELECT count(*)
131+
FROM "reminders"
132+
WHERE "reminders"."isFlagged"
133+
"""
134+
}results: {
135+
"""
136+
┌───┐
137+
│ 2 │
138+
└───┘
139+
"""
140+
}
141+
assertQuery(
142+
Reminder.where(\.isFlagged).or(Reminder.all).count()
143+
) {
144+
"""
145+
SELECT count(*)
146+
FROM "reminders"
147+
WHERE "reminders"."isFlagged"
148+
"""
149+
}results: {
150+
"""
151+
┌───┐
152+
│ 2 │
153+
└───┘
154+
"""
155+
}
96156
}
97157

98158
@Test func not() {
@@ -128,6 +188,21 @@ extension SnapshotTests {
128188
└───┘
129189
"""
130190
}
191+
assertQuery(
192+
Reminder.all.not().count()
193+
) {
194+
"""
195+
SELECT count(*)
196+
FROM "reminders"
197+
WHERE NOT (1)
198+
"""
199+
} results: {
200+
"""
201+
┌───┐
202+
│ 0 │
203+
└───┘
204+
"""
205+
}
131206
}
132207

133208
@Test func optionalBoolean() throws {

0 commit comments

Comments
 (0)