mirror of https://github.com/oxen-io/session-ios
				
				
				
			
			You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			720 lines
		
	
	
		
			33 KiB
		
	
	
	
		
			Swift
		
	
			
		
		
	
	
			720 lines
		
	
	
		
			33 KiB
		
	
	
	
		
			Swift
		
	
| // Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
 | |
| 
 | |
| import Foundation
 | |
| import GRDB
 | |
| 
 | |
| import Quick
 | |
| import Nimble
 | |
| 
 | |
| @testable import SessionUtilitiesKit
 | |
| 
 | |
| class PersistableRecordUtilitiesSpec: QuickSpec {
 | |
|     override class func spec() {
 | |
|         // MARK: Configuration
 | |
|         
 | |
|         @TestState var customWriter: DatabaseQueue! = try! DatabaseQueue()
 | |
|         @TestState var mockStorage: Storage! = SynchronousStorage(
 | |
|             customWriter: customWriter,
 | |
|             migrationTargets: [
 | |
|                 TestTarget.self
 | |
|             ],
 | |
|             using: Dependencies()
 | |
|         )
 | |
|         
 | |
|         // MARK: - a PersistableRecord
 | |
|         describe("a PersistableRecord") {
 | |
|             // MARK: -- before running the add column migration
 | |
|             context("before running the add column migration") {
 | |
|                 // MARK: ---- fails when using the standard insert
 | |
|                 it("fails when using the standard insert") {
 | |
|                     mockStorage.write { db in
 | |
|                         expect {
 | |
|                             try TestType(columnA: "Test1", columnB: "Test1B").insert(db)
 | |
|                         }
 | |
|                         .to(throwError())
 | |
|                     }
 | |
|                 }
 | |
|                 
 | |
|                 // MARK: ---- fails when using the standard inserted
 | |
|                 it("fails when using the standard inserted") {
 | |
|                     mockStorage.write { db in
 | |
|                         expect {
 | |
|                             try MutableTestType(columnA: "Test2", columnB: "Test2B").inserted(db)
 | |
|                         }
 | |
|                         .to(throwError())
 | |
|                     }
 | |
|                 }
 | |
|                 
 | |
|                 // MARK: ---- fails when using the standard save and the item does not already exist
 | |
|                 it("fails when using the standard save and the item does not already exist") {
 | |
|                     mockStorage.write { db in
 | |
|                         expect {
 | |
|                             try TestType(columnA: "Test3", columnB: "Test3B").save(db)
 | |
|                         }
 | |
|                         .to(throwError())
 | |
|                     }
 | |
|                 }
 | |
|                 
 | |
|                 // MARK: ---- fails when using the standard saved and the item does not already exist
 | |
|                 it("fails when using the standard saved and the item does not already exist") {
 | |
|                     mockStorage.write { db in
 | |
|                         expect {
 | |
|                             try MutableTestType(columnA: "Test4", columnB: "Test4B").saved(db)
 | |
|                         }
 | |
|                         .to(throwError())
 | |
|                     }
 | |
|                 }
 | |
|                 
 | |
|                 // MARK: ---- fails when using the standard upsert and the item does not already exist
 | |
|                 it("fails when using the standard upsert and the item does not already exist") {
 | |
|                     mockStorage.write { db in
 | |
|                         expect {
 | |
|                             try TestType(columnA: "Test5", columnB: "Test5B").upsert(db)
 | |
|                         }
 | |
|                         .to(throwError())
 | |
|                     }
 | |
|                 }
 | |
|                 
 | |
|                 // MARK: ---- fails when using the standard mutable upsert and the item does not already exist
 | |
|                 it("fails when using the standard mutable upsert and the item does not already exist") {
 | |
|                     mockStorage.write { db in
 | |
|                         expect {
 | |
|                             var result = MutableTestType(columnA: "Test6", columnB: "Test6B")
 | |
|                             try result.upsert(db)
 | |
|                             return result
 | |
|                         }
 | |
|                         .to(throwError())
 | |
|                     }
 | |
|                 }
 | |
|                 
 | |
|                 // MARK: ---- fails when using the standard upsert and the item already exists
 | |
|                 it("fails when using the standard upsert and the item already exists") {
 | |
|                     mockStorage.write { db in
 | |
|                         expect {
 | |
|                             try db.execute(
 | |
|                                 sql: "INSERT INTO TestType (columnA) VALUES (?)",
 | |
|                                 arguments: StatementArguments(["Test19"])
 | |
|                             )
 | |
|                             try TestType(columnA: "Test19", columnB: "Test19B").upsert(db)
 | |
|                         }
 | |
|                         .to(throwError())
 | |
|                     }
 | |
|                 }
 | |
|                 
 | |
|                 // MARK: ---- fails when using the standard mutable upsert and the item already exists
 | |
|                 it("fails when using the standard mutable upsert and the item already exists") {
 | |
|                     mockStorage.write { db in
 | |
|                         expect {
 | |
|                             try db.execute(
 | |
|                                 sql: "INSERT INTO MutableTestType (columnA) VALUES (?)",
 | |
|                                 arguments: StatementArguments(["Test20"])
 | |
|                             )
 | |
|                             var result = MutableTestType(id: 1, columnA: "Test20", columnB: "Test20B")
 | |
|                             try result.upsert(db)
 | |
|                             return result
 | |
|                         }
 | |
|                         .to(throwError())
 | |
|                     }
 | |
|                 }
 | |
|                 
 | |
|                 // MARK: ---- succeeds when using the migration safe insert
 | |
|                 it("succeeds when using the migration safe insert") {
 | |
|                     mockStorage.write { db in
 | |
|                         expect {
 | |
|                             try TestType(columnA: "Test7", columnB: "Test7B").migrationSafeInsert(db)
 | |
|                         }
 | |
|                         .toNot(throwError())
 | |
|                     }
 | |
|                     
 | |
|                     mockStorage.read { db in
 | |
|                         expect(try TestType.fetchAll(db))
 | |
|                             .toNot(beNil())
 | |
|                     }
 | |
|                 }
 | |
|                 
 | |
|                 // MARK: ---- succeeds when using the migration safe inserted
 | |
|                 it("succeeds when using the migration safe inserted") {
 | |
|                     mockStorage.write { db in
 | |
|                         expect {
 | |
|                             try MutableTestType(columnA: "Test8", columnB: "Test8B").migrationSafeInserted(db)
 | |
|                         }
 | |
|                         .toNot(throwError())
 | |
|                         
 | |
|                         expect {
 | |
|                             try MutableTestType(columnA: "Test9", columnB: "Test9B")
 | |
|                                 .migrationSafeInserted(db)
 | |
|                                 .id
 | |
|                         }
 | |
|                         .toNot(beNil())
 | |
|                     }
 | |
|                     
 | |
|                     mockStorage.read { db in
 | |
|                         expect(try MutableTestType.fetchAll(db))
 | |
|                             .toNot(beNil())
 | |
|                     }
 | |
|                 }
 | |
|                 
 | |
|                 // MARK: ---- succeeds when using the migration safe save and the item does not already exist
 | |
|                 it("succeeds when using the migration safe save and the item does not already exist") {
 | |
|                     mockStorage.write { db in
 | |
|                         expect {
 | |
|                             try TestType(columnA: "Test10", columnB: "Test10B").migrationSafeSave(db)
 | |
|                         }
 | |
|                         .toNot(throwError())
 | |
|                     }
 | |
|                 }
 | |
|                 
 | |
|                 // MARK: ---- succeeds when using the migration safe saved and the item does not already exist
 | |
|                 it("succeeds when using the migration safe saved and the item does not already exist") {
 | |
|                     mockStorage.write { db in
 | |
|                         expect {
 | |
|                             try MutableTestType(columnA: "Test11", columnB: "Test11B").migrationSafeSaved(db)
 | |
|                         }
 | |
|                         .toNot(throwError())
 | |
|                         
 | |
|                         expect {
 | |
|                             try MutableTestType(columnA: "Test12", columnB: "Test12B")
 | |
|                                 .migrationSafeSaved(db)
 | |
|                                 .id
 | |
|                         }
 | |
|                         .toNot(beNil())
 | |
|                     }
 | |
|                     
 | |
|                     mockStorage.read { db in
 | |
|                         expect(try MutableTestType.fetchAll(db))
 | |
|                             .toNot(beNil())
 | |
|                     }
 | |
|                 }
 | |
|                 
 | |
|                 // MARK: ---- succeeds when using the migration safe upsert and the item does not already exist
 | |
|                 it("succeeds when using the migration safe upsert and the item does not already exist") {
 | |
|                     mockStorage.write { db in
 | |
|                         expect {
 | |
|                             try TestType(columnA: "Test13", columnB: "Test13B").migrationSafeUpsert(db)
 | |
|                         }
 | |
|                         .toNot(throwError())
 | |
|                     }
 | |
|                 }
 | |
|                 
 | |
|                 // MARK: ---- succeeds when using the migration safe mutable upsert and the item does not already exist
 | |
|                 it("succeeds when using the migration safe mutable upsert and the item does not already exist") {
 | |
|                     mockStorage.write { db in
 | |
|                         expect {
 | |
|                             let result = MutableTestType(columnA: "Test14", columnB: "Test14B")
 | |
|                             try result.migrationSafeUpsert(db)
 | |
|                             return result
 | |
|                         }
 | |
|                         .toNot(throwError())
 | |
|                     }
 | |
|                     
 | |
|                     mockStorage.read { db in
 | |
|                         expect(try MutableTestType.fetchAll(db))
 | |
|                             .toNot(beNil())
 | |
|                     }
 | |
|                 }
 | |
|                 
 | |
|                 // MARK: ---- succeeds when using the standard save and the item already exists
 | |
|                 it("succeeds when using the standard save and the item already exists") {
 | |
|                     /// **Note:** The built-in 'update' method only updates existing columns so this shouldn't fail
 | |
|                     mockStorage.write { db in
 | |
|                         expect {
 | |
|                             try db.execute(
 | |
|                                 sql: "INSERT INTO TestType (columnA) VALUES (?)",
 | |
|                                 arguments: StatementArguments(["Test16"])
 | |
|                             )
 | |
|                             try TestType(columnA: "Test16", columnB: "Test16B").save(db)
 | |
|                         }
 | |
|                         .toNot(throwError())
 | |
|                     }
 | |
|                 }
 | |
|                 
 | |
|                 // MARK: ---- succeeds when using the standard saved and the item already exists
 | |
|                 it("succeeds when using the standard saved and the item already exists") {
 | |
|                     /// **Note:** The built-in 'update' method only updates existing columns so this won't fail
 | |
|                     /// due to the structure discrepancy but won't update the id as that only happens on insert
 | |
|                     mockStorage.write { db in
 | |
|                         expect {
 | |
|                             try db.execute(
 | |
|                                 sql: "INSERT INTO MutableTestType (columnA) VALUES (?)",
 | |
|                                 arguments: StatementArguments(["Test17"])
 | |
|                             )
 | |
|                             _ = try MutableTestType(id: 1, columnA: "Test17", columnB: "Test17B").saved(db)
 | |
|                         }
 | |
|                         .toNot(throwError())
 | |
|                         
 | |
|                         expect {
 | |
|                             try db.execute(
 | |
|                                 sql: "INSERT INTO MutableTestType (columnA) VALUES (?)",
 | |
|                                 arguments: StatementArguments(["Test18"])
 | |
|                             )
 | |
|                             return try MutableTestType(id: 2, columnA: "Test18", columnB: "Test18B")
 | |
|                                 .saved(db)
 | |
|                                 .id
 | |
|                         }
 | |
|                         .toNot(beNil())
 | |
|                     }
 | |
|                     
 | |
|                     mockStorage.read { db in
 | |
|                         let types: [MutableTestType]? = try MutableTestType.fetchAll(db)
 | |
|                         
 | |
|                         expect(types).toNot(beNil())
 | |
|                         expect(types?.compactMap { $0.id }.count).to(equal(types?.count))
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             
 | |
|             // MARK: -- after running the add column migration
 | |
|             context("after running the add column migration") {
 | |
|                 beforeEach {
 | |
|                     var migrator: DatabaseMigrator = DatabaseMigrator()
 | |
|                     migrator.registerMigration(
 | |
|                         mockStorage,
 | |
|                         targetIdentifier: TestAddColumnMigration.target,
 | |
|                         migration: TestAddColumnMigration.self,
 | |
|                         using: Dependencies()
 | |
|                     )
 | |
|                     
 | |
|                     expect { try migrator.migrate(customWriter) }
 | |
|                         .toNot(throwError())
 | |
|                 }
 | |
|                 
 | |
|                 // MARK: ---- succeeds when using the standard insert
 | |
|                 it("succeeds when using the standard insert") {
 | |
|                     mockStorage.write { db in
 | |
|                         expect {
 | |
|                             try TestType(columnA: "Test1", columnB: "Test1B").insert(db)
 | |
|                         }
 | |
|                         .toNot(throwError())
 | |
|                     }
 | |
|                     
 | |
|                     mockStorage.read { db in
 | |
|                         expect(try TestType.fetchAll(db))
 | |
|                             .toNot(beNil())
 | |
|                     }
 | |
|                 }
 | |
|                 
 | |
|                 // MARK: ---- succeeds when using the standard inserted
 | |
|                 it("succeeds when using the standard inserted") {
 | |
|                     mockStorage.write { db in
 | |
|                         expect {
 | |
|                             try MutableTestType(columnA: "Test2", columnB: "Test2B").inserted(db)
 | |
|                         }
 | |
|                         .toNot(throwError())
 | |
|                     }
 | |
|                     
 | |
|                     mockStorage.read { db in
 | |
|                         expect(try MutableTestType.fetchAll(db))
 | |
|                             .toNot(beNil())
 | |
|                     }
 | |
|                 }
 | |
|                 
 | |
|                 // MARK: ---- succeeds when using the standard save and the item does not already exist
 | |
|                 it("succeeds when using the standard save and the item does not already exist") {
 | |
|                     mockStorage.write { db in
 | |
|                         expect {
 | |
|                             try TestType(columnA: "Test3", columnB: "Test3B").save(db)
 | |
|                         }
 | |
|                         .toNot(throwError())
 | |
|                     }
 | |
|                 }
 | |
|                 
 | |
|                 // MARK: ---- succeeds when using the standard saved and the item does not already exist
 | |
|                 it("succeeds when using the standard saved and the item does not already exist") {
 | |
|                     mockStorage.write { db in
 | |
|                         expect {
 | |
|                             try MutableTestType(columnA: "Test3", columnB: "Test3B").saved(db)
 | |
|                         }
 | |
|                         .toNot(throwError())
 | |
|                     }
 | |
|                 }
 | |
|                 
 | |
|                 // MARK: ---- succeeds when using the standard save and the item already exists
 | |
|                 it("succeeds when using the standard save and the item already exists") {
 | |
|                     mockStorage.write { db in
 | |
|                         expect {
 | |
|                             try db.execute(
 | |
|                                 sql: "INSERT INTO TestType (columnA) VALUES (?)",
 | |
|                                 arguments: StatementArguments(["Test4"])
 | |
|                             )
 | |
|                             try TestType(columnA: "Test4", columnB: "Test4B").save(db)
 | |
|                         }
 | |
|                         .toNot(throwError())
 | |
|                     }
 | |
|                 }
 | |
|                 
 | |
|                 // MARK: ---- succeeds when using the standard saved and the item already exists
 | |
|                 it("succeeds when using the standard saved and the item already exists") {
 | |
|                     /// **Note:** The built-in 'update' method won't update the id as that only happens on insert
 | |
|                     mockStorage.write { db in
 | |
|                         expect {
 | |
|                             try db.execute(
 | |
|                                 sql: "INSERT INTO MutableTestType (columnA) VALUES (?)",
 | |
|                                 arguments: StatementArguments(["Test5"])
 | |
|                             )
 | |
|                             _ = try MutableTestType(id: 1, columnA: "Test5", columnB: "Test5B").saved(db)
 | |
|                         }
 | |
|                         .toNot(throwError())
 | |
|                         
 | |
|                         expect {
 | |
|                             try db.execute(
 | |
|                                 sql: "INSERT INTO MutableTestType (columnA) VALUES (?)",
 | |
|                                 arguments: StatementArguments(["Test6"])
 | |
|                             )
 | |
|                             return try MutableTestType(id: 2, columnA: "Test6", columnB: "Test6B")
 | |
|                                 .saved(db)
 | |
|                                 .id
 | |
|                         }
 | |
|                         .toNot(beNil())
 | |
|                     }
 | |
|                     
 | |
|                     mockStorage.read { db in
 | |
|                         let types: [MutableTestType]? = try MutableTestType.fetchAll(db)
 | |
|                         
 | |
|                         expect(types).toNot(beNil())
 | |
|                         expect(types?.compactMap { $0.id }.count).to(equal(types?.count))
 | |
|                     }
 | |
|                 }
 | |
|                 
 | |
|                 // MARK: ---- succeeds when using the standard upsert and the item does not already exist
 | |
|                 it("succeeds when using the standard upsert and the item does not already exist") {
 | |
|                     mockStorage.write { db in
 | |
|                         expect {
 | |
|                             try TestType(columnA: "Test7", columnB: "Test7B").upsert(db)
 | |
|                         }
 | |
|                         .toNot(throwError())
 | |
|                     }
 | |
|                 }
 | |
|                 
 | |
|                 // MARK: ---- succeeds when using the standard mutable upsert and the item does not already exist
 | |
|                 it("succeeds when using the standard mutable upsert and the item does not already exist") {
 | |
|                     mockStorage.write { db in
 | |
|                         expect {
 | |
|                             var result = MutableTestType(columnA: "Test8", columnB: "Test8B")
 | |
|                             try result.upsert(db)
 | |
|                             return result
 | |
|                         }
 | |
|                         .toNot(throwError())
 | |
|                     }
 | |
|                 }
 | |
|                 
 | |
|                 // MARK: ---- succeeds when using the standard upsert and the item already exists
 | |
|                 it("succeeds when using the standard upsert and the item already exists") {
 | |
|                     mockStorage.write { db in
 | |
|                         expect {
 | |
|                             try db.execute(
 | |
|                                 sql: "INSERT INTO TestType (columnA) VALUES (?)",
 | |
|                                 arguments: StatementArguments(["Test9"])
 | |
|                             )
 | |
|                             try TestType(columnA: "Test9", columnB: "Test9B").upsert(db)
 | |
|                         }
 | |
|                         .toNot(throwError())
 | |
|                     }
 | |
|                 }
 | |
|                 
 | |
|                 // MARK: ---- succeeds when using the standard mutable upsert and the item already exists
 | |
|                 it("succeeds when using the standard mutable upsert and the item already exists") {
 | |
|                     /// **Note:** The built-in 'update' method won't update the id as that only happens on insert
 | |
|                     mockStorage.write { db in
 | |
|                         expect {
 | |
|                             try db.execute(
 | |
|                                 sql: "INSERT INTO MutableTestType (columnA) VALUES (?)",
 | |
|                                 arguments: StatementArguments(["Test10"])
 | |
|                             )
 | |
|                             var result = MutableTestType(id: 1, columnA: "Test10", columnB: "Test10B")
 | |
|                             try result.upsert(db)
 | |
|                             return result
 | |
|                         }
 | |
|                         .toNot(throwError())
 | |
|                         
 | |
|                         expect {
 | |
|                             try db.execute(
 | |
|                                 sql: "INSERT INTO MutableTestType (columnA) VALUES (?)",
 | |
|                                 arguments: StatementArguments(["Test11"])
 | |
|                             )
 | |
|                             var result = MutableTestType(id: 2, columnA: "Test11", columnB: "Test11B")
 | |
|                             try result.upsert(db)
 | |
|                             return result.id
 | |
|                         }
 | |
|                         .toNot(beNil())
 | |
|                     }
 | |
|                     
 | |
|                     mockStorage.read { db in
 | |
|                         let types: [MutableTestType]? = try MutableTestType.fetchAll(db)
 | |
|                         
 | |
|                         expect(types).toNot(beNil())
 | |
|                         expect(types?.compactMap { $0.id }.count).to(equal(types?.count))
 | |
|                     }
 | |
|                 }
 | |
|                 
 | |
|                 // MARK: ---- succeeds when using the migration safe insert
 | |
|                 it("succeeds when using the migration safe insert") {
 | |
|                     mockStorage.write { db in
 | |
|                         expect {
 | |
|                             try TestType(columnA: "Test12", columnB: "Test12B").migrationSafeInsert(db)
 | |
|                         }
 | |
|                         .toNot(throwError())
 | |
|                     }
 | |
|                     
 | |
|                     mockStorage.read { db in
 | |
|                         expect(try TestType.fetchAll(db))
 | |
|                             .toNot(beNil())
 | |
|                     }
 | |
|                 }
 | |
|                 
 | |
|                 // MARK: ---- succeeds when using the migration safe inserted
 | |
|                 it("succeeds when using the migration safe inserted") {
 | |
|                     mockStorage.write { db in
 | |
|                         expect {
 | |
|                             try MutableTestType(columnA: "Test13", columnB: "Test13B").migrationSafeInserted(db)
 | |
|                         }
 | |
|                         .toNot(throwError())
 | |
|                         
 | |
|                         expect {
 | |
|                             try MutableTestType(columnA: "Test14", columnB: "Test14B")
 | |
|                                 .migrationSafeInserted(db)
 | |
|                                 .id
 | |
|                         }
 | |
|                         .toNot(beNil())
 | |
|                     }
 | |
|                     
 | |
|                     mockStorage.read { db in
 | |
|                         expect(try MutableTestType.fetchAll(db))
 | |
|                             .toNot(beNil())
 | |
|                     }
 | |
|                 }
 | |
|                 
 | |
|                 // MARK: ---- succeeds when using the migration safe save and the item does not already exist
 | |
|                 it("succeeds when using the migration safe save and the item does not already exist") {
 | |
|                     mockStorage.write { db in
 | |
|                         expect {
 | |
|                             try TestType(columnA: "Test15", columnB: "Test15B").migrationSafeSave(db)
 | |
|                         }
 | |
|                         .toNot(throwError())
 | |
|                     }
 | |
|                 }
 | |
|                 
 | |
|                 // MARK: ---- succeeds when using the migration safe saved and the item does not already exist
 | |
|                 it("succeeds when using the migration safe saved and the item does not already exist") {
 | |
|                     mockStorage.write { db in
 | |
|                         expect {
 | |
|                             try MutableTestType(columnA: "Test16", columnB: "Test16B").migrationSafeSaved(db)
 | |
|                         }
 | |
|                         .toNot(throwError())
 | |
|                     }
 | |
|                 }
 | |
|                 
 | |
|                 // MARK: ---- succeeds when using the migration safe save and the item already exists
 | |
|                 it("succeeds when using the migration safe save and the item already exists") {
 | |
|                     mockStorage.write { db in
 | |
|                         expect {
 | |
|                             try db.execute(
 | |
|                                 sql: "INSERT INTO TestType (columnA) VALUES (?)",
 | |
|                                 arguments: StatementArguments(["Test17"])
 | |
|                             )
 | |
|                             try TestType(columnA: "Test17", columnB: "Test17B").migrationSafeSave(db)
 | |
|                         }
 | |
|                         .toNot(throwError())
 | |
|                     }
 | |
|                 }
 | |
|                 
 | |
|                 // MARK: ---- succeeds when using the migration safe saved and the item already exists
 | |
|                 it("succeeds when using the migration safe saved and the item already exists") {
 | |
|                     /// **Note:** The built-in 'update' method won't update the id as that only happens on insert
 | |
|                     mockStorage.write { db in
 | |
|                         expect {
 | |
|                             try db.execute(
 | |
|                                 sql: "INSERT INTO MutableTestType (columnA) VALUES (?)",
 | |
|                                 arguments: StatementArguments(["Test18"])
 | |
|                             )
 | |
|                             _ = try MutableTestType(id: 1, columnA: "Test18", columnB: "Test18B")
 | |
|                                 .migrationSafeSaved(db)
 | |
|                         }
 | |
|                         .toNot(throwError())
 | |
|                         
 | |
|                         expect {
 | |
|                             try db.execute(
 | |
|                                 sql: "INSERT INTO MutableTestType (columnA) VALUES (?)",
 | |
|                                 arguments: StatementArguments(["Test19"])
 | |
|                             )
 | |
|                             return try MutableTestType(id: 2, columnA: "Test19", columnB: "Test19B")
 | |
|                                 .migrationSafeSaved(db)
 | |
|                                 .id
 | |
|                         }
 | |
|                         .toNot(beNil())
 | |
|                     }
 | |
|                     
 | |
|                     mockStorage.read { db in
 | |
|                         let types: [MutableTestType]? = try MutableTestType.fetchAll(db)
 | |
|                         
 | |
|                         expect(types).toNot(beNil())
 | |
|                         expect(types?.compactMap { $0.id }.count).to(equal(types?.count))
 | |
|                     }
 | |
|                 }
 | |
|                 
 | |
|                 // MARK: ---- succeeds when using the migration safe upsert and the item does not already exist
 | |
|                 it("succeeds when using the migration safe upsert and the item does not already exist") {
 | |
|                     mockStorage.write { db in
 | |
|                         expect {
 | |
|                             try TestType(columnA: "Test20", columnB: "Test20B").migrationSafeUpsert(db)
 | |
|                         }
 | |
|                         .toNot(throwError())
 | |
|                     }
 | |
|                 }
 | |
|                 
 | |
|                 // MARK: ---- succeeds when using the migration safe mutable upsert and the item does not already exist
 | |
|                 it("succeeds when using the migration safe mutable upsert and the item does not already exist") {
 | |
|                     mockStorage.write { db in
 | |
|                         expect {
 | |
|                             let result = MutableTestType(columnA: "Test21", columnB: "Test21B")
 | |
|                             try result.migrationSafeUpsert(db)
 | |
|                             return result
 | |
|                         }
 | |
|                         .toNot(throwError())
 | |
|                     }
 | |
|                 }
 | |
|                 
 | |
|                 // MARK: ---- succeeds when using the migration safe upsert and the item already exists
 | |
|                 it("succeeds when using the migration safe upsert and the item already exists") {
 | |
|                     mockStorage.write { db in
 | |
|                         expect {
 | |
|                             try db.execute(
 | |
|                                 sql: "INSERT INTO TestType (columnA) VALUES (?)",
 | |
|                                 arguments: StatementArguments(["Test22"])
 | |
|                             )
 | |
|                             try TestType(columnA: "Test22", columnB: "Test22B").migrationSafeUpsert(db)
 | |
|                         }
 | |
|                         .toNot(throwError())
 | |
|                     }
 | |
|                 }
 | |
|                 
 | |
|                 // MARK: ---- succeeds when using the migration safe mutable upsert and the item already exists
 | |
|                 it("succeeds when using the migration safe mutable upsert and the item already exists") {
 | |
|                     /// **Note:** The built-in 'update' method won't update the id as that only happens on insert
 | |
|                     mockStorage.write { db in
 | |
|                         expect {
 | |
|                             try db.execute(
 | |
|                                 sql: "INSERT INTO MutableTestType (columnA) VALUES (?)",
 | |
|                                 arguments: StatementArguments(["Test23"])
 | |
|                             )
 | |
|                             let result = MutableTestType(id: 1, columnA: "Test23", columnB: "Test23B")
 | |
|                             try result.migrationSafeUpsert(db)
 | |
|                             return result
 | |
|                         }
 | |
|                         .toNot(throwError())
 | |
|                         
 | |
|                         expect {
 | |
|                             try db.execute(
 | |
|                                 sql: "INSERT INTO MutableTestType (columnA) VALUES (?)",
 | |
|                                 arguments: StatementArguments(["Test24"])
 | |
|                             )
 | |
|                             let result = MutableTestType(id: 2, columnA: "Test24", columnB: "Test24B")
 | |
|                             try result.migrationSafeUpsert(db)
 | |
|                             return result.id
 | |
|                         }
 | |
|                         .toNot(beNil())
 | |
|                     }
 | |
|                     
 | |
|                     mockStorage.read { db in
 | |
|                         let types: [MutableTestType]? = try MutableTestType.fetchAll(db)
 | |
|                         
 | |
|                         expect(types).toNot(beNil())
 | |
|                         expect(types?.compactMap { $0.id }.count).to(equal(types?.count))
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| // MARK: - Test Types
 | |
| 
 | |
| fileprivate struct TestType: Codable, FetchableRecord, PersistableRecord, TableRecord, ColumnExpressible {
 | |
|     public static var databaseTableName: String { "TestType" }
 | |
|     
 | |
|     public typealias Columns = CodingKeys
 | |
|     public enum CodingKeys: String, CodingKey, ColumnExpression {
 | |
|         case columnA
 | |
|         case columnB
 | |
|     }
 | |
|     
 | |
|     public let columnA: String
 | |
|     public let columnB: String?
 | |
| }
 | |
| 
 | |
| fileprivate struct MutableTestType: Codable, FetchableRecord, MutablePersistableRecord, TableRecord, ColumnExpressible {
 | |
|     public static var databaseTableName: String { "MutableTestType" }
 | |
|     
 | |
|     public typealias Columns = CodingKeys
 | |
|     public enum CodingKeys: String, CodingKey, ColumnExpression {
 | |
|         case id
 | |
|         case columnA
 | |
|         case columnB
 | |
|     }
 | |
|     
 | |
|     public var id: Int64?
 | |
|     public let columnA: String
 | |
|     public let columnB: String?
 | |
|     
 | |
|     init(id: Int64? = nil, columnA: String, columnB: String?) {
 | |
|         self.id = id
 | |
|         self.columnA = columnA
 | |
|         self.columnB = columnB
 | |
|     }
 | |
|     
 | |
|     mutating func didInsert(_ inserted: InsertionSuccess) {
 | |
|         self.id = inserted.rowID
 | |
|     }
 | |
| }
 | |
| 
 | |
| fileprivate enum TestInsertTestTypeMigration: Migration {
 | |
|     static let target: TargetMigrations.Identifier = .test
 | |
|     static let identifier: String = "TestInsertTestType"
 | |
|     static let needsConfigSync: Bool = false
 | |
|     static let minExpectedRunDuration: TimeInterval = 0
 | |
|     static let fetchedTables: [(TableRecord & FetchableRecord).Type] = []
 | |
|     static let createdOrAlteredTables: [(FetchableRecord & TableRecord).Type] = [TestType.self, MutableTestType.self]
 | |
|     static let droppedTables: [(TableRecord & FetchableRecord).Type] = []
 | |
|     
 | |
|     static func migrate(_ db: Database, using dependencies: Dependencies) throws {
 | |
|         try db.create(table: TestType.self) { t in
 | |
|             t.column(.columnA, .text).primaryKey()
 | |
|         }
 | |
|         
 | |
|         try db.create(table: MutableTestType.self) { t in
 | |
|             t.column(.id, .integer).primaryKey(autoincrement: true)
 | |
|             t.column(.columnA, .text).unique()
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| fileprivate enum TestAddColumnMigration: Migration {
 | |
|     static let target: TargetMigrations.Identifier = .test
 | |
|     static let identifier: String = "TestAddColumn"
 | |
|     static let needsConfigSync: Bool = false
 | |
|     static let minExpectedRunDuration: TimeInterval = 0
 | |
|     static let fetchedTables: [(TableRecord & FetchableRecord).Type] = []
 | |
|     static let createdOrAlteredTables: [(FetchableRecord & TableRecord).Type] = [TestType.self, MutableTestType.self]
 | |
|     static let droppedTables: [(TableRecord & FetchableRecord).Type] = []
 | |
|     
 | |
|     static func migrate(_ db: Database, using dependencies: Dependencies) throws {
 | |
|         try db.alter(table: TestType.self) { t in
 | |
|             t.add(.columnB, .text)
 | |
|         }
 | |
|         
 | |
|         try db.alter(table: MutableTestType.self) { t in
 | |
|             t.add(.columnB, .text)
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| fileprivate struct TestTarget: MigratableTarget {
 | |
|     static func migrations() -> TargetMigrations {
 | |
|         return TargetMigrations(
 | |
|             identifier: .test,
 | |
|             migrations: (0..<100)
 | |
|                 .map { _ in [] }
 | |
|                 .appending([TestInsertTestTypeMigration.self])
 | |
|         )
 | |
|     }
 | |
| }
 |