add
This commit is contained in:
@@ -1,713 +0,0 @@
|
||||
import XCTest
|
||||
import GRDB
|
||||
|
||||
private class Person : Record {
|
||||
var id: Int64!
|
||||
var name: String!
|
||||
var age: Int?
|
||||
var creationDate: Date!
|
||||
|
||||
init(id: Int64? = nil, name: String? = nil, age: Int? = nil, creationDate: Date? = nil) {
|
||||
self.id = id
|
||||
self.name = name
|
||||
self.age = age
|
||||
self.creationDate = creationDate
|
||||
super.init()
|
||||
}
|
||||
|
||||
static func setup(inDatabase db: Database) throws {
|
||||
try db.execute(sql: """
|
||||
CREATE TABLE persons (
|
||||
id INTEGER PRIMARY KEY,
|
||||
creationDate TEXT NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
age INT)
|
||||
""")
|
||||
}
|
||||
|
||||
// Record
|
||||
|
||||
override class var databaseTableName: String {
|
||||
"persons"
|
||||
}
|
||||
|
||||
required init(row: Row) throws {
|
||||
id = row["id"]
|
||||
age = row["age"]
|
||||
name = row["name"]
|
||||
creationDate = row["creationDate"]
|
||||
try super.init(row: row)
|
||||
}
|
||||
|
||||
override func encode(to container: inout PersistenceContainer) throws {
|
||||
container["id"] = id
|
||||
container["name"] = name
|
||||
container["age"] = age
|
||||
container["creationDate"] = creationDate
|
||||
}
|
||||
|
||||
override func willInsert(_ db: Database) throws {
|
||||
if creationDate == nil {
|
||||
creationDate = Date()
|
||||
}
|
||||
try super.willInsert(db)
|
||||
}
|
||||
|
||||
override func didInsert(_ inserted: InsertionSuccess) {
|
||||
super.didInsert(inserted)
|
||||
id = inserted.rowID
|
||||
}
|
||||
}
|
||||
|
||||
private class IntegerPropertyOnRealAffinityColumn : Record {
|
||||
var value: Int?
|
||||
|
||||
init(value: Int?) {
|
||||
self.value = value
|
||||
super.init()
|
||||
}
|
||||
|
||||
// Record
|
||||
|
||||
required init(row: Row) throws {
|
||||
value = row["value"]
|
||||
try super.init(row: row)
|
||||
}
|
||||
|
||||
override func encode(to container: inout PersistenceContainer) throws {
|
||||
container["value"] = value
|
||||
}
|
||||
}
|
||||
|
||||
private class PersonWithModifiedCaseColumns: Record {
|
||||
var id: Int64!
|
||||
var name: String!
|
||||
var age: Int?
|
||||
var creationDate: Date!
|
||||
|
||||
init(id: Int64? = nil, name: String? = nil, age: Int? = nil, creationDate: Date? = nil) {
|
||||
self.id = id
|
||||
self.name = name
|
||||
self.age = age
|
||||
self.creationDate = creationDate
|
||||
super.init()
|
||||
}
|
||||
|
||||
// Record
|
||||
|
||||
override class var databaseTableName: String {
|
||||
"persons"
|
||||
}
|
||||
|
||||
required init(row: Row) throws {
|
||||
id = row["ID"]
|
||||
age = row["AGE"]
|
||||
name = row["NAME"]
|
||||
creationDate = row["CREATIONDATE"]
|
||||
try super.init(row: row)
|
||||
}
|
||||
|
||||
override func encode(to container: inout PersistenceContainer) throws {
|
||||
container["ID"] = id
|
||||
container["NAME"] = name
|
||||
container["AGE"] = age
|
||||
container["CREATIONDATE"] = creationDate
|
||||
}
|
||||
|
||||
override func willInsert(_ db: Database) throws {
|
||||
if creationDate == nil {
|
||||
creationDate = Date()
|
||||
}
|
||||
try super.willInsert(db)
|
||||
}
|
||||
|
||||
override func didInsert(_ inserted: InsertionSuccess) {
|
||||
super.didInsert(inserted)
|
||||
id = inserted.rowID
|
||||
}
|
||||
}
|
||||
|
||||
class RecordEditedTests: GRDBTestCase {
|
||||
|
||||
override func setup(_ dbWriter: some DatabaseWriter) throws {
|
||||
var migrator = DatabaseMigrator()
|
||||
migrator.registerMigration("createPerson", migrate: Person.setup)
|
||||
try migrator.migrate(dbWriter)
|
||||
}
|
||||
|
||||
func testRecordIsEditedAfterInit() {
|
||||
// Create a Record. No fetch has happen, so we don't know if it is
|
||||
// identical to its eventual row in the database. So it is edited.
|
||||
let person = Person(name: "Arthur", age: 41)
|
||||
XCTAssertTrue(person.hasDatabaseChanges)
|
||||
}
|
||||
|
||||
func testRecordIsEditedAfterInitFromRow() throws {
|
||||
// Create a Record from a row. The row may not come from the database.
|
||||
// So it is edited.
|
||||
let row = Row(["name": "Arthur", "age": 41])
|
||||
let person = try Person(row: row)
|
||||
XCTAssertTrue(person.hasDatabaseChanges)
|
||||
}
|
||||
|
||||
func testRecordIsNotEditedAfterFullFetch() throws {
|
||||
// Fetch a record from a row that contains all the columns in
|
||||
// persistence container: An update statement, which only saves the
|
||||
// columns in persistence container would perform no change. So the
|
||||
// record is not edited.
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
try Person(name: "Arthur", age: 41).insert(db)
|
||||
let person = try Person.fetchOne(db, sql: "SELECT * FROM persons")!
|
||||
XCTAssertFalse(person.hasDatabaseChanges)
|
||||
}
|
||||
try dbQueue.inDatabase { db in
|
||||
try PersonWithModifiedCaseColumns(name: "Arthur", age: 41).insert(db)
|
||||
let person = try PersonWithModifiedCaseColumns.fetchOne(db, sql: "SELECT * FROM persons")!
|
||||
XCTAssertFalse(person.hasDatabaseChanges)
|
||||
}
|
||||
}
|
||||
|
||||
func testRecordIsNotEditedAfterFullFetchWithIntegerPropertyOnRealAffinityColumn() throws {
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
try db.execute(sql: "CREATE TABLE t (value REAL)")
|
||||
try db.execute(sql: "INSERT INTO t (value) VALUES (1)")
|
||||
let record = try IntegerPropertyOnRealAffinityColumn.fetchOne(db, sql: "SELECT * FROM t")!
|
||||
XCTAssertFalse(record.hasDatabaseChanges)
|
||||
}
|
||||
}
|
||||
|
||||
func testRecordIsNotEditedAfterWiderThanFullFetch() throws {
|
||||
// Fetch a record from a row that contains all the columns in
|
||||
// persistence container, plus extra ones: An update statement,
|
||||
// which only saves the columns in persistence container would
|
||||
// perform no change. So the record is not edited.
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
try Person(name: "Arthur", age: 41).insert(db)
|
||||
let person = try Person.fetchOne(db, sql: "SELECT *, 1 AS foo FROM persons")!
|
||||
XCTAssertFalse(person.hasDatabaseChanges)
|
||||
}
|
||||
try dbQueue.inDatabase { db in
|
||||
try PersonWithModifiedCaseColumns(name: "Arthur", age: 41).insert(db)
|
||||
let person = try PersonWithModifiedCaseColumns.fetchOne(db, sql: "SELECT *, 1 AS foo FROM persons")!
|
||||
XCTAssertFalse(person.hasDatabaseChanges)
|
||||
}
|
||||
}
|
||||
|
||||
func testRecordIsEditedAfterPartialFetch() throws {
|
||||
// Fetch a record from a row that does not contain all the columns in
|
||||
// persistence container: An update statement saves the columns in
|
||||
// persistence container, so it may perform unpredictable change.
|
||||
// So the record is edited.
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
try Person(name: "Arthur", age: 41).insert(db)
|
||||
let person = try Person.fetchOne(db, sql: "SELECT name FROM persons")!
|
||||
XCTAssertTrue(person.hasDatabaseChanges)
|
||||
}
|
||||
try dbQueue.inDatabase { db in
|
||||
try PersonWithModifiedCaseColumns(name: "Arthur", age: 41).insert(db)
|
||||
let person = try PersonWithModifiedCaseColumns.fetchOne(db, sql: "SELECT name FROM persons")!
|
||||
XCTAssertTrue(person.hasDatabaseChanges)
|
||||
}
|
||||
}
|
||||
|
||||
func testRecordIsNotEditedAfterInsert() throws {
|
||||
// After insertion, a record is not edited.
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
let person = Person(name: "Arthur", age: 41)
|
||||
try person.insert(db)
|
||||
XCTAssertFalse(person.hasDatabaseChanges)
|
||||
}
|
||||
try dbQueue.inDatabase { db in
|
||||
let person = PersonWithModifiedCaseColumns(name: "Arthur", age: 41)
|
||||
try person.insert(db)
|
||||
XCTAssertFalse(person.hasDatabaseChanges)
|
||||
}
|
||||
}
|
||||
|
||||
func testRecordIsEditedAfterValueChange() throws {
|
||||
// Any change in a value exposed in persistence container yields a
|
||||
// record that is edited.
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
do {
|
||||
let person = Person(name: "Arthur")
|
||||
try person.insert(db)
|
||||
XCTAssertTrue(person.name != nil)
|
||||
person.name = "Bobby" // non-nil vs. non-nil
|
||||
XCTAssertTrue(person.hasDatabaseChanges)
|
||||
}
|
||||
do {
|
||||
let person = Person(name: "Arthur")
|
||||
try person.insert(db)
|
||||
XCTAssertTrue(person.name != nil)
|
||||
person.name = nil // non-nil vs. nil
|
||||
XCTAssertTrue(person.hasDatabaseChanges)
|
||||
}
|
||||
do {
|
||||
let person = Person(name: "Arthur")
|
||||
try person.insert(db)
|
||||
XCTAssertTrue(person.age == nil)
|
||||
person.age = 41 // nil vs. non-nil
|
||||
XCTAssertTrue(person.hasDatabaseChanges)
|
||||
}
|
||||
}
|
||||
try dbQueue.inDatabase { db in
|
||||
do {
|
||||
let person = PersonWithModifiedCaseColumns(name: "Arthur")
|
||||
try person.insert(db)
|
||||
XCTAssertTrue(person.name != nil)
|
||||
person.name = "Bobby" // non-nil vs. non-nil
|
||||
XCTAssertTrue(person.hasDatabaseChanges)
|
||||
}
|
||||
do {
|
||||
let person = PersonWithModifiedCaseColumns(name: "Arthur")
|
||||
try person.insert(db)
|
||||
XCTAssertTrue(person.name != nil)
|
||||
person.name = nil // non-nil vs. nil
|
||||
XCTAssertTrue(person.hasDatabaseChanges)
|
||||
}
|
||||
do {
|
||||
let person = PersonWithModifiedCaseColumns(name: "Arthur")
|
||||
try person.insert(db)
|
||||
XCTAssertTrue(person.age == nil)
|
||||
person.age = 41 // nil vs. non-nil
|
||||
XCTAssertTrue(person.hasDatabaseChanges)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testRecordIsNotEditedAfterSameValueChange() throws {
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
do {
|
||||
let person = Person(name: "Arthur")
|
||||
try person.insert(db)
|
||||
XCTAssertTrue(person.name != nil)
|
||||
person.name = "Arthur" // non-nil vs. non-nil
|
||||
XCTAssertFalse(person.hasDatabaseChanges)
|
||||
}
|
||||
do {
|
||||
let person = Person(name: "Arthur")
|
||||
try person.insert(db)
|
||||
XCTAssertTrue(person.age == nil)
|
||||
person.age = nil // nil vs. nil
|
||||
XCTAssertFalse(person.hasDatabaseChanges)
|
||||
}
|
||||
}
|
||||
try dbQueue.inDatabase { db in
|
||||
do {
|
||||
let person = PersonWithModifiedCaseColumns(name: "Arthur")
|
||||
try person.insert(db)
|
||||
XCTAssertTrue(person.name != nil)
|
||||
person.name = "Arthur" // non-nil vs. non-nil
|
||||
XCTAssertFalse(person.hasDatabaseChanges)
|
||||
}
|
||||
do {
|
||||
let person = PersonWithModifiedCaseColumns(name: "Arthur")
|
||||
try person.insert(db)
|
||||
XCTAssertTrue(person.age == nil)
|
||||
person.age = nil // nil vs. nil
|
||||
XCTAssertFalse(person.hasDatabaseChanges)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testRecordIsNotEditedAfterUpdate() throws {
|
||||
// After update, a record is not edited.
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
let person = Person(name: "Arthur", age: 41)
|
||||
try person.insert(db)
|
||||
person.name = "Bobby"
|
||||
try person.update(db)
|
||||
XCTAssertFalse(person.hasDatabaseChanges)
|
||||
}
|
||||
try dbQueue.inDatabase { db in
|
||||
let person = PersonWithModifiedCaseColumns(name: "Arthur", age: 41)
|
||||
try person.insert(db)
|
||||
person.name = "Bobby"
|
||||
try person.update(db)
|
||||
XCTAssertFalse(person.hasDatabaseChanges)
|
||||
}
|
||||
}
|
||||
|
||||
func testRecordIsNotEditedAfterSave() throws {
|
||||
// After save, a record is not edited.
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
let person = Person(name: "Arthur", age: 41)
|
||||
try person.save(db)
|
||||
XCTAssertFalse(person.hasDatabaseChanges)
|
||||
person.name = "Bobby"
|
||||
XCTAssertTrue(person.hasDatabaseChanges)
|
||||
try person.save(db)
|
||||
XCTAssertFalse(person.hasDatabaseChanges)
|
||||
}
|
||||
try dbQueue.inDatabase { db in
|
||||
let person = PersonWithModifiedCaseColumns(name: "Arthur", age: 41)
|
||||
try person.save(db)
|
||||
XCTAssertFalse(person.hasDatabaseChanges)
|
||||
person.name = "Bobby"
|
||||
XCTAssertTrue(person.hasDatabaseChanges)
|
||||
try person.save(db)
|
||||
XCTAssertFalse(person.hasDatabaseChanges)
|
||||
}
|
||||
}
|
||||
|
||||
func testRecordIsEditedAfterPrimaryKeyChange() throws {
|
||||
// After reload, a record is not edited.
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
let person = Person(name: "Arthur", age: 41)
|
||||
try person.insert(db)
|
||||
person.id = person.id + 1
|
||||
XCTAssertTrue(person.hasDatabaseChanges)
|
||||
}
|
||||
try dbQueue.inDatabase { db in
|
||||
let person = PersonWithModifiedCaseColumns(name: "Arthur", age: 41)
|
||||
try person.insert(db)
|
||||
person.id = person.id + 1
|
||||
XCTAssertTrue(person.hasDatabaseChanges)
|
||||
}
|
||||
}
|
||||
|
||||
func testChangesAfterInit() throws {
|
||||
let person = Person(name: "Arthur", age: 41)
|
||||
let changes = try person.databaseChanges
|
||||
XCTAssertEqual(changes.count, 4)
|
||||
for (column, old) in changes {
|
||||
switch column {
|
||||
case "id":
|
||||
XCTAssertTrue(old == nil)
|
||||
case "name":
|
||||
XCTAssertTrue(old == nil)
|
||||
case "age":
|
||||
XCTAssertTrue(old == nil)
|
||||
case "creationDate":
|
||||
XCTAssertTrue(old == nil)
|
||||
default:
|
||||
XCTFail("Unexpected column: \(column)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testChangesAfterInitFromRow() throws {
|
||||
let person = try Person(row: Row(["name": "Arthur", "age": 41]))
|
||||
let changes = try person.databaseChanges
|
||||
XCTAssertEqual(changes.count, 4)
|
||||
for (column, old) in changes {
|
||||
switch column {
|
||||
case "id":
|
||||
XCTAssertTrue(old == nil)
|
||||
case "name":
|
||||
XCTAssertTrue(old == nil)
|
||||
case "age":
|
||||
XCTAssertTrue(old == nil)
|
||||
case "creationDate":
|
||||
XCTAssertTrue(old == nil)
|
||||
default:
|
||||
XCTFail("Unexpected column: \(column)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testChangesAfterFullFetch() throws {
|
||||
// Fetch a record from a row that contains all the columns in
|
||||
// persistence container: An update statement, which only saves the
|
||||
// columns in persistence container would perform no change. So the
|
||||
// record is not edited.
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
try Person(name: "Arthur", age: 41).insert(db)
|
||||
do {
|
||||
let person = try Person.fetchOne(db, sql: "SELECT * FROM persons")!
|
||||
let changes = try person.databaseChanges
|
||||
XCTAssertEqual(changes.count, 0)
|
||||
}
|
||||
do {
|
||||
let persons = try Person.fetchAll(db, sql: "SELECT * FROM persons")
|
||||
let changes = try persons[0].databaseChanges
|
||||
XCTAssertEqual(changes.count, 0)
|
||||
}
|
||||
do {
|
||||
let persons = try Person.fetchCursor(db, sql: "SELECT * FROM persons")
|
||||
let changes = try persons.next()!.databaseChanges
|
||||
XCTAssertEqual(changes.count, 0)
|
||||
}
|
||||
do {
|
||||
let person = try Person.fetchOne(db, sql: "SELECT * FROM persons", adapter: SuffixRowAdapter(fromIndex: 0))!
|
||||
let changes = try person.databaseChanges
|
||||
XCTAssertEqual(changes.count, 0)
|
||||
}
|
||||
}
|
||||
try dbQueue.inDatabase { db in
|
||||
try PersonWithModifiedCaseColumns(name: "Arthur", age: 41).insert(db)
|
||||
let person = try PersonWithModifiedCaseColumns.fetchOne(db, sql: "SELECT * FROM persons")!
|
||||
let changes = try person.databaseChanges
|
||||
XCTAssertEqual(changes.count, 0)
|
||||
}
|
||||
}
|
||||
|
||||
func testChangesAfterPartialFetch() throws {
|
||||
// Fetch a record from a row that does not contain all the columns in
|
||||
// persistence container: An update statement saves the columns in
|
||||
// persistence container, so it may perform unpredictable change.
|
||||
// So the record is edited.
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
try Person(name: "Arthur", age: 41).insert(db)
|
||||
let person = try Person.fetchOne(db, sql: "SELECT name FROM persons")!
|
||||
let changes = try person.databaseChanges
|
||||
XCTAssertEqual(changes.count, 3)
|
||||
for (column, old) in changes {
|
||||
switch column {
|
||||
case "id":
|
||||
XCTAssertTrue(old == nil)
|
||||
case "age":
|
||||
XCTAssertTrue(old == nil)
|
||||
case "creationDate":
|
||||
XCTAssertTrue(old == nil)
|
||||
default:
|
||||
XCTFail("Unexpected column: \(column)")
|
||||
}
|
||||
}
|
||||
}
|
||||
try dbQueue.inDatabase { db in
|
||||
try PersonWithModifiedCaseColumns(name: "Arthur", age: 41).insert(db)
|
||||
let person = try PersonWithModifiedCaseColumns.fetchOne(db, sql: "SELECT name FROM persons")!
|
||||
let changes = try person.databaseChanges
|
||||
XCTAssertEqual(changes.count, 3)
|
||||
for (column, old) in changes {
|
||||
switch column {
|
||||
case "ID":
|
||||
XCTAssertTrue(old == nil)
|
||||
case "AGE":
|
||||
XCTAssertTrue(old == nil)
|
||||
case "CREATIONDATE":
|
||||
XCTAssertTrue(old == nil)
|
||||
default:
|
||||
XCTFail("Unexpected column: \(column)")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testChangesAfterInsert() throws {
|
||||
// After insertion, a record is not edited.
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
let person = Person(name: "Arthur", age: 41)
|
||||
try person.insert(db)
|
||||
let changes = try person.databaseChanges
|
||||
XCTAssertEqual(changes.count, 0)
|
||||
}
|
||||
try dbQueue.inDatabase { db in
|
||||
let person = PersonWithModifiedCaseColumns(name: "Arthur", age: 41)
|
||||
try person.insert(db)
|
||||
let changes = try person.databaseChanges
|
||||
XCTAssertEqual(changes.count, 0)
|
||||
}
|
||||
}
|
||||
|
||||
func testChangesAfterValueChange() throws {
|
||||
// Any change in a value exposed in persistence container yields a
|
||||
// record that is edited.
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
let person = Person(name: "Arthur", age: nil)
|
||||
try person.insert(db)
|
||||
|
||||
person.name = "Bobby" // non-nil -> non-nil
|
||||
person.age = 41 // nil -> non-nil
|
||||
person.creationDate = nil // non-nil -> nil
|
||||
let changes = try person.databaseChanges
|
||||
XCTAssertEqual(changes.count, 3)
|
||||
for (column, old) in changes {
|
||||
switch column {
|
||||
case "name":
|
||||
XCTAssertEqual(old, "Arthur".databaseValue)
|
||||
case "age":
|
||||
XCTAssertEqual(old, DatabaseValue.null)
|
||||
case "creationDate":
|
||||
XCTAssertTrue(Date.fromDatabaseValue(old!) != nil)
|
||||
default:
|
||||
XCTFail("Unexpected column: \(column)")
|
||||
}
|
||||
}
|
||||
}
|
||||
try dbQueue.inDatabase { db in
|
||||
let person = PersonWithModifiedCaseColumns(name: "Arthur", age: nil)
|
||||
try person.insert(db)
|
||||
|
||||
person.name = "Bobby" // non-nil -> non-nil
|
||||
person.age = 41 // nil -> non-nil
|
||||
person.creationDate = nil // non-nil -> nil
|
||||
let changes = try person.databaseChanges
|
||||
XCTAssertEqual(changes.count, 3)
|
||||
for (column, old) in changes {
|
||||
switch column {
|
||||
case "NAME":
|
||||
XCTAssertEqual(old, "Arthur".databaseValue)
|
||||
case "AGE":
|
||||
XCTAssertEqual(old, DatabaseValue.null)
|
||||
case "CREATIONDATE":
|
||||
XCTAssertTrue(Date.fromDatabaseValue(old!) != nil)
|
||||
default:
|
||||
XCTFail("Unexpected column: \(column)")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testChangesAfterUpdate() throws {
|
||||
// After update, a record is not edited.
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
let person = Person(name: "Arthur", age: 41)
|
||||
try person.insert(db)
|
||||
person.name = "Bobby"
|
||||
try person.update(db)
|
||||
XCTAssertFalse(person.hasDatabaseChanges)
|
||||
try XCTAssert(person.databaseChanges.isEmpty)
|
||||
}
|
||||
try dbQueue.inDatabase { db in
|
||||
let person = PersonWithModifiedCaseColumns(name: "Arthur", age: 41)
|
||||
try person.insert(db)
|
||||
person.name = "Bobby"
|
||||
try person.update(db)
|
||||
XCTAssertFalse(person.hasDatabaseChanges)
|
||||
try XCTAssert(person.databaseChanges.isEmpty)
|
||||
}
|
||||
}
|
||||
|
||||
func testChangesAfterSave() throws {
|
||||
// After save, a record is not edited.
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
let person = Person(name: "Arthur", age: 41)
|
||||
try person.save(db)
|
||||
XCTAssertFalse(person.hasDatabaseChanges)
|
||||
try XCTAssert(person.databaseChanges.isEmpty)
|
||||
|
||||
person.name = "Bobby"
|
||||
let changes = try person.databaseChanges
|
||||
XCTAssertEqual(changes.count, 1)
|
||||
for (column, old) in changes {
|
||||
switch column {
|
||||
case "name":
|
||||
XCTAssertEqual(old, "Arthur".databaseValue)
|
||||
default:
|
||||
XCTFail("Unexpected column: \(column)")
|
||||
}
|
||||
}
|
||||
try person.save(db)
|
||||
XCTAssertFalse(person.hasDatabaseChanges)
|
||||
try XCTAssert(person.databaseChanges.isEmpty)
|
||||
}
|
||||
try dbQueue.inDatabase { db in
|
||||
let person = PersonWithModifiedCaseColumns(name: "Arthur", age: 41)
|
||||
try person.save(db)
|
||||
XCTAssertFalse(person.hasDatabaseChanges)
|
||||
try XCTAssert(person.databaseChanges.isEmpty)
|
||||
|
||||
person.name = "Bobby"
|
||||
let changes = try person.databaseChanges
|
||||
XCTAssertEqual(changes.count, 1)
|
||||
for (column, old) in changes {
|
||||
switch column {
|
||||
case "NAME":
|
||||
XCTAssertEqual(old, "Arthur".databaseValue)
|
||||
default:
|
||||
XCTFail("Unexpected column: \(column)")
|
||||
}
|
||||
}
|
||||
try person.save(db)
|
||||
XCTAssertFalse(person.hasDatabaseChanges)
|
||||
try XCTAssert(person.databaseChanges.isEmpty)
|
||||
}
|
||||
}
|
||||
|
||||
func testChangesAfterPrimaryKeyChange() throws {
|
||||
// After reload, a record is not edited.
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
let person = Person(name: "Arthur", age: 41)
|
||||
try person.insert(db)
|
||||
person.id = person.id + 1
|
||||
let changes = try person.databaseChanges
|
||||
XCTAssertEqual(changes.count, 1)
|
||||
for (column, old) in changes {
|
||||
switch column {
|
||||
case "id":
|
||||
XCTAssertEqual(old, (person.id - 1).databaseValue)
|
||||
default:
|
||||
XCTFail("Unexpected column: \(column)")
|
||||
}
|
||||
}
|
||||
}
|
||||
try dbQueue.inDatabase { db in
|
||||
let person = PersonWithModifiedCaseColumns(name: "Arthur", age: 41)
|
||||
try person.insert(db)
|
||||
person.id = person.id + 1
|
||||
let changes = try person.databaseChanges
|
||||
XCTAssertEqual(changes.count, 1)
|
||||
for (column, old) in changes {
|
||||
switch column {
|
||||
case "ID":
|
||||
XCTAssertEqual(old, (person.id - 1).databaseValue)
|
||||
default:
|
||||
XCTFail("Unexpected column: \(column)")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testUpdateChanges() throws {
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
let person = Person(name: "Arthur", age: 41)
|
||||
|
||||
do {
|
||||
XCTAssertTrue(person.hasDatabaseChanges)
|
||||
try person.updateChanges(db)
|
||||
XCTFail("Expected RecordError")
|
||||
} catch RecordError.recordNotFound(databaseTableName: "persons", key: ["id": .null]) { }
|
||||
|
||||
try person.insert(db)
|
||||
|
||||
// Nothing to update
|
||||
let initialChangesCount = db.totalChangesCount
|
||||
XCTAssertFalse(person.hasDatabaseChanges)
|
||||
try XCTAssertFalse(person.updateChanges(db))
|
||||
XCTAssertEqual(db.totalChangesCount, initialChangesCount)
|
||||
|
||||
// Nothing to update
|
||||
person.age = 41
|
||||
XCTAssertFalse(person.hasDatabaseChanges)
|
||||
try XCTAssertFalse(person.updateChanges(db))
|
||||
XCTAssertEqual(db.totalChangesCount, initialChangesCount)
|
||||
|
||||
// Update single column
|
||||
person.age = 42
|
||||
try XCTAssertEqual(Set(person.databaseChanges.keys), ["age"])
|
||||
try XCTAssertTrue(person.updateChanges(db))
|
||||
XCTAssertEqual(db.totalChangesCount, initialChangesCount + 1)
|
||||
XCTAssertEqual(lastSQLQuery, "UPDATE \"persons\" SET \"age\"=42 WHERE \"id\"=1")
|
||||
|
||||
// Update two columns
|
||||
person.name = "Barbara"
|
||||
person.age = 43
|
||||
try XCTAssertEqual(Set(person.databaseChanges.keys), ["age", "name"])
|
||||
try XCTAssertTrue(person.updateChanges(db))
|
||||
XCTAssertEqual(db.totalChangesCount, initialChangesCount + 2)
|
||||
let fetchedPerson = try Person.fetchOne(db, key: person.id)
|
||||
XCTAssertEqual(fetchedPerson?.name, person.name)
|
||||
XCTAssertEqual(fetchedPerson?.age, person.age)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user