Skip to content

Commit 5d7bcc6

Browse files
committed
Add QueryExpression<Optional>.map,flatMap
This PR adds helpers that make it a little easier to work with optional query expressions in a builder. For example, if you want to execute a `LIKE` operator on an optional string, you currently have to resort to one of the following workarounds: ```swift .where { ($0.title ?? "").like("%foo%") } // or: .where { #sql("\($0.title) LIKE '%foo%') } ``` This PR introduces `map` and `flatMap` operations on optional `QueryExpression`s that unwraps the expression, giving you additional flexibility in how you express your builder code: ```swift .where { $0.title.map { $0.like("%foo%") } ?? false } ``` While this is more code than the above options, some may prefer its readability, and should we merge the other optional helpers from #61, it could be further shortened: ```swift .where { $0.title.map { $0.like("%foo%") } } ```
1 parent ea20f9c commit 5d7bcc6

File tree

2 files changed

+45
-0
lines changed

2 files changed

+45
-0
lines changed

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/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+
}

0 commit comments

Comments
 (0)