diff --git a/Sources/CodableDatastore/Persistence/Disk Persistence/Datastore/DatastoreIndex.swift b/Sources/CodableDatastore/Persistence/Disk Persistence/Datastore/DatastoreIndex.swift index cf81e20..cdb2746 100644 --- a/Sources/CodableDatastore/Persistence/Disk Persistence/Datastore/DatastoreIndex.swift +++ b/Sources/CodableDatastore/Persistence/Disk Persistence/Datastore/DatastoreIndex.swift @@ -67,20 +67,35 @@ extension DiskPersistence.Datastore.Index { case direct(index: DatastoreIndexIdentifier, manifest: DatastoreIndexManifestIdentifier) case secondary(index: DatastoreIndexIdentifier, manifest: DatastoreIndexManifestIdentifier) + var indexID: DatastoreRootManifest.IndexID { + switch self { + case .primary(_): .primary + case .direct(let id, _): .direct(index: id) + case .secondary(let id, _): .secondary(index: id) + } + } + var manifestID: DatastoreIndexManifestIdentifier { switch self { - case .primary(let id), - .direct(_, let id), - .secondary(_, let id): - return id + case .primary(let id): id + case .direct(_, let id): id + case .secondary(_, let id): id } } func with(manifestID: DatastoreIndexManifestIdentifier) -> Self { switch self { - case .primary: return .primary(manifest: manifestID) - case .direct(let indexID, _): return .direct(index: indexID, manifest: manifestID) - case .secondary(let indexID, _): return .secondary(index: indexID, manifest: manifestID) + case .primary: .primary(manifest: manifestID) + case .direct(let indexID, _): .direct(index: indexID, manifest: manifestID) + case .secondary(let indexID, _): .secondary(index: indexID, manifest: manifestID) + } + } + + init(_ id: DatastoreRootManifest.IndexManifestID) { + switch id { + case .primary(let manifest): self = .primary(manifest: manifest) + case .direct(let index, let manifest): self = .direct(index: index, manifest: manifest) + case .secondary(let index, let manifest): self = .secondary(index: index, manifest: manifest) } } } @@ -91,9 +106,7 @@ extension DiskPersistence.Datastore.Index { extension DiskPersistence.Datastore.Index { /// The URL that points to the manifest. nonisolated var manifestURL: URL { - datastore - .manifestsURL(for: id) - .appendingPathComponent("\(id.manifestID).indexmanifest", isDirectory: false) + datastore.manifestURL(for: id) } } @@ -129,7 +142,7 @@ extension DiskPersistence.Datastore.Index { } /// Make sure the directories exists first. - try FileManager.default.createDirectory(at: datastore.manifestsURL(for: id), withIntermediateDirectories: true) + try FileManager.default.createDirectory(at: datastore.manifestsURL(for: id.indexID), withIntermediateDirectories: true) /// Encode the provided manifest, and write it to disk. let data = Data(manifest.bytes) diff --git a/Sources/CodableDatastore/Persistence/Disk Persistence/Datastore/DatastorePage.swift b/Sources/CodableDatastore/Persistence/Disk Persistence/Datastore/DatastorePage.swift index 22ca051..869cb0a 100644 --- a/Sources/CodableDatastore/Persistence/Disk Persistence/Datastore/DatastorePage.swift +++ b/Sources/CodableDatastore/Persistence/Disk Persistence/Datastore/DatastorePage.swift @@ -78,15 +78,7 @@ extension DiskPersistence.Datastore.Page { extension DiskPersistence.Datastore.Page { /// The URL that points to the page. nonisolated var pageURL: URL { - let baseURL = datastore.pagesURL(for: id.index) - - guard let components = try? id.page.components else { preconditionFailure("Components could not be determined for Page.") } - - return baseURL - .appendingPathComponent(components.year, isDirectory: true) - .appendingPathComponent(components.monthDay, isDirectory: true) - .appendingPathComponent(components.hourMinute, isDirectory: true) - .appendingPathComponent("\(id.page).datastorepage", isDirectory: false) + datastore.pageURL(for: id) } } diff --git a/Sources/CodableDatastore/Persistence/Disk Persistence/Datastore/DatastoreRoot.swift b/Sources/CodableDatastore/Persistence/Disk Persistence/Datastore/DatastoreRoot.swift index a283a3f..76f0cc8 100644 --- a/Sources/CodableDatastore/Persistence/Disk Persistence/Datastore/DatastoreRoot.swift +++ b/Sources/CodableDatastore/Persistence/Disk Persistence/Datastore/DatastoreRoot.swift @@ -56,7 +56,7 @@ extension DiskPersistence.Datastore.RootObject: Hashable { extension DiskPersistence.Datastore.RootObject { /// The URL that points to the root object on disk. nonisolated var rootObjectURL: URL { - datastore.rootURL.appendingPathComponent("\(id).json", isDirectory: false) + datastore.rootURL(for: id) } } diff --git a/Sources/CodableDatastore/Persistence/Disk Persistence/Datastore/DatastoreRootManifest.swift b/Sources/CodableDatastore/Persistence/Disk Persistence/Datastore/DatastoreRootManifest.swift index 9b9c068..4a0a799 100644 --- a/Sources/CodableDatastore/Persistence/Disk Persistence/Datastore/DatastoreRootManifest.swift +++ b/Sources/CodableDatastore/Persistence/Disk Persistence/Datastore/DatastoreRootManifest.swift @@ -83,5 +83,21 @@ extension DatastoreRootManifest { self = .secondary(index: index, manifest: manifest) } } + + var indexID: DatastoreRootManifest.IndexID { + switch self { + case .primary(_): .primary + case .direct(let id, _): .direct(index: id) + case .secondary(let id, _): .secondary(index: id) + } + } + + var manifestID: DatastoreIndexManifestIdentifier { + switch self { + case .primary(let id): id + case .direct(_, let id): id + case .secondary(_, let id): id + } + } } } diff --git a/Sources/CodableDatastore/Persistence/Disk Persistence/Datastore/PersistenceDatastore.swift b/Sources/CodableDatastore/Persistence/Disk Persistence/Datastore/PersistenceDatastore.swift index 9bb3be8..f1ac416 100644 --- a/Sources/CodableDatastore/Persistence/Disk Persistence/Datastore/PersistenceDatastore.swift +++ b/Sources/CodableDatastore/Persistence/Disk Persistence/Datastore/PersistenceDatastore.swift @@ -57,9 +57,7 @@ extension DiskPersistence { extension DiskPersistence.Datastore { /// The URL that points to the Datastore directory. nonisolated var datastoreURL: URL { - snapshot - .datastoresURL - .appendingPathComponent("\(id).datastore", isDirectory: true) + snapshot.datastoreURL(for: id) } /// The URL that points to the Root directory. @@ -68,40 +66,62 @@ extension DiskPersistence.Datastore { .appendingPathComponent("Root", isDirectory: true) } + /// The URL for the specified root. + nonisolated func rootURL(for id: DatastoreRootIdentifier) -> URL { + rootURL.appendingPathComponent("\(id).json", isDirectory: false) + } + /// The URL that points to the DirectIndexes directory. nonisolated var directIndexesURL: URL { - datastoreURL - .appendingPathComponent("DirectIndexes", isDirectory: true) + datastoreURL.appendingPathComponent("DirectIndexes", isDirectory: true) } /// The URL that points to the SecondaryIndexes directory. nonisolated var secondaryIndexesURL: URL { - datastoreURL - .appendingPathComponent("SecondaryIndexes", isDirectory: true) + datastoreURL.appendingPathComponent("SecondaryIndexes", isDirectory: true) } - nonisolated func indexURL(for indexID: Index.ID) -> URL { + /// The root URL of a partifular index directory. + nonisolated func indexURL(for indexID: DatastoreRootManifest.IndexID) -> URL { switch indexID { case .primary: - return directIndexesURL - .appendingPathComponent("Primary.datastoreindex", isDirectory: true) - case .direct(let indexID, _): - return directIndexesURL - .appendingPathComponent("\(indexID).datastoreindex", isDirectory: true) - case .secondary(let indexID, _): - return secondaryIndexesURL - .appendingPathComponent("\(indexID).datastoreindex", isDirectory: true) + directIndexesURL.appendingPathComponent("Primary.datastoreindex", isDirectory: true) + case .direct(let indexID): + directIndexesURL.appendingPathComponent("\(indexID).datastoreindex", isDirectory: true) + case .secondary(let indexID): + secondaryIndexesURL.appendingPathComponent("\(indexID).datastoreindex", isDirectory: true) } } - nonisolated func manifestsURL(for indexID: Index.ID) -> URL { - indexURL(for: indexID) - .appendingPathComponent("Manifest", isDirectory: true) + /// The URL of an index's manifests directory. + nonisolated func manifestsURL(for id: DatastoreRootManifest.IndexID) -> URL { + indexURL(for: id).appendingPathComponent("Manifest", isDirectory: true) + } + + /// The URL of an index's root manifest. + nonisolated func manifestURL(for id: Index.ID) -> URL { + manifestURL(for: DatastoreRootManifest.IndexManifestID(id)) } - nonisolated func pagesURL(for indexID: Index.ID) -> URL { - indexURL(for: indexID) - .appendingPathComponent("Pages", isDirectory: true) + /// The URL of an index's root manifest. + nonisolated func manifestURL(for id: DatastoreRootManifest.IndexManifestID) -> URL { + manifestsURL(for: id.indexID).appendingPathComponent("\(id.manifestID).indexmanifest", isDirectory: false) + } + + /// The URL of an index's pages directory.. + nonisolated func pagesURL(for id: Index.ID) -> URL { + indexURL(for: id.indexID).appendingPathComponent("Pages", isDirectory: true) + } + + /// The URL of a particular page. + nonisolated func pageURL(for id: Page.ID) -> URL { + guard let components = try? id.page.components else { preconditionFailure("Components could not be determined for Page.") } + + return pagesURL(for: id.index) + .appendingPathComponent(components.year, isDirectory: true) + .appendingPathComponent(components.monthDay, isDirectory: true) + .appendingPathComponent(components.hourMinute, isDirectory: true) + .appendingPathComponent("\(id.page).datastorepage", isDirectory: false) } } @@ -198,7 +218,7 @@ extension DiskPersistence.Datastore { extension DiskPersistence.Datastore { /// Load the root object from disk for the given identifier. func loadRootObject(for rootIdentifier: DatastoreRootIdentifier) throws -> DatastoreRootManifest { - let rootObjectURL = rootURL.appendingPathComponent("\(rootIdentifier).json", isDirectory: false) + let rootObjectURL = rootURL(for: rootIdentifier) let data = try Data(contentsOf: rootObjectURL) @@ -218,7 +238,7 @@ extension DiskPersistence.Datastore { try FileManager.default.createDirectory(at: secondaryIndexesURL, withIntermediateDirectories: true) } - let rootObjectURL = rootURL.appendingPathComponent("\(manifest.id).json", isDirectory: false) + let rootObjectURL = rootURL(for: manifest.id) /// Encode the provided manifest, and write it to disk. let data = try JSONEncoder.shared.encode(manifest) diff --git a/Sources/CodableDatastore/Persistence/Disk Persistence/Snapshot/Snapshot.swift b/Sources/CodableDatastore/Persistence/Disk Persistence/Snapshot/Snapshot.swift index 908ee88..15e15dd 100644 --- a/Sources/CodableDatastore/Persistence/Disk Persistence/Snapshot/Snapshot.swift +++ b/Sources/CodableDatastore/Persistence/Disk Persistence/Snapshot/Snapshot.swift @@ -95,6 +95,11 @@ extension Snapshot { snapshotURL.appendingPathComponent("Datastores", isDirectory: true) } + /// The URL for a specific datastore within the snapshot. + nonisolated func datastoreURL(for id: DatastoreIdentifier) -> URL { + datastoresURL.appendingPathComponent("\(id).datastore", isDirectory: true) + } + /// The URL that points to the Inbox directory. nonisolated var inboxURL: URL { snapshotURL.appendingPathComponent("Inbox", isDirectory: true) @@ -316,13 +321,11 @@ private enum SnapshotTaskLocals { extension Snapshot { /// Load the datastore for the given key. func loadDatastore(for key: DatastoreKey, from iteration: SnapshotIteration) -> (DiskPersistence.Datastore, DatastoreRootIdentifier?) { - let datastoreInfo: (id: DatastoreIdentifier, root: DatastoreRootIdentifier?) = { - if let info = iteration.dataStores[key] { - return (info.id, info.root) - } else { - return (DatastoreIdentifier(name: key.rawValue), nil) - } - }() + let datastoreInfo = if let info = iteration.dataStores[key] { + (id: info.id, root: info.root) + } else { + (id: DatastoreIdentifier(name: key.rawValue), root: DatastoreRootIdentifier?.none) + } if let datastore = datastores[datastoreInfo.id] { return (datastore, datastoreInfo.root)