Skip to content

Commit

Permalink
Avoid optionals in JSON Data to String conversions
Browse files Browse the repository at this point in the history
  • Loading branch information
groue committed Sep 22, 2024
1 parent 89aa353 commit 972aa33
Show file tree
Hide file tree
Showing 8 changed files with 13 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ private class DatabaseValueEncoder: Encoder {
// eventually perform JSON decoding.
// TODO: possible optimization: avoid this conversion to string,
// and store raw data bytes as an SQLite string
let jsonString = String(data: jsonData, encoding: .utf8)!
let jsonString = String(decoding: jsonData, as: UTF8.self)
try jsonString.encode(to: self)
}
}
Expand Down
5 changes: 1 addition & 4 deletions GRDB/Dump/DumpFormats/JSONDumpFormat.swift
Original file line number Diff line number Diff line change
Expand Up @@ -166,10 +166,7 @@ extension JSONDumpFormat: DumpFormat {

private func formattedValue(_ value: some Encodable) throws -> String {
let data = try encoder.encode(value)
guard let string = String(data: data, encoding: .utf8) else {
throw EncodingError.invalidValue(data, .init(codingPath: [], debugDescription: "Invalid JSON data"))
}
return string
return String(decoding: data, as: UTF8.self)
}
}

Expand Down
2 changes: 1 addition & 1 deletion GRDB/QueryInterface/Request/RequestProtocols.swift
Original file line number Diff line number Diff line change
Expand Up @@ -464,7 +464,7 @@ extension TableRequest where Self: FilteredRequest, Self: TypedRequest {
"Requesting by key requires a single-column primary key in the table \(databaseTableName)")
let column = primaryKey.columns[0]
let strategy = recordType.databaseDataEncodingStrategy(for: column)
let expressions = datas.map { strategy.encode($0).sqlExpression }
let expressions = try datas.map { try strategy.encode($0).sqlExpression }
return expressions
})
} else if Keys.Element.self == Date.self || Keys.Element.self == Optional<Date>.self {
Expand Down
4 changes: 2 additions & 2 deletions GRDB/Record/EncodableRecord+Encodable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ private class RecordEncoder<Record: EncodableRecord>: Encoder {
fileprivate func encode<T>(_ value: T, forKey key: any CodingKey) throws where T: Encodable {
if let data = value as? Data {
let column = keyEncodingStrategy.column(forKey: key)
let dbValue = Record.databaseDataEncodingStrategy(for: column).encode(data)
let dbValue = try Record.databaseDataEncodingStrategy(for: column).encode(data)
_persistenceContainer[column] = dbValue
} else if let date = value as? Date {
let column = keyEncodingStrategy.column(forKey: key)
Expand Down Expand Up @@ -156,7 +156,7 @@ private class RecordEncoder<Record: EncodableRecord>: Encoder {
// eventually perform JSON decoding.
// TODO: possible optimization: avoid this conversion to string,
// and store raw data bytes as an SQLite string
let jsonString = String(data: jsonData, encoding: .utf8)!
let jsonString = String(decoding: jsonData, as: UTF8.self)
persist(jsonString, forKey: key)
}
}
Expand Down
6 changes: 4 additions & 2 deletions GRDB/Record/EncodableRecord.swift
Original file line number Diff line number Diff line change
Expand Up @@ -486,13 +486,15 @@ public enum DatabaseDataEncodingStrategy: Sendable {
/// Encodes `Data` column as the result of the user-provided function.
case custom(@Sendable (Data) -> (any DatabaseValueConvertible)?)

func encode(_ data: Data) -> DatabaseValue {
func encode(_ data: Data) throws -> DatabaseValue {
switch self {
case .deferredToData:
return data.databaseValue
case .text:
guard let string = String(data: data, encoding: .utf8) else {
fatalError("Invalid UTF8 data")
throw EncodingError.invalidValue(data, EncodingError.Context(
codingPath: [],
debugDescription: "Non-UTF8 data can't be encoded as text in the database"))
}
return string.databaseValue
case .custom(let format):
Expand Down
1 change: 1 addition & 0 deletions Scripts/swiftlint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ disabled_rules:
- nesting
- non_optional_string_data_conversion
- opening_brace
- optional_data_string_conversion
- redundant_optional_initialization
- syntactic_sugar
- todo
Expand Down
2 changes: 1 addition & 1 deletion Tests/GRDBTests/FoundationDateComponentsTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -708,7 +708,7 @@ class FoundationDateComponentsTests : GRDBTestCase {
}
let record = Record(date: DatabaseDateComponents(DateComponents(year: 2018, month: 12, day: 31), format: .YMD))
let jsonData = try JSONEncoder().encode(record)
let json = String(data: jsonData, encoding: .utf8)!
let json = String(decoding: jsonData, as: UTF8.self)
XCTAssertEqual(json, """
{"date":"2018-12-31"}
""")
Expand Down
4 changes: 2 additions & 2 deletions Tests/GRDBTests/MutablePersistableRecordEncodableTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -782,7 +782,7 @@ extension MutablePersistableRecordEncodableTests {

let encoder = JSONEncoder()
encoder.outputFormatting = [.sortedKeys, .prettyPrinted]
let json = try String(data: encoder.encode(record), encoding: .utf8)!
let json = try String(decoding: encoder.encode(record), as: UTF8.self)
XCTAssertEqual(json, """
{
"nestedKeyed" : {
Expand All @@ -808,7 +808,7 @@ extension MutablePersistableRecordEncodableTests {
let encoder = JSONEncoder()
encoder.userInfo = [testKeyRoot: "root", testKeyNested: "nested"]
encoder.outputFormatting = [.sortedKeys, .prettyPrinted]
let json = try String(data: encoder.encode(record), encoding: .utf8)
let json = try String(decoding: encoder.encode(record), as: UTF8.self)
XCTAssertEqual(json, """
{
"context" : "root",
Expand Down

0 comments on commit 972aa33

Please sign in to comment.