<commit_before>///
///  GenericCoreDataStack.swift
///
///  Copyright 2016 <NAME>
///
///  Licensed under the Apache License, Version 2.0 (the "License");
///  you may not use this file except in compliance with the License.
///  You may obtain a copy of the License at
///
///  http://www.apache.org/licenses/LICENSE-2.0
///
///  Unless required by applicable law or agreed to in writing, software
///  distributed under the License is distributed on an "AS IS" BASIS,
///  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
///  See the License for the specific language governing permissions and
///  limitations under the License.
///
///  Created by <NAME> on 1/6/16.
///
import Foundation
import CoreData
import TraceLog

///
/// The name of the default configuration in the model.  If you have not
/// created any configurations, this will be the only configuration avaialble.
///
/// Use this name if you override the options passed.
///
public let defaultModelConfigurationName: String = "PF_DEFAULT_CONFIGURATION_NAME"

///
/// An option – when set to true – will check if the persistent store and the model are incompatible.
/// If so, the underlying persistent store will be removed and replaced.
///
public let overwriteIncompatibleStoreOption: String = "overwriteIncompatibleStoreOption"

///
/// Default options passed to attached and configure the persistent stores.
///
public let defaultStoreOptions: [AnyHashable: Any] = [
    NSMigratePersistentStoresAutomaticallyOption    : true,
    NSInferMappingModelAutomaticallyOption          : true
]

///
/// If no storeType is passed in, this store type will be used
///
public let defaultStoreType = NSSQLiteStoreType

///
/// PersistentStore configuration settings.
///
public typealias PersistentStoreConfiguration = (storeType: String, storeOptions: [AnyHashable: Any]?, migrationManager: NSMigrationManager?)

///
/// Configuration options dictionary keyed by configuration name.
/// The name is the name you listed in your model.
///
public typealias ConfigurationOptionsType = [String : PersistentStoreConfiguration]

///
/// The detault configuration options used to configure the persistent store when no override is supplied.
///
public let defaultConfigurationOptions: ConfigurationOptionsType = [defaultModelConfigurationName : (storeType: defaultStoreType, storeOptions: defaultStoreOptions, migrationManager: nil)]

///
/// There are activities that the CoreDataStack will do asyncrhonously as a result of various events.  GenericCoreDataStack currently
/// logs those events, if you would like to handle them yourself, you can set an error block which will be called to allow you to take
/// an alternate action.
///
public typealias asynErrorHandlerBlock = (NSError) -> Void

///
///    A Core Data stack that can be customized with specific NSPersistentStoreCoordinator and a NSManagedObjectContext Context type.
///
open class GenericCoreDataStack<CoordinatorType: NSPersistentStoreCoordinator, ContextType: NSManagedObjectContext>: CoreDataStack {

    /// 
    /// The model this `GenericCoreDataStack` was constructed with.
    ///
    public let managedObjectModel: NSManagedObjectModel

    ///
    /// Returns the `NSPersistentStoreCoordinate` instance that
    /// this `GenericCoreDataStack` contains.  It's type will
    /// be `CoordinatorType` which was given as a generic
    /// parameter during construction.
    ///
    public let persistentStoreCoordinator: CoordinatorType

    ///
    /// The main context.
    ///
    /// This context should be used for read operations only.  Use it for all fetches and NSFechtedResultsControllers.
    ///
    /// It will be maintained automatically and be kept consistent.
    ///
    /// - Warning: You should only use this context on the main thread.  If you must work on a background thread, use the method `edittContext` while on the thread.  See that method for more details
    ///
    public let mainContext: ContextType

    ///
    /// Gets a new NSManagedObjectContext that can be used for updating objects.
    ///
    /// At save time, resource manager will merge those changes back to the mainManagedObjectContext.
    ///
    /// - Note: This method and the returned NSManagedObjectContext can be used on a background thread as long as you get the context while on that thread.  It can also be used on the main thread if gotten while on the main thread.
    ///
    public var editContext: ContextType {

        logInfo(tag) { "Creating edit context for \(Thread.current)..." }

        let context = ContextType(concurrencyType: NSManagedObjectContextConcurrencyType.privateQueueConcurrencyType)
        context.persistentStoreCoordinator = self.persistentStoreCoordinator

        logInfo(tag) { "Edit context created." }

        return context
    }

    fileprivate let rootContext: NSManagedObjectContext
    fileprivate let tag: String
    fileprivate let errorHandlerBlock: (_ error: NSError) -> Void

    ///
    ///  Initializes the receiver with a managed object model.
    ///
    ///   - parameters:
    ///      - managedObjectModel: A managed object model.
    ///      - storeNamePrefix: A String which is appended to the beginning of the persistent store's name.
    ///      - configurationOptions: Optional configuration settings by persistent store config name (see ConfigurationOptionsType for structure)
    ///      - logTag: An optional String that will be used as the tag for logging (default is GenericCoreDataStack).  This is typically used if you are embedding GenericCoreDataStack in something else and you want to to log as your class.
    ///
    public convenience init(managedObjectModel model: NSManagedObjectModel, storeNamePrefix: String, configurationOptions options: ConfigurationOptionsType = defaultConfigurationOptions, asyncErrorBlock: ((_ error: NSError) -> Void)? = nil, logTag tag: String = String(describing: GenericCoreDataStack.self)) throws {
        //
        // Figure out where to put things
        //
        // Note: We use the applications bundle not the classes or modules.
        //
        let baseURL = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)

