<commit_before>//
//  CoreDataManager.swift
//  MBLibrary
//
//  Created by <NAME> on 23/08/2018.
//  Part of code are from <NAME> tutorials at http://kean.github.io/post/core-data-progressive-migrations and https://gist.github.com/kean/28439b29532993b620497621a4545789
//  Copyright © 2018 <NAME>. All rights reserved.
//

import Foundation
import CoreData

public enum MBCoreDataError: Error {
	case incompatibleModels
	case notAStore
}

public class CoreDataManager {

	private let storeType = NSSQLiteStoreType
	private let storeURL: URL
	private let moms: [NSManagedObjectModel]
	private let mappingBundles: [Bundle]
	
	public init(store url: URL, withModelHistory moms: [NSManagedObjectModel], mappingBundles: [Bundle]? = nil) {
		precondition(!moms.isEmpty, "You cannot use CoreData without a Managed Object Model")
		
		self.storeURL = url
		self.moms = moms
		self.mappingBundles = mappingBundles ?? Bundle.allBundles + Bundle.allFrameworks
	}
	
	/// Migrate the store to the latest model if necessary and loads it in a new persistent store coordinator.
	/// - returns: The new persistent store coordinator for the store.
	public func getStoreCoordinator() throws -> NSPersistentStoreCoordinator {
		do {
			try migrateStore()
		} catch MBCoreDataError.notAStore {
			try FileManager.default.removeItem(at: storeURL)
		}
		
		let coordinator = NSPersistentStoreCoordinator(managedObjectModel: moms.last!)
		try coordinator.addPersistentStore(ofType: storeType, configurationName: nil, at: storeURL)
		
		return coordinator
	}
	
	private func migrateStore() throws {
		let idx = try indexOfCompatibleMom(at: storeURL, moms: moms)
		let remaining = moms.suffix(from: (idx + 1))
		guard remaining.count > 0 else {
			// The store already uses the latest model
			return
		}
		
		_ = try remaining.reduce(moms[idx]) { sMom, dMom in
			try migrateStore(from: sMom, to: dMom)
			
			return dMom
		}
	}
	
	private func indexOfCompatibleMom(at storeURL: URL, moms: [NSManagedObjectModel]) throws -> Int {
		do {
			let meta = try NSPersistentStoreCoordinator.metadataForPersistentStore(ofType: storeType, at: storeURL)
			<commit_msg>- Don't attempt to remove a file if it doesn't exists<commit_after>//
//  CoreDataManager.swift
//  MBLibrary
//
//  Created by <NAME> on 23/08/2018.
//  Part of code are from <NAME> tutorials at http://kean.github.io/post/core-data-progressive-migrations and https://gist.github.com/kean/28439b29532993b620497621a4545789
//  Copyright © 2018 <NAME>. All rights reserved.
//

import Foundation
import CoreData

public enum MBCoreDataError: Error {
	case incompatibleModels
	case notAStore
}

public class CoreDataManager {

	private let storeType = NSSQLiteStoreType
	private let storeURL: URL
	private let moms: [NSManagedObjectModel]
	private let mappingBundles: [Bundle]
	
	public init(store url: URL, withModelHistory moms: [NSManagedObjectModel], mappingBundles: [Bundle]? = nil) {
		precondition(!moms.isEmpty, "You cannot use CoreData without a Managed Object Model")
		
		self.storeURL = url
		self.moms = moms
		self.mappingBundles = mappingBundles ?? Bundle.allBundles + Bundle.allFrameworks
	}
	
	/// Migrate the store to the latest model if necessary and loads it in a new persistent store coordinator.
	/// - returns: The new persistent store coordinator for the store.
	public func getStoreCoordinator() throws -> NSPersistentStoreCoordinator {
		do {
			try migrateStore()
		} catch MBCoreDataError.notAStore {
			if FileManager.default.fileExists(atPath: storeURL.absoluteString) {
				try FileManager.default.removeItem(at: storeURL)
			}
		}
		
		let coordinator = NSPersistentStoreCoordinator(managedObjectModel: moms.last!)
		try coordinator.addPersistentStore(ofType: storeType, configurationName: nil, at: storeURL)
		
		return coordinator
	}
	
	private func migrateStore() throws {
		let idx = try indexOfCompatibleMom(at: storeURL, moms: moms)
		let remaining = moms.suffix(from: (idx + 1))
		guard remaining.count > 0 else {
			// The store already uses the latest model
			return
		}
		
		_ = try remaining.reduce(moms[idx]) { sMom, dMom in
			try migrateStore(from: sMom, to: dMom)
			
			return dMom
		}
	}
	
	private func indexOfCompatibleMom(at storeURL: URL, moms: [NSManagedObjectModel]) throws -> Int {
		do {
			let meta = try NSPersistentStoreCoordinator.metadataForPersistentStore(ofType: storeType, at: storeURL)
			
{'fraction_non_alphanumeric': 0.09001823154056518, 'fraction_numerical': 0.01959890610756609, 'mean_word_length': 4.145369284876905, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 15, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, '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': '4199470', 'n_tokens_mistral': 1564, 'n_tokens_neox': 1340, 'n_words': 405}