Skip to content

Commit 639bc6a

Browse files
committed
Compile SQLKit under Embedded Swift
Motivation: Embedded Swift has no Codable, no reflection, no existential metatypes, and no `_StringProcessing`. A number of SQLKit declarations depend on one of those and are the only thing standing between the SwiftNIO-free configuration and a `wasm32-unknown-wasip1-embedded` build. The bound-parameter constraint is the interesting case. SQLKit spells it `Encodable`, but SQLKit itself never encodes a bound value: `SQLBind` hands the existential to `SQLSerializer.write(bind:)`, which appends it to `binds` and emits a placeholder. The constraint is a marker, and the actual extraction happens in the driver. That makes a vacuous `#if hasFeature(Embedded) public protocol Encodable {}` shim look attractive — it would leave every use site unchanged. It does not work. The marker exists precisely to carry a value across the module boundary to a driver that must get the value back out, and a protocol with no requirements carries nothing: under Embedded there is no `encode(to:)` to call, no reflection, and no dynamic cast to fall back on, so the bind path would compile and then be inert. Shadowing `Swift.Encodable` in a public signature would also collide with the same shim in other modules and cannot be made `internal`, because the constraint appears in public and `@inlinable` declarations. Modifications: Introduce `SQLBindable`, the constraint used for bound parameter values. It is `typealias SQLBindable = Encodable` except under Embedded Swift, where it resolves to a new lightweight `SQLBindValue` protocol carrying a driver-neutral `SQLDataValue`, with conformances for the standard primitives. `SQLBindValue` is what replaces `encode(to:)` for the driver. The public declarations that spelled `some`/`any Encodable & Sendable` for a bound value now spell `some`/`any SQLBindable & Sendable`. Off Embedded that is the same type, so this is source- and ABI-compatible. Declarations that take a Codable *model* rather than a bound value keep saying `Encodable`; they live inside `!hasFeature(Embedded)` regions, where the two spellings are identical anyway. Everything else is elision: - Gate the Codable engine (`SQLQueryEncoder`, `SQLRowDecoder`, `SomeCodingKey`, the `SQLCodingUtilities` helpers, and the model-shaped builder overloads `set(model:)` / `insert(models:)` / `decode(model:)`) behind `#if !hasFeature(Embedded)`. - Move the generic `withSession(_:)` protocol requirement to an extension default under Embedded: a generic method cannot go in a witness table there, which would otherwise make `any SQLDatabase` unusable. - Replace reflection- and existential-dependent paths (metatype casts in `SQLDatabaseReportedVersion` and the deprecated shims, description formatting in `SQLSerializer`/`SQLQueryString`, the `as?`-based `LIMIT 1` optimization in `first()`) with Embedded-safe equivalents. - `StringHandling`: `trimmingPrefix(_:)` and the regex-backed replacement helper come from `_StringProcessing`, which the Embedded stdlib does not ship; fall through to the existing hand-rolled implementations there. - `SQLKitBenchmark` needs XCTest and Codable, so the whole target's contents are gated on `!hasFeature(Embedded)`. Every `#if` encloses the doc comment of the declaration it gates rather than sitting between the two, which would detach the comment and silently empty the published documentation for that symbol. Result: SQLKit compiles for `wasm32-unknown-wasip1-embedded`. On every other target the only change to the generated symbol graph is the added `SQLBindable` typealias: every other symbol is still present, with byte-identical `docComment` line counts, and `diagnose-api-breaking-changes` reports no differences. Building for the Embedded target additionally requires an Embedded-clean `apple/swift-log`; see the pull request description.
1 parent 84ba06c commit 639bc6a

45 files changed

