import XCTest import GRDB // MinimalSingle is the most tiny class with a Single row primary key which // supports read and write operations of Record. class MinimalSingle: Record, Hashable { var UUID: String? init(UUID: String? = nil) { self.UUID = UUID super.init() } static func setup(inDatabase db: Database) throws { try db.execute(sql: "CREATE TABLE minimalSingles (UUID TEXT NOT NULL PRIMARY KEY)") } // Record override class var databaseTableName: String { "minimalSingles" } required init(row: Row) throws { UUID = row["UUID"] try super.init(row: row) } override func encode(to container: inout PersistenceContainer) throws { container["UUID"] = UUID } static func == (lhs: MinimalSingle, rhs: MinimalSingle) -> Bool { lhs.UUID == rhs.UUID } func hash(into hasher: inout Hasher) { hasher.combine(UUID) } } @available(iOS 13, macOS 10.15, tvOS 13, watchOS 6, *) extension MinimalSingle: Identifiable { /// Test non-optional ID type var id: String { UUID! } } class RecordMinimalPrimaryKeySingleTests: GRDBTestCase { override func setup(_ dbWriter: some DatabaseWriter) throws { var migrator = DatabaseMigrator() migrator.registerMigration("createMinimalSingle", migrate: MinimalSingle.setup) try migrator.migrate(dbWriter) } // MARK: - Insert func testInsertWithNilPrimaryKeyThrowsDatabaseError() throws { let dbQueue = try makeDatabaseQueue() try dbQueue.inDatabase { db in let record = MinimalSingle() XCTAssertTrue(record.UUID == 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 = MinimalSingle() record.UUID = "theUUID" try record.insert(db) let row = try Row.fetchOne(db, sql: "SELECT * FROM minimalSingles WHERE UUID = ?", arguments: [record.UUID])! try assert(record, isEncodedIn: row) } } func testInsertWithNotNilPrimaryKeyThatMatchesARowThrowsDatabaseError() throws { let dbQueue = try makeDatabaseQueue() try dbQueue.inDatabase { db in let record = MinimalSingle() record.UUID = "theUUID" 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 = MinimalSingle() record.UUID = "theUUID" try record.insert(db) try record.delete(db) try record.insert(db) let row = try Row.fetchOne(db, sql: "SELECT * FROM minimalSingles WHERE UUID = ?", arguments: [record.UUID])! try assert(record, isEncodedIn: row) } } // MARK: - Update func testUpdateWithNotNilPrimaryKeyThatDoesNotMatchAnyRowThrowsRecordNotFound() throws { let dbQueue = try makeDatabaseQueue() try dbQueue.inDatabase { db in let record = MinimalSingle() record.UUID = "theUUID" do { try record.update(db) XCTFail("Expected RecordError.recordNotFound") } catch let RecordError.recordNotFound(databaseTableName: databaseTableName, key: key) { // Expected RecordError.recordNotFound XCTAssertEqual(databaseTableName, "minimalSingles") XCTAssertEqual(key, ["UUID": "theUUID".databaseValue]) } } } func testUpdateWithNotNilPrimaryKeyThatMatchesARowUpdatesThatRow() throws { let dbQueue = try makeDatabaseQueue() try dbQueue.inDatabase { db in let record = MinimalSingle() record.UUID = "theUUID" try record.insert(db) try record.update(db) let row = try Row.fetchOne(db, sql: "SELECT * FROM minimalSingles WHERE UUID = ?", arguments: [record.UUID])! try assert(record, isEncodedIn: row) } } func testUpdateAfterDeleteThrowsRecordNotFound() throws { let dbQueue = try makeDatabaseQueue() try dbQueue.inDatabase { db in let record = MinimalSingle() record.UUID = "theUUID" 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, "minimalSingles") XCTAssertEqual(key, ["UUID": "theUUID".databaseValue]) } } } // MARK: - Save func testSaveWithNilPrimaryKeyThrowsDatabaseError() throws { let dbQueue = try makeDatabaseQueue() try dbQueue.inDatabase { db in let record = MinimalSingle() XCTAssertTrue(record.UUID == 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 = MinimalSingle() record.UUID = "theUUID" try record.save(db) let row = try Row.fetchOne(db, sql: "SELECT * FROM minimalSingles WHERE UUID = ?", arguments: [record.UUID])! try assert(record, isEncodedIn: row) } } func testSaveWithNotNilPrimaryKeyThatMatchesARowUpdatesThatRow() throws { let dbQueue = try makeDatabaseQueue() try dbQueue.inDatabase { db in let record = MinimalSingle() record.UUID = "theUUID" try record.insert(db) try record.save(db) let row = try Row.fetchOne(db, sql: "SELECT * FROM minimalSingles WHERE UUID = ?", arguments: [record.UUID])! try assert(record, isEncodedIn: row) } } func testSaveAfterDeleteInsertsARow() throws { let dbQueue = try makeDatabaseQueue() try dbQueue.inDatabase { db in let record = MinimalSingle() record.UUID = "theUUID" try record.insert(db) try record.delete(db) try record.save(db) let row = try Row.fetchOne(db, sql: "SELECT * FROM minimalSingles WHERE UUID = ?", arguments: [record.UUID])! try assert(record, isEncodedIn: row) } } // MARK: - Delete func testDeleteWithNotNilPrimaryKeyThatDoesNotMatchAnyRowDoesNothing() throws { let dbQueue = try makeDatabaseQueue() try dbQueue.inDatabase { db in let record = MinimalSingle() record.UUID = "theUUID" let deleted = try record.delete(db) XCTAssertFalse(deleted) } } func testDeleteWithNotNilPrimaryKeyThatMatchesARowDeletesThatRow() throws { let dbQueue = try makeDatabaseQueue() try dbQueue.inDatabase { db in let record = MinimalSingle() record.UUID = "theUUID" try record.insert(db) let deleted = try record.delete(db) XCTAssertTrue(deleted) let row = try Row.fetchOne(db, sql: "SELECT * FROM minimalSingles WHERE UUID = ?", arguments: [record.UUID]) XCTAssertTrue(row == nil) } } func testDeleteAfterDeleteDoesNothing() throws { let dbQueue = try makeDatabaseQueue() try dbQueue.inDatabase { db in let record = MinimalSingle() record.UUID = "theUUID" 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 = MinimalSingle() record1.UUID = "theUUID1" try record1.insert(db) let record2 = MinimalSingle() record2.UUID = "theUUID2" try record2.insert(db) do { let cursor = try MinimalSingle.fetchCursor(db, keys: []) try XCTAssertNil(cursor.next()) } do { let cursor = try MinimalSingle.fetchCursor(db, keys: [["UUID": record1.UUID], ["UUID": record2.UUID]]) let fetchedRecords = try [cursor.next()!, cursor.next()!] XCTAssertEqual(Set(fetchedRecords.map { $0.UUID! }), Set([record1.UUID!, record2.UUID!])) XCTAssertTrue(try cursor.next() == nil) // end } do { let cursor = try MinimalSingle.fetchCursor(db, keys: [["UUID": record1.UUID], ["UUID": nil]]) let fetchedRecord = try cursor.next()! XCTAssertEqual(fetchedRecord.UUID!, record1.UUID!) XCTAssertTrue(try cursor.next() == nil) // end } } } func testFetchAllWithKeys() throws { let dbQueue = try makeDatabaseQueue() try dbQueue.inDatabase { db in let record1 = MinimalSingle() record1.UUID = "theUUID1" try record1.insert(db) let record2 = MinimalSingle() record2.UUID = "theUUID2" try record2.insert(db) do { let fetchedRecords = try MinimalSingle.fetchAll(db, keys: []) XCTAssertEqual(fetchedRecords.count, 0) } do { let fetchedRecords = try MinimalSingle.fetchAll(db, keys: [["UUID": record1.UUID], ["UUID": record2.UUID]]) XCTAssertEqual(fetchedRecords.count, 2) XCTAssertEqual(Set(fetchedRecords.map { $0.UUID! }), Set([record1.UUID!, record2.UUID!])) } do { let fetchedRecords = try MinimalSingle.fetchAll(db, keys: [["UUID": record1.UUID], ["UUID": nil]]) XCTAssertEqual(fetchedRecords.count, 1) XCTAssertEqual(fetchedRecords.first!.UUID, record1.UUID!) } } } func testFetchSetWithKeys() throws { let dbQueue = try makeDatabaseQueue() try dbQueue.inDatabase { db in let record1 = MinimalSingle() record1.UUID = "theUUID1" try record1.insert(db) let record2 = MinimalSingle() record2.UUID = "theUUID2" try record2.insert(db) do { let fetchedRecords = try MinimalSingle.fetchSet(db, keys: []) XCTAssertEqual(fetchedRecords.count, 0) } do { let fetchedRecords = try MinimalSingle.fetchSet(db, keys: [["UUID": record1.UUID], ["UUID": record2.UUID]]) XCTAssertEqual(fetchedRecords.count, 2) XCTAssertEqual(Set(fetchedRecords.map { $0.UUID! }), Set([record1.UUID!, record2.UUID!])) } do { let fetchedRecords = try MinimalSingle.fetchSet(db, keys: [["UUID": record1.UUID], ["UUID": nil]]) XCTAssertEqual(fetchedRecords.count, 1) XCTAssertEqual(fetchedRecords.first!.UUID, record1.UUID!) } } } func testFetchOneWithKey() throws { let dbQueue = try makeDatabaseQueue() try dbQueue.inDatabase { db in let record = MinimalSingle() record.UUID = "theUUID" try record.insert(db) let fetchedRecord = try MinimalSingle.fetchOne(db, key: ["UUID": record.UUID])! XCTAssertTrue(fetchedRecord.UUID == record.UUID) XCTAssertEqual(lastSQLQuery, "SELECT * FROM \"minimalSingles\" WHERE \"UUID\" = '\(record.UUID!)'") } } func testFindWithKey() throws { let dbQueue = try makeDatabaseQueue() try dbQueue.inDatabase { db in let record = MinimalSingle() record.UUID = "theUUID" try record.insert(db) let fetchedRecord = try MinimalSingle.find(db, key: ["UUID": record.UUID]) XCTAssertTrue(fetchedRecord.UUID == record.UUID) XCTAssertEqual(lastSQLQuery, "SELECT * FROM \"minimalSingles\" WHERE \"UUID\" = '\(record.UUID!)'") } } // MARK: - Fetch With Key Request func testFetchCursorWithKeysRequest() throws { let dbQueue = try makeDatabaseQueue() try dbQueue.inDatabase { db in let record1 = MinimalSingle() record1.UUID = "theUUID1" try record1.insert(db) let record2 = MinimalSingle() record2.UUID = "theUUID2" try record2.insert(db) do { let cursor = try MinimalSingle.filter(keys: []).fetchCursor(db) try XCTAssertNil(cursor.next()) } do { let cursor = try MinimalSingle.filter(keys: [["UUID": record1.UUID], ["UUID": record2.UUID]]).fetchCursor(db) let fetchedRecords = try [cursor.next()!, cursor.next()!] XCTAssertEqual(Set(fetchedRecords.map { $0.UUID! }), Set([record1.UUID!, record2.UUID!])) XCTAssertTrue(try cursor.next() == nil) // end } do { let cursor = try MinimalSingle.filter(keys: [["UUID": record1.UUID], ["UUID": nil]]).fetchCursor(db) let fetchedRecord = try cursor.next()! XCTAssertEqual(fetchedRecord.UUID!, record1.UUID!) XCTAssertTrue(try cursor.next() == nil) // end } } } func testFetchAllWithKeysRequest() throws { let dbQueue = try makeDatabaseQueue() try dbQueue.inDatabase { db in let record1 = MinimalSingle() record1.UUID = "theUUID1" try record1.insert(db) let record2 = MinimalSingle() record2.UUID = "theUUID2" try record2.insert(db) do { let fetchedRecords = try MinimalSingle.filter(keys: []).fetchAll(db) XCTAssertEqual(fetchedRecords.count, 0) } do { let fetchedRecords = try MinimalSingle.filter(keys: [["UUID": record1.UUID], ["UUID": record2.UUID]]).fetchAll(db) XCTAssertEqual(fetchedRecords.count, 2) XCTAssertEqual(Set(fetchedRecords.map { $0.UUID! }), Set([record1.UUID!, record2.UUID!])) } do { let fetchedRecords = try MinimalSingle.filter(keys: [["UUID": record1.UUID], ["UUID": nil]]).fetchAll(db) XCTAssertEqual(fetchedRecords.count, 1) XCTAssertEqual(fetchedRecords.first!.UUID, record1.UUID!) } } } func testFetchSetWithKeysRequest() throws { let dbQueue = try makeDatabaseQueue() try dbQueue.inDatabase { db in let record1 = MinimalSingle() record1.UUID = "theUUID1" try record1.insert(db) let record2 = MinimalSingle() record2.UUID = "theUUID2" try record2.insert(db) do { let fetchedRecords = try MinimalSingle.filter(keys: []).fetchSet(db) XCTAssertEqual(fetchedRecords.count, 0) } do { let fetchedRecords = try MinimalSingle.filter(keys: [["UUID": record1.UUID], ["UUID": record2.UUID]]).fetchSet(db) XCTAssertEqual(fetchedRecords.count, 2) XCTAssertEqual(Set(fetchedRecords.map { $0.UUID! }), Set([record1.UUID!, record2.UUID!])) } do { let fetchedRecords = try MinimalSingle.filter(keys: [["UUID": record1.UUID], ["UUID": nil]]).fetchSet(db) XCTAssertEqual(fetchedRecords.count, 1) XCTAssertEqual(fetchedRecords.first!.UUID, record1.UUID!) } } } func testFetchOneWithKeyRequest() throws { let dbQueue = try makeDatabaseQueue() try dbQueue.inDatabase { db in let record = MinimalSingle() record.UUID = "theUUID" try record.insert(db) let fetchedRecord = try MinimalSingle.filter(key: ["UUID": record.UUID]).fetchOne(db)! XCTAssertTrue(fetchedRecord.UUID == record.UUID) XCTAssertEqual(lastSQLQuery, "SELECT * FROM \"minimalSingles\" WHERE \"UUID\" = '\(record.UUID!)'") } } // MARK: - Order By Primary Key func testOrderByPrimaryKey() throws { let dbQueue = try makeDatabaseQueue() try dbQueue.inDatabase { db in let request = MinimalSingle.orderByPrimaryKey() try assertEqualSQL(db, request, "SELECT * FROM \"minimalSingles\" ORDER BY \"UUID\"") } } // MARK: - Stable order func testStableOrder() throws { let dbQueue = try makeDatabaseQueue() try dbQueue.inDatabase { db in let request = MinimalSingle.all().withStableOrder() try assertEqualSQL(db, request, "SELECT * FROM \"minimalSingles\" ORDER BY \"UUID\"") } } // MARK: - Fetch With Primary Key func testFetchCursorWithPrimaryKeys() throws { let dbQueue = try makeDatabaseQueue() try dbQueue.inDatabase { db in let record1 = MinimalSingle() record1.UUID = "theUUID1" try record1.insert(db) let record2 = MinimalSingle() record2.UUID = "theUUID2" try record2.insert(db) do { let UUIDs: [String] = [] let cursor = try MinimalSingle.fetchCursor(db, keys: UUIDs) try XCTAssertNil(cursor.next()) } do { let UUIDs = [record1.UUID!, record2.UUID!] let cursor = try MinimalSingle.fetchCursor(db, keys: UUIDs) let fetchedRecords = try [cursor.next()!, cursor.next()!] XCTAssertEqual(Set(fetchedRecords.map { $0.UUID! }), Set(UUIDs)) XCTAssertTrue(try cursor.next() == nil) // end } if #available(iOS 13, macOS 10.15, tvOS 13, watchOS 6, *) { do { let UUIDs: [String] = [] let cursor = try MinimalSingle.fetchCursor(db, ids: UUIDs) try XCTAssertNil(cursor.next()) } do { let UUIDs = [record1.UUID!, record2.UUID!] let cursor = try MinimalSingle.fetchCursor(db, ids: UUIDs) let fetchedRecords = try [cursor.next()!, cursor.next()!] XCTAssertEqual(Set(fetchedRecords.map { $0.UUID! }), Set(UUIDs)) XCTAssertTrue(try cursor.next() == nil) // end } } } } func testFetchAllWithPrimaryKeys() throws { let dbQueue = try makeDatabaseQueue() try dbQueue.inDatabase { db in let record1 = MinimalSingle() record1.UUID = "theUUID1" try record1.insert(db) let record2 = MinimalSingle() record2.UUID = "theUUID2" try record2.insert(db) do { let UUIDs: [String] = [] let fetchedRecords = try MinimalSingle.fetchAll(db, keys: UUIDs) XCTAssertEqual(fetchedRecords.count, 0) } do { let UUIDs = [record1.UUID!, record2.UUID!] let fetchedRecords = try MinimalSingle.fetchAll(db, keys: UUIDs) XCTAssertEqual(fetchedRecords.count, 2) XCTAssertEqual(Set(fetchedRecords.map { $0.UUID! }), Set(UUIDs)) } if #available(iOS 13, macOS 10.15, tvOS 13, watchOS 6, *) { do { let UUIDs: [String] = [] let fetchedRecords = try MinimalSingle.fetchAll(db, ids: UUIDs) XCTAssertEqual(fetchedRecords.count, 0) } do { let UUIDs = [record1.UUID!, record2.UUID!] let fetchedRecords = try MinimalSingle.fetchAll(db, ids: UUIDs) XCTAssertEqual(fetchedRecords.count, 2) XCTAssertEqual(Set(fetchedRecords.map { $0.UUID! }), Set(UUIDs)) } } } } func testFetchSetWithPrimaryKeys() throws { let dbQueue = try makeDatabaseQueue() try dbQueue.inDatabase { db in let record1 = MinimalSingle() record1.UUID = "theUUID1" try record1.insert(db) let record2 = MinimalSingle() record2.UUID = "theUUID2" try record2.insert(db) do { let UUIDs: [String] = [] let fetchedRecords = try MinimalSingle.fetchSet(db, keys: UUIDs) XCTAssertEqual(fetchedRecords.count, 0) } do { let UUIDs = [record1.UUID!, record2.UUID!] let fetchedRecords = try MinimalSingle.fetchSet(db, keys: UUIDs) XCTAssertEqual(fetchedRecords.count, 2) XCTAssertEqual(Set(fetchedRecords.map { $0.UUID! }), Set(UUIDs)) } if #available(iOS 13, macOS 10.15, tvOS 13, watchOS 6, *) { do { let UUIDs: [String] = [] let fetchedRecords = try MinimalSingle.fetchSet(db, ids: UUIDs) XCTAssertEqual(fetchedRecords.count, 0) } do { let UUIDs = [record1.UUID!, record2.UUID!] let fetchedRecords = try MinimalSingle.fetchSet(db, ids: UUIDs) XCTAssertEqual(fetchedRecords.count, 2) XCTAssertEqual(Set(fetchedRecords.map { $0.UUID! }), Set(UUIDs)) } } } } func testFetchOneWithPrimaryKey() throws { let dbQueue = try makeDatabaseQueue() try dbQueue.inDatabase { db in let record = MinimalSingle() record.UUID = "theUUID" try record.insert(db) do { let id: String? = nil let fetchedRecord = try MinimalSingle.fetchOne(db, key: id) XCTAssertTrue(fetchedRecord == nil) } do { let fetchedRecord = try MinimalSingle.fetchOne(db, key: record.UUID)! XCTAssertTrue(fetchedRecord.UUID == record.UUID) XCTAssertEqual(lastSQLQuery, "SELECT * FROM \"minimalSingles\" WHERE \"UUID\" = '\(record.UUID!)'") } if #available(iOS 13, macOS 10.15, tvOS 13, watchOS 6, *) { do { let fetchedRecord = try MinimalSingle.fetchOne(db, id: record.UUID!)! XCTAssertTrue(fetchedRecord.UUID == record.UUID) XCTAssertEqual(lastSQLQuery, "SELECT * FROM \"minimalSingles\" WHERE \"UUID\" = '\(record.UUID!)'") } } } } func testFindWithPrimaryKey() throws { let dbQueue = try makeDatabaseQueue() try dbQueue.inDatabase { db in let record = MinimalSingle() record.UUID = "theUUID" try record.insert(db) do { let id: String? = nil _ = try MinimalSingle.find(db, key: id) XCTFail("Expected RecordError") } catch RecordError.recordNotFound(databaseTableName: "minimalSingles", key: ["UUID": .null]) { } do { let fetchedRecord = try MinimalSingle.find(db, key: record.UUID) XCTAssertTrue(fetchedRecord.UUID == record.UUID) XCTAssertEqual(lastSQLQuery, "SELECT * FROM \"minimalSingles\" WHERE \"UUID\" = '\(record.UUID!)'") } if #available(iOS 13, macOS 10.15, tvOS 13, watchOS 6, *) { do { _ = try MinimalSingle.find(db, id: "missing") XCTFail("Expected RecordError") } catch RecordError.recordNotFound(databaseTableName: "minimalSingles", key: ["UUID": "missing".databaseValue]) { } do { let fetchedRecord = try MinimalSingle.find(db, id: record.UUID!) XCTAssertTrue(fetchedRecord.UUID == record.UUID) XCTAssertEqual(lastSQLQuery, "SELECT * FROM \"minimalSingles\" WHERE \"UUID\" = '\(record.UUID!)'") } } } } // MARK: - Fetch With Primary Key Request func testFetchCursorWithPrimaryKeysRequest() throws { let dbQueue = try makeDatabaseQueue() try dbQueue.inDatabase { db in let record1 = MinimalSingle() record1.UUID = "theUUID1" try record1.insert(db) let record2 = MinimalSingle() record2.UUID = "theUUID2" try record2.insert(db) do { let UUIDs: [String] = [] let cursor = try MinimalSingle.filter(keys: UUIDs).fetchCursor(db) try XCTAssertNil(cursor.next()) } do { let UUIDs = [record1.UUID!, record2.UUID!] let cursor = try MinimalSingle.filter(keys: UUIDs).fetchCursor(db) let fetchedRecords = try [cursor.next()!, cursor.next()!] XCTAssertEqual(Set(fetchedRecords.map { $0.UUID! }), Set(UUIDs)) XCTAssertTrue(try cursor.next() == nil) // end } if #available(iOS 13, macOS 10.15, tvOS 13, watchOS 6, *) { do { let UUIDs: [String] = [] let cursor = try MinimalSingle.filter(ids: UUIDs).fetchCursor(db) try XCTAssertNil(cursor.next()) } do { let UUIDs = [record1.UUID!, record2.UUID!] let cursor = try MinimalSingle.filter(ids: UUIDs).fetchCursor(db) let fetchedRecords = try [cursor.next()!, cursor.next()!] XCTAssertEqual(Set(fetchedRecords.map { $0.UUID! }), Set(UUIDs)) XCTAssertTrue(try cursor.next() == nil) // end } } } } func testFetchAllWithPrimaryKeysRequest() throws { let dbQueue = try makeDatabaseQueue() try dbQueue.inDatabase { db in let record1 = MinimalSingle() record1.UUID = "theUUID1" try record1.insert(db) let record2 = MinimalSingle() record2.UUID = "theUUID2" try record2.insert(db) do { let UUIDs: [String] = [] let fetchedRecords = try MinimalSingle.filter(keys: UUIDs).fetchAll(db) XCTAssertEqual(fetchedRecords.count, 0) } do { let UUIDs = [record1.UUID!, record2.UUID!] let fetchedRecords = try MinimalSingle.filter(keys: UUIDs).fetchAll(db) XCTAssertEqual(fetchedRecords.count, 2) XCTAssertEqual(Set(fetchedRecords.map { $0.UUID! }), Set(UUIDs)) } if #available(iOS 13, macOS 10.15, tvOS 13, watchOS 6, *) { do { let UUIDs: [String] = [] let fetchedRecords = try MinimalSingle.filter(ids: UUIDs).fetchAll(db) XCTAssertEqual(fetchedRecords.count, 0) } do { let UUIDs = [record1.UUID!, record2.UUID!] let fetchedRecords = try MinimalSingle.filter(ids: UUIDs).fetchAll(db) XCTAssertEqual(fetchedRecords.count, 2) XCTAssertEqual(Set(fetchedRecords.map { $0.UUID! }), Set(UUIDs)) } } } } func testFetchSetWithPrimaryKeysRequest() throws { let dbQueue = try makeDatabaseQueue() try dbQueue.inDatabase { db in let record1 = MinimalSingle() record1.UUID = "theUUID1" try record1.insert(db) let record2 = MinimalSingle() record2.UUID = "theUUID2" try record2.insert(db) do { let UUIDs: [String] = [] let fetchedRecords = try MinimalSingle.filter(keys: UUIDs).fetchSet(db) XCTAssertEqual(fetchedRecords.count, 0) } do { let UUIDs = [record1.UUID!, record2.UUID!] let fetchedRecords = try MinimalSingle.filter(keys: UUIDs).fetchSet(db) XCTAssertEqual(fetchedRecords.count, 2) XCTAssertEqual(Set(fetchedRecords.map { $0.UUID! }), Set(UUIDs)) } if #available(iOS 13, macOS 10.15, tvOS 13, watchOS 6, *) { do { let UUIDs: [String] = [] let fetchedRecords = try MinimalSingle.filter(ids: UUIDs).fetchSet(db) XCTAssertEqual(fetchedRecords.count, 0) } do { let UUIDs = [record1.UUID!, record2.UUID!] let fetchedRecords = try MinimalSingle.filter(ids: UUIDs).fetchSet(db) XCTAssertEqual(fetchedRecords.count, 2) XCTAssertEqual(Set(fetchedRecords.map { $0.UUID! }), Set(UUIDs)) } } } } func testFetchOneWithPrimaryKeyRequest() throws { let dbQueue = try makeDatabaseQueue() try dbQueue.inDatabase { db in let record = MinimalSingle() record.UUID = "theUUID" try record.insert(db) do { let id: String? = nil let fetchedRecord = try MinimalSingle.filter(key: id).fetchOne(db) XCTAssertTrue(fetchedRecord == nil) } do { let fetchedRecord = try MinimalSingle.filter(key: record.UUID).fetchOne(db)! XCTAssertTrue(fetchedRecord.UUID == record.UUID) XCTAssertEqual(lastSQLQuery, "SELECT * FROM \"minimalSingles\" WHERE \"UUID\" = '\(record.UUID!)'") } if #available(iOS 13, macOS 10.15, tvOS 13, watchOS 6, *) { do { let fetchedRecord = try MinimalSingle.filter(id: record.UUID!).fetchOne(db)! XCTAssertTrue(fetchedRecord.UUID == record.UUID) XCTAssertEqual(lastSQLQuery, "SELECT * FROM \"minimalSingles\" WHERE \"UUID\" = '\(record.UUID!)'") } } } } // MARK: - Exists func testExistsWithNotNilPrimaryKeyThatDoesNotMatchAnyRowReturnsFalse() throws { let dbQueue = try makeDatabaseQueue() try dbQueue.inDatabase { db in let record = MinimalSingle() record.UUID = "theUUID" XCTAssertFalse(try record.exists(db)) } } func testExistsWithNotNilPrimaryKeyThatMatchesARowReturnsTrue() throws { let dbQueue = try makeDatabaseQueue() try dbQueue.inDatabase { db in let record = MinimalSingle() record.UUID = "theUUID" try record.insert(db) XCTAssertTrue(try record.exists(db)) } } func testExistsAfterDeleteReturnsTrue() throws { let dbQueue = try makeDatabaseQueue() try dbQueue.inDatabase { db in let record = MinimalSingle() record.UUID = "theUUID" try record.insert(db) try record.delete(db) XCTAssertFalse(try record.exists(db)) } } // MARK: Select PrimaryKey func test_static_selectPrimaryKey() throws { let dbQueue = try makeDatabaseQueue() try dbQueue.inDatabase { db in let record = MinimalSingle() record.UUID = "theUUID" try record.insert(db) let ids: [String] = try MinimalSingle.selectPrimaryKey().fetchAll(db) XCTAssertEqual(ids, ["theUUID"]) let rows = try MinimalSingle.selectPrimaryKey(as: Row.self).fetchAll(db) XCTAssertEqual(rows, [["UUID": "theUUID"]]) } } func test_request_selectPrimaryKey() throws { let dbQueue = try makeDatabaseQueue() try dbQueue.inDatabase { db in let record = MinimalSingle() record.UUID = "theUUID" try record.insert(db) let ids: [String] = try MinimalSingle.all().selectPrimaryKey().fetchAll(db) XCTAssertEqual(ids, ["theUUID"]) let rows = try MinimalSingle.all().selectPrimaryKey(as: Row.self).fetchAll(db) XCTAssertEqual(rows, [["UUID": "theUUID"]]) } } }