Makes insert work + Store provides ids to match django ids

multistore
Laurent 2 years ago
parent daa34132c4
commit 9cfa848a11
  1. 4
      LeStorage.xcodeproj/project.pbxproj
  2. 21
      LeStorage/Services.swift
  3. 20
      LeStorage/Storable.swift
  4. 39
      LeStorage/Store.swift
  5. 27
      LeStorage/StoredCollection.swift

@ -17,6 +17,7 @@
C4A47D532B6D2C5F00ADC637 /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A47D522B6D2C5F00ADC637 /* Logger.swift */; };
C4A47D552B6D2DBF00ADC637 /* FileUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A47D542B6D2DBF00ADC637 /* FileUtils.swift */; };
C4A47D612B6D3C1300ADC637 /* Services.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A47D602B6D3C1300ADC637 /* Services.swift */; };
C4A47D652B6E92FE00ADC637 /* Storable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A47D642B6E92FE00ADC637 /* Storable.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@ -41,6 +42,7 @@
C4A47D522B6D2C5F00ADC637 /* Logger.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Logger.swift; sourceTree = "<group>"; };
C4A47D542B6D2DBF00ADC637 /* FileUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileUtils.swift; sourceTree = "<group>"; };
C4A47D602B6D3C1300ADC637 /* Services.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Services.swift; sourceTree = "<group>"; };
C4A47D642B6E92FE00ADC637 /* Storable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Storable.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -87,6 +89,7 @@
C425D4382B6D24E1002A7B48 /* LeStorage.docc */,
C4A47D602B6D3C1300ADC637 /* Services.swift */,
C425D4572B6D2519002A7B48 /* Store.swift */,
C4A47D642B6E92FE00ADC637 /* Storable.swift */,
C4A47D4E2B6D280200ADC637 /* StoredCollection.swift */,
C4A47D582B6D352900ADC637 /* Utils */,
);
@ -225,6 +228,7 @@
C425D4392B6D24E1002A7B48 /* LeStorage.docc in Sources */,
C4A47D612B6D3C1300ADC637 /* Services.swift in Sources */,
C4A47D552B6D2DBF00ADC637 /* FileUtils.swift in Sources */,
C4A47D652B6E92FE00ADC637 /* Storable.swift in Sources */,
C4A47D4F2B6D280200ADC637 /* StoredCollection.swift in Sources */,
C425D4582B6D2519002A7B48 /* Store.swift in Sources */,
);

@ -38,6 +38,13 @@ class Services {
fileprivate func runRequest<T : Decodable>(_ request: URLRequest) async throws -> T {
let task: (Data, URLResponse) = try await URLSession.shared.data(for: request)
if let response = task.1 as? HTTPURLResponse {
let statusCode = response.statusCode
Logger.log("status code = \(statusCode)")
}
Logger.log("response = \(String(data: task.0, encoding: .utf8))")
return try jsonDecoder.decode(T.self, from: task.0)
}
@ -64,6 +71,7 @@ class Services {
}
var request = URLRequest(url: url)
request.httpMethod = method.rawValue
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
return request
}
@ -75,18 +83,21 @@ class Services {
}
func insert<T : Storable>(_ instance: T) async throws -> T {
let postRequest = try postRequest(servicePath: T.resourceName + "/")
var postRequest = try postRequest(servicePath: T.resourceName + "/")
postRequest.httpBody = try instance.jsonData()
return try await self.runRequest(postRequest)
}
func update<T : Storable>(_ instance: T) async throws -> T {
let postRequest = try putRequest(servicePath: T.resourceName + "/")
return try await self.runRequest(postRequest)
var putRequest = try putRequest(servicePath: T.resourceName + "/")
putRequest.httpBody = try instance.jsonData()
return try await self.runRequest(putRequest)
}
func delete<T : Storable>(_ instance: T) async throws -> T {
let postRequest = try deleteRequest(servicePath: T.resourceName + "/")
return try await self.runRequest(postRequest)
var deleteRequest = try deleteRequest(servicePath: T.resourceName + "/")
deleteRequest.httpBody = try instance.jsonData()
return try await self.runRequest(deleteRequest)
}
}

