Fixes and improvements

sync3
Laurent 6 months ago
parent fb6999a66c
commit 775bed665b
  1. 16
      LeStorage/Codables/SyncData.swift
  2. 6
      LeStorage/Services.swift
  3. 22
      LeStorage/StoreCenter.swift
  4. 31
      LeStorage/SyncedCollection.swift

@ -28,8 +28,8 @@ class SyncData {
var grants: [SyncedStorableArray] = [] var grants: [SyncedStorableArray] = []
var revocations: [ObjectIdentifierArray] = [] var revocations: [ObjectIdentifierArray] = []
var revocationParents: [[ObjectIdentifierArray]] = [] var revocationParents: [[ObjectIdentifierArray]] = []
var relationshipSets: [SyncedStorableArray] = [] // var relationshipSets: [SyncedStorableArray] = []
var relationshipRemovals: [ObjectIdentifierArray] = [] // var relationshipRemovals: [ObjectIdentifierArray] = []
var sharedRelationshipSets: [SyncedStorableArray] = [] var sharedRelationshipSets: [SyncedStorableArray] = []
var sharedRelationshipRemovals: [ObjectIdentifierArray] = [] var sharedRelationshipRemovals: [ObjectIdentifierArray] = []
var date: String? var date: String?
@ -60,12 +60,12 @@ class SyncData {
} }
} }
if let relationshipSets = json["relationship_sets"] as? [String: Any] { // if let relationshipSets = json["relationship_sets"] as? [String: Any] {
self.relationshipSets = try storeCenter.decodeDictionary(relationshipSets) // self.relationshipSets = try storeCenter.decodeDictionary(relationshipSets)
} // }
if let relationshipRemovals = json["relationship_removals"] as? [String: Any] { // if let relationshipRemovals = json["relationship_removals"] as? [String: Any] {
self.relationshipRemovals = try storeCenter.decodeObjectIdentifierDictionary(relationshipRemovals) // self.relationshipRemovals = try storeCenter.decodeObjectIdentifierDictionary(relationshipRemovals)
} // }
if let sharedRelationshipSets = json["shared_relationship_sets"] as? [String: Any] { if let sharedRelationshipSets = json["shared_relationship_sets"] as? [String: Any] {
self.sharedRelationshipSets = try storeCenter.decodeDictionary(sharedRelationshipSets) self.sharedRelationshipSets = try storeCenter.decodeDictionary(sharedRelationshipSets)
} }

