swift-libs/Tests/Persistence/Helpers/TestPersistenceService.swift
Javier Cicchelli c0a49b2a85 [Feature] Persistence (#5)
This PR contains the work done to implement some useful protocols, classes and extensions to use to setup a persistence layer in an application.

To provide further details about the work done:
 - [x] declared the `Persistence` target in the Package file;
 - [x] forgot to declare the `Communications` and `Persistence` target to the `SwiftLibs` library in the `Package` file;
 - [x] defined the `Service` public protocol;
 - [x] implemented the `Fetcher` generic class;
 - [x] implemented the `bitBucket` static property in the `URL+Devices` public extension;
 - [x] updated the `README` file.

Co-authored-by: Javier Cicchelli <javier@rock-n-code.com>
Reviewed-on: #5
2023-04-17 23:12:11 +00:00

128 lines
3.0 KiB
Swift

//
// TestPersistenceService.swift
// PersistenceTests
//
// Created by Javier Cicchelli on 17/04/2023.
// Copyright © 2023 Röck+Cöde. All rights reserved.
//
import CoreData
import Persistence
struct TestPersistenceService {
// MARK: Properties
static let shared = TestPersistenceService()
private let container: NSPersistentContainer
var viewContext: NSManagedObjectContext {
container.viewContext
}
// MARK: Initialisers
init() {
guard
let modelURL = Bundle.module.url(forResource: .Model.name, withExtension: .Model.extension),
let managedObjectModel = NSManagedObjectModel(contentsOf: modelURL)
else {
fatalError("Could not load the Core Data model from the module.")
}
self.container = .init(
name: .Model.name,
managedObjectModel: managedObjectModel
)
setContainer()
}
}
// MARK: - Service
extension TestPersistenceService: Service {
// MARK: Functions
func makeTaskContext() -> NSManagedObjectContext {
let taskContext = container.newBackgroundContext()
taskContext.automaticallyMergesChangesFromParent = true
taskContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
return taskContext
}
func makeChildContext() -> NSManagedObjectContext {
let context = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
context.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
context.parent = container.viewContext
context.automaticallyMergesChangesFromParent = true
return context
}
func save(context: NSManagedObjectContext) throws {
guard context.hasChanges else {
return
}
try context.save()
}
func save(childContext context: NSManagedObjectContext) throws {
guard context.hasChanges else {
return
}
try context.save()
guard
let parent = context.parent,
parent == container.viewContext
else {
return
}
try parent.performAndWait {
try parent.save()
}
}
}
// MARK: - Helpers
private extension TestPersistenceService {
// MARK: Functions
func setContainer() {
container.persistentStoreDescriptions = [
.init(url: .bitBucket)
]
container.loadPersistentStores { _, error in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
}
container.viewContext.automaticallyMergesChangesFromParent = false
}
}
// MARK: - String+Constants
private extension String {
enum Model {
static let name = "TestModel"
static let `extension` = "momd"
}
}