Removed the StoreIdentifier concept to just use a String and a default parameter named store_id to send to the server

sync2
Laurent 1 year ago
parent 7059cc913b
commit 8b7c39c0de
  1. 9
      LeStorage/Services.swift
  2. 2
      LeStorage/Storable.swift
  3. 84
      LeStorage/Store.swift
  4. 24
      LeStorage/StoreCenter.swift
  5. 2
      LeStorage/StoredCollection.swift

@ -188,7 +188,7 @@ public class Services {
/// Returns a GET request for the resource /// Returns a GET request for the resource
/// - Parameters: /// - Parameters:
/// - type: the type of the request resource /// - type: the type of the request resource
fileprivate func _getRequest<T: SyncedStorable>(type: T.Type, identifier: StoreIdentifier?) fileprivate func _getRequest<T: SyncedStorable>(type: T.Type, identifier: String?)
throws throws
-> URLRequest -> URLRequest
{ {
@ -243,11 +243,12 @@ public class Services {
/// - identifier: an optional StoreIdentifier that allows to filter GET requests with the StoreIdentifier values /// - identifier: an optional StoreIdentifier that allows to filter GET requests with the StoreIdentifier values
fileprivate func _baseRequest( fileprivate func _baseRequest(
servicePath: String, method: HTTPMethod, requiresToken: Bool? = nil, servicePath: String, method: HTTPMethod, requiresToken: Bool? = nil,
identifier: StoreIdentifier? = nil identifier: String? = nil
) throws -> URLRequest { ) throws -> URLRequest {
var urlString = baseURL + servicePath var urlString = baseURL + servicePath
if let identifier { if let identifier {
urlString.append(identifier.urlComponent) let component = "?store_id=\(identifier)"
urlString.append(component)
} }
guard let url = URL(string: urlString) else { guard let url = URL(string: urlString) else {
throw ServiceError.urlCreationError(url: urlString) throw ServiceError.urlCreationError(url: urlString)
@ -403,7 +404,7 @@ public class Services {
// MARK: - Services // MARK: - Services
/// Executes a GET request /// Executes a GET request
public func get<T: SyncedStorable>(identifier: StoreIdentifier? = nil) async throws -> [T] { public func get<T: SyncedStorable>(identifier: String? = nil) async throws -> [T] {
let getRequest = try _getRequest(type: T.self, identifier: identifier) let getRequest = try _getRequest(type: T.self, identifier: identifier)
return try await self._runRequest(getRequest) return try await self._runRequest(getRequest)
} }

@ -28,8 +28,6 @@ public protocol Storable: Codable, Identifiable, NSObjectProtocol {
/// so when we do that on the server, we also need to do it locally /// so when we do that on the server, we also need to do it locally
func deleteDependencies() func deleteDependencies()
// static var relationshipNames: [String] { get }
func copy(from other: any Storable) func copy(from other: any Storable)
} }

@ -17,21 +17,21 @@ public enum StoreError: Error {
case cannotSyncCollection(name: String) case cannotSyncCollection(name: String)
} }
public struct StoreIdentifier { //public struct StoreIdentifier {
var value: String // var value: String
var parameterName: String // var parameterName: String
//
public init(value: String, parameterName: String) { // public init(value: String, parameterName: String) {
self.value = value // self.value = value
self.parameterName = parameterName // self.parameterName = parameterName
} // }
//
var urlComponent: String { // var urlComponent: String {
return "?\(self.parameterName)=\(self.value)" // return "?\(self.parameterName)=\(self.value)"
} // }
} //}
open class Store { final public class Store {
/// The Store singleton /// The Store singleton
public static let main = Store() public static let main = Store()
@ -43,7 +43,7 @@ open class Store {
static let storageDirectory = "storage" static let storageDirectory = "storage"
/// The store identifier, used to name the store directory, and to perform filtering requests to the server /// The store identifier, used to name the store directory, and to perform filtering requests to the server
fileprivate(set) var identifier: StoreIdentifier? = nil fileprivate(set) var identifier: String? = nil
/// Indicates whether the store directory has been created at the init /// Indicates whether the store directory has been created at the init
fileprivate var _created: Bool = false fileprivate var _created: Bool = false
@ -52,8 +52,8 @@ open class Store {
self._createDirectory(directory: Store.storageDirectory) self._createDirectory(directory: Store.storageDirectory)
} }
public required init(identifier: String, parameter: String) { public required init(identifier: String) {
self.identifier = StoreIdentifier(value: identifier, parameterName: parameter) self.identifier = identifier
let directory = "\(Store.storageDirectory)/\(identifier)" let directory = "\(Store.storageDirectory)/\(identifier)"
self._createDirectory(directory: directory) self._createDirectory(directory: directory)
} }
@ -145,6 +145,16 @@ open class Store {
throw StoreError.collectionNotRegistered(type: T.resourceName()) throw StoreError.collectionNotRegistered(type: T.resourceName())
} }
subscript<T>(_ type: T.Type) -> StoredCollection<T> {
get {
do {
return try self.collection()
} catch {
fatalError(error.localizedDescription)
}
}
}
/// Loads all collection with the data from the server /// Loads all collection with the data from the server
public func loadCollectionsFromServer() { public func loadCollectionsFromServer() {
for collection in self._syncedCollections() { for collection in self._syncedCollections() {
@ -216,7 +226,7 @@ open class Store {
/// Returns the directory URL of the store /// Returns the directory URL of the store
fileprivate func _directoryPath() throws -> URL { fileprivate func _directoryPath() throws -> URL {
var url = try FileUtils.pathForDirectoryInDocuments(directory: Store.storageDirectory) var url = try FileUtils.pathForDirectoryInDocuments(directory: Store.storageDirectory)
if let identifier = self.identifier?.value { if let identifier {
url.append(component: identifier) url.append(component: identifier)
} }
return url return url
@ -289,42 +299,4 @@ open class Store {
return self._collections.values.allSatisfy { $0.hasLoaded } return self._collections.values.allSatisfy { $0.hasLoaded }
} }
// fileprivate var _validIds: [String] = []
//
// fileprivate func _migrate<T : Storable>(_ collection: StoredCollection<T>, identifier: StoreIdentifier, type: T.Type) {
//
// self._validIds.append(identifier.value)
//
// let oldCollection: StoredCollection<T> = StoredCollection<T>(synchronized: false, store: Store.main, asynchronousIO: false)
//
// let filtered: [T] = oldCollection.items.filter { item in
// var propertyValue: String? = item.stringForPropertyName(identifier.parameterName)
// if propertyValue == nil {
// let values = T.relationshipNames.map { item.stringForPropertyName($0) }
// propertyValue = values.compactMap { $0 }.first
// }
// return self._validIds.first(where: { $0 == propertyValue }) != nil
// }
//
// if filtered.count > 0 {
// self._validIds.append(contentsOf: filtered.map { $0.stringId })
// try? collection.addOrUpdateNoSync(contentOfs: filtered)
// Logger.log("Migrated \(filtered.count) \(T.resourceName())")
// }
// }
} }
//fileprivate extension Storable {
//
// func stringForPropertyName(_ propertyName: String) -> String? {
// let mirror = Mirror(reflecting: self)
// for child in mirror.children {
// if let label = child.label, label == "_\(propertyName)" {
// return child.value as? String
// }
// }
// return nil
// }
//
//}

@ -105,7 +105,7 @@ public class StoreCenter {
/// - Parameters: /// - Parameters:
/// - store: A store to save /// - store: A store to save
fileprivate func _registerStore(store: Store) { fileprivate func _registerStore(store: Store) {
guard let identifier = store.identifier?.value else { guard let identifier = store.identifier else {
fatalError("The store has no identifier") fatalError("The store has no identifier")
} }
if self._stores[identifier] != nil { if self._stores[identifier] != nil {
@ -118,11 +118,11 @@ public class StoreCenter {
/// - Parameters: /// - Parameters:
/// - identifier: The store identifer /// - identifier: The store identifer
/// - parameter: The parameter name used to filter data on the server /// - parameter: The parameter name used to filter data on the server
public func store<T: Store>(identifier: String, parameter: String) -> T { public func store(identifier: String) -> Store {
if let store = self._stores[identifier] as? T { if let store = self._stores[identifier] {
return store return store
} else { } else {
let store = T(identifier: identifier, parameter: parameter) let store = Store(identifier: identifier)
self._registerStore(store: store) self._registerStore(store: store)
return store return store
} }
@ -350,7 +350,7 @@ public class StoreCenter {
} }
/// Retrieves all the items on the server /// Retrieves all the items on the server
func getItems<T: SyncedStorable>(identifier: StoreIdentifier? = nil) async throws -> [T] { func getItems<T: SyncedStorable>(identifier: String? = nil) async throws -> [T] {
return try await self.service().get(identifier: identifier) return try await self.service().get(identifier: identifier)
} }
@ -483,9 +483,15 @@ public class StoreCenter {
} }
fileprivate func _store(id: String?) -> Store? { fileprivate func _store(id: String?) -> Store {
if let storeId = id { if let storeId = id {
return self._stores[storeId] if let store = self._stores[storeId] {
return store
} else {
let store = Store(identifier: storeId)
self._registerStore(store: store)
return store
}
} else { } else {
return Store.main return Store.main
} }
@ -501,7 +507,7 @@ public class StoreCenter {
let hasAlreadyBeenDeleted: Bool = self._hasAlreadyBeenDeleted(instance) let hasAlreadyBeenDeleted: Bool = self._hasAlreadyBeenDeleted(instance)
if !hasAlreadyBeenDeleted { if !hasAlreadyBeenDeleted {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) { DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
self._store(id: storeId)?.addOrUpdateIfNewer(instance) self._store(id: storeId).addOrUpdateIfNewer(instance)
} }
} }
} }
@ -511,7 +517,7 @@ public class StoreCenter {
DispatchQueue.main.async { DispatchQueue.main.async {
do { do {
let type = try StoreCenter.classFromName(model) let type = try StoreCenter.classFromName(model)
try self._store(id: storeId)?.deleteNoSync(type: type, id: id) try self._store(id: storeId).deleteNoSync(type: type, id: id)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }

@ -238,7 +238,7 @@ public class StoredCollection<T: Storable>: RandomAccessCollection, SomeCollecti
} }
fileprivate func _affectStoreIdIfNecessary(instance: T) { fileprivate func _affectStoreIdIfNecessary(instance: T) {
if let storeId = self.store.identifier?.value { if let storeId = self.store.identifier {
if var altStorable = instance as? SideStorable { if var altStorable = instance as? SideStorable {
altStorable.storeId = storeId altStorable.storeId = storeId
} else { } else {

Loading…
Cancel
Save