diff --git a/Sources/Papyrus/PapyrusStore.swift b/Sources/Papyrus/PapyrusStore.swift index 1527a95..770db37 100644 --- a/Sources/Papyrus/PapyrusStore.swift +++ b/Sources/Papyrus/PapyrusStore.swift @@ -146,13 +146,9 @@ public struct PapyrusStore: Sendable { /// Saves all objects to the store. /// - Parameter objects: An array of objects to add to the store. public func save(objects: [T]) async where T: Sendable { - await withTaskGroup(of: Void.self, body: { group in - for object in objects { - group.addTask { - await self.save(object) - } - } - }) + for object in objects { + await self.save(object) + } } private func save(_ object: PapyrusEncodingWrapper, filename: String) { @@ -161,6 +157,7 @@ public struct PapyrusStore: Sendable { let data = try self.encoder.encode(object) let url = self.fileURL(for: object.typeDescription, filename: filename) try data.write(to: url) + try self.fileManager.setAttributes([.modificationDate: Date.now], ofItemAtPath: url.path) self.logger.debug("Saved: \(object.typeDescription) [Filename: \(filename)]") } catch { self.logger.fault("Failed to save: \(error)") @@ -277,7 +274,6 @@ public struct PapyrusStore: Sendable { group.addTask { await self.delete(objects: objectsToDelete) } - group.addTask { await self.save(objects: objects) } @@ -308,7 +304,6 @@ public struct PapyrusStore: Sendable { group.addTask { await self.delete(objects: objectsToDelete) } - group.addTask { await self.save(objects: objects) } diff --git a/Sources/Papyrus/Queries/CollectionQuery.swift b/Sources/Papyrus/Queries/CollectionQuery.swift index 7b12e22..e1be5d7 100644 --- a/Sources/Papyrus/Queries/CollectionQuery.swift +++ b/Sources/Papyrus/Queries/CollectionQuery.swift @@ -1,4 +1,3 @@ -import Combine import Foundation /// `PapyrusStore.CollectionQuery` is a mechanism for querying `Papyrus` objects. @@ -21,28 +20,33 @@ public class CollectionQuery where T: Papyrus { } // MARK: API - + /// Executes the query. If filter or sort parameters are /// set, they will be applied to the results. /// - Returns: The results of the query. public func execute() async -> [T] { - guard let directoryNames = try? self.fileManager.contentsOfDirectory(atPath: self.directoryURL.path) else { return [] } + guard let filenames = try? self.fileManager.contentsOfDirectory(atPath: self.directoryURL.path) + else { return [] } + + var results: [(Date, T)] = [] + for filename in filenames { + let url = self.directoryURL.appendingPathComponent(filename) + do { + let data = try Data(contentsOf: url) + let model = try decoder.decode(T.self, from: data) + let modifiedDate = try self.fileManager.attributesOfItem( + atPath: url.path + )[.modificationDate] as? Date ?? .now + results.append((modifiedDate, model)) + } catch { + continue + } + } do { - return try directoryNames - .map { self.directoryURL.appendingPathComponent($0) } - .compactMap { - do - { - let data = try Data(contentsOf: $0) - return try decoder.decode(T.self, from: data) - } - catch - { - // TODO: Log error. - return nil - } - } + return try results + .sorted { $0.0 < $1.0 } + .map(\.1) .filter(self.filter) .sorted(by: self.sort) } catch { diff --git a/Tests/PapyrusTests/CollectionQueryTests.swift b/Tests/PapyrusTests/CollectionQueryTests.swift index 8fac7e5..a091c02 100644 --- a/Tests/PapyrusTests/CollectionQueryTests.swift +++ b/Tests/PapyrusTests/CollectionQueryTests.swift @@ -26,14 +26,15 @@ final class CollectionQueryTests: XCTestCase { // MARK: Tests - func testFetchingAll() async throws { + func test_fetchingAll() async throws { let query = CollectionQuery(directoryURL: self.storeDirectory) - let results = await query.execute().count + let results = await query.execute() - XCTAssertEqual(results, self.numberOfDummyObjects) + XCTAssertEqual(results.count, self.numberOfDummyObjects) + XCTAssertEqual(results.map(\.integerValue), [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) } - func testFiltering() async throws { + func test_filter() async throws { let query = CollectionQuery(directoryURL: self.storeDirectory) .filter { $0.integerValue > 5 } let results = await query.execute().count @@ -41,7 +42,7 @@ final class CollectionQueryTests: XCTestCase { XCTAssertEqual(results, 5) } - func testSorting() async throws { + func test_sort() async throws { let query = CollectionQuery(directoryURL: self.storeDirectory) .sort { $0.integerValue > $1.integerValue } let results = await query.execute() @@ -49,7 +50,7 @@ final class CollectionQueryTests: XCTestCase { XCTAssertEqual(results.first?.integerValue, 10) } - func testFiltersAppliedToObserverPublisher() async throws { + func test_filter_whenAppliedToStream() async throws { let collection = try await CollectionQuery(directoryURL: self.storeDirectory) .filter { $0.integerValue > 5 } .stream() @@ -58,7 +59,7 @@ final class CollectionQueryTests: XCTestCase { XCTAssertEqual(collection?.count, 5) } - func testSortAppliedToStream() async throws { + func test_sort_whenAppliedToStream() async throws { let collection = try await CollectionQuery(directoryURL: self.storeDirectory) .sort { $0.integerValue > $1.integerValue } .stream()