SQLite.swift icon indicating copy to clipboard operation
SQLite.swift copied to clipboard

Error when using `decode` on a `pluck` result

Open tylerbrandt opened this issue 3 years ago • 2 comments

Issues are used to track bugs and feature requests. Need help or have a general question? Ask on Stack Overflow (tag sqlite.swift).

Build Information

SQLite.swift version: 0.13.2 (installed with Xcode "Add packages...") Xcode version: 13.2.1 macOS version: 12.3

Description of issue

When I try to decode a Codable type using db.prepare and iterating over the results, it works. However, when use db.pluck to fetch at most one of the same type, it fails with the error:

DecodingError
  ▿ dataCorrupted : Context
    - codingPath : 0 elements
    - debugDescription : "decoding a single value container is not supported"
    - underlyingError : nil

Playground code to reproduce the error above (I created as a new page in the SQLite.swift playground):

import SQLite

var db = try Connection(.inMemory)

struct User: Codable {
  let name: String
}

let id = Expression<Int64>("id")
let name = Expression<String>("name")

let userTable = Table("user")
try db.run(userTable.create() { tbl in
  tbl.column(id, primaryKey: true)
  tbl.column(name)
})

try db.run(userTable.insert(User(name: "User 1")))

let results = try db.pluck(userTable)
print(try results?.decode() as User?)

Looking at the source code for the string in question, it seems like this is triggering the SQLiteDecoder.singleValueContainer method, and the error is being thrown intentionally, but this limitation isn't noted in the docs so it's possible I'm doing something wrong.

tylerbrandt avatar Mar 21 '22 18:03 tylerbrandt

I ran into the same issue. It seems that Swift's Codable implementation defaults to that container type when it doesn't quite know what the generic type V is, despite not generating a complier error.

You can get Swift to generate a complier error like so....

let connection = try Database.getConnection()
let id = Expression<String>("id")
let windowTable = CaptureWindow.getTable()

do {
    if let row = try connection.pluck(windowTable.filter(id == windowID)) {
        let window = try row.decode()
        return window
    }
} catch {
    print(error.localizedDescription)
}

return nil

To resolve, I specified the type.

let window: CaptureWindow = try row.decode()

(Note: I'm working on a project that already had a number of Codable extensions, which might play a role in this issue. I had to comment some of them out to get SQLite.swift Codable working. You might want to check for extensions in your project as well.)

lightandshadow68 avatar Apr 25 '23 14:04 lightandshadow68

Just ran into this again, even when specifying the type as indicated above. To resolve, I switched to...

let session = try row.decode() as CaptureSession

lightandshadow68 avatar Aug 01 '23 20:08 lightandshadow68