add
This commit is contained in:
@@ -1,820 +0,0 @@
|
||||
import XCTest
|
||||
import GRDB
|
||||
|
||||
// Person has a RowID primary key, and an overridden insert() method.
|
||||
private class Person : Record, Hashable {
|
||||
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
|
||||
}
|
||||
|
||||
static func == (lhs: Person, rhs: Person) -> Bool {
|
||||
lhs.id == rhs.id
|
||||
&& lhs.name == rhs.name
|
||||
&& lhs.age == rhs.age
|
||||
&& lhs.creationDate == rhs.creationDate
|
||||
}
|
||||
|
||||
func hash(into hasher: inout Hasher) {
|
||||
hasher.combine(id)
|
||||
hasher.combine(name)
|
||||
hasher.combine(age)
|
||||
hasher.combine(creationDate)
|
||||
}
|
||||
}
|
||||
|
||||
class RecordPrimaryKeyRowIDTests: GRDBTestCase {
|
||||
|
||||
override func setup(_ dbWriter: some DatabaseWriter) throws {
|
||||
var migrator = DatabaseMigrator()
|
||||
migrator.registerMigration("createPerson", migrate: Person.setup)
|
||||
try migrator.migrate(dbWriter)
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Insert
|
||||
|
||||
func testInsertWithNilPrimaryKeyInsertsARowAndSetsPrimaryKey() throws {
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
let record = Person(name: "Arthur")
|
||||
XCTAssertTrue(record.id == nil)
|
||||
try record.insert(db)
|
||||
XCTAssertTrue(record.id != nil)
|
||||
|
||||
let row = try Row.fetchOne(db, sql: "SELECT * FROM persons WHERE id = ?", arguments: [record.id])!
|
||||
try assert(record, isEncodedIn: row)
|
||||
}
|
||||
}
|
||||
|
||||
func testRollbackedInsertWithNilPrimaryKeyDoesNotResetPrimaryKey() throws {
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
let record = Person(name: "Arthur")
|
||||
try dbQueue.inTransaction { db in
|
||||
XCTAssertTrue(record.id == nil)
|
||||
try record.insert(db)
|
||||
XCTAssertTrue(record.id != nil)
|
||||
|
||||
let row = try Row.fetchOne(db, sql: "SELECT * FROM persons WHERE id = ?", arguments: [record.id])!
|
||||
try assert(record, isEncodedIn: row)
|
||||
return .rollback
|
||||
}
|
||||
// This is debatable, actually.
|
||||
XCTAssertTrue(record.id != nil)
|
||||
}
|
||||
|
||||
func testInsertWithNotNilPrimaryKeyThatDoesNotMatchAnyRowInsertsARow() throws {
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
let record = Person(id: 123456, name: "Arthur")
|
||||
try record.insert(db)
|
||||
|
||||
let row = try Row.fetchOne(db, sql: "SELECT * FROM persons WHERE id = ?", arguments: [record.id])!
|
||||
try assert(record, isEncodedIn: row)
|
||||
}
|
||||
}
|
||||
|
||||
func testRollbackedInsertWithNotNilPrimaryKeyDoeNotResetPrimaryKey() throws {
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
let record = Person(id: 123456, name: "Arthur")
|
||||
try dbQueue.inTransaction { db in
|
||||
try record.insert(db)
|
||||
XCTAssertEqual(record.id!, 123456)
|
||||
return .rollback
|
||||
}
|
||||
XCTAssertEqual(record.id!, 123456)
|
||||
}
|
||||
|
||||
func testInsertWithNotNilPrimaryKeyThatMatchesARowThrowsDatabaseError() throws {
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
let record = Person(name: "Arthur")
|
||||
try record.insert(db)
|
||||
do {
|
||||
try record.insert(db)
|
||||
XCTFail("Expected DatabaseError")
|
||||
} catch is DatabaseError {
|
||||
// Expected DatabaseError
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testInsertAfterDeleteInsertsARow() throws {
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
let record = Person(name: "Arthur")
|
||||
try record.insert(db)
|
||||
try record.delete(db)
|
||||
try record.insert(db)
|
||||
|
||||
let row = try Row.fetchOne(db, sql: "SELECT * FROM persons WHERE id = ?", arguments: [record.id])!
|
||||
try assert(record, isEncodedIn: row)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Update
|
||||
|
||||
func testUpdateWithNilPrimaryKeyThrowsRecordNotFound() throws {
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
let record = Person(id: nil, name: "Arthur")
|
||||
do {
|
||||
try record.update(db)
|
||||
XCTFail("Expected RecordError.recordNotFound")
|
||||
} catch let RecordError.recordNotFound(databaseTableName: databaseTableName, key: key) {
|
||||
// Expected RecordError.recordNotFound
|
||||
XCTAssertEqual(databaseTableName, "persons")
|
||||
XCTAssertEqual(key, ["id": .null])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testUpdateWithNotNilPrimaryKeyThatDoesNotMatchAnyRowThrowsRecordNotFound() throws {
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
let record = Person(id: 123456, name: "Arthur")
|
||||
do {
|
||||
try record.update(db)
|
||||
XCTFail("Expected RecordError.recordNotFound")
|
||||
} catch let RecordError.recordNotFound(databaseTableName: databaseTableName, key: key) {
|
||||
// Expected RecordError.recordNotFound
|
||||
XCTAssertEqual(databaseTableName, "persons")
|
||||
XCTAssertEqual(key, ["id": record.id.databaseValue])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testUpdateWithNotNilPrimaryKeyThatMatchesARowUpdatesThatRow() throws {
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
let record = Person(name: "Arthur", age: 41)
|
||||
try record.insert(db)
|
||||
record.age = record.age! + 1
|
||||
try record.update(db)
|
||||
|
||||
let row = try Row.fetchOne(db, sql: "SELECT * FROM persons WHERE id = ?", arguments: [record.id])!
|
||||
try assert(record, isEncodedIn: row)
|
||||
}
|
||||
}
|
||||
|
||||
func testUpdateAfterDeleteThrowsRecordNotFound() throws {
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
let record = Person(name: "Arthur")
|
||||
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, "persons")
|
||||
XCTAssertEqual(key, ["id": record.id.databaseValue])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Save
|
||||
|
||||
func testSaveWithNilPrimaryKeyInsertsARowAndSetsPrimaryKey() throws {
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
let record = Person(name: "Arthur")
|
||||
XCTAssertTrue(record.id == nil)
|
||||
try record.save(db)
|
||||
XCTAssertTrue(record.id != nil)
|
||||
|
||||
let row = try Row.fetchOne(db, sql: "SELECT * FROM persons WHERE id = ?", arguments: [record.id])!
|
||||
try assert(record, isEncodedIn: row)
|
||||
}
|
||||
}
|
||||
|
||||
func testSaveWithNotNilPrimaryKeyThatDoesNotMatchAnyRowInsertsARow() throws {
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
let record = Person(id: 123456, name: "Arthur")
|
||||
try record.save(db)
|
||||
|
||||
let row = try Row.fetchOne(db, sql: "SELECT * FROM persons WHERE id = ?", arguments: [record.id])!
|
||||
try assert(record, isEncodedIn: row)
|
||||
}
|
||||
}
|
||||
|
||||
func testSaveWithNotNilPrimaryKeyThatMatchesARowUpdatesThatRow() throws {
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
let record = Person(name: "Arthur", age: 41)
|
||||
try record.insert(db)
|
||||
try record.save(db) // Test that useless update succeeds. It is a proof that save() has performed an UPDATE statement, and not an INSERT statement: INSERT would have throw a database error for duplicated key.
|
||||
record.age = record.age! + 1
|
||||
try record.save(db) // Actual update
|
||||
|
||||
let row = try Row.fetchOne(db, sql: "SELECT * FROM persons WHERE id = ?", arguments: [record.id])!
|
||||
try assert(record, isEncodedIn: row)
|
||||
}
|
||||
}
|
||||
|
||||
func testSaveAfterDeleteInsertsARow() throws {
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
let record = Person(name: "Arthur")
|
||||
try record.insert(db)
|
||||
try record.delete(db)
|
||||
try record.save(db)
|
||||
|
||||
let row = try Row.fetchOne(db, sql: "SELECT * FROM persons WHERE id = ?", arguments: [record.id])!
|
||||
try assert(record, isEncodedIn: row)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Delete
|
||||
|
||||
func testDeleteWithNilPrimaryKey() throws {
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
let record = Person(id: nil, name: "Arthur")
|
||||
let deleted = try record.delete(db)
|
||||
XCTAssertFalse(deleted)
|
||||
}
|
||||
}
|
||||
|
||||
func testDeleteWithNotNilPrimaryKeyThatDoesNotMatchAnyRowDoesNothing() throws {
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
let record = Person(id: 123456, name: "Arthur")
|
||||
let deleted = try record.delete(db)
|
||||
XCTAssertFalse(deleted)
|
||||
}
|
||||
}
|
||||
|
||||
func testDeleteWithNotNilPrimaryKeyThatMatchesARowDeletesThatRow() throws {
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
let record = Person(name: "Arthur")
|
||||
try record.insert(db)
|
||||
let deleted = try record.delete(db)
|
||||
XCTAssertTrue(deleted)
|
||||
|
||||
let row = try Row.fetchOne(db, sql: "SELECT * FROM persons WHERE id = ?", arguments: [record.id])
|
||||
XCTAssertTrue(row == nil)
|
||||
}
|
||||
}
|
||||
|
||||
func testDeleteAfterDeleteDoesNothing() throws {
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
let record = Person(name: "Arthur")
|
||||
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 = Person(name: "Arthur")
|
||||
try record1.insert(db)
|
||||
let record2 = Person(name: "Barbara")
|
||||
try record2.insert(db)
|
||||
|
||||
do {
|
||||
let cursor = try Person.fetchCursor(db, keys: [])
|
||||
try XCTAssertNil(cursor.next())
|
||||
}
|
||||
|
||||
do {
|
||||
let cursor = try Person.fetchCursor(db, keys: [["id": record1.id], ["id": record2.id]])
|
||||
let fetchedRecords = try [cursor.next()!, cursor.next()!]
|
||||
XCTAssertEqual(Set(fetchedRecords.map(\.id)), Set([record1.id, record2.id]))
|
||||
XCTAssertTrue(try cursor.next() == nil) // end
|
||||
}
|
||||
|
||||
do {
|
||||
let cursor = try Person.fetchCursor(db, keys: [["id": record1.id], ["id": nil]])
|
||||
let fetchedRecord = try cursor.next()!
|
||||
XCTAssertEqual(fetchedRecord.id!, record1.id!)
|
||||
XCTAssertTrue(try cursor.next() == nil) // end
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testFetchAllWithKeys() throws {
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
let record1 = Person(name: "Arthur")
|
||||
try record1.insert(db)
|
||||
let record2 = Person(name: "Barbara")
|
||||
try record2.insert(db)
|
||||
|
||||
do {
|
||||
let fetchedRecords = try Person.fetchAll(db, keys: [])
|
||||
XCTAssertEqual(fetchedRecords.count, 0)
|
||||
}
|
||||
|
||||
do {
|
||||
let fetchedRecords = try Person.fetchAll(db, keys: [["id": record1.id], ["id": record2.id]])
|
||||
XCTAssertEqual(fetchedRecords.count, 2)
|
||||
XCTAssertEqual(Set(fetchedRecords.map(\.id)), Set([record1.id, record2.id]))
|
||||
}
|
||||
|
||||
do {
|
||||
let fetchedRecords = try Person.fetchAll(db, keys: [["id": record1.id], ["id": nil]])
|
||||
XCTAssertEqual(fetchedRecords.count, 1)
|
||||
XCTAssertEqual(fetchedRecords.first!.id, record1.id!)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testFetchSetWithKeys() throws {
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
let record1 = Person(name: "Arthur")
|
||||
try record1.insert(db)
|
||||
let record2 = Person(name: "Barbara")
|
||||
try record2.insert(db)
|
||||
|
||||
do {
|
||||
let fetchedRecords = try Person.fetchSet(db, keys: [])
|
||||
XCTAssertEqual(fetchedRecords.count, 0)
|
||||
}
|
||||
|
||||
do {
|
||||
let fetchedRecords = try Person.fetchSet(db, keys: [["id": record1.id], ["id": record2.id]])
|
||||
XCTAssertEqual(fetchedRecords.count, 2)
|
||||
XCTAssertEqual(Set(fetchedRecords.map(\.id)), Set([record1.id, record2.id]))
|
||||
}
|
||||
|
||||
do {
|
||||
let fetchedRecords = try Person.fetchSet(db, keys: [["id": record1.id], ["id": nil]])
|
||||
XCTAssertEqual(fetchedRecords.count, 1)
|
||||
XCTAssertEqual(fetchedRecords.first!.id, record1.id!)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testFetchOneWithKey() throws {
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
let record = Person(name: "Arthur")
|
||||
try record.insert(db)
|
||||
|
||||
let fetchedRecord = try Person.fetchOne(db, key: ["id": record.id])!
|
||||
XCTAssertTrue(fetchedRecord.id == record.id)
|
||||
XCTAssertTrue(fetchedRecord.name == record.name)
|
||||
XCTAssertTrue(fetchedRecord.age == record.age)
|
||||
XCTAssertTrue(abs(fetchedRecord.creationDate.timeIntervalSince(record.creationDate)) < 1e-3) // ISO-8601 is precise to the millisecond.
|
||||
XCTAssertEqual(lastSQLQuery, "SELECT * FROM \"persons\" WHERE \"id\" = \(record.id!)")
|
||||
}
|
||||
}
|
||||
|
||||
func testFindWithKey() throws {
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
let record = Person(name: "Arthur")
|
||||
try record.insert(db)
|
||||
|
||||
let fetchedRecord = try Person.find(db, key: ["id": record.id])
|
||||
XCTAssertTrue(fetchedRecord.id == record.id)
|
||||
XCTAssertTrue(fetchedRecord.name == record.name)
|
||||
XCTAssertTrue(fetchedRecord.age == record.age)
|
||||
XCTAssertTrue(abs(fetchedRecord.creationDate.timeIntervalSince(record.creationDate)) < 1e-3) // ISO-8601 is precise to the millisecond.
|
||||
XCTAssertEqual(lastSQLQuery, "SELECT * FROM \"persons\" WHERE \"id\" = \(record.id!)")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Fetch With Key Request
|
||||
|
||||
func testFetchCursorWithKeysRequest() throws {
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
let record1 = Person(name: "Arthur")
|
||||
try record1.insert(db)
|
||||
let record2 = Person(name: "Barbara")
|
||||
try record2.insert(db)
|
||||
|
||||
do {
|
||||
let cursor = try Person.filter(keys: []).fetchCursor(db)
|
||||
try XCTAssertNil(cursor.next())
|
||||
}
|
||||
|
||||
do {
|
||||
let cursor = try Person.filter(keys: [["id": record1.id], ["id": record2.id]]).fetchCursor(db)
|
||||
let fetchedRecords = try [cursor.next()!, cursor.next()!]
|
||||
XCTAssertEqual(Set(fetchedRecords.map(\.id)), Set([record1.id, record2.id]))
|
||||
XCTAssertTrue(try cursor.next() == nil) // end
|
||||
}
|
||||
|
||||
do {
|
||||
let cursor = try Person.filter(keys: [["id": record1.id], ["id": nil]]).fetchCursor(db)
|
||||
let fetchedRecord = try cursor.next()!
|
||||
XCTAssertEqual(fetchedRecord.id!, record1.id!)
|
||||
XCTAssertTrue(try cursor.next() == nil) // end
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testFetchAllWithKeysRequest() throws {
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
let record1 = Person(name: "Arthur")
|
||||
try record1.insert(db)
|
||||
let record2 = Person(name: "Barbara")
|
||||
try record2.insert(db)
|
||||
|
||||
do {
|
||||
let fetchedRecords = try Person.filter(keys: []).fetchAll(db)
|
||||
XCTAssertEqual(fetchedRecords.count, 0)
|
||||
}
|
||||
|
||||
do {
|
||||
let fetchedRecords = try Person.filter(keys: [["id": record1.id], ["id": record2.id]]).fetchAll(db)
|
||||
XCTAssertEqual(fetchedRecords.count, 2)
|
||||
XCTAssertEqual(Set(fetchedRecords.map(\.id)), Set([record1.id, record2.id]))
|
||||
}
|
||||
|
||||
do {
|
||||
let fetchedRecords = try Person.filter(keys: [["id": record1.id], ["id": nil]]).fetchAll(db)
|
||||
XCTAssertEqual(fetchedRecords.count, 1)
|
||||
XCTAssertEqual(fetchedRecords.first!.id, record1.id!)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testFetchSetWithKeysRequest() throws {
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
let record1 = Person(name: "Arthur")
|
||||
try record1.insert(db)
|
||||
let record2 = Person(name: "Barbara")
|
||||
try record2.insert(db)
|
||||
|
||||
do {
|
||||
let fetchedRecords = try Person.filter(keys: []).fetchSet(db)
|
||||
XCTAssertEqual(fetchedRecords.count, 0)
|
||||
}
|
||||
|
||||
do {
|
||||
let fetchedRecords = try Person.filter(keys: [["id": record1.id], ["id": record2.id]]).fetchSet(db)
|
||||
XCTAssertEqual(fetchedRecords.count, 2)
|
||||
XCTAssertEqual(Set(fetchedRecords.map(\.id)), Set([record1.id, record2.id]))
|
||||
}
|
||||
|
||||
do {
|
||||
let fetchedRecords = try Person.filter(keys: [["id": record1.id], ["id": nil]]).fetchSet(db)
|
||||
XCTAssertEqual(fetchedRecords.count, 1)
|
||||
XCTAssertEqual(fetchedRecords.first!.id, record1.id!)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testFetchOneWithKeyRequest() throws {
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
let record = Person(name: "Arthur")
|
||||
try record.insert(db)
|
||||
|
||||
let fetchedRecord = try Person.filter(key: ["id": record.id]).fetchOne(db)!
|
||||
XCTAssertTrue(fetchedRecord.id == record.id)
|
||||
XCTAssertTrue(fetchedRecord.name == record.name)
|
||||
XCTAssertTrue(fetchedRecord.age == record.age)
|
||||
XCTAssertTrue(abs(fetchedRecord.creationDate.timeIntervalSince(record.creationDate)) < 1e-3) // ISO-8601 is precise to the millisecond.
|
||||
XCTAssertEqual(lastSQLQuery, "SELECT * FROM \"persons\" WHERE \"id\" = \(record.id!)")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Order By Primary Key
|
||||
|
||||
func testOrderByPrimaryKey() throws {
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
let request = Person.orderByPrimaryKey()
|
||||
try assertEqualSQL(db, request, "SELECT * FROM \"persons\" ORDER BY \"id\"")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Stable order
|
||||
|
||||
func testStableOrder() throws {
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
let request = Person.all().withStableOrder()
|
||||
try assertEqualSQL(db, request, "SELECT * FROM \"persons\" ORDER BY \"id\"")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Fetch With Primary Key
|
||||
|
||||
func testFetchCursorWithPrimaryKeys() throws {
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
let record1 = Person(name: "Arthur")
|
||||
try record1.insert(db)
|
||||
let record2 = Person(name: "Barbara")
|
||||
try record2.insert(db)
|
||||
|
||||
do {
|
||||
let ids: [Int64] = []
|
||||
let cursor = try Person.fetchCursor(db, keys: ids)
|
||||
try XCTAssertNil(cursor.next())
|
||||
}
|
||||
|
||||
do {
|
||||
let ids = [record1.id!, record2.id!]
|
||||
let cursor = try Person.fetchCursor(db, keys: ids)
|
||||
let fetchedRecords = try [cursor.next()!, cursor.next()!]
|
||||
XCTAssertEqual(Set(fetchedRecords.map(\.id)), Set(ids))
|
||||
XCTAssertTrue(try cursor.next() == nil) // end
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testFetchAllWithPrimaryKeys() throws {
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
let record1 = Person(name: "Arthur")
|
||||
try record1.insert(db)
|
||||
let record2 = Person(name: "Barbara")
|
||||
try record2.insert(db)
|
||||
|
||||
do {
|
||||
let ids: [Int64] = []
|
||||
let fetchedRecords = try Person.fetchAll(db, keys: ids)
|
||||
XCTAssertEqual(fetchedRecords.count, 0)
|
||||
}
|
||||
|
||||
do {
|
||||
let ids = [record1.id!, record2.id!]
|
||||
let fetchedRecords = try Person.fetchAll(db, keys: ids)
|
||||
XCTAssertEqual(fetchedRecords.count, 2)
|
||||
XCTAssertEqual(Set(fetchedRecords.map(\.id)), Set(ids))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testFetchSetWithPrimaryKeys() throws {
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
let record1 = Person(name: "Arthur")
|
||||
try record1.insert(db)
|
||||
let record2 = Person(name: "Barbara")
|
||||
try record2.insert(db)
|
||||
|
||||
do {
|
||||
let ids: [Int64] = []
|
||||
let fetchedRecords = try Person.fetchSet(db, keys: ids)
|
||||
XCTAssertEqual(fetchedRecords.count, 0)
|
||||
}
|
||||
|
||||
do {
|
||||
let ids = [record1.id!, record2.id!]
|
||||
let fetchedRecords = try Person.fetchSet(db, keys: ids)
|
||||
XCTAssertEqual(fetchedRecords.count, 2)
|
||||
XCTAssertEqual(Set(fetchedRecords.map(\.id)), Set(ids))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testFetchOneWithPrimaryKey() throws {
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
let record = Person(name: "Arthur")
|
||||
try record.insert(db)
|
||||
|
||||
do {
|
||||
let id: Int64? = nil
|
||||
let fetchedRecord = try Person.fetchOne(db, key: id)
|
||||
XCTAssertTrue(fetchedRecord == nil)
|
||||
}
|
||||
|
||||
do {
|
||||
let fetchedRecord = try Person.fetchOne(db, key: record.id)!
|
||||
XCTAssertTrue(fetchedRecord.id == record.id)
|
||||
XCTAssertTrue(fetchedRecord.name == record.name)
|
||||
XCTAssertTrue(fetchedRecord.age == record.age)
|
||||
XCTAssertTrue(abs(fetchedRecord.creationDate.timeIntervalSince(record.creationDate)) < 1e-3) // ISO-8601 is precise to the millisecond.
|
||||
XCTAssertEqual(lastSQLQuery, "SELECT * FROM \"persons\" WHERE \"id\" = \(record.id!)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testFindWithPrimaryKey() throws {
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
let record = Person(name: "Arthur")
|
||||
try record.insert(db)
|
||||
|
||||
do {
|
||||
let id: Int64? = nil
|
||||
_ = try Person.find(db, key: id)
|
||||
XCTFail("Expected RecordError")
|
||||
} catch RecordError.recordNotFound(databaseTableName: "persons", key: ["id": .null]) { }
|
||||
|
||||
do {
|
||||
let fetchedRecord = try Person.find(db, key: record.id)
|
||||
XCTAssertTrue(fetchedRecord.id == record.id)
|
||||
XCTAssertTrue(fetchedRecord.name == record.name)
|
||||
XCTAssertTrue(fetchedRecord.age == record.age)
|
||||
XCTAssertTrue(abs(fetchedRecord.creationDate.timeIntervalSince(record.creationDate)) < 1e-3) // ISO-8601 is precise to the millisecond.
|
||||
XCTAssertEqual(lastSQLQuery, "SELECT * FROM \"persons\" WHERE \"id\" = \(record.id!)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Fetch With Primary Key Request
|
||||
|
||||
func testFetchCursorWithPrimaryKeysRequest() throws {
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
let record1 = Person(name: "Arthur")
|
||||
try record1.insert(db)
|
||||
let record2 = Person(name: "Barbara")
|
||||
try record2.insert(db)
|
||||
|
||||
do {
|
||||
let ids: [Int64] = []
|
||||
let cursor = try Person.filter(keys: ids).fetchCursor(db)
|
||||
try XCTAssertNil(cursor.next())
|
||||
}
|
||||
|
||||
do {
|
||||
let ids = [record1.id!, record2.id!]
|
||||
let cursor = try Person.filter(keys: ids).fetchCursor(db)
|
||||
let fetchedRecords = try [cursor.next()!, cursor.next()!]
|
||||
XCTAssertEqual(Set(fetchedRecords.map(\.id)), Set(ids))
|
||||
XCTAssertTrue(try cursor.next() == nil) // end
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testFetchAllWithPrimaryKeysRequest() throws {
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
let record1 = Person(name: "Arthur")
|
||||
try record1.insert(db)
|
||||
let record2 = Person(name: "Barbara")
|
||||
try record2.insert(db)
|
||||
|
||||
do {
|
||||
let ids: [Int64] = []
|
||||
let fetchedRecords = try Person.filter(keys: ids).fetchAll(db)
|
||||
XCTAssertEqual(fetchedRecords.count, 0)
|
||||
}
|
||||
|
||||
do {
|
||||
let ids = [record1.id!, record2.id!]
|
||||
let fetchedRecords = try Person.filter(keys: ids).fetchAll(db)
|
||||
XCTAssertEqual(fetchedRecords.count, 2)
|
||||
XCTAssertEqual(Set(fetchedRecords.map(\.id)), Set(ids))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testFetchSetWithPrimaryKeysRequest() throws {
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
let record1 = Person(name: "Arthur")
|
||||
try record1.insert(db)
|
||||
let record2 = Person(name: "Barbara")
|
||||
try record2.insert(db)
|
||||
|
||||
do {
|
||||
let ids: [Int64] = []
|
||||
let fetchedRecords = try Person.filter(keys: ids).fetchSet(db)
|
||||
XCTAssertEqual(fetchedRecords.count, 0)
|
||||
}
|
||||
|
||||
do {
|
||||
let ids = [record1.id!, record2.id!]
|
||||
let fetchedRecords = try Person.filter(keys: ids).fetchSet(db)
|
||||
XCTAssertEqual(fetchedRecords.count, 2)
|
||||
XCTAssertEqual(Set(fetchedRecords.map(\.id)), Set(ids))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testFetchOneWithPrimaryKeyRequest() throws {
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
let record = Person(name: "Arthur")
|
||||
try record.insert(db)
|
||||
|
||||
do {
|
||||
let id: Int64? = nil
|
||||
let fetchedRecord = try Person.filter(key: id).fetchOne(db)
|
||||
XCTAssertTrue(fetchedRecord == nil)
|
||||
}
|
||||
|
||||
do {
|
||||
let fetchedRecord = try Person.filter(key: record.id).fetchOne(db)!
|
||||
XCTAssertTrue(fetchedRecord.id == record.id)
|
||||
XCTAssertTrue(fetchedRecord.name == record.name)
|
||||
XCTAssertTrue(fetchedRecord.age == record.age)
|
||||
XCTAssertTrue(abs(fetchedRecord.creationDate.timeIntervalSince(record.creationDate)) < 1e-3) // ISO-8601 is precise to the millisecond.
|
||||
XCTAssertEqual(lastSQLQuery, "SELECT * FROM \"persons\" WHERE \"id\" = \(record.id!)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Exists
|
||||
|
||||
func testExistsWithNilPrimaryKeyReturnsFalse() throws {
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
let record = Person(id: nil, name: "Arthur")
|
||||
XCTAssertFalse(try record.exists(db))
|
||||
}
|
||||
}
|
||||
|
||||
func testExistsWithNotNilPrimaryKeyThatDoesNotMatchAnyRowReturnsFalse() throws {
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
let record = Person(id: 123456, name: "Arthur")
|
||||
XCTAssertFalse(try record.exists(db))
|
||||
}
|
||||
}
|
||||
|
||||
func testExistsWithNotNilPrimaryKeyThatMatchesARowReturnsTrue() throws {
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
let record = Person(name: "Arthur")
|
||||
try record.insert(db)
|
||||
XCTAssertTrue(try record.exists(db))
|
||||
}
|
||||
}
|
||||
|
||||
func testExistsAfterDeleteReturnsTrue() throws {
|
||||
let dbQueue = try makeDatabaseQueue()
|
||||
try dbQueue.inDatabase { db in
|
||||
let record = Person(name: "Arthur")
|
||||
try record.insert(db)
|
||||
try record.delete(db)
|
||||
XCTAssertFalse(try record.exists(db))
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user