diff --git a/GRDB/Core/DatabaseWriter.swift b/GRDB/Core/DatabaseWriter.swift index 3ffde08bc1..3f5b11060c 100644 --- a/GRDB/Core/DatabaseWriter.swift +++ b/GRDB/Core/DatabaseWriter.swift @@ -72,7 +72,7 @@ public protocol DatabaseWriter : DatabaseReader { /// /// For example: /// - /// try writer.write { db in + /// try writer.writeWithoutTransaction { db in /// try db.execute("DELETE FROM player") /// try writer.readFromCurrentState { db in /// // Guaranteed to be zero diff --git a/GRDB/Record/FetchableRecord+Decodable.swift b/GRDB/Record/FetchableRecord+Decodable.swift index 44e510cfa2..26a3c7c91e 100644 --- a/GRDB/Record/FetchableRecord+Decodable.swift +++ b/GRDB/Record/FetchableRecord+Decodable.swift @@ -79,7 +79,12 @@ private struct RowKeyedDecodingContainer: KeyedDecodingContainer } else if dbValue.isNull { return nil } else { - return try T(from: RowDecoder(row: row, codingPath: codingPath + [key])) + if let data = row.dataNoCopy(named: key.stringValue), let dataString = String(data: data, encoding: .utf8), JSONSerialization.isValidJSONObject([dataString]) { + // If data is valid JSON then decode it into model + return try JSONDecoder().decode(type.self, from: data) + } else { + return try T(from: RowDecoder(row: row, codingPath: codingPath + [key])) + } } } diff --git a/GRDB/Record/PersistableRecord+Encodable.swift b/GRDB/Record/PersistableRecord+Encodable.swift index 135e8a149a..7787630e3e 100644 --- a/GRDB/Record/PersistableRecord+Encodable.swift +++ b/GRDB/Record/PersistableRecord+Encodable.swift @@ -28,6 +28,7 @@ private struct PersistableRecordKeyedEncodingContainer : KeyedEn mutating func encode(_ value: Float, forKey key: Key) throws { encode(value, key.stringValue) } mutating func encode(_ value: Double, forKey key: Key) throws { encode(value, key.stringValue) } mutating func encode(_ value: String, forKey key: Key) throws { encode(value, key.stringValue) } + mutating func encode(_ value: Encodable, forKey key: Key) throws { encode(value.encodeToString(), key.stringValue) } /// Encodes the given value for the given key. /// @@ -194,6 +195,17 @@ private struct PersistableRecordEncoder : Encoder { } } +public extension Encodable { + /// Encode model (self) into JSON string + func encodeToString() -> String? { + let json = try! JSONEncoder().encode(self) + if let content = String(data: json, encoding: .utf8) { + return content + } + return nil + } +} + extension MutablePersistableRecord where Self: Encodable { public func encode(to container: inout PersistenceContainer) { // The inout container parameter won't enter an escaping closure since diff --git a/TODO.md b/TODO.md index 6a281cbbb5..60263427e2 100644 --- a/TODO.md +++ b/TODO.md @@ -23,6 +23,7 @@ - [ ] Avoid code duplication: https://forums.swift.org/t/c-interoperability-combinations-of-library-and-os-versions/14029/4 - [ ] Expose FTS5 in regular GRDB: https://github.com/groue/GRDB.swift/issues/373 - [ ] Allow joining methods on DerivableRequest +- [ ] Make *all* conversion errors provide sql + arguments + column name Swift 4.2