fluent
fluent copied to clipboard
Problem with data types when using aggregate functions
Describe the issue
Unable to interpret value of PSQL type NUMERIC
Vapor version
4.102.1
Operating system and version
macos 15
Swift version
swiftlang-6.0.0.6.8
Steps to reproduce
1 - Create a table with columns using other tools
2 - Fluent code that causes an exception
final class CleanedShares: Model, @unchecked Sendable {
static var schema: String { "cleaned_shares" }
@ID(custom: "id", generatedBy: .database)
var id: Int64?
@Timestamp(key: "created_at", on: .create)
var createdAt: Date?
@Timestamp(key: "updated_at", on: .update)
var updatedAt: Date?
@Field(key: "user_id")
var userId: Int64
@Field(key: "shares")
var shares: Int64
/// See `Table`
init() {}
init(
userId: Int64,
shares: Int64
) {
self.userId = userId
self.shares = shares
}
}
struct Sum: Codable {
var sum: Int64
}
3 - Calling the following functions causes a postgres error
let object = try await db.query(CleanedShares.self).sum(\.$shares) // CRASH
let object = try await db.query(CleanedShares.self).aggregate(.sum, \.$shares, as: Sum.self) // CRASH
Swift.DecodingError.dataCorrupted(Swift.DecodingError.Context(codingPath: [SomeCodingKey(stringValue: "aggregate (0)", intValue: nil)], debugDescription: "Unable to interpret value of PSQL type NUMERIC: ByteBuffer { readerIndex: 0, writerIndex: 14, readableBytes: 14, capacity: 14, storageCapacity: 2048, slice: _ByteBufferSlice { 63..<77 }, storage: 0x0000000135011400 (2048 bytes) }", underlyingError: nil))
- How to "fix"
- works if you change the type to Decaimal in the mode
@Field(key: "shares")
var shares: Decimal
and
struct Sum: Codable {
var sum: Decimal
}
but at the same time we remember that in the database it is Int8 byte, that is, it is Int64, and we specified the Decimal floating point type
- the only acceptable working option is to write raw sql
guard
let object = try await sqlDataBase.raw(
"""
SELECT SUM(\(unsafeRaw: try CleanedShares.field(\CleanedShares.$shares))) AS sum
FROM \(unsafeRaw: CleanedShares.schema);
"""
).first(decoding: Sum.self)
else {
throw AppError("Aggregate sum - failed")
}
But codable struct must have Decimal type of the "sum" property anyway
struct Sum: Codable {
var sum: Decimal
}
Total:
in total, everything works “normally” only if in the model and in the encoded structure this field is in Decimal format
Outcome
No response
Additional notes
No response