Skip to content

Commit

Permalink
Deprecations and core data stores customization (#19)
Browse files Browse the repository at this point in the history
  • Loading branch information
omaralbeik authored Nov 8, 2022
1 parent 55941bf commit 505db9d
Show file tree
Hide file tree
Showing 17 changed files with 300 additions and 105 deletions.
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,10 @@ Stores comes pre-equipped with the following stores:

```swift
// Store for multiple objects
let store = MultiUserDefaultsStore<User>(identifier: "users")
let store = MultiUserDefaultsStore<User>(suiteName: "users")

// Store for a single object
let store = SingleUserDefaultsStore<User>(identifier: "users")
let store = SingleUserDefaultsStore<User>(suiteName: "users")
```
</details>
</li>
Expand All @@ -87,10 +87,10 @@ let store = SingleUserDefaultsStore<User>(identifier: "users")

```swift
// Store for multiple objects
let store = MultiFileSystemStore<User>(identifier: "users")
let store = MultiFileSystemStore<User>(path: "users")

// Store for a single object
let store = SingleFileSystemStore<User>(identifier: "users")
let store = SingleFileSystemStore<User>(path: "users")
```
</details>
</li>
Expand All @@ -101,10 +101,10 @@ let store = SingleFileSystemStore<User>(identifier: "users")

```swift
// Store for multiple objects
let store = MultiCoreDataStore<User>(identifier: "users")
let store = MultiCoreDataStore<User>(databaseName: "users")

// Store for a single object
let store = SingleCoreDataStore<User>(identifier: "users")
let store = SingleCoreDataStore<User>(databaseName: "users")
```
</details>
</li>
Expand Down
9 changes: 6 additions & 3 deletions Sources/CoreData/Database.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,21 @@
import CoreData
import Foundation

private final class Container: NSPersistentContainer {
final class Container: NSPersistentContainer {
override class func defaultDirectoryURL() -> URL {
super.defaultDirectoryURL().appendingPathComponent("CoreDataStore")
}

required init(name: String) {
super.init(name: name, managedObjectModel: Database.entityModel)
}
}

final class Database {
let context: NSManagedObjectContext
private(set) var url: URL?

init(name: String) {
let container = Container(name: name, managedObjectModel: Self.entityModel)
init(name: String, container: NSPersistentContainer) {
context = container.viewContext
container.loadPersistentStores { description, error in
if let error = error {
Expand Down
14 changes: 12 additions & 2 deletions Sources/CoreData/MultiCoreDataStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,22 @@ public final class MultiCoreDataStore<
/// doing this might cause stores to have corrupted data.
///
/// - Parameter databaseName: store's database name.
/// - Parameter containerProvider: Optional closure that can be used to provide a custom
/// provider for the given entity model. Defaults to `nil` which uses the default container.
///
/// > Important: If you decided to use a custom container, do not forget to set containers's
/// `managedObjectModel` to the provided model.
///
/// > Note: Creating a store is a fairly cheap operation, you can create multiple instances of the same store
/// with a same database name.
public init(databaseName: String) {
public init(
databaseName: String,
containerProvider: ((NSManagedObjectModel) -> NSPersistentContainer)? = nil
) {
self.databaseName = databaseName
database = .init(name: databaseName)
let container = containerProvider?(Database.entityModel)
?? Container(name: databaseName)
database = .init(name: databaseName, container: container)
}

/// URL for where the core data SQLite database is stored.
Expand Down
14 changes: 12 additions & 2 deletions Sources/CoreData/SingleCoreDataStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,22 @@ public final class SingleCoreDataStore<Object: Codable>: SingleObjectStore {
/// doing this might cause stores to have corrupted data.
///
/// - Parameter databaseName: store's database name.
/// - Parameter containerProvider: Optional closure that can be used to provide a custom
/// provider for the given entity model. Defaults to `nil` which uses the default container.
///
/// > Important: If you decided to use a custom container, do not forget to set containers's
/// `managedObjectModel` to the provided model.
///
/// > Note: Creating a store is a fairly cheap operation, you can create multiple instances of the same store
/// with a same database name.
public init(databaseName: String) {
public init(
databaseName: String,
containerProvider: ((NSManagedObjectModel) -> NSPersistentContainer)? = nil
) {
self.databaseName = databaseName
database = .init(name: databaseName)
let container = containerProvider?(Database.entityModel)
?? Container(name: databaseName)
database = .init(name: databaseName, container: container)
}

/// URL for where the core data SQLite database is stored.
Expand Down
50 changes: 37 additions & 13 deletions Sources/FileSystem/MultiFileSystemStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,32 +15,56 @@ public final class MultiFileSystemStore<
let lock = NSRecursiveLock()
let logger = Logger()

/// Store's unique identifier.
///
/// > Important: Never use the same identifier for multiple stores with different object types,
/// doing this might cause stores to have corrupted data.
public let identifier: String

/// Directory where the store folder is created.
public let directory: FileManager.SearchPathDirectory

/// Initialize store with given identifier.
/// Store's path.
///
/// > Note: This is used to create the directory where files are saved:
/// >
/// > `{directory}/Stores/MultiObjects/{path}/{ID}.json`
///
/// > Important: Never use the same path for multiple stores with different object types,
/// doing this might cause stores to have corrupted data.
public let path: String

/// Initialize store with given directory and path.
///
/// > Important: Never use the same identifier for multiple stores with different object types,
/// > Important: Never use the same path for multiple stores with different object types,
/// doing this might cause stores to have corrupted data.
///
/// - Parameter identifier: store's unique identifier.
/// - Parameter directory: directory where the store folder is created.
/// Defaults to `.applicationSupportDirectory`
/// - Parameter path: store's path.
///
/// > Note: Creating a store is a fairly cheap operation, you can create multiple instances of the same store
/// with a same identifier and directory.
/// > Note: Directory and path are used to create the directory where files are saved:
/// >
/// > `{directory}/Stores/MultiObjects/{path}/{ID}.json`
/// >
/// > Creating a store is a fairly cheap operation, you can create multiple instances of the same store
/// with a same directory and path.
public required init(
directory: FileManager.SearchPathDirectory = .applicationSupportDirectory,
path: String
) {
self.directory = directory
self.path = path
}

// MARK: - Deprecated

/// Deprecated: Store's unique identifier.
@available(*, deprecated, renamed: "path")
public var identifier: String { path }

/// Deprecated: Initialize store with given identifier and directory.
@available(*, deprecated, renamed: "init(directory:path:)")
public required init(
identifier: String,
directory: FileManager.SearchPathDirectory = .applicationSupportDirectory
) {
self.identifier = identifier
self.directory = directory
self.path = identifier
}

// MARK: - MultiObjectStore
Expand Down Expand Up @@ -203,7 +227,7 @@ extension MultiFileSystemStore {
)
.appendingPathComponent("Stores", isDirectory: true)
.appendingPathComponent("MultiObjects", isDirectory: true)
.appendingPathComponent(identifier, isDirectory: true)
.appendingPathComponent(path, isDirectory: true)
if manager.fileExists(atPath: url.path) == false {
try manager.createDirectory(
atPath: url.path,
Expand Down
50 changes: 37 additions & 13 deletions Sources/FileSystem/SingleFileSystemStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,32 +13,56 @@ public final class SingleFileSystemStore<Object: Codable>: SingleObjectStore {
let lock = NSRecursiveLock()
let logger = Logger()

/// Store's unique identifier.
///
/// > Important: Never use the same identifier for multiple stores with different object types,
/// doing this might cause stores to have corrupted data.
public let identifier: String

/// Directory where the store folder is created.
public let directory: FileManager.SearchPathDirectory

/// Initialize store with given identifier.
/// Store's path.
///
/// > Note: This is used to create the directory where the file is saved:
/// >
/// > `{directory}/Stores/SingleObject/{path}/object.json`
///
/// > Important: Never use the same path for multiple stores with different object types,
/// doing this might cause stores to have corrupted data.
public let path: String

/// Initialize store with given directory and path.
///
/// > Important: Never use the same identifier for multiple stores with different object types,
/// > Important: Never use the same path for multiple stores with different object types,
/// doing this might cause stores to have corrupted data.
///
/// - Parameter identifier: store's unique identifier.
/// - Parameter directory: directory where the store folder is created.
/// Defaults to `.applicationSupportDirectory`
/// - Parameter path: store's path.
///
/// > Note: Creating a store is a fairly cheap operation, you can create multiple instances of the same store
/// with a same identifier and directory.
/// > Note: Directory and path are used to create the directory where the file is saved:
/// >
/// > `{directory}/Stores/SingleObject/{path}/object.json`
/// >
/// > Creating a store is a fairly cheap operation, you can create multiple instances of the same store
/// with a same directory and path.
public required init(
directory: FileManager.SearchPathDirectory = .applicationSupportDirectory,
path: String
) {
self.directory = directory
self.path = path
}

// MARK: - Deprecated

/// Deprecated: Store's unique identifier.
@available(*, deprecated, renamed: "name")
public var identifier: String { path }

/// Deprecated: Initialize store with given identifier and directory.
@available(*, deprecated, renamed: "init(directory:name:)")
public required init(
identifier: String,
directory: FileManager.SearchPathDirectory = .applicationSupportDirectory
) {
self.identifier = identifier
self.directory = directory
self.path = identifier
}

// MARK: - SingleObjectStore
Expand Down Expand Up @@ -100,7 +124,7 @@ extension SingleFileSystemStore {
)
.appendingPathComponent("Stores", isDirectory: true)
.appendingPathComponent("SingleObject", isDirectory: true)
.appendingPathComponent(identifier, isDirectory: true)
.appendingPathComponent(path, isDirectory: true)
if manager.fileExists(atPath: url.path) == false {
try manager.createDirectory(
atPath: url.path,
Expand Down
10 changes: 10 additions & 0 deletions Sources/Keychain/MultiKeychainStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ public final class MultiKeychainStore<

/// Store's unique identifier.
///
/// Note: This is used to create the underlying service name `kSecAttrService` where objects are
/// stored.
///
/// `com.omaralbeik.stores.multi.{identifier}`
///
/// > Important: Never use the same identifier for multiple stores with different object types,
/// doing this might cause stores to have corrupted data.
public let identifier: String
Expand All @@ -28,6 +33,11 @@ public final class MultiKeychainStore<

/// Initialize store.
///
/// Note: This is used to create the underlying service name `kSecAttrService` where objects are
/// stored.
///
/// `com.omaralbeik.stores.multi.{identifier}`
///
/// > Important: Never use the same identifier for multiple stores with different object types,
/// doing this might cause stores to have corrupted data.
///
Expand Down
10 changes: 10 additions & 0 deletions Sources/Keychain/SingleKeychainStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ public final class SingleKeychainStore<Object: Codable>: SingleObjectStore {

/// Store's unique identifier.
///
/// Note: This is used to create the underlying service name `kSecAttrService` where the object is
/// stored.
///
/// `com.omaralbeik.stores.single.{identifier}`
///
/// > Important: Never use the same identifier for multiple stores with different object types,
/// doing this might cause stores to have corrupted data.
public let identifier: String
Expand All @@ -26,6 +31,11 @@ public final class SingleKeychainStore<Object: Codable>: SingleObjectStore {

/// Initialize store.
///
/// Note: This is used to create the underlying service name `kSecAttrService` where the object is
/// stored.
///
/// `com.omaralbeik.stores.single.{identifier}`
///
/// > Important: Never use the same identifier for multiple stores with different object types,
/// doing this might cause stores to have corrupted data.
///
Expand Down
Loading

0 comments on commit 505db9d

Please sign in to comment.