Skip to content

Commit a430fb8

Browse files
authored
Merge branch 'main' into query-fragment-segments
2 parents 79210ad + 073c8ae commit a430fb8

File tree

8 files changed

+124
-32
lines changed

8 files changed

+124
-32
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ jobs:
3434
strategy:
3535
matrix:
3636
swift:
37+
- '6.0'
3738
- '6.1'
3839
runs-on: ubuntu-latest
3940
container: swift:${{ matrix.swift }}

Sources/StructuredQueries/Macros.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,3 +132,10 @@ public macro sql<QueryValue>(
132132
as queryValueType: QueryValue.Type = QueryValue.self
133133
) -> SQLQueryExpression<QueryValue> =
134134
#externalMacro(module: "StructuredQueriesMacros", type: "SQLMacro")
135+
136+
@freestanding(expression)
137+
public macro sql(
138+
_ queryFragment: QueryFragment,
139+
as queryValueType: Any.Type = Any.self
140+
) -> SQLQueryExpression<Any> =
141+
#externalMacro(module: "StructuredQueriesMacros", type: "SQLMacro")

Sources/StructuredQueriesCore/Documentation.docc/Extensions/QueryExpression.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,8 @@
2828
2929
- ``jsonArrayLength()``
3030
- ``jsonGroupArray(order:filter:)``
31+
32+
### Optionality
33+
34+
- ``map(_:)``
35+
- ``flatMap(_:)``

Sources/StructuredQueriesCore/Internal/Deprecations.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ extension Table {
8989
or conflictResolution: ConflictResolution? = nil,
9090
_ columns: (TableColumns) -> (TableColumn<Self, V1>, repeat TableColumn<Self, each V2>),
9191
select selection: () -> Select<(C1, repeat each C2), From, Joins>,
92-
onConflict updates: ((inout Updates<Self>) -> Void)?,
92+
onConflict updates: ((inout Updates<Self>) -> Void)?
9393
) -> InsertOf<Self>
9494
where C1.QueryValue == V1, (repeat (each C2).QueryValue) == (repeat each V2) {
9595
insert(or: conflictResolution, columns, select: selection, onConflictDoUpdate: updates)

Sources/StructuredQueriesCore/Optional.swift

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,3 +137,43 @@ where Wrapped.TableColumns: PrimaryKeyedTableDefinition {
137137
self[dynamicMember: \.primaryKey]
138138
}
139139
}
140+
141+
extension QueryExpression where QueryValue: _OptionalProtocol {
142+
/// Creates and optionalizes a new expression from this one by applying an unwrapped version of
143+
/// this expression to a given closure.
144+
///
145+
/// ```swift
146+
/// Reminder.where {
147+
/// $0.dueDate.map { $0 > Date() }
148+
/// }
149+
/// // SELECT … FROM "reminders"
150+
/// // WHERE "reminders"."dueDate" > '2018-01-29 00:08:00.000'
151+
/// ```
152+
///
153+
/// - Parameter transform: A closure that takes an unwrapped version of this expression.
154+
/// - Returns: The result of the transform function, optionalized.
155+
public func map<T>(
156+
_ transform: (SQLQueryExpression<QueryValue.Wrapped>) -> some QueryExpression<T>
157+
) -> some QueryExpression<T?> {
158+
SQLQueryExpression(transform(SQLQueryExpression(queryFragment)).queryFragment)
159+
}
160+
161+
/// Creates a new optional expression from this one by applying an unwrapped version of this
162+
/// expression to a given closure.
163+
///
164+
/// ```swift
165+
/// Reminder.select {
166+
/// $0.dueDate.flatMap { $0.max() }
167+
/// }
168+
/// // SELECT max("reminders"."dueDate") FROM "reminders"
169+
/// // => [Date?]
170+
/// ```
171+
///
172+
/// - Parameter transform: A closure that takes an unwrapped version of this expression.
173+
/// - Returns: The result of the transform function.
174+
public func flatMap<T>(
175+
_ transform: (SQLQueryExpression<QueryValue.Wrapped>) -> some QueryExpression<T?>
176+
) -> some QueryExpression<T?> {
177+
SQLQueryExpression(transform(SQLQueryExpression(queryFragment)).queryFragment)
178+
}
179+
}

Sources/StructuredQueriesCore/Statements/Select.swift

