625 lines
27 KiB
Swift
625 lines
27 KiB
Swift
import XCTest
|
|
import GRDB
|
|
|
|
class DatabaseTests : GRDBTestCase {
|
|
|
|
func testCreateTable() throws {
|
|
let dbQueue = try makeDatabaseQueue()
|
|
try dbQueue.inDatabase { db in
|
|
XCTAssertFalse(try db.tableExists("persons"))
|
|
try db.execute(sql: """
|
|
CREATE TABLE persons (
|
|
id INTEGER PRIMARY KEY,
|
|
name TEXT,
|
|
age INT)
|
|
""")
|
|
XCTAssertTrue(try db.tableExists("persons"))
|
|
}
|
|
}
|
|
|
|
func testCreateTemporaryTable() throws {
|
|
let dbQueue = try makeDatabaseQueue()
|
|
try dbQueue.inDatabase { db in
|
|
XCTAssertFalse(try db.tableExists("persons"))
|
|
try db.execute(sql: """
|
|
CREATE TEMPORARY TABLE persons (
|
|
id INTEGER PRIMARY KEY,
|
|
name TEXT,
|
|
age INT)
|
|
""")
|
|
XCTAssertTrue(try db.tableExists("persons"))
|
|
}
|
|
}
|
|
|
|
func testMultipleStatementsWithoutArguments() throws {
|
|
let dbQueue = try makeDatabaseQueue()
|
|
try dbQueue.inDatabase { db in
|
|
XCTAssertFalse(try db.tableExists("persons"))
|
|
XCTAssertFalse(try db.tableExists("pets"))
|
|
try db.execute(sql: """
|
|
CREATE TABLE persons (id INTEGER PRIMARY KEY, name TEXT, age INT);
|
|
CREATE TABLE pets (id INTEGER PRIMARY KEY, name TEXT, age INT);
|
|
""")
|
|
XCTAssertTrue(try db.tableExists("persons"))
|
|
XCTAssertTrue(try db.tableExists("pets"))
|
|
}
|
|
}
|
|
|
|
func testUpdateStatement() throws {
|
|
let dbQueue = try makeDatabaseQueue()
|
|
try dbQueue.inDatabase { db in
|
|
try db.execute(sql: "CREATE TABLE persons (name TEXT, age INT)")
|
|
|
|
// The tested function:
|
|
let statement = try db.makeStatement(sql: "INSERT INTO persons (name, age) VALUES ('Arthur', 41)")
|
|
try statement.execute()
|
|
|
|
let row = try Row.fetchOne(db, sql: "SELECT * FROM persons")!
|
|
XCTAssertEqual(row[0] as String, "Arthur")
|
|
XCTAssertEqual(row[1] as Int, 41)
|
|
}
|
|
}
|
|
|
|
func testUpdateStatementWithArrayBinding() throws {
|
|
let dbQueue = try makeDatabaseQueue()
|
|
try dbQueue.inDatabase { db in
|
|
try db.execute(sql: "CREATE TABLE persons (name TEXT, age INT)")
|
|
|
|
let statement = try db.makeStatement(sql: "INSERT INTO persons (name, age) VALUES (?, ?)")
|
|
try statement.execute(arguments: ["Arthur", 41])
|
|
|
|
let row = try Row.fetchOne(db, sql: "SELECT * FROM persons")!
|
|
XCTAssertEqual(row[0] as String, "Arthur")
|
|
XCTAssertEqual(row[1] as Int, 41)
|
|
}
|
|
}
|
|
|
|
func testUpdateStatementWithDictionaryBinding() throws {
|
|
let dbQueue = try makeDatabaseQueue()
|
|
try dbQueue.inDatabase { db in
|
|
try db.execute(sql: "CREATE TABLE persons (name TEXT, age INT)")
|
|
|
|
let statement = try db.makeStatement(sql: "INSERT INTO persons (name, age) VALUES (:name, :age)")
|
|
try statement.execute(arguments: ["name": "Arthur", "age": 41])
|
|
|
|
let row = try Row.fetchOne(db, sql: "SELECT * FROM persons")!
|
|
XCTAssertEqual(row[0] as String, "Arthur")
|
|
XCTAssertEqual(row[1] as Int, 41)
|
|
}
|
|
}
|
|
|
|
func testUpdateStatementLiteral() throws {
|
|
let dbQueue = try makeDatabaseQueue()
|
|
try dbQueue.inDatabase { db in
|
|
try db.execute(sql: "CREATE TABLE persons (name TEXT, age INT)")
|
|
|
|
// The tested function:
|
|
let statement = try db.makeStatement(literal: "INSERT INTO persons (name, age) VALUES ('Arthur', 41)")
|
|
try statement.execute()
|
|
|
|
let row = try Row.fetchOne(db, sql: "SELECT * FROM persons")!
|
|
XCTAssertEqual(row[0] as String, "Arthur")
|
|
XCTAssertEqual(row[1] as Int, 41)
|
|
}
|
|
}
|
|
|
|
func testUpdateStatementLiteralWithArguments() throws {
|
|
let dbQueue = try makeDatabaseQueue()
|
|
try dbQueue.inDatabase { db in
|
|
try db.execute(sql: "CREATE TABLE persons (name TEXT, age INT)")
|
|
|
|
// The tested function:
|
|
let statement = try db.makeStatement(literal: "INSERT INTO persons (name, age) VALUES (\("Arthur"), \(41))")
|
|
try statement.execute()
|
|
|
|
let row = try Row.fetchOne(db, sql: "SELECT * FROM persons")!
|
|
XCTAssertEqual(row[0] as String, "Arthur")
|
|
XCTAssertEqual(row[1] as Int, 41)
|
|
}
|
|
}
|
|
|
|
func testUpdateStatementLiteralWithArrayBinding() throws {
|
|
let dbQueue = try makeDatabaseQueue()
|
|
try dbQueue.inDatabase { db in
|
|
try db.execute(sql: "CREATE TABLE persons (name TEXT, age INT)")
|
|
|
|
let statement = try db.makeStatement(literal: "INSERT INTO persons (name, age) VALUES (?, ?)")
|
|
try statement.execute(arguments: ["Arthur", 41])
|
|
|
|
let row = try Row.fetchOne(db, sql: "SELECT * FROM persons")!
|
|
XCTAssertEqual(row[0] as String, "Arthur")
|
|
XCTAssertEqual(row[1] as Int, 41)
|
|
}
|
|
}
|
|
|
|
func testUpdateStatementLiteralWithDictionaryBinding() throws {
|
|
let dbQueue = try makeDatabaseQueue()
|
|
try dbQueue.inDatabase { db in
|
|
try db.execute(sql: "CREATE TABLE persons (name TEXT, age INT)")
|
|
|
|
let statement = try db.makeStatement(literal: "INSERT INTO persons (name, age) VALUES (:name, :age)")
|
|
try statement.execute(arguments: ["name": "Arthur", "age": 41])
|
|
|
|
let row = try Row.fetchOne(db, sql: "SELECT * FROM persons")!
|
|
XCTAssertEqual(row[0] as String, "Arthur")
|
|
XCTAssertEqual(row[1] as Int, 41)
|
|
}
|
|
}
|
|
|
|
func testCachedUpdateStatementLiteral() throws {
|
|
let dbQueue = try makeDatabaseQueue()
|
|
try dbQueue.inDatabase { db in
|
|
try db.execute(sql: "CREATE TABLE persons (name TEXT, age INT)")
|
|
|
|
// The tested function:
|
|
let statement = try db.cachedStatement(literal: "INSERT INTO persons (name, age) VALUES ('Arthur', 41)")
|
|
try statement.execute()
|
|
|
|
let row = try Row.fetchOne(db, sql: "SELECT * FROM persons")!
|
|
XCTAssertEqual(row[0] as String, "Arthur")
|
|
XCTAssertEqual(row[1] as Int, 41)
|
|
}
|
|
}
|
|
|
|
func testCachedUpdateStatementLiteralWithArguments() throws {
|
|
let dbQueue = try makeDatabaseQueue()
|
|
try dbQueue.inDatabase { db in
|
|
try db.execute(sql: "CREATE TABLE persons (name TEXT, age INT)")
|
|
|
|
// The tested function:
|
|
let statement = try db.cachedStatement(literal: "INSERT INTO persons (name, age) VALUES (\("Arthur"), \(41))")
|
|
try statement.execute()
|
|
|
|
let row = try Row.fetchOne(db, sql: "SELECT * FROM persons")!
|
|
XCTAssertEqual(row[0] as String, "Arthur")
|
|
XCTAssertEqual(row[1] as Int, 41)
|
|
}
|
|
}
|
|
|
|
func testCachedUpdateStatementLiteralWithArrayBinding() throws {
|
|
let dbQueue = try makeDatabaseQueue()
|
|
try dbQueue.inDatabase { db in
|
|
try db.execute(sql: "CREATE TABLE persons (name TEXT, age INT)")
|
|
|
|
let statement = try db.cachedStatement(literal: "INSERT INTO persons (name, age) VALUES (?, ?)")
|
|
try statement.execute(arguments: ["Arthur", 41])
|
|
|
|
let row = try Row.fetchOne(db, sql: "SELECT * FROM persons")!
|
|
XCTAssertEqual(row[0] as String, "Arthur")
|
|
XCTAssertEqual(row[1] as Int, 41)
|
|
}
|
|
}
|
|
|
|
func testCachedUpdateStatementLiteralWithDictionaryBinding() throws {
|
|
let dbQueue = try makeDatabaseQueue()
|
|
try dbQueue.inDatabase { db in
|
|
try db.execute(sql: "CREATE TABLE persons (name TEXT, age INT)")
|
|
|
|
let statement = try db.cachedStatement(literal: "INSERT INTO persons (name, age) VALUES (:name, :age)")
|
|
try statement.execute(arguments: ["name": "Arthur", "age": 41])
|
|
|
|
let row = try Row.fetchOne(db, sql: "SELECT * FROM persons")!
|
|
XCTAssertEqual(row[0] as String, "Arthur")
|
|
XCTAssertEqual(row[1] as Int, 41)
|
|
}
|
|
}
|
|
|
|
func testDatabaseExecute() throws {
|
|
let dbQueue = try makeDatabaseQueue()
|
|
try dbQueue.inDatabase { db in
|
|
try db.execute(sql: "CREATE TABLE persons (name TEXT, age INT)")
|
|
|
|
// The tested function:
|
|
try db.execute(sql: "INSERT INTO persons (name, age) VALUES ('Arthur', 41)")
|
|
|
|
let row = try Row.fetchOne(db, sql: "SELECT * FROM persons")!
|
|
XCTAssertEqual(row[0] as String, "Arthur")
|
|
XCTAssertEqual(row[1] as Int, 41)
|
|
}
|
|
}
|
|
|
|
func testDatabaseExecuteChanges() throws {
|
|
let dbQueue = try makeDatabaseQueue()
|
|
try dbQueue.inDatabase { db in
|
|
XCTAssertEqual(db.changesCount, 0)
|
|
XCTAssertEqual(db.totalChangesCount, 0)
|
|
XCTAssertEqual(db.lastInsertedRowID, 0)
|
|
|
|
try db.execute(sql: "CREATE TABLE persons (id INTEGER PRIMARY KEY, name TEXT)")
|
|
|
|
try db.execute(sql: "INSERT INTO persons (name) VALUES ('Arthur')")
|
|
XCTAssertEqual(db.changesCount, 1)
|
|
XCTAssertEqual(db.totalChangesCount, 1)
|
|
XCTAssertEqual(db.lastInsertedRowID, 1)
|
|
|
|
try db.execute(sql: "INSERT INTO persons (name) VALUES (?)", arguments: ["Barbara"])
|
|
XCTAssertEqual(db.changesCount, 1)
|
|
XCTAssertEqual(db.totalChangesCount, 2)
|
|
XCTAssertEqual(db.lastInsertedRowID, 2)
|
|
|
|
try db.execute(sql: "DELETE FROM persons")
|
|
XCTAssertEqual(db.changesCount, 2)
|
|
XCTAssertEqual(db.totalChangesCount, 4)
|
|
XCTAssertEqual(db.lastInsertedRowID, 2)
|
|
}
|
|
}
|
|
|
|
func testDatabaseExecuteWithArrayBinding() throws {
|
|
let dbQueue = try makeDatabaseQueue()
|
|
try dbQueue.inDatabase { db in
|
|
try db.execute(sql: "CREATE TABLE persons (name TEXT, age INT)")
|
|
|
|
// The tested function:
|
|
try db.execute(sql: "INSERT INTO persons (name, age) VALUES (?, ?)", arguments: ["Arthur", 41])
|
|
|
|
let row = try Row.fetchOne(db, sql: "SELECT * FROM persons")!
|
|
XCTAssertEqual(row[0] as String, "Arthur")
|
|
XCTAssertEqual(row[1] as Int, 41)
|
|
}
|
|
}
|
|
|
|
func testDatabaseExecuteWithDictionaryBinding() throws {
|
|
let dbQueue = try makeDatabaseQueue()
|
|
try dbQueue.inDatabase { db in
|
|
try db.execute(sql: "CREATE TABLE persons (name TEXT, age INT)")
|
|
|
|
// The tested function:
|
|
try db.execute(sql: "INSERT INTO persons (name, age) VALUES (:name, :age)", arguments: ["name": "Arthur", "age": 41])
|
|
|
|
let row = try Row.fetchOne(db, sql: "SELECT * FROM persons")!
|
|
XCTAssertEqual(row[0] as String, "Arthur")
|
|
XCTAssertEqual(row[1] as Int, 41)
|
|
}
|
|
}
|
|
|
|
func testSelectStatement() throws {
|
|
let dbQueue = try makeDatabaseQueue()
|
|
try dbQueue.inDatabase { db in
|
|
try db.execute(sql: "CREATE TABLE persons (name TEXT, age INT)")
|
|
try db.execute(sql: "INSERT INTO persons (name, age) VALUES (:name, :age)", arguments: ["name": "Arthur", "age": 41])
|
|
try db.execute(sql: "INSERT INTO persons (name, age) VALUES (:name, :age)", arguments: ["name": "Barbara", "age": nil])
|
|
|
|
let statement = try db.makeStatement(sql: "SELECT * FROM persons")
|
|
let rows = try Row.fetchAll(statement)
|
|
XCTAssertEqual(rows.count, 2)
|
|
}
|
|
}
|
|
|
|
func testSelectStatementWithArrayBinding() throws {
|
|
let dbQueue = try makeDatabaseQueue()
|
|
try dbQueue.inDatabase { db in
|
|
try db.execute(sql: "CREATE TABLE persons (name TEXT, age INT)")
|
|
try db.execute(sql: "INSERT INTO persons (name, age) VALUES (:name, :age)", arguments: ["name": "Arthur", "age": 41])
|
|
try db.execute(sql: "INSERT INTO persons (name, age) VALUES (:name, :age)", arguments: ["name": "Barbara", "age": nil])
|
|
|
|
let statement = try db.makeStatement(sql: "SELECT * FROM persons WHERE name = ?")
|
|
let rows = try Row.fetchAll(statement, arguments: ["Arthur"])
|
|
XCTAssertEqual(rows.count, 1)
|
|
}
|
|
}
|
|
|
|
func testSelectStatementWithDictionaryBinding() throws {
|
|
let dbQueue = try makeDatabaseQueue()
|
|
try dbQueue.inDatabase { db in
|
|
try db.execute(sql: "CREATE TABLE persons (name TEXT, age INT)")
|
|
try db.execute(sql: "INSERT INTO persons (name, age) VALUES (:name, :age)", arguments: ["name": "Arthur", "age": 41])
|
|
try db.execute(sql: "INSERT INTO persons (name, age) VALUES (:name, :age)", arguments: ["name": "Barbara", "age": nil])
|
|
|
|
let statement = try db.makeStatement(sql: "SELECT * FROM persons WHERE name = :name")
|
|
let rows = try Row.fetchAll(statement, arguments: ["name": "Arthur"])
|
|
XCTAssertEqual(rows.count, 1)
|
|
}
|
|
}
|
|
|
|
func testSelectStatementLiteral() throws {
|
|
let dbQueue = try makeDatabaseQueue()
|
|
try dbQueue.inDatabase { db in
|
|
try db.execute(sql: "CREATE TABLE persons (name TEXT, age INT)")
|
|
try db.execute(sql: "INSERT INTO persons (name, age) VALUES (:name, :age)", arguments: ["name": "Arthur", "age": 41])
|
|
try db.execute(sql: "INSERT INTO persons (name, age) VALUES (:name, :age)", arguments: ["name": "Barbara", "age": nil])
|
|
|
|
let statement = try db.makeStatement(literal: "SELECT * FROM persons")
|
|
let rows = try Row.fetchAll(statement)
|
|
XCTAssertEqual(rows.count, 2)
|
|
}
|
|
}
|
|
|
|
func testSelectStatementLiteralWithArguments() throws {
|
|
let dbQueue = try makeDatabaseQueue()
|
|
try dbQueue.inDatabase { db in
|
|
try db.execute(sql: "CREATE TABLE persons (name TEXT, age INT)")
|
|
try db.execute(sql: "INSERT INTO persons (name, age) VALUES (:name, :age)", arguments: ["name": "Arthur", "age": 41])
|
|
try db.execute(sql: "INSERT INTO persons (name, age) VALUES (:name, :age)", arguments: ["name": "Barbara", "age": nil])
|
|
|
|
let statement = try db.makeStatement(literal: "SELECT * FROM persons WHERE name = \("Arthur")")
|
|
let rows = try Row.fetchAll(statement)
|
|
XCTAssertEqual(rows.count, 1)
|
|
}
|
|
}
|
|
|
|
func testSelectStatementLiteralWithArrayBinding() throws {
|
|
let dbQueue = try makeDatabaseQueue()
|
|
try dbQueue.inDatabase { db in
|
|
try db.execute(sql: "CREATE TABLE persons (name TEXT, age INT)")
|
|
try db.execute(sql: "INSERT INTO persons (name, age) VALUES (:name, :age)", arguments: ["name": "Arthur", "age": 41])
|
|
try db.execute(sql: "INSERT INTO persons (name, age) VALUES (:name, :age)", arguments: ["name": "Barbara", "age": nil])
|
|
|
|
let statement = try db.makeStatement(literal: "SELECT * FROM persons WHERE name = ?")
|
|
let rows = try Row.fetchAll(statement, arguments: ["Arthur"])
|
|
XCTAssertEqual(rows.count, 1)
|
|
}
|
|
}
|
|
|
|
func testSelectStatementLiteralWithDictionaryBinding() throws {
|
|
let dbQueue = try makeDatabaseQueue()
|
|
try dbQueue.inDatabase { db in
|
|
try db.execute(sql: "CREATE TABLE persons (name TEXT, age INT)")
|
|
try db.execute(sql: "INSERT INTO persons (name, age) VALUES (:name, :age)", arguments: ["name": "Arthur", "age": 41])
|
|
try db.execute(sql: "INSERT INTO persons (name, age) VALUES (:name, :age)", arguments: ["name": "Barbara", "age": nil])
|
|
|
|
let statement = try db.makeStatement(literal: "SELECT * FROM persons WHERE name = :name")
|
|
let rows = try Row.fetchAll(statement, arguments: ["name": "Arthur"])
|
|
XCTAssertEqual(rows.count, 1)
|
|
}
|
|
}
|
|
|
|
func testCachedSelectStatementLiteral() throws {
|
|
let dbQueue = try makeDatabaseQueue()
|
|
try dbQueue.inDatabase { db in
|
|
try db.execute(sql: "CREATE TABLE persons (name TEXT, age INT)")
|
|
try db.execute(sql: "INSERT INTO persons (name, age) VALUES (:name, :age)", arguments: ["name": "Arthur", "age": 41])
|
|
try db.execute(sql: "INSERT INTO persons (name, age) VALUES (:name, :age)", arguments: ["name": "Barbara", "age": nil])
|
|
|
|
let statement = try db.cachedStatement(literal: "SELECT * FROM persons")
|
|
let rows = try Row.fetchAll(statement)
|
|
XCTAssertEqual(rows.count, 2)
|
|
}
|
|
}
|
|
|
|
func testCachedSelectStatementLiteralWithArguments() throws {
|
|
let dbQueue = try makeDatabaseQueue()
|
|
try dbQueue.inDatabase { db in
|
|
try db.execute(sql: "CREATE TABLE persons (name TEXT, age INT)")
|
|
try db.execute(sql: "INSERT INTO persons (name, age) VALUES (:name, :age)", arguments: ["name": "Arthur", "age": 41])
|
|
try db.execute(sql: "INSERT INTO persons (name, age) VALUES (:name, :age)", arguments: ["name": "Barbara", "age": nil])
|
|
|
|
let statement = try db.cachedStatement(literal: "SELECT * FROM persons WHERE name = \("Arthur")")
|
|
let rows = try Row.fetchAll(statement)
|
|
XCTAssertEqual(rows.count, 1)
|
|
}
|
|
}
|
|
|
|
func testCachedSelectStatementLiteralWithArrayBinding() throws {
|
|
let dbQueue = try makeDatabaseQueue()
|
|
try dbQueue.inDatabase { db in
|
|
try db.execute(sql: "CREATE TABLE persons (name TEXT, age INT)")
|
|
try db.execute(sql: "INSERT INTO persons (name, age) VALUES (:name, :age)", arguments: ["name": "Arthur", "age": 41])
|
|
try db.execute(sql: "INSERT INTO persons (name, age) VALUES (:name, :age)", arguments: ["name": "Barbara", "age": nil])
|
|
|
|
let statement = try db.cachedStatement(literal: "SELECT * FROM persons WHERE name = ?")
|
|
let rows = try Row.fetchAll(statement, arguments: ["Arthur"])
|
|
XCTAssertEqual(rows.count, 1)
|
|
}
|
|
}
|
|
|
|
func testCachedSelectStatementLiteralWithDictionaryBinding() throws {
|
|
let dbQueue = try makeDatabaseQueue()
|
|
try dbQueue.inDatabase { db in
|
|
try db.execute(sql: "CREATE TABLE persons (name TEXT, age INT)")
|
|
try db.execute(sql: "INSERT INTO persons (name, age) VALUES (:name, :age)", arguments: ["name": "Arthur", "age": 41])
|
|
try db.execute(sql: "INSERT INTO persons (name, age) VALUES (:name, :age)", arguments: ["name": "Barbara", "age": nil])
|
|
|
|
let statement = try db.cachedStatement(literal: "SELECT * FROM persons WHERE name = :name")
|
|
let rows = try Row.fetchAll(statement, arguments: ["name": "Arthur"])
|
|
XCTAssertEqual(rows.count, 1)
|
|
}
|
|
}
|
|
|
|
func testRowValueAtIndex() throws {
|
|
let dbQueue = try makeDatabaseQueue()
|
|
try dbQueue.inDatabase { db in
|
|
try db.execute(sql: "CREATE TABLE persons (name TEXT, age INT)")
|
|
try db.execute(sql: "INSERT INTO persons (name, age) VALUES (:name, :age)", arguments: ["name": "Arthur", "age": 41])
|
|
try db.execute(sql: "INSERT INTO persons (name, age) VALUES (:name, :age)", arguments: ["name": "Barbara", "age": nil])
|
|
|
|
var names: [String?] = []
|
|
var ages: [Int?] = []
|
|
let rows = try Row.fetchCursor(db, sql: "SELECT * FROM persons ORDER BY name")
|
|
while let row = try rows.next() {
|
|
// The tested function:
|
|
let name: String? = row[0]
|
|
let age: Int? = row[1]
|
|
names.append(name)
|
|
ages.append(age)
|
|
}
|
|
|
|
XCTAssertEqual(names[0]!, "Arthur")
|
|
XCTAssertEqual(names[1]!, "Barbara")
|
|
XCTAssertEqual(ages[0]!, 41)
|
|
XCTAssertNil(ages[1])
|
|
}
|
|
}
|
|
|
|
func testRowValueNamed() throws {
|
|
let dbQueue = try makeDatabaseQueue()
|
|
try dbQueue.inDatabase { db in
|
|
try db.execute(sql: "CREATE TABLE persons (name TEXT, age INT)")
|
|
try db.execute(sql: "INSERT INTO persons (name, age) VALUES (:name, :age)", arguments: ["name": "Arthur", "age": 41])
|
|
try db.execute(sql: "INSERT INTO persons (name, age) VALUES (:name, :age)", arguments: ["name": "Barbara", "age": nil])
|
|
|
|
var names: [String?] = []
|
|
var ages: [Int?] = []
|
|
let rows = try Row.fetchCursor(db, sql: "SELECT * FROM persons ORDER BY name")
|
|
while let row = try rows.next() {
|
|
// The tested function:
|
|
let name: String? = row["name"]
|
|
let age: Int? = row["age"]
|
|
names.append(name)
|
|
ages.append(age)
|
|
}
|
|
|
|
XCTAssertEqual(names[0]!, "Arthur")
|
|
XCTAssertEqual(names[1]!, "Barbara")
|
|
XCTAssertEqual(ages[0]!, 41)
|
|
XCTAssertNil(ages[1])
|
|
}
|
|
}
|
|
|
|
func testDatabaseCanBeUsedOutsideOfDatabaseQueueBlockAsLongAsTheQueueIsCorrect() throws {
|
|
let dbQueue = try makeDatabaseQueue()
|
|
var database: Database? = nil
|
|
dbQueue.inDatabase { db in
|
|
database = db
|
|
}
|
|
try dbQueue.inDatabase { _ in
|
|
try database!.execute(sql: "CREATE TABLE persons (name TEXT)")
|
|
}
|
|
}
|
|
|
|
func testFailedCommitIsRollbacked() throws {
|
|
let dbQueue = try makeDatabaseQueue()
|
|
try dbQueue.inDatabase { db in
|
|
try db.execute(sql: "CREATE TABLE parent (id INTEGER PRIMARY KEY)")
|
|
try db.execute(sql: "CREATE TABLE child (parentID INTEGER NOT NULL REFERENCES parent(id))")
|
|
}
|
|
|
|
do {
|
|
try dbQueue.inTransaction { db in
|
|
do {
|
|
try db.execute(sql: "PRAGMA defer_foreign_keys = ON")
|
|
try db.execute(sql: "INSERT INTO child (parentID) VALUES (1)")
|
|
} catch {
|
|
XCTFail()
|
|
}
|
|
return .commit
|
|
}
|
|
XCTFail()
|
|
} catch let error as DatabaseError {
|
|
XCTAssertEqual(error.resultCode, .SQLITE_CONSTRAINT)
|
|
XCTAssertEqual(error.message!, "FOREIGN KEY constraint failed")
|
|
XCTAssertEqual(error.sql!, "COMMIT TRANSACTION")
|
|
XCTAssertEqual(error.description, "SQLite error 19: FOREIGN KEY constraint failed - while executing `COMMIT TRANSACTION`")
|
|
}
|
|
|
|
// Make sure we can open another transaction
|
|
try dbQueue.inTransaction { db in .commit }
|
|
}
|
|
|
|
func testExplicitTransactionManagement() throws {
|
|
let dbQueue = try makeDatabaseQueue()
|
|
|
|
try dbQueue.writeWithoutTransaction { db in
|
|
try db.beginTransaction()
|
|
XCTAssertEqual(lastSQLQuery, "BEGIN DEFERRED TRANSACTION")
|
|
try db.rollback()
|
|
XCTAssertEqual(lastSQLQuery, "ROLLBACK TRANSACTION")
|
|
try db.beginTransaction(.immediate)
|
|
XCTAssertEqual(lastSQLQuery, "BEGIN IMMEDIATE TRANSACTION")
|
|
try db.commit()
|
|
XCTAssertEqual(lastSQLQuery, "COMMIT TRANSACTION")
|
|
}
|
|
}
|
|
|
|
func testReadOnly() throws {
|
|
let dbQueue = try makeDatabaseQueue()
|
|
try dbQueue.inDatabase { db in
|
|
try db.execute(sql: "CREATE TABLE t (id INTEGER PRIMARY KEY)")
|
|
|
|
// Write access OK
|
|
try db.execute(sql: "INSERT INTO t DEFAULT VALUES")
|
|
|
|
try db.readOnly {
|
|
do {
|
|
try db.execute(sql: "INSERT INTO t DEFAULT VALUES")
|
|
XCTFail()
|
|
} catch let error as DatabaseError {
|
|
XCTAssertEqual(error.resultCode, .SQLITE_READONLY)
|
|
}
|
|
|
|
// Reentrancy
|
|
try db.readOnly {
|
|
do {
|
|
try db.execute(sql: "INSERT INTO t DEFAULT VALUES")
|
|
XCTFail()
|
|
} catch let error as DatabaseError {
|
|
XCTAssertEqual(error.resultCode, .SQLITE_READONLY)
|
|
}
|
|
}
|
|
|
|
// Still read-only
|
|
do {
|
|
try db.execute(sql: "INSERT INTO t DEFAULT VALUES")
|
|
XCTFail()
|
|
} catch let error as DatabaseError {
|
|
XCTAssertEqual(error.resultCode, .SQLITE_READONLY)
|
|
}
|
|
}
|
|
|
|
// Write access OK
|
|
try db.execute(sql: "INSERT INTO t DEFAULT VALUES")
|
|
}
|
|
}
|
|
|
|
func testReadOnlyTransaction() throws {
|
|
dbConfiguration.defaultTransactionKind = .immediate
|
|
let dbQueue = try makeDatabaseQueue()
|
|
try dbQueue.inDatabase { db in
|
|
do {
|
|
sqlQueries.removeAll()
|
|
try db.inSavepoint { .commit }
|
|
try db.inTransaction { .commit }
|
|
try db.inTransaction(.immediate) { .commit }
|
|
XCTAssertEqual(Set(sqlQueries), ["BEGIN IMMEDIATE TRANSACTION", "COMMIT TRANSACTION"])
|
|
}
|
|
|
|
try db.readOnly {
|
|
sqlQueries.removeAll()
|
|
try db.inSavepoint { .commit }
|
|
try db.inTransaction { .commit }
|
|
XCTAssertEqual(Set(sqlQueries), ["BEGIN DEFERRED TRANSACTION", "COMMIT TRANSACTION"])
|
|
do {
|
|
try db.inTransaction(.immediate) { .commit }
|
|
XCTFail("Expected error")
|
|
} catch DatabaseError.SQLITE_READONLY { }
|
|
}
|
|
}
|
|
}
|
|
|
|
func testCheckpoint() throws {
|
|
do {
|
|
// Not a WAL database
|
|
let dbQueue = try makeDatabaseQueue()
|
|
let result = try dbQueue.inDatabase {
|
|
try $0.checkpoint()
|
|
}
|
|
XCTAssertEqual(result.walFrameCount, -1)
|
|
XCTAssertEqual(result.checkpointedFrameCount, -1)
|
|
}
|
|
do {
|
|
// WAL database
|
|
let dbPool = try makeDatabasePool()
|
|
let result = try dbPool.writeWithoutTransaction {
|
|
try $0.checkpoint()
|
|
}
|
|
XCTAssertGreaterThanOrEqual(result.walFrameCount, 0)
|
|
XCTAssertGreaterThanOrEqual(result.checkpointedFrameCount, 0)
|
|
}
|
|
do {
|
|
// WAL database + TRUNCATE
|
|
let dbPool = try makeDatabasePool()
|
|
let result = try dbPool.writeWithoutTransaction {
|
|
try $0.checkpoint(.truncate)
|
|
}
|
|
XCTAssertEqual(result.walFrameCount, 0)
|
|
XCTAssertEqual(result.checkpointedFrameCount, 0)
|
|
}
|
|
}
|
|
|
|
func testMaximumStatementArgumentCount() throws {
|
|
let dbQueue = try makeDatabaseQueue()
|
|
let count = try dbQueue.read { $0.maximumStatementArgumentCount }
|
|
// 999 should be safe: https://www.sqlite.org/limits.html
|
|
XCTAssertGreaterThanOrEqual(count, 999)
|
|
}
|
|
}
|