Add storeParent logic to manage directories when data is added/removed + sharingStatus refactoring to handle shared/granted states

sync3
Laurent 6 months ago
parent 27bb855c8d
commit 96b6c657e3
  1. 4
      LeStorage/Codables/ApiCall.swift
  2. 1
      LeStorage/Codables/DataAccess.swift
  3. 3
      LeStorage/Codables/DataLog.swift
  4. 1
      LeStorage/Codables/FailedAPICall.swift
  5. 7
      LeStorage/Codables/GetSyncData.swift
  6. 1
      LeStorage/Codables/Log.swift
  7. 4
      LeStorage/Codables/SyncData.swift
  8. 8
      LeStorage/ModelObject.swift
  9. 2
      LeStorage/Storable.swift
  10. 54
      LeStorage/Store.swift
  11. 81
      LeStorage/StoreCenter.swift
  12. 27
      LeStorage/StoredCollection.swift
  13. 16
      LeStorage/SyncedCollection.swift
  14. 7
      LeStorage/SyncedStorable.swift

@ -30,6 +30,7 @@ public class ApiCall<T: Storable>: ModelObject, Storable, SomeCall {
public static func resourceName() -> String { return "apicalls_" + T.resourceName() } public static func resourceName() -> String { return "apicalls_" + T.resourceName() }
static func tokenExemptedMethods() -> [HTTPMethod] { return [] } static func tokenExemptedMethods() -> [HTTPMethod] { return [] }
public static func storeParent() -> Bool { return false }
public var id: String = Store.randomId() public var id: String = Store.randomId()
@ -112,7 +113,8 @@ class OldApiCall<T: Storable>: ModelObject, Storable, SomeCall {
static func resourceName() -> String { return "apicalls_" + T.resourceName() } static func resourceName() -> String { return "apicalls_" + T.resourceName() }
static func tokenExemptedMethods() -> [HTTPMethod] { return [] } static func tokenExemptedMethods() -> [HTTPMethod] { return [] }
static func storeParent() -> Bool { return false }
var id: String = Store.randomId() var id: String = Store.randomId()
/// The transactionId to group calls together /// The transactionId to group calls together

@ -13,6 +13,7 @@ class DataAccess: SyncedModelObject, SyncedStorable {
static func resourceName() -> String { return "data-access" } static func resourceName() -> String { return "data-access" }
static func relationships() -> [Relationship] { return [] } static func relationships() -> [Relationship] { return [] }
static var copyServerResponse: Bool = false static var copyServerResponse: Bool = false
static func storeParent() -> Bool { return false }
override required init() { override required init() {
super.init() super.init()

@ -12,7 +12,8 @@ class DataLog: ModelObject, Storable {
static func resourceName() -> String { return "data-logs" } static func resourceName() -> String { return "data-logs" }
static func tokenExemptedMethods() -> [HTTPMethod] { return [] } static func tokenExemptedMethods() -> [HTTPMethod] { return [] }
static func relationships() -> [Relationship] { return [] } static func relationships() -> [Relationship] { return [] }
static func storeParent() -> Bool { return false }
var id: String = Store.randomId() var id: String = Store.randomId()
/// The id of the underlying data /// The id of the underlying data

@ -13,6 +13,7 @@ class FailedAPICall: SyncedModelObject, SyncedStorable {
static func tokenExemptedMethods() -> [HTTPMethod] { return [] } static func tokenExemptedMethods() -> [HTTPMethod] { return [] }
static func relationships() -> [Relationship] { return [] } static func relationships() -> [Relationship] { return [] }
static var copyServerResponse: Bool = false static var copyServerResponse: Bool = false
static func storeParent() -> Bool { return false }
override required init() { override required init() {
self.callId = "" self.callId = ""

@ -9,6 +9,10 @@ import Foundation
class GetSyncData: SyncedModelObject, SyncedStorable, URLParameterConvertible { class GetSyncData: SyncedModelObject, SyncedStorable, URLParameterConvertible {
static func tokenExemptedMethods() -> [HTTPMethod] { return [] }
static var copyServerResponse: Bool = false
static func storeParent() -> Bool { return false }
var date: String = "" var date: String = ""
enum CodingKeys: String, CodingKey { enum CodingKeys: String, CodingKey {
@ -25,9 +29,6 @@ class GetSyncData: SyncedModelObject, SyncedStorable, URLParameterConvertible {
try super.init(from: decoder) try super.init(from: decoder)
} }
static func tokenExemptedMethods() -> [HTTPMethod] { return [] }
static var copyServerResponse: Bool = false
static func resourceName() -> String { static func resourceName() -> String {
return "sync-data" return "sync-data"
} }

@ -13,6 +13,7 @@ class Log: SyncedModelObject, SyncedStorable {
static func tokenExemptedMethods() -> [HTTPMethod] { return [] } static func tokenExemptedMethods() -> [HTTPMethod] { return [] }
static func relationships() -> [Relationship] { return [] } static func relationships() -> [Relationship] { return [] }
static var copyServerResponse: Bool = false static var copyServerResponse: Bool = false
static func storeParent() -> Bool { return false }
override required init() { override required init() {
super.init() super.init()

@ -25,6 +25,7 @@ class SyncData {
var updates: [SyncedStorableArray] = [] var updates: [SyncedStorableArray] = []
var deletions: [ObjectIdentifierArray] = [] var deletions: [ObjectIdentifierArray] = []
var shared: [SyncedStorableArray] = []
var grants: [SyncedStorableArray] = [] var grants: [SyncedStorableArray] = []
var revocations: [ObjectIdentifierArray] = [] var revocations: [ObjectIdentifierArray] = []
var revocationParents: [[ObjectIdentifierArray]] = [] var revocationParents: [[ObjectIdentifierArray]] = []
@ -47,6 +48,9 @@ class SyncData {
if let deletions = json["deletions"] as? [String: Any] { if let deletions = json["deletions"] as? [String: Any] {
self.deletions = try storeCenter.decodeObjectIdentifierDictionary(deletions) self.deletions = try storeCenter.decodeObjectIdentifierDictionary(deletions)
} }
if let shared = json["shared"] as? [String: Any] {
self.shared = try storeCenter.decodeDictionary(shared)
}
if let grants = json["grants"] as? [String: Any] { if let grants = json["grants"] as? [String: Any] {
self.grants = try storeCenter.decodeDictionary(grants) self.grants = try storeCenter.decodeDictionary(grants)
} }

@ -56,7 +56,7 @@ open class SyncedModelObject: BaseModelObject {
public var relatedUser: String? = nil public var relatedUser: String? = nil
public var lastUpdate: Date = Date() public var lastUpdate: Date = Date()
public var shared: Bool? public var sharing: SharingStatus?
public override init() { public override init() {
super.init() super.init()
@ -73,7 +73,7 @@ open class SyncedModelObject: BaseModelObject {
let container = try decoder.container(keyedBy: CodingKeys.self) let container = try decoder.container(keyedBy: CodingKeys.self)
self.relatedUser = try container.decodeIfPresent(String.self, forKey: .relatedUser) self.relatedUser = try container.decodeIfPresent(String.self, forKey: .relatedUser)
self.lastUpdate = try container.decodeIfPresent(Date.self, forKey: .lastUpdate) ?? Date() self.lastUpdate = try container.decodeIfPresent(Date.self, forKey: .lastUpdate) ?? Date()
self.shared = try container.decodeIfPresent(Bool.self, forKey: .shared) self.sharing = try container.decodeIfPresent(SharingStatus.self, forKey: .shared)
try super.init(from: decoder) try super.init(from: decoder)
} }
@ -83,8 +83,8 @@ open class SyncedModelObject: BaseModelObject {
var container = encoder.container(keyedBy: CodingKeys.self) var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(relatedUser, forKey: .relatedUser) try container.encode(relatedUser, forKey: .relatedUser)
try container.encode(lastUpdate, forKey: .lastUpdate) try container.encode(lastUpdate, forKey: .lastUpdate)
if self.shared == true { if self.sharing != nil {
try container.encodeIfPresent(shared, forKey: .shared) try container.encodeIfPresent(sharing, forKey: .shared)
} }
try super.encode(to: encoder) try super.encode(to: encoder)

@ -35,6 +35,8 @@ public protocol Storable: Codable, Identifiable, NSObjectProtocol {
/// This method returns RelationShips objects of the type /// This method returns RelationShips objects of the type
static func relationships() -> [Relationship] static func relationships() -> [Relationship]
static func storeParent() -> Bool
} }
extension Storable { extension Storable {

@ -112,13 +112,13 @@ final public class Store {
/// - Parameters: /// - Parameters:
/// - indexed: Creates an index to quickly access the data /// - indexed: Creates an index to quickly access the data
/// - inMemory: Indicates if the collection should only live in memory, and not write into a file /// - inMemory: Indicates if the collection should only live in memory, and not write into a file
public func registerSynchronizedCollection<T : SyncedStorable>(indexed: Bool = false, inMemory: Bool = false, limit: Int? = nil, synchronousLoading: Bool = false) -> SyncedCollection<T> { public func registerSynchronizedCollection<T : SyncedStorable>(indexed: Bool = false, inMemory: Bool = false, limit: Int? = nil, synchronousLoading: Bool = false, noLoad: Bool = false) -> SyncedCollection<T> {
if let collection: SyncedCollection<T> = try? self.syncedCollection() { if let collection: SyncedCollection<T> = try? self.syncedCollection() {
return collection return collection
} }
let collection = SyncedCollection<T>(store: self, indexed: indexed, inMemory: inMemory, limit: limit, synchronousLoading: synchronousLoading) let collection = SyncedCollection<T>(store: self, indexed: indexed, inMemory: inMemory, limit: limit, synchronousLoading: synchronousLoading, noLoad: noLoad)
self._collections[T.resourceName()] = collection self._collections[T.resourceName()] = collection
self._baseCollections[T.resourceName()] = collection.collection self._baseCollections[T.resourceName()] = collection.collection
@ -207,7 +207,7 @@ final public class Store {
do { do {
return try self.syncedCollection() return try self.syncedCollection()
} catch { } catch {
return self.registerSynchronizedCollection(indexed: true, inMemory: false) return self.registerSynchronizedCollection(indexed: true, inMemory: false, noLoad: true)
} }
} }
@ -253,7 +253,7 @@ final public class Store {
/// Calls addOrUpdateIfNewer from the collection corresponding to the instance /// Calls addOrUpdateIfNewer from the collection corresponding to the instance
@MainActor @MainActor
func addOrUpdateIfNewer<T: SyncedStorable>(_ instance: T, shared: Bool) { func addOrUpdateIfNewer<T: SyncedStorable>(_ instance: T, shared: SharingStatus?) {
let collection: SyncedCollection<T> = self.registerOrGetSyncedCollection(T.self) let collection: SyncedCollection<T> = self.registerOrGetSyncedCollection(T.self)
collection.addOrUpdateIfNewer(instance, shared: shared) collection.addOrUpdateIfNewer(instance, shared: shared)
} }
@ -294,7 +294,7 @@ final public class Store {
} }
} }
public func deleteUnusedSharedDependencies<T: SyncedStorable>(type: T.Type, shouldBeSynchronized: Bool, _ handler: (T) throws -> Bool) { public func deleteUnusedSharedDependencies<T: SyncedStorable>(type: T.Type, _ handler: (T) throws -> Bool) {
do { do {
let collection: SyncedCollection<T> = try self.syncedCollection() let collection: SyncedCollection<T> = try self.syncedCollection()
let items = try collection.items.filter(handler) let items = try collection.items.filter(handler)
@ -305,12 +305,21 @@ final public class Store {
} }
public func deleteUnusedSharedDependencies<T: SyncedStorable>(type: T.Type) {
do {
let collection: SyncedCollection<T> = try self.syncedCollection()
self.deleteUnusedSharedDependencies(collection.items)
} catch {
Logger.error(error)
}
}
/// Deletes dependencies of shared objects that are not used elsewhere in the system /// Deletes dependencies of shared objects that are not used elsewhere in the system
/// Similar to _deleteDependencies but only for unused shared objects /// Similar to _deleteDependencies but only for unused shared objects
public func deleteUnusedSharedDependencies<T: SyncedStorable>(_ items: [T]) { public func deleteUnusedSharedDependencies<T: SyncedStorable>(_ items: [T]) {
do { do {
for item in items { for item in items {
guard item.shared == true else { continue } guard item.sharing != nil else { continue }
if self.referenceCount(type: T.self, id: item.stringId) == 0 { if self.referenceCount(type: T.self, id: item.stringId) == 0 {
// Only delete if the shared item has no references // Only delete if the shared item has no references
item.deleteUnusedSharedDependencies(store: self) item.deleteUnusedSharedDependencies(store: self)
@ -333,17 +342,40 @@ final public class Store {
} }
public func deleteDependencies<T: Storable>(type: T.Type, actionOption: ActionOption, _ isIncluded: (any Storable) -> Bool) { public func deleteDependencies<T>(type: T.Type, actionOption: ActionOption, _ isIncluded: (T) -> Bool) where T: SyncedStorable {
do { do {
let collection: any SomeCollection = try self.someCollection(type: type) let collection = try self.someCollection(type: type)
collection.deleteDependencies(actionOption: actionOption, isIncluded) if let syncCollection = collection as? SyncedCollection<T> {
syncCollection.deleteDependencies(actionOption: actionOption, isIncluded)
}
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
} }
public func deleteDependencies<T>(type: T.Type, actionOption: ActionOption, _ isIncluded: (T) -> Bool) where T: Storable {
do {
let collection = try self.someCollection(type: type)
if let syncCollection = collection as? StoredCollection<T> {
syncCollection.deleteDependencies(actionOption: actionOption, isIncluded)
}
} catch {
Logger.error(error)
}
}
// public func deleteDependencies<T: Storable>(type: T.Type, actionOption: ActionOption, _ isIncluded: (T) -> Bool) {
//
// do {
// let collection: any SomeCollection = try self.someCollection(type: type)
// if let syncCollection = collection as? SyncedCollection<T> {
// collection.deleteDependencies(actionOption: actionOption, isIncluded)
// } catch {
// Logger.error(error)
// }
//
// }
// MARK: - Write // MARK: - Write
/// Returns the directory URL of the store /// Returns the directory URL of the store

@ -182,6 +182,8 @@ public class StoreCenter {
} }
} }
} }
// MARK: - Store management
/// Registers a store into the list of stores /// Registers a store into the list of stores
/// - Parameters: /// - Parameters:
@ -200,7 +202,7 @@ 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 requestStore(identifier: String) -> Store { func requestStore(identifier: String) -> Store {
if let store = self._stores[identifier] { if let store = self._stores[identifier] {
return store return store
} else { } else {
@ -210,6 +212,29 @@ public class StoreCenter {
} }
} }
/// Returns the store corresponding to the provided id, and creates one if necessary, otherwise returns the main store
fileprivate func _requestStore(id: String?) -> Store {
if let storeId = id {
if let store = self._stores[storeId] {
return store
} else {
let store = Store(storeCenter: self, identifier: storeId)
self._registerStore(store: store)
return store
}
} else {
return self.mainStore
}
}
fileprivate func _store(id: String?) -> Store? {
if let storeId = id, let store = self._stores[storeId] {
return store
} else {
return self.mainStore
}
}
public func store(identifier: String) throws -> Store { public func store(identifier: String) throws -> Store {
if let store = self._stores[identifier] { if let store = self._stores[identifier] {
return store return store
@ -217,6 +242,15 @@ public class StoreCenter {
throw StoreError.storeNotRegistered(id: identifier) throw StoreError.storeNotRegistered(id: identifier)
} }
/// Deletes the directory using its identifier
/// - Parameters:
/// - identifier: The name of the directory
public func destroyStore(identifier: String) {
let directory = "\(self.directoryName)/\(identifier)"
FileManager.default.deleteDirectoryInDocuments(directoryName: directory)
self._stores.removeValue(forKey: identifier)
}
// MARK: - Settings // MARK: - Settings
/// Sets the user info given a user /// Sets the user info given a user
@ -535,7 +569,7 @@ public class StoreCenter {
} }
func itemsRetrieved<T: SyncedStorable>(_ results: [T], storeId: String?, clear: Bool) async { func itemsRetrieved<T: SyncedStorable>(_ results: [T], storeId: String?, clear: Bool) async {
await self._store(id: storeId).loadCollectionItems(results, clear: clear) await self._requestStore(id: storeId).loadCollectionItems(results, clear: clear)
} }
/// Returns the names of all collections /// Returns the names of all collections
@ -631,7 +665,7 @@ public class StoreCenter {
} }
let array = try self.decodeDictionary(json) let array = try self.decodeDictionary(json)
await self._syncAddOrUpdate(array, shared: true) await self._syncAddOrUpdate(array, shared: .shared)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -642,11 +676,12 @@ public class StoreCenter {
await self._syncAddOrUpdate(syncData.updates) await self._syncAddOrUpdate(syncData.updates)
await self._syncDelete(syncData.deletions) await self._syncDelete(syncData.deletions)
await self._syncAddOrUpdate(syncData.grants, shared: true) await self._syncAddOrUpdate(syncData.shared, shared: .shared)
await self._syncAddOrUpdate(syncData.grants, shared: .granted)
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)
await self._syncAddOrUpdate(syncData.sharedRelationshipSets, shared: true) await self._syncAddOrUpdate(syncData.sharedRelationshipSets, shared: .granted)
await self._syncRevoke(syncData.sharedRelationshipRemovals) await self._syncRevoke(syncData.sharedRelationshipRemovals)
Logger.log("sync content: updates = \(syncData.updates.count) / deletions = \(syncData.deletions.count), grants = \(syncData.grants.count)") Logger.log("sync content: updates = \(syncData.updates.count) / deletions = \(syncData.deletions.count), grants = \(syncData.grants.count)")
@ -668,7 +703,7 @@ public class StoreCenter {
/// - updateArrays: the server updates /// - updateArrays: the server updates
/// - shared: indicates if the content should be flagged as shared /// - shared: indicates if the content should be flagged as shared
@MainActor @MainActor
func _syncAddOrUpdate(_ updateArrays: [SyncedStorableArray], shared: Bool = false) async { func _syncAddOrUpdate(_ updateArrays: [SyncedStorableArray], shared: SharingStatus? = nil) async {
for updateArray in updateArrays { for updateArray in updateArrays {
for item in updateArray.items { for item in updateArray.items {
@ -727,21 +762,6 @@ public class StoreCenter {
} }
/// Returns the store corresponding to the provided id, and creates one if necessary
fileprivate func _store(id: String?) -> Store {
if let storeId = id {
if let store = self._stores[storeId] {
return store
} else {
let store = Store(storeCenter: self, identifier: storeId)
self._registerStore(store: store)
return store
}
} else {
return self.mainStore
}
}
/// Returns whether a data has already been deleted by, to avoid inserting it again /// Returns whether a data has already been deleted by, to avoid inserting it again
fileprivate func _hasAlreadyBeenDeleted<T: Storable>(_ instance: T) -> Bool { fileprivate func _hasAlreadyBeenDeleted<T: Storable>(_ instance: T) -> Bool {
return self._deleteLogs.contains(where: { return self._deleteLogs.contains(where: {
@ -750,10 +770,10 @@ public class StoreCenter {
} }
/// Adds or updates an instance into the store /// Adds or updates an instance into the store
func synchronizationAddOrUpdate<T: SyncedStorable>(_ instance: T, storeId: String?, shared: Bool) async { func synchronizationAddOrUpdate<T: SyncedStorable>(_ instance: T, storeId: String?, shared: SharingStatus?) async {
let hasAlreadyBeenDeleted: Bool = self._hasAlreadyBeenDeleted(instance) let hasAlreadyBeenDeleted: Bool = self._hasAlreadyBeenDeleted(instance)
if !hasAlreadyBeenDeleted { if !hasAlreadyBeenDeleted {
await self._store(id: storeId).addOrUpdateIfNewer(instance, shared: shared) await self._requestStore(id: storeId).addOrUpdateIfNewer(instance, shared: shared)
} }
} }
@ -761,7 +781,7 @@ public class StoreCenter {
@MainActor @MainActor
func synchronizationDelete<T: SyncedStorable>(id: String, type: T.Type, storeId: String?) { func synchronizationDelete<T: SyncedStorable>(id: String, type: T.Type, storeId: String?) {
do { do {
try self._store(id: storeId).deleteNoSyncNoCascade(type: type, id: id) try self._store(id: storeId)?.deleteNoSyncNoCascade(type: type, id: id)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -776,7 +796,7 @@ public class StoreCenter {
if self._instanceShared(id: id, type: type) { if self._instanceShared(id: id, type: type) {
let count = self.mainStore.referenceCount(type: type, id: id) let count = self.mainStore.referenceCount(type: type, id: id)
if count == 0 { if count == 0 {
try self._store(id: storeId).deleteNoSyncNoCascade(type: type, id: id) try self._store(id: storeId)?.deleteNoSyncNoCascade(type: type, id: id)
} }
} }
} catch { } catch {
@ -788,7 +808,7 @@ public class StoreCenter {
fileprivate func _instanceShared<T: SyncedStorable>(id: String, type: T.Type) -> Bool { fileprivate func _instanceShared<T: SyncedStorable>(id: String, type: T.Type) -> Bool {
let realId: T.ID = T.buildRealId(id: id) let realId: T.ID = T.buildRealId(id: id)
let instance: T? = self.mainStore.findById(realId) let instance: T? = self.mainStore.findById(realId)
return instance?.shared == true return instance?.sharing != nil
} }
/// Deletes a data log by data id /// Deletes a data log by data id
@ -967,15 +987,6 @@ public class StoreCenter {
return !self._blackListedUserName.contains(where: { $0 == userName }) return !self._blackListedUserName.contains(where: { $0 == userName })
} }
/// Deletes the directory using its identifier
/// - Parameters:
/// - identifier: The name of the directory
public func destroyStore(identifier: String) {
let directory = "\(self.directoryName)/\(identifier)"
FileManager.default.deleteDirectoryInDocuments(directoryName: directory)
self._stores.removeValue(forKey: identifier)
}
// MARK: - Instant update // MARK: - Instant update
/// Updates a local object with a server instance /// Updates a local object with a server instance

@ -105,7 +105,7 @@ public class StoredCollection<T: Storable>: SomeCollection {
} }
} }
init(store: Store, indexed: Bool = false, inMemory: Bool = false, limit: Int? = nil, synchronousLoading: Bool = false, delegate: (any CollectionDelegate<T>)? = nil) { init(store: Store, indexed: Bool = false, inMemory: Bool = false, limit: Int? = nil, synchronousLoading: Bool = false, noLoad: Bool = false, delegate: (any CollectionDelegate<T>)? = nil) {
if indexed { if indexed {
self._indexes = [:] self._indexes = [:]
} }
@ -114,15 +114,18 @@ public class StoredCollection<T: Storable>: SomeCollection {
self.limit = limit self.limit = limit
self._delegate = delegate self._delegate = delegate
if synchronousLoading { if noLoad {
Task { self.hasLoaded = true
await self.loadFromFile()
}
} else { } else {
Task(priority: .high) { Task {
await self.load() if synchronousLoading {
await self.loadFromFile()
} else {
await self.load()
}
} }
} }
} }
init(store: Store) { init(store: Store) {
@ -322,6 +325,11 @@ public class StoredCollection<T: Storable>: SomeCollection {
instance.store = self.store instance.store = self.store
self._indexes?[instance.id] = instance self._indexes?[instance.id] = instance
self._applyLimitIfPresent() self._applyLimitIfPresent()
if T.storeParent() {
_ = self.storeCenter.requestStore(identifier: instance.stringId) // make directory
}
return true return true
} }
@ -361,6 +369,11 @@ public class StoredCollection<T: Storable>: SomeCollection {
} }
self.localDeleteOnly(instance: instance) self.localDeleteOnly(instance: instance)
if T.storeParent() {
self.storeCenter.destroyStore(identifier: instance.stringId)
}
return true return true
} }

@ -19,10 +19,10 @@ public class SyncedCollection<T : SyncedStorable>: SomeSyncedCollection, Collect
let store: Store let store: Store
let collection: StoredCollection<T> let collection: StoredCollection<T>
init(store: Store, indexed: Bool = false, inMemory: Bool = false, limit: Int? = nil, synchronousLoading: Bool = false) { init(store: Store, indexed: Bool = false, inMemory: Bool = false, limit: Int? = nil, synchronousLoading: Bool = false, noLoad: Bool = false) {
self.store = store self.store = store
self.collection = StoredCollection<T>(store: store, indexed: indexed, limit: limit, synchronousLoading: synchronousLoading) self.collection = StoredCollection<T>(store: store, indexed: indexed, limit: limit, synchronousLoading: synchronousLoading, noLoad: noLoad)
} }
@ -115,7 +115,7 @@ public class SyncedCollection<T : SyncedStorable>: SomeSyncedCollection, Collect
let result = self.collection.addOrUpdate(instance: instance) let result = self.collection.addOrUpdate(instance: instance)
if result.method == .update { if result.method == .update {
if instance.shared == true { if instance.sharing != nil {
self._cleanUpSharedDependencies() self._cleanUpSharedDependencies()
} }
} }
@ -252,7 +252,7 @@ public class SyncedCollection<T : SyncedStorable>: SomeSyncedCollection, Collect
fileprivate func _deleteUnusedSharedInstances() { fileprivate func _deleteUnusedSharedInstances() {
let sharedItems = self.collection.items.filter { $0.shared == true } let sharedItems = self.collection.items.filter { $0.sharing != nil }
for sharedItem in sharedItems { for sharedItem in sharedItems {
self.store.deleteUnusedSharedIfNecessary(sharedItem) self.store.deleteUnusedSharedIfNecessary(sharedItem)
} }
@ -331,7 +331,7 @@ public class SyncedCollection<T : SyncedStorable>: SomeSyncedCollection, Collect
func deleteUnusedShared(instance: T) { func deleteUnusedShared(instance: T) {
guard instance.shared == true else { return } guard instance.sharing != nil else { return }
self.delete(instance: instance) self.delete(instance: instance)
instance.deleteUnusedSharedDependencies(store: self.store) instance.deleteUnusedSharedDependencies(store: self.store)
@ -412,7 +412,7 @@ public class SyncedCollection<T : SyncedStorable>: SomeSyncedCollection, Collect
// MARK: - Synchronization // MARK: - Synchronization
/// Adds or update an instance if it is newer than the local instance /// Adds or update an instance if it is newer than the local instance
func addOrUpdateIfNewer(_ instance: T, shared: Bool) { func addOrUpdateIfNewer(_ instance: T, shared: SharingStatus?) {
// defer { // defer {
// self.triggerWrite() // self.triggerWrite()
@ -426,9 +426,7 @@ public class SyncedCollection<T : SyncedStorable>: SomeSyncedCollection, Collect
print("do not update \(T.resourceName()): \(instance.lastUpdate.timeIntervalSince1970) / local: \(localInstance.lastUpdate.timeIntervalSince1970)") print("do not update \(T.resourceName()): \(instance.lastUpdate.timeIntervalSince1970) / local: \(localInstance.lastUpdate.timeIntervalSince1970)")
} }
} else { // insert } else { // insert
if shared { instance.sharing = shared
instance.shared = true
}
self.collection.add(instance: instance, actionOption: .standard) self.collection.add(instance: instance, actionOption: .standard)
} }

@ -7,10 +7,15 @@
import Foundation import Foundation
public enum SharingStatus: Int, Codable {
case shared = 1
case granted
}
public protocol SyncedStorable: Storable { public protocol SyncedStorable: Storable {
var lastUpdate: Date { get set } var lastUpdate: Date { get set }
var shared: Bool? { get set } var sharing: SharingStatus? { get set }
init() init()

Loading…
Cancel
Save