Skip to content

Commit 6b3f436

Browse files
authored
Publicize jsonObject helper (#124)
* Publicize `jsonObject` helper * fix * wip * Make a method
1 parent 2d07e03 commit 6b3f436

File tree

6 files changed

+179
-13
lines changed

6 files changed

+179
-13
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
2929
- ``jsonArrayLength()``
3030
- ``jsonGroupArray(order:filter:)``
31+
- ``jsonObject()``
3132
- ``jsonPatch(_:)``
3233
3334
### Optionality

Sources/StructuredQueriesCore/SQLite/JSONFunctions.swift

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ extension PrimaryKeyedTableDefinition where QueryValue: Codable & Sendable {
115115
AggregateFunction(
116116
"json_group_array",
117117
isDistinct: isDistinct,
118-
[jsonObject.queryFragment],
118+
[jsonObject().queryFragment],
119119
order: order?.queryFragment,
120120
filter: filter?.queryFragment
121121
)
@@ -188,16 +188,18 @@ extension PrimaryKeyedTableDefinition where QueryValue: _OptionalProtocol & Coda
188188
return AggregateFunction(
189189
"json_group_array",
190190
isDistinct: isDistinct,
191-
[jsonObject.queryFragment],
191+
[QueryValue.columns.jsonObject().queryFragment],
192192
order: order?.queryFragment,
193193
filter: filterQueryFragment
194194
)
195195
}
196196
}
197197

198-
extension PrimaryKeyedTableDefinition {
199-
200-
fileprivate var jsonObject: some QueryExpression<QueryValue> {
198+
extension TableDefinition where QueryValue: Codable & Sendable {
199+
/// A JSON representation of a table's columns.
200+
///
201+
/// Useful for referencing a table row in a larger JSON selection.
202+
public func jsonObject() -> some QueryExpression<_CodableJSONRepresentation<QueryValue>> {
201203
func open<TableColumn: TableColumnExpression>(_ column: TableColumn) -> QueryFragment {
202204
typealias Value = TableColumn.QueryValue._Optionalized.Wrapped
203205

@@ -240,8 +242,15 @@ extension PrimaryKeyedTableDefinition {
240242
let fragment: QueryFragment = Self.allColumns
241243
.map { open($0) }
242244
.joined(separator: ", ")
243-
return SQLQueryExpression(
244-
"CASE WHEN \(primaryKey.isNot(nil)) THEN json_object(\(fragment)) END"
245-
)
245+
return QueryFunction("json_object", SQLQueryExpression(fragment))
246+
}
247+
}
248+
249+
extension Optional.TableColumns where QueryValue: Codable & Sendable {
250+
/// A JSON representation of a table's columns.
251+
///
252+
/// Useful for referencing a table row in a larger JSON selection.
253+
public func jsonObject() -> some QueryExpression<_CodableJSONRepresentation<Wrapped>?> {
254+
Case().when(rowid.isNot(nil), then: Wrapped.columns.jsonObject())
246255
}
247256
}

Sources/StructuredQueriesSQLite/SQLiteQueryDecoder.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ struct SQLiteQueryDecoder: QueryDecoder {
2828
@inlinable
2929
mutating func decode(_ columnType: [UInt8].Type) throws -> [UInt8]? {
3030
defer { currentIndex += 1 }
31+
precondition(sqlite3_column_count(statement) > currentIndex)
3132
guard sqlite3_column_type(statement, currentIndex) != SQLITE_NULL else { return nil }
3233
return [UInt8](
3334
UnsafeRawBufferPointer(
@@ -51,6 +52,7 @@ struct SQLiteQueryDecoder: QueryDecoder {
5152
@inlinable
5253
mutating func decode(_ columnType: Double.Type) throws -> Double? {
5354
defer { currentIndex += 1 }
55+
precondition(sqlite3_column_count(statement) > currentIndex)
5456
guard sqlite3_column_type(statement, currentIndex) != SQLITE_NULL else { return nil }
5557
return sqlite3_column_double(statement, currentIndex)
5658
}
@@ -63,13 +65,15 @@ struct SQLiteQueryDecoder: QueryDecoder {
6365
@inlinable
6466
mutating func decode(_ columnType: Int64.Type) throws -> Int64? {
6567
defer { currentIndex += 1 }
68+
precondition(sqlite3_column_count(statement) > currentIndex)
6669
guard sqlite3_column_type(statement, currentIndex) != SQLITE_NULL else { return nil }
6770
return sqlite3_column_int64(statement, currentIndex)
6871
}
6972

7073
@inlinable
7174
mutating func decode(_ columnType: String.Type) throws -> String? {
7275
defer { currentIndex += 1 }
76+
precondition(sqlite3_column_count(statement) > currentIndex)
7377
guard sqlite3_column_type(statement, currentIndex) != SQLITE_NULL else { return nil }
7478
return String(cString: sqlite3_column_text(statement, currentIndex))
7579
}

0 commit comments

Comments
 (0)