        try self.init(managedObjectModel: model, storeLocationURL: baseURL, storeNamePrefix: storeNamePrefix, configurationOptions: options, asyncErrorBlock: asyncErrorBlock, logTag: tag)
    }

    ///
    ///  Initializes the receiver with a managed object model.
    ///
    ///   - parameters:
    ///      - managedObjectModel: A managed object model.
    ///      - configurationOptions: Optional configuration settings by persistent store config name (see ConfigurationOptionsType for structure)
    ///      - storeURL: An optional String which is appended to the beginning of the persistent store's name.
    ///      - logTag: An optional String that will be used as the tag for logging (default is GenericCoreDataStack).  This is typically used if you are embedding GenericCoreDataStack in something else and you want to to log as your class.
    ///
    required public init(managedObjectModel model: NSManagedObjectModel, storeLocationURL: URL, storeNamePrefix: String? = nil, configurationOptions options: ConfigurationOptionsType = defaultConfigurationOptions, asyncErrorBlock: ((_ error: NSError) -> Void)? = nil, logTag tag: String = String(describing: GenericCoreDataStack.self)) throws {
        
        self.managedObjectModel = model
        self.tag = tag
        
        if let asyncErrorBlock = asyncErrorBlock {
            self.errorHandlerBlock = asyncErrorBlock
        } else {
            self.errorHandlerBlock = { (error: NSError) -> Void in
                logError { error.localizedDescription }
            }
        }
        
        /// Create the coordinator
        self.persistentStoreCoordinator = CoordinatorType(managedObjectModel: managedObjectModel)

        /// Create teh root context for saving
        self.rootContext = ContextType(concurrencyType: .privateQueueConcurrencyType)
        self.rootContext.persistentStoreCoordinator = self.persistentStoreCoordinator

        /// Now the main thread context
        self.mainContext = ContextType(concurrencyType: .mainQueueConcurrencyType)
        self.mainContext.parent = self.rootContext

        logInfo(tag) { "Store path: \(storeLocationURL)" }
        
        let configurations = managedObjectModel.configurations<commit_msg>Using the AsynErrorHandlerBlock typealias for all references and converted it to use Error instead of NSError.<commit_after>///
///  GenericCoreDataStack.swift
///
///  Copyright 2016 <NAME>
///
///  Licensed under the Apache License, Version 2.0 (the "License");
///  you may not use this file except in compliance with the License.
///  You may obtain a copy of the License at
///
///  http://www.apache.org/licenses/LICENSE-2.0
///
///  Unless required by applicable law or agreed to in writing, software
///  distributed under the License is distributed on an "AS IS" BASIS,
///  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
///  See the License for the specific language governing permissions and
///  limitations under the License.
///
///  Created by T<NAME> on 1/6/16.
///
import Foundation
import CoreData
import TraceLog

///
/// The name of the default configuration in the model.  If you have not
/// created any configurations, this will be the only configuration avaialble.
///
/// Use this name if you override the options passed.
///
public let defaultModelConfigurationName: String = "PF_DEFAULT_CONFIGURATION_NAME"

///
/// An option – when set to true – will check if the persistent store and the model are incompatible.
/// If so, the underlying persistent store will be removed and replaced.
///
public let overwriteIncompatibleStoreOption: String = "overwriteIncompatibleStoreOption"

///
/// Default options passed to attached and configure the persistent stores.
///
public let defaultStoreOptions: [AnyHashable: Any] = [
    NSMigratePersistentStoresAutomaticallyOption    : true,
    NSInferMappingModelAutomaticallyOption          : true
]

///
/// If no storeType is passed in, this store type will be used
///
public let defaultStoreType = NSSQLiteStoreType

///
/// PersistentStore configuration settings.
///
public typealias PersistentStoreConfiguration = (storeType: String, storeOptions: [AnyHashable: Any]?, migrationManager: NSMigrationManager?)

///
/// Configuration options dictionary keyed by configuration name.
/// The name is the name you listed in your model.
///
public typealias ConfigurationOptionsType = [String : PersistentStoreConfiguration]

///
/// The detault configuration options used to configure the persistent store when no override is supplied.
///
public let defaultConfigurationOptions: ConfigurationOptionsType = [defaultModelConfigurationName : (storeType: defaultStoreType, storeOptions: defaultStoreOptions, migrationManager: nil)]

///
/// There are activities that the CoreDataStack will do asyncrhonously as a result of various events.  GenericCoreDataStack currently
/// logs those events, if you would like to handle them yourself, you can set an error block which will be called to allow you to take
/// an alternate action.
///
public typealias AsynErrorHandlerBlock = (Error) -> Void

///
///    A Core Data stack that can be customized with specific NSPersistentStoreCoordinator and a NSManagedObjectContext Context type.
///
open class GenericCoreDataStack<CoordinatorType: NSPersistentStoreCoordinator, ContextType: NSManagedObjectContext>: CoreDataStack {

    /// 
    /// The model this `GenericCoreDataStack` was constructed with.
    ///
    public let managedObjectModel: NSManagedObjectModel

    ///
    /// Returns the `NSPersistentStoreCoordinate` instance that
    /// this `GenericCoreDataStack` contains.  It's type will
    /// be `CoordinatorType` which was given as a generic
    /// parameter during construction.
    ///
    public let persistentStoreCoordinator: CoordinatorType

    ///
    /// The main context.
    ///
    /// This context should be used for read operations only.  Use it for all fetches and NSFechtedResultsControllers.
    ///
    /// It will be maintained automatically and be kept consistent.
    ///
    /// - Warning: You should only use this context on the main thread.  If you must work on a background thread, use the method `edittContext` while on the thread.  See that method for more details
    ///
    public let mainContext: ContextType

    ///
    /// Gets a new NSManagedObjectContext that can be used for updating objects.
    ///
    /// At save time, resource manager will merge those changes back to the mainManagedObjectContext.
    ///
    /// - Note: This method and the returned NSManagedObjectContext can be used on a background thread as long as you get the context while on that thread.  It can also be used on the main thread if gotten while on the main thread.
    ///
    public var editContext: ContextType {

        logInfo(tag) { "Creating edit context for \(Thread.current)..." }

        let context = ContextType(concurrencyType: NSManagedObjectContextConcurrencyType.privateQueueConcurrencyType)
        context.persistentStoreCoordinator = self.persistentStoreCoordinator

        logInfo(tag) { "Edit context created." }

        return context
    }

    fileprivate let rootContext: NSManagedObjectContext
    fileprivate let tag: String
    fileprivate let errorHandlerBlock: AsynErrorHandlerBlock

    ///
    ///  Initializes the receiver with a managed object model.
    ///
    ///   - parameters:
    ///      - managedObjectModel: A managed object model.
    ///      - storeNamePrefix: A String which is appended to the beginning of the persistent store's name.
    ///      - configurationOptions: Optional configuration settings by persistent store config name (see ConfigurationOptionsType for structure)
    ///      - logTag: An optional String that will be used as the tag for logging (default is GenericCoreDataStack).  This is typically used if you are embedding GenericCoreDataStack in something else and you want to to log as your class.
    ///
    public convenience init(managedObjectModel model: NSManagedObjectModel, storeNamePrefix: String, configurationOptions options: ConfigurationOptionsType = defaultConfigurationOptions, asyncErrorBlock: AsynErrorHandlerBlock? = nil, logTag tag: String = String(describing: GenericCoreDataStack.self)) throws {
        //
        // Figure out where to put things
        //
        // Note: We use the applications bundle not the classes or modules.
        //
        let baseURL = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)

        try self.init(managedObjectModel: model, storeLocationURL: baseURL, storeNamePrefix: storeNamePrefix, configurationOptions: options, asyncErrorBlock: asyncErrorBlock, logTag: tag)
    }

    ///
    ///  Initializes the receiver with a managed object model.
    ///
    ///   - parameters:
    ///      - managedObjectModel: A managed object model.
    ///      - configurationOptions: Optional configuration settings by persistent store config name (see ConfigurationOptionsType for structure)
    ///      - storeURL: An optional String which is appended to the beginning of the persistent store's name.
    ///      - logTag: An optional String that will be used as the tag for logging (default is GenericCoreDataStack).  This is typically used if you are embedding GenericCoreDataStack in something else and you want to to log as your class.
    ///
    required public init(managedObjectModel model: NSManagedObjectModel, storeLocationURL: URL, storeNamePrefix: String? = nil, configurationOptions options: ConfigurationOptionsType = defaultConfigurationOptions, asyncErrorBlock: AsynErrorHandlerBlock? = nil, logTag tag: String = String(describing: GenericCoreDataStack.self)) throws {
        
        self.managedObjectModel = model
        self.tag = tag
        
        if let asyncErrorBlock = asyncErrorBlock {
            self.errorHandlerBlock = asyncErrorBlock
        } else {
            self.errorHandlerBlock = { (error: Error) -> Void in
                logError { "\(error)" }
            }
        }
        
        /// Create the coordinator
        self.persistentStoreCoordinator = CoordinatorType(managedObjectModel: managedObjectModel)

        /// Create teh root context for saving
        self.rootContext = ContextType(concurrencyType: .privateQueueConcurrencyType)
        self.rootContext.persistentStoreCoordinator = self.persistentStoreCoordinator

        /// Now the main thread context
        self.mainContext = ContextType(concurrencyType: .mainQueueConcurrencyType)
        self.mainContext.parent = self.rootContext

        logInfo(tag) { "Store path: \(storeLocationURL)" }
        
        let configurations = managedObjectModel.configurations
{'fraction_non_alphanumeric': 0.07938465151782044, 'fraction_numerical': 0.0014091949973577594, 'mean_word_length': 3.1339805825242717, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 16, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '918640', 'n_tokens_mistral': 4100, 'n_tokens_neox': 4014, 'n_words': 1680}