sync2
Laurent 8 months ago
commit 7125d868ae
  1. 59
      LeStorage/ApiCallCollection.swift
  2. 2
      LeStorage/StoreCenter.swift
  3. 2
      LeStorage/StoredCollection+Sync.swift
  4. 7
      LeStorageTests/ApiCallTests.swift

@ -231,59 +231,24 @@ actor ApiCallCollection<T: SyncedStorable>: SomeCallCollection {
// MARK: - Synchronization // MARK: - Synchronization
/// Returns an APICall instance for the Storable [instance] and an HTTP [method] /// Returns an APICall instance for the Storable [instance] and an HTTP [method]
/// The method updates existing calls or creates a new one /// The method makes some clean up when necessary:
// fileprivate func _call(method: HTTPMethod, instance: T? = nil) async throws -> ApiCall<T>? { /// - When deleting, we delete other calls as they are unecessary
// /// - When updating, we delete other PUT as we don't want them to be executed in random orders
// if let instance {
// return try await self._callForInstance(instance, method: method)
// } else {
// if self.items.contains(where: { $0.method == .get }) {
// return nil
// } else {
// return try self._createGetCall()
// }
// }
// }
// fileprivate func _callForInstance(_ instance: T, method: HTTPMethod, transactionId: String? = nil) async throws -> ApiCall<T> {
//
// // cleanup
// let existingCalls = self.items.filter { $0.data?.id == instance.id }
// self._deleteCalls(existingCalls)
//
// // create
// let call = try self._createCall(method, instance: instance, transactionId: transactionId)
// self._prepareCall(apiCall: call)
// }
func callForInstance(_ instance: T, method: HTTPMethod, transactionId: String? = nil) throws -> ApiCall<T> { func callForInstance(_ instance: T, method: HTTPMethod, transactionId: String? = nil) throws -> ApiCall<T> {
// cleanup // cleanup if necessary
switch method {
case .delete: // we don't want anything else than a DELETE in the queue
let existingCalls = self.items.filter { $0.data?.stringId == instance.stringId } let existingCalls = self.items.filter { $0.data?.stringId == instance.stringId }
if existingCalls.count > 1 { self._deleteCalls(existingCalls)
StoreCenter.main.log(message: "There are multiple calls registered for a single item: \(T.resourceName()), id = \(instance.stringId)") case .put: // we don't want mixed PUT calls so we delete the others
} let existingPuts = self.items.filter { $0.data?.stringId == instance.stringId && $0.method == .put }
let currentHTTPMethod = existingCalls.first?.method self._deleteCalls(existingPuts)
let call: ApiCall<T>
if let currentHTTPMethod {
switch (currentHTTPMethod, method) {
case (.post, .put):
call = try self._createCall(.post, instance: instance, transactionId: transactionId)
case (.post, .delete):
call = try self._createCall(.delete, instance: instance, transactionId: transactionId)
case (.put, .put):
call = try self._createCall(.put, instance: instance, transactionId: transactionId)
case (.put, .delete):
call = try self._createCall(.delete, instance: instance, transactionId: transactionId)
default: default:
call = try self._createCall(method, instance: instance, transactionId: transactionId) break
StoreCenter.main.log(message: "case \(currentHTTPMethod) : \(method) should not happen")
}
} else {
call = try self._createCall(method, instance: instance, transactionId: transactionId)
} }
self._deleteCalls(existingCalls) let call: ApiCall<T> = try self._createCall(method, instance: instance, transactionId: transactionId)
self._prepareCall(apiCall: call) self._prepareCall(apiCall: call)
return call return call

@ -951,7 +951,7 @@ public class StoreCenter {
if let logs = self._logs { if let logs = self._logs {
return logs return logs
} else { } else {
let logsCollection: StoredCollection<Log> = Store.main.registerCollection(limit: 1000) let logsCollection: StoredCollection<Log> = Store.main.registerCollection(limit: 50)
self._logs = logsCollection self._logs = logsCollection
return logsCollection return logsCollection
} }

@ -49,10 +49,10 @@ extension StoredCollection: SomeSyncedCollection where T : SyncedStorable {
self.addOrUpdateNoSync(contentOfs: items) self.addOrUpdateNoSync(contentOfs: items)
} }
} }
self.setAsLoaded()
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
self.setAsLoaded()
} }
/// Updates a local item from a server instance. This method is typically used when the server makes update /// Updates a local item from a server instance. This method is typically used when the server makes update

@ -37,10 +37,13 @@ struct ApiCallTests {
thing.name = "woo" thing.name = "woo"
let _ = try await collection.sendUpdate(thing) let _ = try await collection.sendUpdate(thing)
await #expect(collection.items.count == 1) await #expect(collection.items.count == 2) // one post and one put
if let apiCall = await collection.items.first { if let apiCall = await collection.items.first {
#expect(apiCall.method == .post) #expect(apiCall.method == .post)
} }
if let apiCall = await collection.items.last {
#expect(apiCall.method == .put)
}
let _ = try await collection.sendDeletion(thing) let _ = try await collection.sendDeletion(thing)
await #expect(collection.items.count == 1) await #expect(collection.items.count == 1)
@ -60,6 +63,8 @@ struct ApiCallTests {
thing.name = "woo" thing.name = "woo"
let _ = try await collection.sendUpdate(thing) let _ = try await collection.sendUpdate(thing)
let _ = try await collection.sendUpdate(thing)
let _ = try await collection.sendUpdate(thing)
await #expect(collection.items.count == 1) await #expect(collection.items.count == 1)
if let apiCall = await collection.items.first { if let apiCall = await collection.items.first {
#expect(apiCall.method == .put) #expect(apiCall.method == .put)

Loading…
Cancel
Save