@ -33,7 +33,7 @@ let changePasswordCall: ServiceCall = ServiceCall(
path: "change-password/", method: .put, requiresToken: true) path: "change-password/", method: .put, requiresToken: true)
let postDeviceTokenCall: ServiceCall = ServiceCall( let postDeviceTokenCall: ServiceCall = ServiceCall(
path: "device-token/", method: .post, requiresToken: true) path: "device-token/", method: .post, requiresToken: true)
let getUserDataAccessCall: ServiceCall = ServiceCall( let getUserDataAccessCallContent: ServiceCall = ServiceCall(
path: "data-access-content/", method: .get, requiresToken: true) path: "data-access-content/", method: .get, requiresToken: true)
let userNamesCall: ServiceCall = ServiceCall( let userNamesCall: ServiceCall = ServiceCall(
path: "user-names/", method: .get, requiresToken: true) path: "user-names/", method: .get, requiresToken: true)
@ -630,8 +630,8 @@ public class Services {
} }
/// Returns the list of DataAccess /// Returns the list of DataAccess
func getUserDataAccess() async throws { func getUserDataAccessContent() async throws {
let request = try self._baseRequest(call: getUserDataAccessCall) let request = try self._baseRequest(call: getUserDataAccessCallContent)
if let data = try await self._runRequest(request) { if let data = try await self._runRequest(request) {
await self.storeCenter.userDataAccessRetrieved(data) await self.storeCenter.userDataAccessRetrieved(data)
} }

@ -48,7 +48,7 @@ public class StoreCenter {
lazy fileprivate var _deleteLogs: StoredCollection<DataLog> = { self.mainStore.registerCollection() }() lazy fileprivate var _deleteLogs: StoredCollection<DataLog> = { self.mainStore.registerCollection() }()
/// A synchronized collection of DataAccess /// A synchronized collection of DataAccess
fileprivate var _dataAccess: SyncedCollection<DataAccess>? = nil fileprivate(set) var dataAccessCollection: SyncedCollection<DataAccess>? = nil
/// A collection storing FailedAPICall objects /// A collection storing FailedAPICall objects
fileprivate var _failedAPICallsCollection: SyncedCollection<FailedAPICall>? = nil fileprivate var _failedAPICallsCollection: SyncedCollection<FailedAPICall>? = nil
@ -101,7 +101,7 @@ public class StoreCenter {
self.tokenKeychain = KeychainStore(serverId: urlManager.api) self.tokenKeychain = KeychainStore(serverId: urlManager.api)
if self.useSynchronization { if self.useSynchronization {
self._dataAccess = self.mainStore.registerSynchronizedCollection() self.dataAccessCollection = self.mainStore.registerSynchronizedCollection()
} }
Logger.log("Sync URL: \(urlManager.api)") Logger.log("Sync URL: \(urlManager.api)")
@ -250,7 +250,7 @@ public class StoreCenter {
self._failedAPICallsCollection?.reset() self._failedAPICallsCollection?.reset()
self._stores.removeAll() self._stores.removeAll()
self._dataAccess?.reset() self.dataAccessCollection?.reset()
self._deleteLogs.reset() self._deleteLogs.reset()
self._settingsStorage.update { settings in self._settingsStorage.update { settings in
@ -557,7 +557,7 @@ public class StoreCenter {
if self.useSynchronization { if self.useSynchronization {
Task { Task {
do { do {
try await self.service().getUserDataAccess() try await self.service().getUserDataAccessContent()
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -637,8 +637,8 @@ public class StoreCenter {
await self._syncDelete(syncData.deletions) await self._syncDelete(syncData.deletions)
self._syncAddOrUpdate(syncData.grants, shared: true) self._syncAddOrUpdate(syncData.grants, shared: true)
await self.syncRevoke(syncData.revocations, parents: syncData.revocationParents) await self.syncRevoke(syncData.revocations, parents: syncData.revocationParents)
self._syncAddOrUpdate(syncData.relationshipSets) // self._syncAddOrUpdate(syncData.relationshipSets)
await self._syncDelete(syncData.relationshipRemovals) // await self._syncDelete(syncData.relationshipRemovals)
self._syncAddOrUpdate(syncData.sharedRelationshipSets, shared: true) self._syncAddOrUpdate(syncData.sharedRelationshipSets, shared: true)
self._syncRevoke(syncData.sharedRelationshipRemovals) self._syncRevoke(syncData.sharedRelationshipRemovals)
@ -1020,7 +1020,7 @@ public class StoreCenter {
/// Returns the list of users have access to a data given its id /// Returns the list of users have access to a data given its id
public func authorizedUsers(for modelId: String) -> [String] { public func authorizedUsers(for modelId: String) -> [String] {
guard let dataAccessCollection = self._dataAccess else { guard let dataAccessCollection = self.dataAccessCollection else {
return [] return []
} }
if let dataAccess = dataAccessCollection.first(where: { $0.modelId == modelId }) { if let dataAccess = dataAccessCollection.first(where: { $0.modelId == modelId }) {
@ -1031,7 +1031,7 @@ public class StoreCenter {
public func setAuthorizedUsersAsync<T: SyncedStorable>(for instance: T, users: [String]) async throws { public func setAuthorizedUsersAsync<T: SyncedStorable>(for instance: T, users: [String]) async throws {
guard let dataAccessCollection = self._dataAccess else { guard let dataAccessCollection = self.dataAccessCollection else {
throw StoreError.synchronizationInactive throw StoreError.synchronizationInactive
} }
guard let userId = self.userId else { guard let userId = self.userId else {
@ -1040,15 +1040,15 @@ public class StoreCenter {
if let dataAccess = dataAccessCollection.first(where: { $0.modelId == instance.stringId }) { if let dataAccess = dataAccessCollection.first(where: { $0.modelId == instance.stringId }) {
if users.isEmpty { if users.isEmpty {
await dataAccessCollection.deleteAsync(instance: dataAccess) try await dataAccessCollection.deleteAsync(instance: dataAccess)
} else { } else {
dataAccess.sharedWith.removeAll() dataAccess.sharedWith.removeAll()
dataAccess.sharedWith = users dataAccess.sharedWith = users
await dataAccessCollection.addOrUpdateAsync(instance: dataAccess) try await dataAccessCollection.addOrUpdateAsync(instance: dataAccess)
} }
} else { } else {
let dataAccess = DataAccess(owner: userId, sharedWith: users, modelName: String(describing: type(of: instance)), modelId: instance.stringId) let dataAccess = DataAccess(owner: userId, sharedWith: users, modelName: String(describing: type(of: instance)), modelId: instance.stringId)
await dataAccessCollection.addOrUpdateAsync(instance: dataAccess) try await dataAccessCollection.addOrUpdateAsync(instance: dataAccess)
} }
} }

@ -53,6 +53,11 @@ public class SyncedCollection<T : SyncedStorable>: BaseCollection<T>, SomeSynced
} }
} }
func loadOnceAsync() async throws {
let items: [T] = try await self.storeCenter.service().get()
await self.loadItems(items, clear: true)
}
/// 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
/// to an object when it's inserted. The SyncedCollection possibly needs to update its own copy with new values. /// to an object when it's inserted. The SyncedCollection possibly needs to update its own copy with new values.
/// - serverInstance: the instance of the object on the server /// - serverInstance: the instance of the object on the server
@ -85,12 +90,12 @@ public class SyncedCollection<T : SyncedStorable>: BaseCollection<T>, SomeSynced
// MARK: - Basic operations with sync // MARK: - Basic operations with sync
/// Adds or update an instance asynchronously and waits for network operations /// Adds or update an instance asynchronously and waits for network operations
func addOrUpdateAsync(instance: T) async { func addOrUpdateAsync(instance: T) async throws {
if let result = _addOrUpdateCore(instance: instance) { if let result = _addOrUpdateCore(instance: instance) {
if result.isNewItem { if result.isNewItem {
await self._executeBatchOnce(OperationBatch(insert: result.item)) try await self._executeBatchOnce(OperationBatch(insert: result.item))
} else { } else {
await self._executeBatchOnce(OperationBatch(update: result.item)) try await self._executeBatchOnce(OperationBatch(update: result.item))
} }
} }
} }
@ -185,9 +190,9 @@ public class SyncedCollection<T : SyncedStorable>: BaseCollection<T>, SomeSynced
Task { await self._sendOperationBatch(batch) } Task { await self._sendOperationBatch(batch) }
} }
func addOrUpdateAsync(contentOfs sequence: any Sequence<T>) async { func addOrUpdateAsync(contentOfs sequence: any Sequence<T>) async throws {
let batch = self._addOrUpdateCore(contentOfs: sequence) let batch = self._addOrUpdateCore(contentOfs: sequence)
await self._executeBatchOnce(batch) try await self._executeBatchOnce(batch)
} }
/// Proceeds to delete all instance of the collection, properly cleaning up dependencies and sending API calls /// Proceeds to delete all instance of the collection, properly cleaning up dependencies and sending API calls
@ -224,19 +229,19 @@ public class SyncedCollection<T : SyncedStorable>: BaseCollection<T>, SomeSynced
} }
/// Deletes all items of the sequence by id and sets the collection as changed to trigger a write /// Deletes all items of the sequence by id and sets the collection as changed to trigger a write
public func deleteAsync(contentOfs sequence: any RandomAccessCollection<T>) async { public func deleteAsync(contentOfs sequence: any RandomAccessCollection<T>) async throws{
guard sequence.isNotEmpty else { return } guard sequence.isNotEmpty else { return }
let batch = self._deleteCore(contentOfs: sequence) let batch = self._deleteCore(contentOfs: sequence)
await self._executeBatchOnce(batch) try await self._executeBatchOnce(batch)
} }
/// Deletes an instance and writes /// Deletes an instance and writes
func deleteAsync(instance: T) async { func deleteAsync(instance: T) async throws{
defer { defer {
self.setChanged() self.setChanged()
} }
self._deleteNoWrite(instance: instance) self._deleteNoWrite(instance: instance)
await self._executeBatchOnce(OperationBatch(delete: instance)) try await self._executeBatchOnce(OperationBatch(delete: instance))
} }
/// Deletes an instance and writes /// Deletes an instance and writes
@ -327,12 +332,8 @@ public class SyncedCollection<T : SyncedStorable>: BaseCollection<T>, SomeSynced
} }
} }
fileprivate func _executeBatchOnce(_ batch: OperationBatch<T>) async { fileprivate func _executeBatchOnce(_ batch: OperationBatch<T>) async throws {
do { try await self.storeCenter.singleBatchExecution(batch)
try await self.storeCenter.singleBatchExecution(batch)
} catch {
Logger.error(error)
}
} }
// MARK: Single calls // MARK: Single calls

Loading…
Cancel
Save