Last active
February 21, 2023 07:09
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// 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