stephencelis / SQLite.swift

A type-safe, Swift-language layer over SQLite3.
MIT License
9.64k stars 1.56k forks source link

SQLiteDecoder & Codable with NULL Values #997

Closed Sevyls closed 10 months ago

Sevyls commented 4 years ago

Are null values actually supported by your SQLiteDecoder?

Build Information

CocoaPods, SQLite.swift version 0.12.2 iOS 13.4, XCode 11.4.1

General guidelines

I just tried to read an array of my table's contents, but then I got an exception.

In Coding.swift:235 I get an error by QueryError.unexpectedNullValue.

Are null values within Codables supported?

TenMaKo commented 4 years ago

No. You need to handle it yourself.

I came up with this if you wanna try :

Put this somewhere

protocol SQLiteCompatibleType: Encodable {}
extension Int: SQLiteCompatibleType {}
extension String: SQLiteCompatibleType {}
extension Bool: SQLiteCompatibleType {}
extension Double: SQLiteCompatibleType {}
extension Float: SQLiteCompatibleType {}
extension Data: SQLiteCompatibleType {}

extension KeyedEncodingContainerProtocol {
    mutating func encodeNullable<T>(_ value: T?, forKey key: Key) throws where T: SQLiteCompatibleType {
        if let unwrappedValue = value {
            if let int = unwrappedValue as? Int {
                try self.encode(int, forKey: key)
            } else if let double = unwrappedValue as? Double {
                try self.encode(double, forKey: key)
            } else if let float = unwrappedValue as? Float {
                try self.encode(float, forKey: key)
            } else if let bool = unwrappedValue as? Bool {
                try self.encode(bool, forKey: key)
            } else if let data = unwrappedValue as? Data {
                try self.encode(data, forKey: key)
            } else if let string = unwrappedValue as? String {
                try self.encode(string, forKey: key)
            } else {
                try self.encode(unwrappedValue, forKey: key)
            }
        } else {
            try self.encodeNil(forKey: key)
        }
    }
}

and change the following func in Coding.swift :

func encode<T>(_ value: T, forKey key: Key) throws where T: Swift.Encodable {
            if let data = value as? Data {
                self.encoder.setters.append(Expression(key.stringValue) <- data)
            } else if let string = value as? String {
                self.encoder.setters.append(Expression(key.stringValue) <- string)
            } else {
                let encoded = try JSONEncoder().encode(value)
                let string = String(data: encoded, encoding: .utf8)
                self.encoder.setters.append(Expression(key.stringValue) <- string)
            }
}

And then in func encode(to encoder: Encoder) throws in your object class definition, use encodeNullable and in required convenience init(from decoder: Decoder) throws use decodeIfPresent for optional values

Hope it will help :)

Sevyls commented 4 years ago

Thanks for your support, will try that.

rahulvyas commented 4 years ago

@TenMaKo I have added SQLIte.swift using SPM (Swift Package Manager). How do I update Coding.swift file code ?

TenMaKo commented 4 years ago

@TenMaKo I have added SQLIte.swift using SPM (Swift Package Manager). How do I update Coding.swift file code ?

I don’t use SPM so I’m not sure about this but I think you can’t cause SPM import pre-built packages. Maybe you will need to fork this repo, modify the file and then import the lib from your own repo :/ Again, it’s just a guess.

rahulvyas commented 4 years ago

@TenMaKo Don't you think you should create a PR and then merge this fix into master. More people are facing the issue..

TenMaKo commented 4 years ago

@TenMaKo Don't you think you should create a PR and then merge this fix into master. More people are facing the issue..

No sorry cause this is just a workaround. A clean fix should make standard Codable usage for this lib handle optionals correctly.

rahulvyas commented 4 years ago

@TenMaKo got it thanks for clarification...

nathanfallet commented 3 years ago

@TenMaKo Feel free to open a PR to fix this issue