Lines changed: 320 additions & 163 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Sources/SQLKit/Builders/Implementations/SQLAlterTableBuilder.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,9 @@ public final class SQLAlterTableBuilder: SQLQueryBuilder {
4545
@inlinable
4646
@discardableResult
4747
public func column(_ column: String, type dataType: SQLDataType, _ constraints: [SQLColumnConstraintAlgorithm]) -> Self {
48-
self.column(SQLIdentifier(column), type: dataType, constraints)
48+
// Box each element explicitly: the implicit `[Concrete]`→`[any SQLExpression]` array
49+
// conversion is a dynamic cast, which Embedded Swift forbids.
50+
self.column(SQLIdentifier(column), type: dataType, constraints.map { $0 as any SQLExpression })
4951
}
5052

5153
/// Add a new column to the table.
@@ -81,7 +83,7 @@ public final class SQLAlterTableBuilder: SQLQueryBuilder {
8183
@inlinable
8284
@discardableResult
8385
public func modifyColumn(_ column: String, type dataType: SQLDataType, _ constraints: [SQLColumnConstraintAlgorithm]) -> Self {
84-
self.modifyColumn(SQLIdentifier(column), type: dataType, constraints)
86+
self.modifyColumn(SQLIdentifier(column), type: dataType, constraints.map { $0 as any SQLExpression })
8587
}
8688

8789
/// Change an existing column's type and constraints.

Sources/SQLKit/Builders/Implementations/SQLConflictUpdateBuilder.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ public final class SQLConflictUpdateBuilder: SQLColumnUpdateBuilder, SQLPredicat
3232
return self
3333
}
3434

35+
// Codable model encoding (SQLQueryEncoder) is unavailable in Embedded Swift.
36+
#if !hasFeature(Embedded)
3537
/// Encodes the given `Encodable` value to a sequence of key-value pairs and adds an assignment
3638
/// for each pair which uses the values each column was given in the original `INSERT` query's
3739
/// `VALUES` list.
@@ -75,4 +77,5 @@ public final class SQLConflictUpdateBuilder: SQLColumnUpdateBuilder, SQLPredicat
7577
) throws -> Self {
7678
try encoder.encode(model).reduce(self) { $0.set(excludedValueOf: $1.0) }
7779
}
80+
#endif // !hasFeature(Embedded)
7881
}

