Skip to content

Commit

Permalink
fix(DataStore): throw on missing syncEngine to rollback save
Browse files Browse the repository at this point in the history
  • Loading branch information
lawmicha committed Feb 6, 2024
1 parent 4dfbdaa commit b9528c1
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -148,9 +148,18 @@ final class SQLiteStorageEngineAdapter: StorageEngineAdapter {
condition: QueryPredicate? = nil,
eagerLoad: Bool = true,
completion: DataStoreCallback<M>) {
completion(save(model,
modelSchema: modelSchema,
condition: condition,
eagerLoad: eagerLoad))
}

func save<M: Model>(_ model: M,
modelSchema: ModelSchema,
condition: QueryPredicate? = nil,
eagerLoad: Bool = true) -> DataStoreResult<M> {
guard let connection = connection else {
completion(.failure(DataStoreError.nilSQLiteConnection()))
return
return .failure(DataStoreError.nilSQLiteConnection())
}
do {
let modelType = type(of: model)
Expand All @@ -162,8 +171,7 @@ final class SQLiteStorageEngineAdapter: StorageEngineAdapter {
let dataStoreError = DataStoreError.invalidCondition(
"Cannot apply a condition on model which does not exist.",
"Save the model instance without a condition first.")
completion(.failure(causedBy: dataStoreError))
return
return .failure(causedBy: dataStoreError)
}

let statement = InsertStatement(model: model, modelSchema: modelSchema)
Expand All @@ -179,9 +187,7 @@ final class SQLiteStorageEngineAdapter: StorageEngineAdapter {
let dataStoreError = DataStoreError.invalidCondition(
"Save failed due to condition did not match existing model instance.",
"The save will continue to fail until the model instance is updated.")
completion(.failure(causedBy: dataStoreError))

return
return .failure(causedBy: dataStoreError)
}
}

Expand All @@ -192,23 +198,22 @@ final class SQLiteStorageEngineAdapter: StorageEngineAdapter {
}

// load the recent saved instance and pass it back to the callback
query(modelType, modelSchema: modelSchema,
predicate: model.identifier(schema: modelSchema).predicate,
eagerLoad: eagerLoad) {
switch $0 {
case .success(let result):
if let saved = result.first {
completion(.success(saved))
} else {
completion(.failure(.nonUniqueResult(model: modelType.modelName,
count: result.count)))
}
case .failure(let error):
completion(.failure(error))
let queryResult = query(modelType, modelSchema: modelSchema,
predicate: model.identifier(schema: modelSchema).predicate,
eagerLoad: eagerLoad)
switch queryResult {
case .success(let result):
if let saved = result.first {
return .success(saved)
} else {
return .failure(.nonUniqueResult(model: modelType.modelName,
count: result.count))
}
case .failure(let error):
return .failure(error)
}
} catch {
completion(.failure(causedBy: error))
return .failure(causedBy: error)
}
}

Expand Down Expand Up @@ -321,9 +326,22 @@ final class SQLiteStorageEngineAdapter: StorageEngineAdapter {
paginationInput: QueryPaginationInput? = nil,
eagerLoad: Bool = true,
completion: DataStoreCallback<[M]>) {
completion(query(modelType,
modelSchema: modelSchema,
predicate: predicate,
sort: sort,
paginationInput: paginationInput,
eagerLoad: eagerLoad))
}

func query<M: Model>(_ modelType: M.Type,
modelSchema: ModelSchema,
predicate: QueryPredicate? = nil,
sort: [QuerySortDescriptor]? = nil,
paginationInput: QueryPaginationInput? = nil,
eagerLoad: Bool = true) -> DataStoreResult<[M]> {
guard let connection = connection else {
completion(.failure(DataStoreError.nilSQLiteConnection()))
return
return .failure(DataStoreError.nilSQLiteConnection())
}
do {
let statement = SelectStatement(from: modelSchema,
Expand All @@ -336,9 +354,9 @@ final class SQLiteStorageEngineAdapter: StorageEngineAdapter {
withSchema: modelSchema,
using: statement,
eagerLoad: eagerLoad)
completion(.success(result))
return .success(result)
} catch {
completion(.failure(causedBy: error))
return .failure(causedBy: error)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,36 +210,39 @@ final class StorageEngine: StorageEngineBehavior {

do {
try storageAdapter.transaction {
let wrappedCompletion: DataStoreCallback<M> = { result in
guard modelSchema.isSyncable, let syncEngine = self.syncEngine else {
completion(result)
return
}

guard case .success(let savedModel) = result else {
completion(result)
return
}

self.log.verbose("\(#function) syncing mutation for \(savedModel)")
self.syncMutation(of: savedModel,
modelSchema: modelSchema,
mutationType: mutationType,
predicate: condition,
syncEngine: syncEngine,
completion: completion)
let result = self.storageAdapter.save(model,
modelSchema: modelSchema,
condition: condition,
eagerLoad: eagerLoad)
guard modelSchema.isSyncable else {
completion(result)
return
}

storageAdapter.save(model,
modelSchema: modelSchema,
condition: condition,
eagerLoad: eagerLoad,
completion: wrappedCompletion)
guard case .success(let savedModel) = result else {
completion(result)
return
}

guard let syncEngine else {
let message = "No SyncEngine available to sync mutation event, rollback save."
self.log.verbose("\(#function) \(message) : \(savedModel)")
throw DataStoreError.internalOperation(
message,
"Save was interrupted. `DataStore.stop()` may have been called.",
nil)
}
self.log.verbose("\(#function) syncing mutation for \(savedModel)")
self.syncMutation(of: savedModel,
modelSchema: modelSchema,
mutationType: mutationType,
predicate: condition,
syncEngine: syncEngine,
completion: completion)
}
} catch {
completion(.failure(causedBy: error))
}

}

func save<M: Model>(_ model: M,
Expand Down Expand Up @@ -346,7 +349,7 @@ final class StorageEngine: StorageEngineBehavior {
}
}

@available(iOS 13.0, *)
@available(iOS 13.0, *)
private func syncMutation<M: Model>(of savedModel: M,
modelSchema: ModelSchema,
mutationType: MutationEvent.MutationType,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ protocol StorageEngineAdapter: AnyObject, ModelStorageBehavior, ModelStorageErro

// MARK: - Synchronous APIs

func save<M: Model>(_ model: M,
modelSchema: ModelSchema,
condition: QueryPredicate?,
eagerLoad: Bool) -> DataStoreResult<M>

func exists(_ modelSchema: ModelSchema,
withIdentifier id: ModelIdentifierProtocol,
predicate: QueryPredicate?) throws -> Bool
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,14 @@ class MockSQLiteStorageEngineAdapter: StorageEngineAdapter {
: completion(.success(model))
}

func save<M: Model>(_ model: M,
modelSchema: ModelSchema,
condition: QueryPredicate?,
eagerLoad: Bool) -> DataStoreResult<M> {
XCTFail("Not yet implemented")
return .failure(.internalOperation("", "", nil))
}

func save<M: Model>(_ model: M,
modelSchema: ModelSchema,
condition where: QueryPredicate?,
Expand Down

0 comments on commit b9528c1

Please sign in to comment.