5

I'm trying to use SQLite.swift's Codable functionality to insert a row, but am getting the following error message:

Swift.EncodingError.Context(codingPath: [], debugDescription: "Top-level 
MyEnum encoded as number JSON fragment.", underlyingError: nil))

My enum extends Int and Codable:

enum MyEnum : Int, Codable {
    case FIRSTVAL = 0, SECONDVAL = 1
}

And the class consuming it looks like this:

class MyClass : Codable {        
    static let tableRef = Table("MyTable")

    static let idColumn = Expression<Int>("MyTableId");
    static let nameColumn = Expression<String>("Name")
    static let myEnumValColumn = Expression<Int>("MyEnumVal")

    static func createTable(_ db : Connection) throws {            
        try db.run(tableRef.create(ifNotExists: true) { t in
            t.column(idColumn, primaryKey: true)
            t.column(nameColumn)
            t.column(myEnumValColumn)
        })            
    }

    var MyTableId : Int!
    var Name : String
    var MyEnumVal : MyEnum
}

The code that attempts to insert the row and causes the error to be thrown:

try db.run(MyClass.tableRef.insert(anInstanceOfMyClass))

I know in the documentation for SQLite.swift it says:

The encodable and decodable objects can only use the following types:

  • Int, Bool, Float, Double, String
  • Nested Codable types that will be encoded as JSON to a single column

Is there a way to force it to use the rawValue of the enum (as it extends Int anyway), perhaps by implementing the encode/decode method manually for either MyEnum or MyClass? I'm trying to avoid having to manually write code to deserialise the row from the database back into an object and serialise from an object ready for the database. For example I previously had the following methods in MyClass (as well as other bits of code that loaded entities from the DB too and had to deserialise them):

init(row : Row) {
    self.MyTableId = row[MyClass.idColumn]
    self.Name = row[MyClass.nameColumn]       
    self.MyEnumVal = MyEnum(rawValue: Int(row[MyClass.myEnumValColumn]))!
}

func insert(_ db : Connection) throws {
    let insert = MyClass.tableRef.insert(
        MyClass.idColumn <- Int(MyTableId),
        MyClass.nameColumn <- Name,
        MyClass.myEnumValColumn <- Int(MyEnumVal.rawValue)
    )
    try db.run(insert)
}
Neil Mountford
  • 1,951
  • 3
  • 21
  • 31

0 Answers0