From 948f1f34445fed479b666ee8c8c51de8bd442986 Mon Sep 17 00:00:00 2001 From: Laurent Date: Tue, 11 Mar 2025 15:27:27 +0100 Subject: [PATCH] Allow ApiCall execute from external projects --- LeStorage/ApiCallCollection.swift | 19 +++++++++--- LeStorage/Services.swift | 44 +++++++++++++++------------ LeStorage/StoreCenter.swift | 4 +-- LeStorage/StoredCollection+Sync.swift | 4 ++- 4 files changed, 44 insertions(+), 27 deletions(-) diff --git a/LeStorage/ApiCallCollection.swift b/LeStorage/ApiCallCollection.swift index e49245e..98bedae 100644 --- a/LeStorage/ApiCallCollection.swift +++ b/LeStorage/ApiCallCollection.swift @@ -194,7 +194,8 @@ actor ApiCallCollection: SomeCallCollection { } else { let results = try await self._executeApiCalls(batch) if T.copyServerResponse { - StoreCenter.main.updateLocalInstances(results) + let instances = results.compactMap { $0.data } + StoreCenter.main.updateLocalInstances(instances) } } } catch { @@ -292,7 +293,7 @@ actor ApiCallCollection: SomeCallCollection { } } - func executeBatch(_ batch: OperationBatch) async throws -> [T] { + func executeBatch(_ batch: OperationBatch) async throws -> [OperationResult] { var apiCalls: [ApiCall] = [] let transactionId = Store.randomId() @@ -339,8 +340,18 @@ actor ApiCallCollection: SomeCallCollection { /// Executes an API call /// For POST requests, potentially copies additional data coming from the server during the insert - fileprivate func _executeApiCalls(_ apiCalls: [ApiCall]) async throws -> [T] { - return try await StoreCenter.main.execute(apiCalls: apiCalls) + fileprivate func _executeApiCalls(_ apiCalls: [ApiCall]) async throws -> [OperationResult] { + let results = try await StoreCenter.main.execute(apiCalls: apiCalls) + for result in results { + switch result.status { + case 200..<300: + self.deleteById(result.apiCallId) + default: + break + } + + } + return results } /// Returns the content of the API call file as a String diff --git a/LeStorage/Services.swift b/LeStorage/Services.swift index 18bf1ab..560fc5e 100644 --- a/LeStorage/Services.swift +++ b/LeStorage/Services.swift @@ -297,14 +297,14 @@ public class Services { /// - request: the URLRequest to run /// - apiCallId: the id of the ApiCall to delete in case of success, or to schedule for a rerun in case of failure fileprivate func _runSyncPostRequest( - _ request: URLRequest, type: T.Type) async throws -> [T] { + _ request: URLRequest, type: T.Type) async throws -> [OperationResult] { let debugURL = request.url?.absoluteString ?? "" // print("Run \(request.httpMethod ?? "") \(debugURL)") let task: (Data, URLResponse) = try await URLSession.shared.data(for: request) -// print("sync POST \(String(describing: T.self)) => \(String(data: task.0, encoding: .utf8) ?? "")") + // print("sync POST \(String(describing: T.self)) => \(String(data: task.0, encoding: .utf8) ?? "")") var rescheduleApiCalls: Bool = false - var successes: [T] = [] + var results: [OperationResult] = [] if let response = task.1 as? HTTPURLResponse { let statusCode = response.statusCode @@ -313,20 +313,24 @@ public class Services { case 200..<300: // success let decoded: BatchResponse = try self._decode(data: task.0) + results = decoded.results + for result in decoded.results { switch result.status { case 200..<300: - if let data = result.data { - successes.append(data) - } + break + // if let data = result.data { + // successes.append(data) + // } - try await StoreCenter.main.deleteApiCallById(type: T.self, id: result.apiCallId) + // try await StoreCenter.main.deleteApiCallById(type: T.self, id: result.apiCallId) default: if let message = result.message { print(message) } rescheduleApiCalls = true + break } } @@ -357,7 +361,7 @@ public class Services { try? await StoreCenter.main.rescheduleApiCalls(type: T.self) } - return successes + return results } /// Returns the URLRequest for an ApiCall @@ -547,7 +551,7 @@ public class Services { } /// Executes an ApiCall - func runApiCalls(_ apiCalls: [ApiCall]) async throws -> [T] { + func runApiCalls(_ apiCalls: [ApiCall]) async throws -> [OperationResult] { let request = try self._syncPostRequest(from: apiCalls) return try await self._runSyncPostRequest(request, type: T.self) } @@ -774,21 +778,21 @@ public class Services { /// Executes a POST request public func post(_ instance: T) async throws -> T? { let apiCall: ApiCall = ApiCall(method: .post, data: instance) - let results: [T] = try await self.runApiCalls([apiCall]) - return results.first + let results: [OperationResult] = try await self.runApiCalls([apiCall]) + return results.first?.data } /// Executes a PUT request - public func put(_ instance: T) async throws -> T { + public func put(_ instance: T) async throws -> T? { let apiCall: ApiCall = ApiCall(method: .put, data: instance) - let results: [T] = try await self.runApiCalls([apiCall]) - return results.first! + let results: [OperationResult] = try await self.runApiCalls([apiCall]) + return results.first?.data } - public func delete(_ instance: T) async throws -> T { + public func delete(_ instance: T) async throws -> T? { let apiCall: ApiCall = ApiCall(method: .delete, data: instance) - let results: [T] = try await self.runApiCalls([apiCall]) - return results.first! + let results: [OperationResult] = try await self.runApiCalls([apiCall]) + return results.first?.data } /// Returns a POST request for the resource @@ -831,11 +835,11 @@ struct BatchResponse: Decodable { var results: [OperationResult] } -struct OperationResult: Decodable { +public struct OperationResult: Decodable { var apiCallId: String - var status: Int + public var status: Int var data: T? - var message: String? + public var message: String? } struct ErrorMessage { diff --git a/LeStorage/StoreCenter.swift b/LeStorage/StoreCenter.swift index d061b28..1ba6628 100644 --- a/LeStorage/StoreCenter.swift +++ b/LeStorage/StoreCenter.swift @@ -388,7 +388,7 @@ public class StoreCenter { } /// Executes an API call - public func execute(apiCalls: [ApiCall]) async throws -> [T] { + public func execute(apiCalls: [ApiCall]) async throws -> [OperationResult] { return try await self.service().runApiCalls(apiCalls) } @@ -400,7 +400,7 @@ public class StoreCenter { && self.userIsAllowed() } - func sendOperationBatch(_ batch: OperationBatch) async throws -> [T] { + func sendOperationBatch(_ batch: OperationBatch) async throws -> [OperationResult] { guard self._canSynchronise() else { return [] } diff --git a/LeStorage/StoredCollection+Sync.swift b/LeStorage/StoredCollection+Sync.swift index e2a5f17..fdf2fc4 100644 --- a/LeStorage/StoredCollection+Sync.swift +++ b/LeStorage/StoredCollection+Sync.swift @@ -216,7 +216,9 @@ extension StoredCollection: SomeSyncedCollection where T : SyncedStorable { do { let success = try await StoreCenter.main.sendOperationBatch(batch) for item in success { - self.updateFromServerInstance(item) + if let data = item.data { + self.updateFromServerInstance(data) + } } } catch { Logger.error(error)