@ -0,0 +1,20 @@
//
// Storable.swift
// LeStorage
//
// Created by Laurent Morvillier on 03/02/2024.
//
import Foundation
public protocol Storable : Codable, Identifiable where ID : StringProtocol {
static var resourceName: String { get }
}
extension Storable {
public func findById<T : Storable>(_ id: String) -> T? {
return Store.main.findById(id)
}
}

@ -7,28 +7,43 @@
import Foundation
protocol ServiceProvider {
var service: Services? { get }
}
public class Store: ServiceProvider {
public class Store {
fileprivate var _synchronizationApiURL: String?
fileprivate var _services: Services?
public static let main = Store()
public static func randomId() -> String {
return UUID().uuidString.lowercased()
}
public init(synchronizationApiURL: String? = nil) {
self._synchronizationApiURL = synchronizationApiURL
if let url = synchronizationApiURL {
self._services = Services(url: url)
public var synchronizationApiURL: String? {
didSet {
if let url = synchronizationApiURL {
self._services = Services(url: url)
}
}
}
fileprivate var _services: Services?
fileprivate var collections: [String : any SomeCollection] = [:]
public init() { }
public func registerCollection<T : Storable>(synchronized: Bool) -> StoredCollection<T> {
return StoredCollection(synchronized: synchronized, serviceProvider: self)
let collection = StoredCollection<T>(synchronized: synchronized, store: self)
self.collections[T.resourceName] = collection
return collection
}
var service: Services? {
return self._services
}
func findById<T : Storable>(_ id: String) -> T? {
guard let collection = self.collections[T.resourceName] as? StoredCollection<T> else {
Logger.w("Collection \(T.resourceName) not registered")
return nil
}
return collection.findById(id)
}
}

@ -7,17 +7,17 @@
import Foundation
public protocol Storable : Codable, Identifiable where ID : Hashable {
static var resourceName: String { get }
protocol SomeCollection : Identifiable {
}
public class StoredCollection<T : Storable> : RandomAccessCollection, ObservableObject {
public class StoredCollection<T : Storable> : RandomAccessCollection, SomeCollection, ObservableObject {
let synchronized: Bool
@Published public fileprivate(set) var items: [T] = []
fileprivate var _serviceProvider: ServiceProvider
fileprivate var _store: Store
fileprivate var _hasChanged: Bool = false {
didSet {
@ -29,9 +29,9 @@ public class StoredCollection<T : Storable> : RandomAccessCollection, Observable
}
}
init(synchronized: Bool, serviceProvider: ServiceProvider) {
init(synchronized: Bool, store: Store) {
self.synchronized = synchronized
self._serviceProvider = serviceProvider
self._store = store
self._load()
}
@ -63,6 +63,12 @@ public class StoredCollection<T : Storable> : RandomAccessCollection, Observable
self._sendDeletionIfNecessary(instance)
}
public func findById(_ id: String) -> T? {
return self.items.first(where: { $0.id == id })
}
// MARK: - File access
fileprivate func _scheduleWrite() {
self._write()
}
@ -114,13 +120,14 @@ public class StoredCollection<T : Storable> : RandomAccessCollection, Observable
// MARK: - Synchronization
fileprivate func _sendInsertionIfNecessary(_ instance: T) {
Logger.log("_sendInsertionIfNecessary...")
guard self.synchronized else {
return
}
Logger.log("Call service...")
Task {
do {
let _ = try await self._serviceProvider.service?.insert(instance)
let _ = try await self._store.service?.insert(instance)
} catch {
Logger.error(error)
}
@ -135,7 +142,7 @@ public class StoredCollection<T : Storable> : RandomAccessCollection, Observable
Task {
do {
let _ = try await self._serviceProvider.service?.insert(instance)
let _ = try await self._store.service?.insert(instance)
} catch {
Logger.error(error)
}
@ -150,7 +157,7 @@ public class StoredCollection<T : Storable> : RandomAccessCollection, Observable
Task {
do {
let _ = try await self._serviceProvider.service?.delete(instance)
let _ = try await self._store.service?.delete(instance)
} catch {
Logger.error(error)
}

Loading…
Cancel
Save