Skip to content

Instantly share code, notes, and snippets.

@groue
Last active February 21, 2023 07:09
Show Gist options
  • Save groue/873b9aad807a719bf4244f5a14cd11cd to your computer and use it in GitHub Desktop.
Save groue/873b9aad807a719bf4244f5a14cd11cd to your computer and use it in GitHub Desktop.
TimestampedRecord: an example protocol for GRDB records that track their creation and modification dates.
/// A type that tracks its creation and modification dates, as described in
/// <https://swiftpackageindex.com/groue/grdb.swift/documentation/grdb/recordtimestamps>
protocol TimestampedRecord {
var creationDate: Date? { get set }
var modificationDate: Date? { get set }
}
extension TimestampedRecord where Self: MutablePersistableRecord {
/// Sets `modificationDate` to the transaction date.
mutating func touch(_ db: Database) throws {
modificationDate = try db.transactionDate
}
/// Sets both `creationDate` and `modificationDate` to the transaction date,
/// if they are not set yet.
///
/// Records that customize the `willInsert` callback can call this method
/// from their implementation.
mutating func initializeTimestamps(_ db: Database) throws {
if creationDate == nil {
creationDate = try db.transactionDate
}
if modificationDate == nil {
modificationDate = try db.transactionDate
}
}
// Default implementation of `willInsert`.
mutating func willInsert(_ db: Database) throws {
try initializeTimestamps(db)
}
/// Sets `modificationDate` to the transaction date, and executes an
/// `UPDATE` statement on all columns.
mutating func updateWithTimestamp(_ db: Database) throws {
try touch(db)
try update(db)
}
}
// ======================
// DEMO
struct Player: Codable, MutablePersistableRecord, FetchableRecord, TimestampedRecord {
var id: Int64?
var creationDate: Date?
var modificationDate: Date?
var name: String
var score: Int
mutating func didInsert(_ inserted: InsertionSuccess) {
id = inserted.rowID
}
}
let dbQueue = try DatabaseQueue()
try dbQueue.write { db in
try db.create(table: "player") { t in
t.autoIncrementedPrimaryKey("id")
t.column("creationDate", .datetime).notNull()
t.column("modificationDate", .datetime).notNull()
t.column("name", .text).notNull()
t.column("score", .integer).notNull()
}
}
try dbQueue.write { db in
// Insertion sets the creation and modification dates
var player = Player(name: "Arthur", score: 1000)
try player.insert(db)
assert(player.creationDate != nil)
assert(player.modificationDate != nil)
// Call updateWithTimestamp() instead of update() in order
// to bump the modification date
player.score += 1
try player.updateWithTimestamp(db)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment