Files
UUVPN/iOS-SwiftUI-Code/GRDB.swift-6.29.3/Tests/GRDBTests/RecordPrimaryKeySingleWithReplaceConflictResolutionTests.swift

761 lines
27 KiB
Swift

import XCTest
import GRDB
class Email : Record, Hashable {
var email: String!
var label: String?
init(email: String? = nil, label: String? = nil) {
self.email = email
self.label = label
super.init()
}
static func setup(inDatabase db: Database) throws {
try db.execute(sql: """
CREATE TABLE emails (
email TEXT NOT NULL PRIMARY KEY ON CONFLICT REPLACE,
label TEXT)
""")
}
// Record
override class var databaseTableName: String {
"emails"
}
required init(row: Row) throws {
email = row["email"]
label = row["label"]
try super.init(row: row)
}
override func encode(to container: inout PersistenceContainer) throws {
container["email"] = email
container["label"] = label
}
static func == (lhs: Email, rhs: Email) -> Bool {
lhs.label == rhs.label && lhs.email == rhs.email
}
func hash(into hasher: inout Hasher) {
hasher.combine(label)
hasher.combine(email)
}
}
class RecordPrimaryKeySingleWithReplaceConflictResolutionTests: GRDBTestCase {
override func setup(_ dbWriter: some DatabaseWriter) throws {
var migrator = DatabaseMigrator()
migrator.registerMigration("createEmail", migrate: Email.setup)
try migrator.migrate(dbWriter)
}
// MARK: - Insert
func testInsertWithNilPrimaryKeyThrowsDatabaseError() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
let record = Email()
XCTAssertTrue(record.email == nil)
do {
try record.insert(db)
XCTFail("Expected DatabaseError")
} catch is DatabaseError {
// Expected DatabaseError
}
}
}
func testInsertWithNotNilPrimaryKeyThatDoesNotMatchAnyRowInsertsARow() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
let record = Email()
record.email = "me@domain.com"
record.label = "Home"
try record.insert(db)
let row = try Row.fetchOne(db, sql: "SELECT * FROM emails WHERE email = ?", arguments: [record.email])!
try assert(record, isEncodedIn: row)
}
}
func testInsertWithNotNilPrimaryKeyThatMatchesARowReplacesARow() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
let record = Email()
record.email = "me@domain.com"
record.label = "Home"
try record.insert(db)
record.label = "Work"
try record.insert(db)
let row = try Row.fetchOne(db, sql: "SELECT * FROM emails WHERE email = ?", arguments: [record.email])!
try assert(record, isEncodedIn: row)
}
}
func testInsertAfterDeleteInsertsARow() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
let record = Email()
record.email = "me@domain.com"
try record.insert(db)
try record.delete(db)
try record.insert(db)
let row = try Row.fetchOne(db, sql: "SELECT * FROM emails WHERE email = ?", arguments: [record.email])!
try assert(record, isEncodedIn: row)
}
}
// MARK: - Update
func testUpdateWithNotNilPrimaryKeyThatDoesNotMatchAnyRowThrowsRecordNotFound() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
let record = Email()
record.email = "me@domain.com"
do {
try record.update(db)
XCTFail("Expected RecordError.recordNotFound")
} catch let RecordError.recordNotFound(databaseTableName: databaseTableName, key: key) {
// Expected RecordError.recordNotFound
XCTAssertEqual(databaseTableName, "emails")
XCTAssertEqual(key, ["email": record.email.databaseValue])
}
}
}
func testUpdateWithNotNilPrimaryKeyThatMatchesARowUpdatesThatRow() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
let record = Email()
record.email = "me@domain.com"
try record.insert(db)
try record.update(db)
let row = try Row.fetchOne(db, sql: "SELECT * FROM emails WHERE email = ?", arguments: [record.email])!
try assert(record, isEncodedIn: row)
}
}
func testUpdateAfterDeleteThrowsRecordNotFound() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
let record = Email()
record.email = "me@domain.com"
try record.insert(db)
try record.delete(db)
do {
try record.update(db)
XCTFail("Expected RecordError.recordNotFound")
} catch let RecordError.recordNotFound(databaseTableName: databaseTableName, key: key) {
// Expected RecordError.recordNotFound
XCTAssertEqual(databaseTableName, "emails")
XCTAssertEqual(key, ["email": record.email.databaseValue])
}
}
}
// MARK: - Save
func testSaveWithNilPrimaryKeyThrowsDatabaseError() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
let record = Email()
XCTAssertTrue(record.email == nil)
do {
try record.save(db)
XCTFail("Expected DatabaseError")
} catch is DatabaseError {
// Expected DatabaseError
}
}
}
func testSaveWithNotNilPrimaryKeyThatDoesNotMatchAnyRowInsertsARow() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
let record = Email()
record.email = "me@domain.com"
try record.save(db)
let row = try Row.fetchOne(db, sql: "SELECT * FROM emails WHERE email = ?", arguments: [record.email])!
try assert(record, isEncodedIn: row)
}
}
func testSaveWithNotNilPrimaryKeyThatMatchesARowUpdatesThatRow() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
let record = Email()
record.email = "me@domain.com"
try record.insert(db)
try record.save(db)
let row = try Row.fetchOne(db, sql: "SELECT * FROM emails WHERE email = ?", arguments: [record.email])!
try assert(record, isEncodedIn: row)
}
}
func testSaveAfterDeleteInsertsARow() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
let record = Email()
record.email = "me@domain.com"
try record.insert(db)
try record.delete(db)
try record.save(db)
let row = try Row.fetchOne(db, sql: "SELECT * FROM emails WHERE email = ?", arguments: [record.email])!
try assert(record, isEncodedIn: row)
}
}
// MARK: - Delete
func testDeleteWithNotNilPrimaryKeyThatDoesNotMatchAnyRowDoesNothing() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
let record = Email()
record.email = "me@domain.com"
let deleted = try record.delete(db)
XCTAssertFalse(deleted)
}
}
func testDeleteWithNotNilPrimaryKeyThatMatchesARowDeletesThatRow() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
let record = Email()
record.email = "me@domain.com"
try record.insert(db)
let deleted = try record.delete(db)
XCTAssertTrue(deleted)
let row = try Row.fetchOne(db, sql: "SELECT * FROM emails WHERE email = ?", arguments: [record.email])
XCTAssertTrue(row == nil)
}
}
func testDeleteAfterDeleteDoesNothing() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
let record = Email()
record.email = "me@domain.com"
try record.insert(db)
var deleted = try record.delete(db)
XCTAssertTrue(deleted)
deleted = try record.delete(db)
XCTAssertFalse(deleted)
}
}
// MARK: - Fetch With Key
func testFetchCursorWithKeys() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
let record1 = Email()
record1.email = "me@domain.com"
try record1.insert(db)
let record2 = Email()
record2.email = "you@domain.com"
try record2.insert(db)
do {
let cursor = try Email.fetchCursor(db, keys: [])
try XCTAssertNil(cursor.next())
}
do {
let cursor = try Email.fetchCursor(db, keys: [["email": record1.email], ["email": record2.email]])
let fetchedRecords = try [cursor.next()!, cursor.next()!]
XCTAssertEqual(Set(fetchedRecords.map(\.email)), Set([record1.email, record2.email]))
XCTAssertTrue(try cursor.next() == nil) // end
}
do {
let cursor = try Email.fetchCursor(db, keys: [["email": record1.email], ["email": nil]])
let fetchedRecord = try cursor.next()!
XCTAssertEqual(fetchedRecord.email, record1.email)
XCTAssertTrue(try cursor.next() == nil) // end
}
}
}
func testFetchAllWithKeys() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
let record1 = Email()
record1.email = "me@domain.com"
try record1.insert(db)
let record2 = Email()
record2.email = "you@domain.com"
try record2.insert(db)
do {
let fetchedRecords = try Email.fetchAll(db, keys: [])
XCTAssertEqual(fetchedRecords.count, 0)
}
do {
let fetchedRecords = try Email.fetchAll(db, keys: [["email": record1.email], ["email": record2.email]])
XCTAssertEqual(fetchedRecords.count, 2)
XCTAssertEqual(Set(fetchedRecords.map(\.email)), Set([record1.email, record2.email]))
}
do {
let fetchedRecords = try Email.fetchAll(db, keys: [["email": record1.email], ["email": nil]])
XCTAssertEqual(fetchedRecords.count, 1)
XCTAssertEqual(fetchedRecords.first!.email, record1.email!)
}
}
}
func testFetchSetWithKeys() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
let record1 = Email()
record1.email = "me@domain.com"
try record1.insert(db)
let record2 = Email()
record2.email = "you@domain.com"
try record2.insert(db)
do {
let fetchedRecords = try Email.fetchSet(db, keys: [])
XCTAssertEqual(fetchedRecords.count, 0)
}
do {
let fetchedRecords = try Email.fetchSet(db, keys: [["email": record1.email], ["email": record2.email]])
XCTAssertEqual(fetchedRecords.count, 2)
XCTAssertEqual(Set(fetchedRecords.map(\.email)), Set([record1.email, record2.email]))
}
do {
let fetchedRecords = try Email.fetchSet(db, keys: [["email": record1.email], ["email": nil]])
XCTAssertEqual(fetchedRecords.count, 1)
XCTAssertEqual(fetchedRecords.first!.email, record1.email!)
}
}
}
func testFetchOneWithKey() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
let record = Email()
record.email = "me@domain.com"
try record.insert(db)
let fetchedRecord = try Email.fetchOne(db, key: ["email": record.email])!
XCTAssertTrue(fetchedRecord.email == record.email)
XCTAssertEqual(lastSQLQuery, "SELECT * FROM \"emails\" WHERE \"email\" = '\(record.email!)'")
}
}
func testFindWithKey() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
let record = Email()
record.email = "me@domain.com"
try record.insert(db)
let fetchedRecord = try Email.find(db, key: ["email": record.email])
XCTAssertTrue(fetchedRecord.email == record.email)
XCTAssertEqual(lastSQLQuery, "SELECT * FROM \"emails\" WHERE \"email\" = '\(record.email!)'")
}
}
// MARK: - Fetch With Key Request
func testFetchCursorWithKeysRequest() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
let record1 = Email()
record1.email = "me@domain.com"
try record1.insert(db)
let record2 = Email()
record2.email = "you@domain.com"
try record2.insert(db)
do {
let cursor = try Email.filter(keys: []).fetchCursor(db)
try XCTAssertNil(cursor.next())
}
do {
let cursor = try Email.filter(keys: [["email": record1.email], ["email": record2.email]]).fetchCursor(db)
let fetchedRecords = try [cursor.next()!, cursor.next()!]
XCTAssertEqual(Set(fetchedRecords.map(\.email)), Set([record1.email, record2.email]))
XCTAssertTrue(try cursor.next() == nil) // end
}
do {
let cursor = try Email.filter(keys: [["email": record1.email], ["email": nil]]).fetchCursor(db)
let fetchedRecord = try cursor.next()!
XCTAssertEqual(fetchedRecord.email, record1.email)
XCTAssertTrue(try cursor.next() == nil) // end
}
}
}
func testFetchAllWithKeysRequest() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
let record1 = Email()
record1.email = "me@domain.com"
try record1.insert(db)
let record2 = Email()
record2.email = "you@domain.com"
try record2.insert(db)
do {
let fetchedRecords = try Email.filter(keys: []).fetchAll(db)
XCTAssertEqual(fetchedRecords.count, 0)
}
do {
let fetchedRecords = try Email.filter(keys: [["email": record1.email], ["email": record2.email]]).fetchAll(db)
XCTAssertEqual(fetchedRecords.count, 2)
XCTAssertEqual(Set(fetchedRecords.map(\.email)), Set([record1.email, record2.email]))
}
do {
let fetchedRecords = try Email.filter(keys: [["email": record1.email], ["email": nil]]).fetchAll(db)
XCTAssertEqual(fetchedRecords.count, 1)
XCTAssertEqual(fetchedRecords.first!.email, record1.email!)
}
}
}
func testFetchSetWithKeysRequest() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
let record1 = Email()
record1.email = "me@domain.com"
try record1.insert(db)
let record2 = Email()
record2.email = "you@domain.com"
try record2.insert(db)
do {
let fetchedRecords = try Email.filter(keys: []).fetchSet(db)
XCTAssertEqual(fetchedRecords.count, 0)
}
do {
let fetchedRecords = try Email.filter(keys: [["email": record1.email], ["email": record2.email]]).fetchSet(db)
XCTAssertEqual(fetchedRecords.count, 2)
XCTAssertEqual(Set(fetchedRecords.map(\.email)), Set([record1.email, record2.email]))
}
do {
let fetchedRecords = try Email.filter(keys: [["email": record1.email], ["email": nil]]).fetchSet(db)
XCTAssertEqual(fetchedRecords.count, 1)
XCTAssertEqual(fetchedRecords.first!.email, record1.email!)
}
}
}
func testFetchOneWithKeyRequest() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
let record = Email()
record.email = "me@domain.com"
try record.insert(db)
let fetchedRecord = try Email.filter(key: ["email": record.email]).fetchOne(db)!
XCTAssertTrue(fetchedRecord.email == record.email)
XCTAssertEqual(lastSQLQuery, "SELECT * FROM \"emails\" WHERE \"email\" = '\(record.email!)'")
}
}
// MARK: - Order By Primary Key
func testOrderByPrimaryKey() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
let request = Email.orderByPrimaryKey()
try assertEqualSQL(db, request, "SELECT * FROM \"emails\" ORDER BY \"email\"")
}
}
// MARK: - Stable order
func testStableOrder() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
let request = Email.all().withStableOrder()
try assertEqualSQL(db, request, "SELECT * FROM \"emails\" ORDER BY \"email\"")
}
}
// MARK: - Fetch With Primary Key
func testFetchCursorWithPrimaryKeys() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
let record1 = Email()
record1.email = "me@domain.com"
try record1.insert(db)
let record2 = Email()
record2.email = "you@domain.com"
try record2.insert(db)
do {
let emails: [String] = []
let cursor = try Email.fetchCursor(db, keys: emails)
try XCTAssertNil(cursor.next())
}
do {
let emails = [record1.email!, record2.email!]
let cursor = try Email.fetchCursor(db, keys: emails)
let fetchedRecords = try [cursor.next()!, cursor.next()!]
XCTAssertEqual(Set(fetchedRecords.map { $0.email! }), Set(emails))
XCTAssertTrue(try cursor.next() == nil) // end
}
}
}
func testFetchAllWithPrimaryKeys() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
let record1 = Email()
record1.email = "me@domain.com"
try record1.insert(db)
let record2 = Email()
record2.email = "you@domain.com"
try record2.insert(db)
do {
let emails: [String] = []
let fetchedRecords = try Email.fetchAll(db, keys: emails)
XCTAssertEqual(fetchedRecords.count, 0)
}
do {
let emails = [record1.email!, record2.email!]
let fetchedRecords = try Email.fetchAll(db, keys: emails)
XCTAssertEqual(fetchedRecords.count, 2)
XCTAssertEqual(Set(fetchedRecords.map(\.email)), Set(emails))
}
}
}
func testFetchSetWithPrimaryKeys() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
let record1 = Email()
record1.email = "me@domain.com"
try record1.insert(db)
let record2 = Email()
record2.email = "you@domain.com"
try record2.insert(db)
do {
let emails: [String] = []
let fetchedRecords = try Email.fetchSet(db, keys: emails)
XCTAssertEqual(fetchedRecords.count, 0)
}
do {
let emails = [record1.email!, record2.email!]
let fetchedRecords = try Email.fetchSet(db, keys: emails)
XCTAssertEqual(fetchedRecords.count, 2)
XCTAssertEqual(Set(fetchedRecords.map(\.email)), Set(emails))
}
}
}
func testFetchOneWithPrimaryKey() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
let record = Email()
record.email = "me@domain.com"
try record.insert(db)
do {
let id: String? = nil
let fetchedRecord = try Email.fetchOne(db, key: id)
XCTAssertTrue(fetchedRecord == nil)
}
do {
let fetchedRecord = try Email.fetchOne(db, key: record.email)!
XCTAssertTrue(fetchedRecord.email == record.email)
XCTAssertEqual(lastSQLQuery, "SELECT * FROM \"emails\" WHERE \"email\" = '\(record.email!)'")
}
}
}
func testFindWithPrimaryKey() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
let record = Email()
record.email = "me@domain.com"
try record.insert(db)
do {
let id: String? = nil
_ = try Email.find(db, key: id)
XCTFail("Expected RecordError")
} catch RecordError.recordNotFound(databaseTableName: "emails", key: ["email": .null]) { }
do {
let fetchedRecord = try Email.find(db, key: record.email)
XCTAssertTrue(fetchedRecord.email == record.email)
XCTAssertEqual(lastSQLQuery, "SELECT * FROM \"emails\" WHERE \"email\" = '\(record.email!)'")
}
}
}
// MARK: - Fetch With Primary Key Request
func testFetchCursorWithPrimaryKeysRequest() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
let record1 = Email()
record1.email = "me@domain.com"
try record1.insert(db)
let record2 = Email()
record2.email = "you@domain.com"
try record2.insert(db)
do {
let emails: [String] = []
let cursor = try Email.filter(keys: emails).fetchCursor(db)
try XCTAssertNil(cursor.next())
}
do {
let emails = [record1.email!, record2.email!]
let cursor = try Email.filter(keys: emails).fetchCursor(db)
let fetchedRecords = try [cursor.next()!, cursor.next()!]
XCTAssertEqual(Set(fetchedRecords.map { $0.email! }), Set(emails))
XCTAssertTrue(try cursor.next() == nil) // end
}
}
}
func testFetchAllWithPrimaryKeysRequest() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
let record1 = Email()
record1.email = "me@domain.com"
try record1.insert(db)
let record2 = Email()
record2.email = "you@domain.com"
try record2.insert(db)
do {
let emails: [String] = []
let fetchedRecords = try Email.filter(keys: emails).fetchAll(db)
XCTAssertEqual(fetchedRecords.count, 0)
}
do {
let emails = [record1.email!, record2.email!]
let fetchedRecords = try Email.filter(keys: emails).fetchAll(db)
XCTAssertEqual(fetchedRecords.count, 2)
XCTAssertEqual(Set(fetchedRecords.map(\.email)), Set(emails))
}
}
}
func testFetchSetWithPrimaryKeysRequest() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
let record1 = Email()
record1.email = "me@domain.com"
try record1.insert(db)
let record2 = Email()
record2.email = "you@domain.com"
try record2.insert(db)
do {
let emails: [String] = []
let fetchedRecords = try Email.filter(keys: emails).fetchSet(db)
XCTAssertEqual(fetchedRecords.count, 0)
}
do {
let emails = [record1.email!, record2.email!]
let fetchedRecords = try Email.filter(keys: emails).fetchSet(db)
XCTAssertEqual(fetchedRecords.count, 2)
XCTAssertEqual(Set(fetchedRecords.map(\.email)), Set(emails))
}
}
}
func testFetchOneWithPrimaryKeyRequest() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
let record = Email()
record.email = "me@domain.com"
try record.insert(db)
do {
let id: String? = nil
let fetchedRecord = try Email.filter(key: id).fetchOne(db)
XCTAssertTrue(fetchedRecord == nil)
}
do {
let fetchedRecord = try Email.filter(key: record.email).fetchOne(db)!
XCTAssertTrue(fetchedRecord.email == record.email)
XCTAssertEqual(lastSQLQuery, "SELECT * FROM \"emails\" WHERE \"email\" = '\(record.email!)'")
}
}
}
// MARK: - Exists
func testExistsWithNotNilPrimaryKeyThatDoesNotMatchAnyRowReturnsFalse() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
let record = Email()
record.email = "me@domain.com"
XCTAssertFalse(try record.exists(db))
}
}
func testExistsWithNotNilPrimaryKeyThatMatchesARowReturnsTrue() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
let record = Email()
record.email = "me@domain.com"
try record.insert(db)
XCTAssertTrue(try record.exists(db))
}
}
func testExistsAfterDeleteReturnsTrue() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
let record = Email()
record.email = "me@domain.com"
try record.insert(db)
try record.delete(db)
XCTAssertFalse(try record.exists(db))
}
}
}