Swift-Kuery-ORM icon indicating copy to clipboard operation
Swift-Kuery-ORM copied to clipboard

RawRepresentable not supported in SQLite

Open jeremyquinn opened this issue 6 years ago • 5 comments

Context and Description

As I mentioned in Issue #42, I get errors encoding and decoding Enums which are RawRepresentable & Codable.

I have a tentative solution but at the moment is is per RawType, so would likely be user-specific.

Maybe this could be added to your codebase as an example or to your documentation. Here is the solution for Int based enum, String etc. is equally trivial.

extension KeyedEncodingContainer {
	public mutating func encodeIfPresent<T>(_ value: T?, forKey key: K) throws where T : Encodable & RawRepresentable, T.RawValue == Int {
		try encodeIfPresent(value?.rawValue, forKey: key)
	}
}

extension KeyedDecodingContainer {
	public func decodeIfPresent<T>(_ type: T.Type, forKey key: K) throws -> T? where T : Decodable & RawRepresentable, T.RawValue == Int {
		if let value = try decodeIfPresent(Int.self, forKey: key) {
			return T.init(rawValue: value)
		}
		return nil
	}
}

Environment Details

Information about your OS, Swift version and Xcode version if on macOS. MacOS 10.13.4 Xcode 9.4 Kitura 2.4.1 SwiftKuery 1.3.1 SwiftKueryORM 0.1.1 SwiftKuerySQLite 1.0.0

Steps to Reproduce

Model struct contains enum :

public struct Bookmark:Codable, Equatable {
    ...
    public var created: Status? // the read status
    ...
}

public enum Status:Int, Codable {
case nought = 0 	// no special status
case unread		// the user would like to see this highlighted as being in their reading list
case read		// this was in the user's reading list but now they are finished
}

jeremyquinn avatar Jun 04 '18 15:06 jeremyquinn

Hey @jeremyquinn, this is something we should definitely support! Maybe we could have a protocol that the enum has to implement so it can be used in the ORM? Could you open a PR with your prototype?

EnriqueL8 avatar Jun 04 '18 15:06 EnriqueL8

Hi @EnriqueL8, glad to know you are interested.

The only way I have managed to make this work so far, is to be specific about the type of the RawValue and use a global extension.

My guess is that an implementation for Int and String RawValue will cover 90% of use cases.

Enums can already be made Codable and were already supported by the JSONDecoder. They just were not supported by your DatabaseDecoder/Encoder.

I want to test this extension has no effect on normal Codable usage. I want to see if it can be added as an extension private to this module only. I plan to add the support for String

jeremyquinn avatar Jun 05 '18 13:06 jeremyquinn

Added PR #46

Sorry, it looks like my last PR got mixed in ...

jeremyquinn avatar Jun 05 '18 16:06 jeremyquinn

Is there still a plan to include this in the near future? I'm running into the same issues.

xeokeri avatar Nov 21 '19 04:11 xeokeri

Seems it is still broken... I realized that somehow DatabaseEncoder only supports types that do not need any mapping/encoding:

    public mutating func encode<T: Encodable>(_ value: T, forKey key: Key) throws {
        if let dataValue = value as? Data {
        } else {
            encoder.values[key.stringValue] = value
        }

when value is an enum type, then values only contains the naked enum value, rather than storing the mapped value (I use a property wrapper that encodes the enums into their rawValue. the wrapper's encoder is invoked when using JSONEncoder, but never invoked when using DatabaseEncoder.

fileprivate class _DatabaseEncoder: Encoder {
    public var values: [String: Any] = [:]
}

lmihalkovic avatar Jun 28 '22 19:06 lmihalkovic