sql-kit
sql-kit copied to clipboard
JSON columns with Date and/or Bool fail decoding
Problem Description
When trying to decode a query that has a JSON column with booleans and/or date values, it fails with an error. Consider the following minimal example:
struct MyContent: Content {
let options: Options
struct Options: Codable {
let isEnabled: Bool
let due: Date
}
}
let query: SQLQueryString = "SELECT JSON_OBJECT('isEnabled', 1, 'due', NOW()) options"
let results = try await db.raw(query).first(decoding: MyContent.self)
Running this code will produce:
Value of type 'Bool' required for key 'isEnabled'.
if we change the Bool
to Int
, we now get an error because of the Date
value:
"Value of type 'Double' required for key 'due'.
The second error can be omitted by changing the type in the due
property, from Date
to String
Expected Behavior
Not sure if this is a bug report, or a feature request. But ideally, Fluent should be able to decode Bool
and Date
types. Or maybe I'm missing something obvious of why this is not the case?
Workaround
In the meantime, I'm implementing Econdable.init(from decoder: Decoder)
to workaround the problem:
struct MyContent: Content {
let options: Options
struct Options: Codable {
let isEnabled: Bool
let due: Date
init(from decoder: Decoder) throws {
let container: KeyedDecodingContainer<CodingKeys> = try decoder.container(keyedBy: CodingKeys.self)
self.isEnabled = (try container.decode(Int.self, forKey: CodingKeys.isEnabled) != 0)
let d = try container.decode(String.self, forKey: CodingKeys.due)
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss.SSSSSS"
formatter.timeZone = TimeZone(secondsFromGMT: 0)
guard let due = formatter.date(from: (try container.decode(String.self, forKey: CodingKeys.due))) else {
throw DecodingError.typeMismatch(Date.self, DecodingError.Context(codingPath: [CodingKeys.due], debugDescription: "String could not be converted to Date"))
}
self.due = due
}
}
}
This workaround now produces proper JSON content:
{
"options": {
"due": "2023-01-13T11:49:59Z",
"isEnabled": true
}
}
Environment
mysql server: 8.0.27 framework: 4.67.4 toolbox: 18.6.0