Lines changed: 5 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ extension Table {
212212
/// - Returns: A select statement that groups by the given column.
213213
public static func group<C: QueryExpression>(
214214
by grouping: (TableColumns) -> C
215-
) -> SelectOf<Self> where C.QueryValue: QueryDecodable {
215+
) -> SelectOf<Self> {
216216
Where().group(by: grouping)
217217
}
218218

@@ -226,12 +226,7 @@ extension Table {
226226
each C3: QueryExpression
227227
>(
228228
by grouping: (TableColumns) -> (C1, C2, repeat each C3)
229-
) -> SelectOf<Self>
230-
where
231-
C1.QueryValue: QueryDecodable,
232-
C2.QueryValue: QueryDecodable,
233-
repeat (each C3).QueryValue: QueryDecodable
234-
{
229+
) -> SelectOf<Self> {
235230
Where().group(by: grouping)
236231
}
237232

@@ -1182,8 +1177,7 @@ extension Select {
11821177
/// - Returns: A new select statement that groups by the given column.
11831178
public func group<C: QueryExpression, each J: Table>(
11841179
by grouping: (From.TableColumns, repeat (each J).TableColumns) -> C
1185-
) -> Self
1186-
where C.QueryValue: QueryDecodable, Joins == (repeat each J) {
1180+
) -> Self where Joins == (repeat each J) {
11871181
_group(by: grouping)
11881182
}
11891183

@@ -1199,13 +1193,7 @@ extension Select {
11991193
each J: Table
12001194
>(
12011195
by grouping: (From.TableColumns, repeat (each J).TableColumns) -> (C1, C2, repeat each C3)
1202-
) -> Self
1203-
where
1204-
C1.QueryValue: QueryDecodable,
1205-
C2.QueryValue: QueryDecodable,
1206-
repeat (each C3).QueryValue: QueryDecodable,
1207-
Joins == (repeat each J)
1208-
{
1196+
) -> Self where Joins == (repeat each J) {
12091197
_group(by: grouping)
12101198
}
12111199

@@ -1214,11 +1202,7 @@ extension Select {
12141202
each J: Table
12151203
>(
12161204
by grouping: (From.TableColumns, repeat (each J).TableColumns) -> (repeat each C)
1217-
) -> Self
1218-
where
1219-
repeat (each C).QueryValue: QueryDecodable,
1220-
Joins == (repeat each J)
1221-
{
1205+
) -> Self where Joins == (repeat each J) {
12221206
var select = self
12231207
select.group
12241208
.append(

Sources/StructuredQueriesCore/Statements/Where.swift

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -387,22 +387,16 @@ extension Where: SelectStatement {
387387
}
388388

389389
/// A select statement for the filtered table grouped by the given column.
390-
public func group<C: QueryExpression>(by grouping: (From.TableColumns) -> C) -> Select<
391-
(), From, ()
392-
>
393-
where C.QueryValue: QueryDecodable {
390+
public func group<C: QueryExpression>(
391+
by grouping: (From.TableColumns) -> C
392+
) -> Select<(), From, ()> {
394393
asSelect().group(by: grouping)
395394
}
396395

397396
/// A select statement for the filtered table grouped by the given columns.
398397
public func group<C1: QueryExpression, C2: QueryExpression, each C3: QueryExpression>(
399398
by grouping: (From.TableColumns) -> (C1, C2, repeat each C3)
400-
) -> SelectOf<From>
401-
where
402-
C1.QueryValue: QueryDecodable,
403-
C2.QueryValue: QueryDecodable,
404-
repeat (each C3).QueryValue: QueryDecodable
405-
{
399+
) -> SelectOf<From> {
406400
asSelect().group(by: grouping)
407401
}
408402

Tests/StructuredQueriesTests/SelectTests.swift

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -644,6 +644,23 @@ extension SnapshotTests {
644644
└───────┴───┘
645645
"""
646646
}
647+
648+
assertQuery(
649+
Reminder.select { ($0.isCompleted, $0.id.count()) }.group { #sql("\($0.isCompleted)") }
650+
) {
651+
"""
652+
SELECT "reminders"."isCompleted", count("reminders"."id")
653+
FROM "reminders"
654+
GROUP BY "reminders"."isCompleted"
655+
"""
656+
} results: {
657+
"""
658+
┌───────┬───┐
659+
│ false │ 7 │
660+
│ true │ 3 │
661+
└───────┴───┘
662+
"""
663+
}
647664
}
648665

649666
@Test func having() {
@@ -1153,6 +1170,50 @@ extension SnapshotTests {
11531170
"""
11541171
}
11551172
}
1173+
1174+
@Test func optionalMapAndFlatMap() {
1175+
do {
1176+
let query: some Statement<Bool?> = Reminder.select {
1177+
$0.priority.map { $0 < Priority.high }
1178+
}
1179+
assertQuery(query) {
1180+
"""
1181+
SELECT ("reminders"."priority" < 3)
1182+
FROM "reminders"
1183+
"""
1184+
} results: {
1185+
"""
1186+
┌───────┐
1187+
│ nil │
1188+
│ nil │
1189+
│ false │
1190+
│ nil │
1191+
│ nil │
1192+
│ false │
1193+
│ true │
1194+
│ false │
1195+
│ nil │
1196+
│ true │
1197+
└───────┘
1198+
"""
1199+
}
1200+
}
1201+
do {
1202+
let query: some Statement<Int?> = Reminder.select { $0.priority.flatMap { $0.max() } }
1203+
assertQuery(query) {
1204+
"""
1205+
SELECT max("reminders"."priority")
1206+
FROM "reminders"
1207+
"""
1208+
} results: {
1209+
"""
1210+
┌───┐
1211+
│ 3 │
1212+
└───┘
1213+
"""
1214+
}
1215+
}
1216+
}
11561217
}
11571218
}
11581219

0 commit comments

Comments
 (0)