|
|
|
|
@ -19,10 +19,10 @@ protocol SomeCollection: CollectionHolder, Identifiable { |
|
|
|
|
var hasLoaded: Bool { get } |
|
|
|
|
var inMemory: Bool { get } |
|
|
|
|
var type: any Storable.Type { get } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func allItems() -> [any Storable] |
|
|
|
|
func referenceCount<S: Storable>(type: S.Type, id: String) -> Int |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
protocol SomeSyncedCollection: SomeCollection { |
|
|
|
|
@ -62,9 +62,8 @@ public class StoredCollection<T: Storable>: RandomAccessCollection, SomeCollecti |
|
|
|
|
|
|
|
|
|
/// Indicates if the collection has loaded locally, with or without a file |
|
|
|
|
fileprivate(set) public var hasLoaded: Bool = false |
|
|
|
|
|
|
|
|
|
fileprivate(set) var limit: Int? = nil |
|
|
|
|
|
|
|
|
|
fileprivate(set) var limit: Int? = nil |
|
|
|
|
|
|
|
|
|
init(store: Store, indexed: Bool = false, inMemory: Bool = false, limit: Int? = nil) { |
|
|
|
|
if indexed { |
|
|
|
|
@ -92,6 +91,10 @@ public class StoredCollection<T: Storable>: RandomAccessCollection, SomeCollecti |
|
|
|
|
return T.resourceName() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public var storeId: String? { |
|
|
|
|
return self.store.identifier |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// MARK: - Loading |
|
|
|
|
|
|
|
|
|
/// Sets the collection as changed to trigger a write |
|
|
|
|
@ -116,7 +119,7 @@ public class StoredCollection<T: Storable>: RandomAccessCollection, SomeCollecti |
|
|
|
|
func loadFromFile() throws { |
|
|
|
|
try self._decodeJSONFile() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Decodes the json file into the items array |
|
|
|
|
fileprivate func _decodeJSONFile() throws { |
|
|
|
|
|
|
|
|
|
@ -155,7 +158,7 @@ public class StoredCollection<T: Storable>: RandomAccessCollection, SomeCollecti |
|
|
|
|
self._indexes = self.items.dictionary { $0.id } |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// MARK: - Basic operations |
|
|
|
|
|
|
|
|
|
/// Adds or updates the provided instance inside the collection |
|
|
|
|
@ -178,7 +181,7 @@ public class StoredCollection<T: Storable>: RandomAccessCollection, SomeCollecti |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// A method the treat the collection as a single instance holder |
|
|
|
|
func setSingletonNoSync(instance: T) { |
|
|
|
|
defer { |
|
|
|
|
@ -194,7 +197,7 @@ public class StoredCollection<T: Storable>: RandomAccessCollection, SomeCollecti |
|
|
|
|
self.delete(instance: instance) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Deletes the instance in the collection and sets the collection as changed to trigger a write |
|
|
|
|
public func delete(instance: T) { |
|
|
|
|
defer { |
|
|
|
|
@ -282,7 +285,7 @@ public class StoredCollection<T: Storable>: RandomAccessCollection, SomeCollecti |
|
|
|
|
self.items = self.items.suffix(limit) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Returns the instance corresponding to the provided [id] |
|
|
|
|
public func findById(_ id: T.ID) -> T? { |
|
|
|
|
if let index = self._indexes, let instance = index[id] { |
|
|
|
|
@ -337,7 +340,8 @@ public class StoredCollection<T: Storable>: RandomAccessCollection, SomeCollecti |
|
|
|
|
try self.store.write(content: jsonString, fileName: T.fileName()) |
|
|
|
|
} catch { |
|
|
|
|
Logger.error(error) |
|
|
|
|
StoreCenter.main.log(message: "write failed for \(T.resourceName()): \(error.localizedDescription)") |
|
|
|
|
StoreCenter.main.log( |
|
|
|
|
message: "write failed for \(T.resourceName()): \(error.localizedDescription)") |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -351,20 +355,21 @@ public class StoredCollection<T: Storable>: RandomAccessCollection, SomeCollecti |
|
|
|
|
self.items.removeAll() |
|
|
|
|
self.store.removeFile(type: T.self) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var type: any Storable.Type { return T.self } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// MARK: - Reference count |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Counts the references to an object - given its type and id - inside the collection |
|
|
|
|
func referenceCount<S: Storable>(type: S.Type, id: String) -> Int { |
|
|
|
|
let relationships = T.relationships().filter { $0.type == type } |
|
|
|
|
guard relationships.count > 0 else { return 0 } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return self.items.reduce(0) { count, item in |
|
|
|
|
count + relationships.filter { relationship in |
|
|
|
|
(item[keyPath: relationship.keyPath] as? String) == id |
|
|
|
|
}.count |
|
|
|
|
count |
|
|
|
|
+ relationships.filter { relationship in |
|
|
|
|
(item[keyPath: relationship.keyPath] as? String) == id |
|
|
|
|
}.count |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|