From 2b26950d67db5ec0bcac429bf735f0f2cd3f29aa Mon Sep 17 00:00:00 2001 From: Laurent Date: Sat, 15 Feb 2025 18:39:31 +0100 Subject: [PATCH] Fix api call creation --- LeStorage/ApiCallCollection.swift | 35 ++++++++++--- LeStorageTests/ApiCallTests.swift | 85 +++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+), 6 deletions(-) create mode 100644 LeStorageTests/ApiCallTests.swift diff --git a/LeStorage/ApiCallCollection.swift b/LeStorage/ApiCallCollection.swift index c0f3bd2..fdab25d 100644 --- a/LeStorage/ApiCallCollection.swift +++ b/LeStorage/ApiCallCollection.swift @@ -216,15 +216,38 @@ actor ApiCallCollection: SomeCallCollection { /// Returns an APICall instance for the Storable [instance] and an HTTP [method] /// The method updates existing calls or creates a new one - fileprivate func _callForInstance(_ instance: T, method: HTTPMethod) async throws -> ApiCall? { + func callForInstance(_ instance: T, method: HTTPMethod) throws -> ApiCall? { // cleanup let existingCalls = self.items.filter { $0.dataId == instance.stringId } - self._deleteCalls(existingCalls) + if existingCalls.count > 1 { + StoreCenter.main.log(message: "There are multiple calls registered for a single item: \(T.resourceName()), id = \(instance.stringId)") + } + let currentHTTPMethod = existingCalls.first?.method + var call: ApiCall? = nil + if let currentHTTPMethod { + switch (currentHTTPMethod, method) { + case (.post, .put): + call = try self._createCall(instance, method: .post) + case (.post, .delete): + self._deleteCalls(existingCalls) + return nil + case (.put, .put): + call = try self._createCall(instance, method: .put) + case (.put, .delete): + call = try self._createCall(instance, method: .delete) + default: + StoreCenter.main.log(message: "case \(currentHTTPMethod) / \(method) should not happen") + } + } else { + call = try self._createCall(instance, method: method) + } + + if let call { + self._deleteCalls(existingCalls) + self._prepareCall(apiCall: call) + } - // create - let call = try self._createCall(instance, method: method) - self._prepareCall(apiCall: call) return call } @@ -291,7 +314,7 @@ actor ApiCallCollection: SomeCallCollection { /// Initiates the process of sending the data with the server fileprivate func _synchronize(_ instance: T, method: HTTPMethod) async throws -> V? { - if let apiCall = try await self._callForInstance(instance, method: method) { + if let apiCall = try self.callForInstance(instance, method: method) { return try await self._executeApiCall(apiCall) } else { return nil diff --git a/LeStorageTests/ApiCallTests.swift b/LeStorageTests/ApiCallTests.swift new file mode 100644 index 0000000..9ee3401 --- /dev/null +++ b/LeStorageTests/ApiCallTests.swift @@ -0,0 +1,85 @@ +// +// ApiCallTests.swift +// LeStorageTests +// +// Created by Laurent Morvillier on 15/02/2025. +// + +import Testing +@testable import LeStorage + +class Thing: ModelObject, Storable { + static func resourceName() -> String { return "thing" } + static func tokenExemptedMethods() -> [LeStorage.HTTPMethod] { return [] } + static func filterByStoreIdentifier() -> Bool { return false } + + var id: String = Store.randomId() + var name: String + + init(name: String) { + self.name = name + } +} + +struct ApiCallTests { + + @Test func testApiCallProvisioning1() async throws { + let collection = ApiCallCollection() + + let thing = Thing(name: "yeah") + + let _ = try await collection.sendInsertion(thing) + + await #expect(collection.items.count == 1) + if let apiCall = await collection.items.first { + #expect(apiCall.method == .post) + } + + thing.name = "woo" + let _ = try await collection.sendUpdate(thing) + await #expect(collection.items.count == 1) + if let apiCall = await collection.items.first { + #expect(apiCall.method == .post) + } + + let _ = try await collection.sendDeletion(thing) + await #expect(collection.items.count == 0) + } + + @Test func testApiCallProvisioning2() async throws { + let collection = ApiCallCollection() + + let thing = Thing(name: "yeah") + + let _ = try await collection.sendUpdate(thing) + + await #expect(collection.items.count == 1) + if let apiCall = await collection.items.first { + #expect(apiCall.method == .put) + } + + thing.name = "woo" + let _ = try await collection.sendUpdate(thing) + await #expect(collection.items.count == 1) + if let apiCall = await collection.items.first { + #expect(apiCall.method == .put) + } + + let _ = try await collection.sendDeletion(thing) + await #expect(collection.items.count == 1) + } + + @Test func testApiCallProvisioning3() async throws { + let collection = ApiCallCollection() + + let thing = Thing(name: "yeah") + + let _ = try await collection.sendDeletion(thing) + await #expect(collection.items.count == 1) + let _ = try await collection.sendDeletion(thing) + await #expect(collection.items.count == 1) + let _ = try await collection.sendDeletion(thing) + await #expect(collection.items.count == 1) + } + +}