Group values by year, month, day #77
-
Hi there, I'm trying to migrate my app to SharingGRDB/StructuredQueries. So far so good. What I'm trying to achieve is to group values by part of a timestamp. I have this table in my database: @Table
struct Weight: Identifiable, Equatable, CustomDebugStringConvertible, Hashable, Codable {
let id: Int
var timestamp: Date
var weightInKilograms: Double
init(id: Int, timestamp: Date, weight: Measurement<UnitMass>) {
self.id = id
self.timestamp = timestamp
self.weight = weight
}
....
} as you can see the timestamp contains a date along with a timestamp. Now what I would like to do is to create an overview of all weights per day: import Foundation
import SharingGRDB
import SwiftUI
@Selection
struct GroupedWeights: Equatable, Hashable {
var date: Date
@Column(as: [Weight].JSONRepresentation.self)
var weights: [Weight]
}
@Observable
class WeightListModel {
@ObservationIgnored
@Dependency(\.defaultDatabase) var database
@ObservationIgnored
@FetchAll
var groupedWeights: [GroupedWeights]
var startDate: Date
var endDate: Date
init(startDate: Date, endDate: Date) {
self.startDate = startDate
self.endDate = endDate
self._groupedWeights = FetchAll(
Weight
.where { $0.timestamp.between(#bind(startDate), and: #bind(endDate)) }
.group { $0.timestamp }
.order { $0.timestamp.desc() }
.select { GroupedWeights.Columns(date: $0.timestamp, weights: $0.jsonGroupArray()) }
)
}
} the code above works, but the select * from weight
group by date(timestamp)
order by timestamp and later I will need: select * from weight
group by strftime('%Y%m', timestamp)
order by timestamp but I'm struggling to implement any of the above. Is it possible to implement anything like this with StructuredQueries? kind regards, Tim |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 4 replies
-
@thinkpractice StructuredQueries comes with a lot of helpers out of the box, but it doesn't currently implement the date functions (we are open to PRs here, but SQLite date functions are in particular quite nuanced/flexible with their input/output). Instead you can use the .group { #sql("date(\($0.timestamp))" }
// or
.group { #sql("strftime('%Y%m', \($0.timestamp))") } The |
Beta Was this translation helpful? Give feedback.
-
@stephencelis the I found out that the same code would not work in the select clause though: .select {
GroupedWeights.Columns(date: #sql("date(\($0.timestamp))" ?? $0.timestamp, weights: $0.jsonGroupArray())
} It throws an error when mapping back to the date in the |
Beta Was this translation helpful? Give feedback.
-
@stephencelis the |
Beta Was this translation helpful? Give feedback.
@thinkpractice Ah, that's true, currently you must specify the type if it can't be inferred, and at the moment it can't here. So you'd need to do:
We can look into if it's possible to weaken this requirement, though!
If you are able to define them in reasonable ways we'd be happy to consider them for inclusion in the library, but they are complicated in how they accept various inputs (dates, text, integers, doubles) and how they can fail.