Sources/SQLKit/Builders/Implementations/SQLCreateTableBuilder.swift

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public final class SQLCreateTableBuilder: SQLQueryBuilder {
3737
@inlinable
3838
@discardableResult
3939
public func column(_ column: String, type dataType: SQLDataType, _ constraints: [SQLColumnConstraintAlgorithm]) -> Self {
40-
self.column(SQLIdentifier(column), type: dataType, constraints)
40+
self.column(SQLIdentifier(column), type: dataType, constraints.map { $0 as any SQLExpression })
4141
}
4242

4343
/// Add a new column by name, type, and constraints.
@@ -66,7 +66,9 @@ public final class SQLCreateTableBuilder: SQLQueryBuilder {
6666
@inlinable
6767
@discardableResult
6868
public func column(definitions: [SQLColumnDefinition]) -> SQLCreateTableBuilder {
69-
self.columns.append(contentsOf: definitions)
69+
// Box each element explicitly: the implicit `[Concrete]`→`[any SQLExpression]` array
70+
// conversion is a dynamic cast, which Embedded Swift forbids.
71+
self.columns.append(contentsOf: definitions.map { $0 as any SQLExpression })
7072
return self
7173
}
7274

@@ -125,7 +127,9 @@ extension SQLCreateTableBuilder {
125127
@inlinable
126128
@discardableResult
127129
public func primaryKey(_ columns: [String], named constraintName: String? = nil) -> Self {
128-
self.primaryKey(columns.map(SQLIdentifier.init(_:)), named: constraintName.map(SQLIdentifier.init(_:)))
130+
// Box each element to `any SQLExpression`: the implicit `[Concrete]`/`Concrete?` →
131+
// `[any SQLExpression]`/`(any SQLExpression)?` conversions are dynamic casts (forbidden in embedded).
132+
self.primaryKey(columns.map { SQLIdentifier($0) as any SQLExpression }, named: constraintName.map { SQLIdentifier($0) as any SQLExpression })
129133
}
130134

131135
/// Add a `PRIMARY KEY` constraint to the table.
@@ -162,7 +166,7 @@ extension SQLCreateTableBuilder {
162166
@inlinable
163167
@discardableResult
164168
public func unique(_ columns: [String], named constraintName: String? = nil) -> Self {
165-
self.unique(columns.map(SQLIdentifier.init(_:)), named: constraintName.map(SQLIdentifier.init(_:)))
169+
self.unique(columns.map { SQLIdentifier($0) as any SQLExpression }, named: constraintName.map { SQLIdentifier($0) as any SQLExpression })
166170
}
167171

168172
/// Add a `UNIQUE` constraint to the table.
@@ -188,7 +192,7 @@ extension SQLCreateTableBuilder {
188192
@inlinable
189193
@discardableResult
190194
public func check(_ expression: any SQLExpression, named constraintName: String? = nil) -> Self {
191-
self.check(expression, named: constraintName.map(SQLIdentifier.init(_:)))
195+
self.check(expression, named: constraintName.map { SQLIdentifier($0) as any SQLExpression })
192196
}
193197

194198
/// Add a `CHECK` constraint to the table.
@@ -226,10 +230,10 @@ extension SQLCreateTableBuilder {
226230
named constraintName: String? = nil
227231
) -> Self {
228232
self.foreignKey(
229-
columns.map(SQLIdentifier.init(_:)),
230-
references: SQLIdentifier(foreignTable), foreignColumns.map(SQLIdentifier.init(_:)),
233+
columns.map { SQLIdentifier($0) as any SQLExpression },
234+
references: SQLIdentifier(foreignTable), foreignColumns.map { SQLIdentifier($0) as any SQLExpression },
231235
onDelete: onDelete, onUpdate: onUpdate,
232-
named: constraintName.map(SQLIdentifier.init(_:))
236+
named: constraintName.map { SQLIdentifier($0) as any SQLExpression }
233237
)
234238
}
235239

Sources/SQLKit/Builders/Implementations/SQLCreateTriggerBuilder.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public final class SQLCreateTriggerBuilder: SQLQueryBuilder {
5252
@inlinable
5353
@discardableResult
5454
public func columns(_ columns: [String]) -> Self {
55-
self.columns(columns.map(SQLIdentifier.init(_:)))
55+
self.columns(columns.map { SQLIdentifier($0) as any SQLExpression })
5656
}
5757

5858
/// Specify the columns to which the trigger applies.

Sources/SQLKit/Builders/Implementations/SQLInsertBuilder.swift

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ public final class SQLInsertBuilder: SQLQueryBuilder, SQLReturningBuilder/*, SQL
3939
self.database = database
4040
}
4141

42+
// Codable model encoding (SQLQueryEncoder) is unavailable in Embedded Swift.
43+
#if !hasFeature(Embedded)
4244
/// Use an `Encodable` value to generate a row to insert and add that row to the query.
4345
///
4446
/// Example usage:
@@ -216,7 +218,8 @@ public final class SQLInsertBuilder: SQLQueryBuilder, SQLReturningBuilder/*, SQL
216218
}
217219
return self
218220
}
219-
221+
#endif // !hasFeature(Embedded)
222+
220223
/// Specify mutiple columns to be included in the list of columns for the query.
221224
///
222225
/// Overwrites any previously specified column list.
@@ -232,7 +235,7 @@ public final class SQLInsertBuilder: SQLQueryBuilder, SQLReturningBuilder/*, SQL
232235
@inlinable
233236
@discardableResult
234237
public func columns(_ columns: [String]) -> Self {
235-
self.columns(columns.map(SQLIdentifier.init(_:)))
238+
self.columns(columns.map { SQLIdentifier($0) as any SQLExpression })
236239
}
237240

238241
/// Specify mutiple columns to be included in the list of columns for the query.
@@ -258,15 +261,15 @@ public final class SQLInsertBuilder: SQLQueryBuilder, SQLReturningBuilder/*, SQL
258261
@inlinable
259262
@discardableResult
260263
@_disfavoredOverload
261-
public func values(_ values: any Encodable & Sendable...) -> Self {
264+
public func values(_ values: any SQLBindable & Sendable...) -> Self {
262265
self.values(values)
263266
}
264267

265268
/// Add a set of values to be inserted as a single row.
266269
@inlinable
267270
@discardableResult
268-
public func values(_ values: [any Encodable & Sendable]) -> Self {
269-
self.values(values.map { SQLBind($0) })
271+
public func values(_ values: [any SQLBindable & Sendable]) -> Self {
272+
self.values(values.map { SQLBind($0) as any SQLExpression })
270273
}
271274

272275
/// Add a set of values to be inserted as a single row.
@@ -334,7 +337,7 @@ public final class SQLInsertBuilder: SQLQueryBuilder, SQLReturningBuilder/*, SQL
334337
@inlinable
335338
@discardableResult
336339
public func ignoringConflicts(with targetColumns: [String] = []) -> Self {
337-
self.ignoringConflicts(with: targetColumns.map(SQLIdentifier.init(_:)))
340+
self.ignoringConflicts(with: targetColumns.map { SQLIdentifier($0) as any SQLExpression })
338341
}
339342

340343
/// Specify that constraint violations for the key over the given columns should cause the conflicting
@@ -365,7 +368,7 @@ public final class SQLInsertBuilder: SQLQueryBuilder, SQLReturningBuilder/*, SQL
365368
with targetColumns: [String] = [],
366369
`do` updatePredicate: (SQLConflictUpdateBuilder) throws -> SQLConflictUpdateBuilder
367370
) rethrows -> Self {
368-
try self.onConflict(with: targetColumns.map(SQLIdentifier.init(_:)), do: updatePredicate)
371+
try self.onConflict(with: targetColumns.map { SQLIdentifier($0) as any SQLExpression }, do: updatePredicate)
369372
}
370373

371374
/// Specify that constraint violations for the key over the given column should cause the conflicting

Sources/SQLKit/Builders/Prototypes/SQLColumnUpdateBuilder.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ public protocol SQLColumnUpdateBuilder: AnyObject {
77
}
88

99
extension SQLColumnUpdateBuilder {
10+
// Codable model encoding (SQLQueryEncoder) is unavailable in Embedded Swift.
11+
#if !hasFeature(Embedded)
1012
/// Using a default-configured ``SQLQueryEncoder``, transform the provided model into a series of key/value
1113
/// pairs and add an assignment for each pair.
1214
///
@@ -66,6 +68,7 @@ extension SQLColumnUpdateBuilder {
6668
) throws -> Self {
6769
try encoder.encode(model).reduce(self) { $0.set(SQLColumn($1.0), to: $1.1) }
6870
}
71+
#endif // !hasFeature(Embedded)
6972

7073
/// Add an assignment setting the named column to the provided `Encodable` value.
7174
///
@@ -76,7 +79,7 @@ extension SQLColumnUpdateBuilder {
7679
/// - bind: The value to assign to the named column.
7780
@inlinable
7881
@discardableResult
79-
public func set(_ column: String, to bind: any Encodable & Sendable) -> Self {
82+
public func set(_ column: String, to bind: any SQLBindable & Sendable) -> Self {
8083
self.set(SQLColumn(column), to: SQLBind(bind))
8184
}
8285

@@ -102,7 +105,7 @@ extension SQLColumnUpdateBuilder {
102105
/// - bind: The value to assign to the given column.
103106
@inlinable
104107
@discardableResult
105-
public func set(_ column: any SQLExpression, to bind: any Encodable & Sendable) -> Self {
108+
public func set(_ column: any SQLExpression, to bind: any SQLBindable & Sendable) -> Self {
106109
self.set(column, to: SQLBind(bind))
107110
}
108111

Sources/SQLKit/Builders/Prototypes/SQLCommonTableExpressionBuilder.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ extension SQLCommonTableExpressionBuilder {
3434
@inlinable
3535
@discardableResult
3636
public func with(_ name: some StringProtocol, columns: [String], as query: some SQLExpression) -> Self {
37-
self.with(name, columns: columns.map(SQLIdentifier.init(_:)), as: query)
37+
self.with(name, columns: columns.map { SQLIdentifier($0) as any SQLExpression }, as: query)
3838
}
3939

4040
/// Specify a subquery to include as a _recursive_ common table expression, for use elsewhere in
@@ -70,7 +70,7 @@ extension SQLCommonTableExpressionBuilder {
7070
@inlinable
7171
@discardableResult
7272
public func with(recursive name: some StringProtocol, columns: [String], as query: some SQLExpression) -> Self {
73-
self.with(recursive: name, columns: columns.map(SQLIdentifier.init(_:)), as: query)
73+
self.with(recursive: name, columns: columns.map { SQLIdentifier($0) as any SQLExpression }, as: query)
7474
}
7575

7676
// MARK: - String name, expression columns
@@ -170,7 +170,7 @@ extension SQLCommonTableExpressionBuilder {
170170
@inlinable
171171
@discardableResult
172172
public func with(_ name: some SQLExpression, columns: [String], as query: some SQLExpression) -> Self {
173-
self.with(name, columns: columns.map(SQLIdentifier.init(_:)), as: query)
173+
self.with(name, columns: columns.map { SQLIdentifier($0) as any SQLExpression }, as: query)
174174
}
175175

176176
/// Specify a subquery to include as a _recursive_ common table expression, for use elsewhere in
@@ -206,7 +206,7 @@ extension SQLCommonTableExpressionBuilder {
206206
@inlinable
207207
@discardableResult
208208
public func with(recursive name: some SQLExpression, columns: [String], as query: some SQLExpression) -> Self {
209-
self.with(recursive: name, columns: columns.map(SQLIdentifier.init(_:)), as: query)
209+
self.with(recursive: name, columns: columns.map { SQLIdentifier($0) as any SQLExpression }, as: query)
210210
}
211211

212212
// MARK: - Expression name, expression columns

Sources/SQLKit/Builders/Prototypes/SQLPredicateBuilder.swift

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ extension SQLPredicateBuilder {
2323
/// SELECT * FROM "planets" WHERE "name" = $0 ["Earth"]
2424
@inlinable
2525
@discardableResult
26-
public func `where`(_ lhs: String, _ op: SQLBinaryOperator, _ rhs: some Encodable & Sendable) -> Self {
26+
public func `where`(_ lhs: String, _ op: SQLBinaryOperator, _ rhs: some SQLBindable & Sendable) -> Self {
2727
self.where(SQLColumn(lhs), op, SQLBind(rhs))
2828
}
2929

@@ -36,8 +36,8 @@ extension SQLPredicateBuilder {
3636
/// SELECT * FROM "planets" WHERE "name" IN ($0, $1) ["Earth", "Mars"]
3737
@inlinable
3838
@discardableResult
39-
public func `where`(_ lhs: String, _ op: SQLBinaryOperator, _ rhs: [some Encodable & Sendable]) -> Self {
40-
self.where(SQLColumn(lhs), op, SQLBind.group(rhs))
39+
public func `where`(_ lhs: String, _ op: SQLBinaryOperator, _ rhs: [some SQLBindable & Sendable]) -> Self {
40+
self.where(SQLColumn(lhs), op, SQLBind.group(rhs.map { $0 as any SQLBindable & Sendable }))
4141
}
4242

4343
/// Adds a column to encodable comparison to this builder's `WHERE` clause by `AND`ing.
@@ -49,7 +49,7 @@ extension SQLPredicateBuilder {
4949
/// SELECT * FROM "planets" WHERE "name" = $0 ["Earth"]
5050
@inlinable
5151
@discardableResult
52-
public func `where`(_ lhs: SQLIdentifier, _ op: SQLBinaryOperator, _ rhs: some Encodable & Sendable) -> Self {
52+
public func `where`(_ lhs: SQLIdentifier, _ op: SQLBinaryOperator, _ rhs: some SQLBindable & Sendable) -> Self {
5353
self.where(SQLColumn(lhs), op, SQLBind(rhs))
5454
}
5555

@@ -62,8 +62,8 @@ extension SQLPredicateBuilder {
6262
/// SELECT * FROM "planets" WHERE "name" IN ($0, $1) ["Earth", "Mars"]
6363
@inlinable
6464
@discardableResult
65-
public func `where`(_ lhs: SQLIdentifier, _ op: SQLBinaryOperator, _ rhs: [some Encodable & Sendable]) -> Self {
66-
self.where(SQLColumn(lhs), op, SQLBind.group(rhs))
65+
public func `where`(_ lhs: SQLIdentifier, _ op: SQLBinaryOperator, _ rhs: [some SQLBindable & Sendable]) -> Self {
66+
self.where(SQLColumn(lhs), op, SQLBind.group(rhs.map { $0 as any SQLBindable & Sendable }))
6767
}
6868

6969
// MARK: - Column/column comparison
@@ -154,7 +154,7 @@ extension SQLPredicateBuilder {
154154
/// SELECT * FROM "planets" WHERE "name" = $0 ["Earth"]
155155
@inlinable
156156
@discardableResult
157-
public func orWhere(_ lhs: String, _ op: SQLBinaryOperator, _ rhs: some Encodable & Sendable) -> Self {
157+
public func orWhere(_ lhs: String, _ op: SQLBinaryOperator, _ rhs: some SQLBindable & Sendable) -> Self {
158158
self.orWhere(SQLColumn(lhs), op, SQLBind(rhs))
159159
}
160160

@@ -167,22 +167,22 @@ extension SQLPredicateBuilder {
167167
/// SELECT * FROM "planets" WHERE "name" IN ($0, $1) ["Earth", "Mars"]
168168
@inlinable
169169
@discardableResult
170-
public func orWhere(_ lhs: String, _ op: SQLBinaryOperator, _ rhs: [some Encodable & Sendable]) -> Self {
171-
self.orWhere(SQLColumn(lhs), op, SQLBind.group(rhs))
170+
public func orWhere(_ lhs: String, _ op: SQLBinaryOperator, _ rhs: [some SQLBindable & Sendable]) -> Self {
171+
self.orWhere(SQLColumn(lhs), op, SQLBind.group(rhs.map { $0 as any SQLBindable & Sendable }))
172172
}
173173

174174
/// Adds a column to encodable comparison to this builder's `WHERE` clause by `OR`ing.
175175
@inlinable
176176
@discardableResult
177-
public func orWhere(_ lhs: SQLIdentifier, _ op: SQLBinaryOperator, _ rhs: some Encodable & Sendable) -> Self {
177+
public func orWhere(_ lhs: SQLIdentifier, _ op: SQLBinaryOperator, _ rhs: some SQLBindable & Sendable) -> Self {
178178
self.orWhere(SQLColumn(lhs), op, SQLBind(rhs))
179179
}
180180

181181
/// Adds a column to encodable array comparison to this builder's `WHERE` clause by `OR`ing.
182182
@inlinable
183183
@discardableResult
184-
public func orWhere(_ lhs: SQLIdentifier, _ op: SQLBinaryOperator, _ rhs: [some Encodable & Sendable]) -> Self {
185-
self.orWhere(SQLColumn(lhs), op, SQLBind.group(rhs))
184+
public func orWhere(_ lhs: SQLIdentifier, _ op: SQLBinaryOperator, _ rhs: [some SQLBindable & Sendable]) -> Self {
185+
self.orWhere(SQLColumn(lhs), op, SQLBind.group(rhs.map { $0 as any SQLBindable & Sendable }))
186186
}
187187

188188
// MARK: - Column/column comparison

Sources/SQLKit/Builders/Prototypes/SQLQueryFetcher.swift

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// `EventLoopFuture` is unavailable where SwiftNIO is not linked. The `async` `first()`/`all()`/
2-
// `run(_:)` families further down are unconditional and carry the whole surface there.
2+
// `run(_:)` families further down are unconditional and carry the whole surface there; their
3+
// `<D: Decodable>` overloads additionally drop out in Embedded Swift, which has no Codable.
34
#if canImport(NIOCore)
45
import class NIOCore.EventLoopFuture
56
#endif
@@ -80,6 +81,7 @@ extension SQLQueryFetcher {
8081
// MARK: - First (async)
8182

8283
extension SQLQueryFetcher {
84+
#if !hasFeature(Embedded)
8385
/// Returns the named column from the first output row, if any, decoded as a given type.
8486
///
8587
/// - Parameters:
@@ -129,6 +131,7 @@ extension SQLQueryFetcher {
129131
public func first<D: Decodable>(decoding type: D.Type, with decoder: SQLRowDecoder) async throws -> D? {
130132
try await self.first()?.decode(model: D.self, with: decoder)
131133
}
134+
#endif // !hasFeature(Embedded)
132135

133136
/// Returns the first output row, if any.
134137
///
@@ -142,7 +145,11 @@ extension SQLQueryFetcher {
142145
/// - Returns: The first output row, if any.
143146
@inlinable
144147
public func first() async throws -> Optional<any SQLRow> {
148+
// `as?` to a different existential is a dynamic cast (unavailable in embedded); skip the
149+
// LIMIT-1 optimization there (correctness is unaffected; we just fetch and take the first).
150+
#if !hasFeature(Embedded)
145151
(self as? any SQLPartialResultBuilder)?.limit(1)
152+
#endif
146153
nonisolated(unsafe) var rows = [any SQLRow]()
147154
try await self.run { if rows.isEmpty { rows.append($0) } }
148155
return rows.first
@@ -218,6 +225,7 @@ extension SQLQueryFetcher {
218225
// MARK: - All (async)
219226

220227
extension SQLQueryFetcher {
228+
#if !hasFeature(Embedded)
221229
/// Returns the named column from each output row, if any, decoded as a given type.
222230
///
223231
/// - Parameters:
@@ -267,6 +275,7 @@ extension SQLQueryFetcher {
267275
public func all<D: Decodable>(decoding type: D.Type, with decoder: SQLRowDecoder) async throws -> [D] {
268276
try await self.all().map { try $0.decode(model: D.self, with: decoder) }
269277
}
278+
#endif // !hasFeature(Embedded)
270279

271280
/// Returns all output rows, if any.
272281
///
@@ -353,6 +362,7 @@ extension SQLQueryFetcher {
353362
// MARK: - Run (async)
354363

355364
extension SQLQueryFetcher {
365+
#if !hasFeature(Embedded)
356366
/// Using a default-configured ``SQLRowDecoder``, call the provided handler closure with the result of decoding
357367
/// each output row, if any, as a given type.
358368
///
@@ -401,6 +411,7 @@ extension SQLQueryFetcher {
401411
) async throws {
402412
try await self.run { row in handler(Result { try row.decode(model: D.self, with: decoder) }) }
403413
}
414+
#endif // !hasFeature(Embedded)
404415

405416
/// Run the query specified by the builder, calling the provided handler closure with each output row, if any, as
406417
/// it is received.

Sources/SQLKit/Builders/Prototypes/SQLReturningBuilder.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ extension SQLReturningBuilder {
1010
/// - Returns: A ``SQLReturningResultBuilder`` which must be used to execute the query.
1111
@inlinable
1212
public func returning(_ columns: String...) -> SQLReturningResultBuilder<Self> {
13-
self.returning(columns.map { SQLColumn($0 == "*" ? SQLLiteral.all : SQLIdentifier($0)) })
13+
self.returning(columns.map { SQLColumn($0 == "*" ? SQLLiteral.all : SQLIdentifier($0)) as any SQLExpression })
1414
}
1515

1616
/// Specify a list of columns to be returned as the result of the query.

0 commit comments

Comments
 (0)