Custom DatabaseValueConvertible
UUID
wrapper doesn’t work with scalar .select
#1802
-
I’m trying to create a type – If I swap out Self-contained example codeimport Foundation
import GRDB
struct Player: Codable, FetchableRecord, PersistableRecord {
static let medals = hasMany(Medal.self)
var id: String
var name: String
}
struct Medal: Codable, FetchableRecord, PersistableRecord {
var id = MedalID()
var playerID: String
}
struct MedalID: Codable, DatabaseValueConvertible {
private var uuid = UUID()
init() {}
init(from decoder: any Decoder) throws {
uuid = try UUID(from: decoder)
}
private init(_ uuid: UUID) {
self.uuid = uuid
}
static func fromDatabaseValue(_ dbValue: DatabaseValue) -> MedalID? {
UUID.fromDatabaseValue(dbValue).map(MedalID.init)
}
var databaseValue: DatabaseValue { uuid.databaseValue }
func encode(to encoder: any Encoder) throws {
try uuid.encode(to: encoder)
}
}
func main() throws {
let dbQueue = try DatabaseQueue()
try dbQueue.write { db in
try db.create(table: "player") { t in
t.primaryKey("id", .text)
t.column("name", .text).notNull()
}
try db.create(table: "medal") { t in
t.primaryKey("id", .blob)
t.belongsTo("player")
}
}
try dbQueue.write { db in
try Player(id: "1", name: "Arthur").insert(db)
try Player(id: "2", name: "Barbara").insert(db)
try Medal(playerID: "1").insert(db)
try Medal(playerID: "1").insert(db)
try Medal(playerID: "1").insert(db)
try Medal(playerID: "2").insert(db)
}
try dbQueue.read { db in
try debugPrint(Medal.fetchAll(db)) // This decodes as you'd expect.
struct PlayerInfo: Decodable, FetchableRecord {
var player: Player
var medalIDs: [MedalID]
static func all() -> QueryInterfaceRequest<PlayerInfo> {
Player
.including(all: Player.medals.select(Column("id")).forKey(CodingKeys.medalIDs))
.asRequest(of: PlayerInfo.self)
}
}
// could not decode String from database value Data(16 bytes) -
// column: "id", column index: 0, row: [id:Data(16 bytes) grdb_playerId:"1"]
try debugPrint(PlayerInfo.all().fetchAll(db))
}
}
try! main() Thanks so much for GRDB! |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 3 replies
-
Hello @lunacookies, Thanks for asking. The sample code looks valid and innocuous to me. I'll have a look. |
Beta Was this translation helpful? Give feedback.
OK. I understand where the problem comes from.
While decoding
PlayerInfo
from a database row, it is theDecodable
conformance ofMedalID
that is used to decode the values loaded from the database, not itsDatabaseValueConvertible
conformance:Unfortunately, the
Decodable
facet ofUUID
has no support for blobs. It requires aString
, fails to decode one from the database blob (as expected - a binary UUID is …