mirror of
https://github.com/JohnEstropia/CoreStore.git
synced 2026-02-25 09:04:59 +01:00
WIP: documentation
This commit is contained in:
@@ -94,9 +94,9 @@ public final class CoreStoreSchema: DynamicSchema {
|
||||
- parameter entities: an array of `Entity<T>` pertaining to all `CoreStoreObject` subclasses to be added to the schema version.
|
||||
- parameter versionLock: an optional list of `VersionLock` hashes for each entity name in the `entities` array. If any `DynamicEntity` doesn't match its version lock hash, an assertion will be raised.
|
||||
*/
|
||||
public convenience init(modelVersion: ModelVersion, entities: [DynamicEntity & Hashable], versionLock: VersionLock? = nil) {
|
||||
public convenience init(modelVersion: ModelVersion, entities: [DynamicEntity], versionLock: VersionLock? = nil) {
|
||||
|
||||
var entityConfigurations: [DynamicEntity & Hashable: Set<String>] = [:]
|
||||
var entityConfigurations: [DynamicEntity: Set<String>] = [:]
|
||||
for entity in entities {
|
||||
|
||||
entityConfigurations[entity] = []
|
||||
@@ -138,15 +138,15 @@ public final class CoreStoreSchema: DynamicSchema {
|
||||
- parameter entityConfigurations: a dictionary with `Entity<T>` pertaining to all `CoreStoreObject` subclasses and the corresponding list of "Configurations" they should be added to. To add an entity only to the default configuration, assign an empty set to its configurations list. Note that regardless of the set configurations, all entities will be added to the default configuration.
|
||||
- parameter versionLock: an optional list of `VersionLock` hashes for each entity name in the `entities` array. If any `DynamicEntity` doesn't match its version lock hash, an assertion will be raised.
|
||||
*/
|
||||
public required init(modelVersion: ModelVersion, entityConfigurations: [DynamicEntity & Hashable: Set<String>], versionLock: VersionLock? = nil) {
|
||||
public required init(modelVersion: ModelVersion, entityConfigurations: [DynamicEntity: Set<String>], versionLock: VersionLock? = nil) {
|
||||
|
||||
var actualEntitiesByConfiguration: [String: Set<AnyEntity>] = [:]
|
||||
var actualEntitiesByConfiguration: [String: Set<DynamicEntity>] = [:]
|
||||
for (entity, configurations) in entityConfigurations {
|
||||
|
||||
for configuration in configurations {
|
||||
|
||||
var entities: Set<AnyEntity>
|
||||
if let existingEntities = actualEntitiesByConfiguration[configurations] {
|
||||
var entities: Set<DynamicEntity>
|
||||
if let existingEntities = actualEntitiesByConfiguration[configuration] {
|
||||
|
||||
entities = existingEntities
|
||||
}
|
||||
@@ -154,11 +154,11 @@ public final class CoreStoreSchema: DynamicSchema {
|
||||
|
||||
entities = []
|
||||
}
|
||||
entities.insert(AnyEntity(entity))
|
||||
actualEntitiesByConfiguration[configurations] = entities
|
||||
entities.insert(entity)
|
||||
actualEntitiesByConfiguration[configuration] = entities
|
||||
}
|
||||
}
|
||||
let allEntities = Set(actualEntitiesByConfiguration.values.joined())
|
||||
let allEntities = Set(entityConfigurations.keys)
|
||||
actualEntitiesByConfiguration[DataStack.defaultConfigurationName] = allEntities
|
||||
|
||||
CoreStore.assert(
|
||||
@@ -205,7 +205,7 @@ public final class CoreStoreSchema: DynamicSchema {
|
||||
return cachedRawModel
|
||||
}
|
||||
let rawModel = NSManagedObjectModel()
|
||||
var entityDescriptionsByEntity: [AnyEntity: NSEntityDescription] = [:]
|
||||
var entityDescriptionsByEntity: [DynamicEntity: NSEntityDescription] = [:]
|
||||
for entity in self.allEntities {
|
||||
|
||||
let entityDescription = self.entityDescription(
|
||||
@@ -234,73 +234,19 @@ public final class CoreStoreSchema: DynamicSchema {
|
||||
|
||||
// MARK: Internal
|
||||
|
||||
// MARK: - AnyEntity
|
||||
|
||||
internal struct AnyEntity: DynamicEntity, Hashable {
|
||||
|
||||
internal init(_ entity: DynamicEntity) {
|
||||
|
||||
self.init(
|
||||
type: entity.type,
|
||||
entityName: entity.entityName,
|
||||
isAbstract: entity.isAbstract,
|
||||
versionHashModifier: entity.versionHashModifier
|
||||
)
|
||||
}
|
||||
|
||||
internal init(type: DynamicObject.Type, entityName: String, isAbstract: Bool, versionHashModifier: String?) {
|
||||
|
||||
self.type = type
|
||||
self.entityName = entityName
|
||||
self.isAbstract = isAbstract
|
||||
self.versionHashModifier = versionHashModifier
|
||||
}
|
||||
|
||||
|
||||
// MARK: Equatable
|
||||
|
||||
static func == (lhs: AnyEntity, rhs: AnyEntity) -> Bool {
|
||||
|
||||
return lhs.type == rhs.type
|
||||
&& lhs.entityName == rhs.entityName
|
||||
&& lhs.isAbstract == rhs.isAbstract
|
||||
&& lhs.versionHashModifier == rhs.versionHashModifier
|
||||
}
|
||||
|
||||
// MARK: Hashable
|
||||
|
||||
var hashValue: Int {
|
||||
|
||||
return ObjectIdentifier(self.type).hashValue
|
||||
^ self.entityName.hashValue
|
||||
^ self.isAbstract.hashValue
|
||||
^ (self.versionHashModifier ?? "").hashValue
|
||||
}
|
||||
|
||||
// MARK: DynamicEntity
|
||||
|
||||
internal let type: DynamicObject.Type
|
||||
internal let entityName: EntityName
|
||||
internal let isAbstract: Bool
|
||||
internal let versionHashModifier: String?
|
||||
}
|
||||
|
||||
|
||||
// MARK: -
|
||||
|
||||
internal let entitiesByConfiguration: [String: Set<AnyEntity>]
|
||||
internal let entitiesByConfiguration: [String: Set<DynamicEntity>]
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private static let barrierQueue = DispatchQueue.concurrent("com.coreStore.coreStoreDataModelBarrierQueue")
|
||||
|
||||
private let allEntities: Set<AnyEntity>
|
||||
private let allEntities: Set<DynamicEntity>
|
||||
|
||||
private var entityDescriptionsByEntity: [CoreStoreSchema.AnyEntity: NSEntityDescription] = [:]
|
||||
private var entityDescriptionsByEntity: [DynamicEntity: NSEntityDescription] = [:]
|
||||
private weak var cachedRawModel: NSManagedObjectModel?
|
||||
|
||||
private func entityDescription(for entity: CoreStoreSchema.AnyEntity, initializer: (CoreStoreSchema.AnyEntity) -> NSEntityDescription) -> NSEntityDescription {
|
||||
private func entityDescription(for entity: DynamicEntity, initializer: (DynamicEntity) -> NSEntityDescription) -> NSEntityDescription {
|
||||
|
||||
if let cachedEntityDescription = self.entityDescriptionsByEntity[entity] {
|
||||
|
||||
@@ -311,12 +257,13 @@ public final class CoreStoreSchema: DynamicSchema {
|
||||
return entityDescription
|
||||
}
|
||||
|
||||
private static func firstPassCreateEntityDescription(from entity: AnyEntity) -> NSEntityDescription {
|
||||
private static func firstPassCreateEntityDescription(from entity: DynamicEntity) -> NSEntityDescription {
|
||||
|
||||
let entityDescription = NSEntityDescription()
|
||||
entityDescription.coreStoreEntity = entity
|
||||
entityDescription.name = entity.entityName
|
||||
entityDescription.isAbstract = entity.isAbstract
|
||||
entityDescription.versionHashModifier = entity.versionHashModifier
|
||||
entityDescription.managedObjectClassName = NSStringFromClass(NSManagedObject.self)
|
||||
|
||||
func createProperties(for type: CoreStoreObject.Type) -> [NSPropertyDescription] {
|
||||
@@ -360,16 +307,16 @@ public final class CoreStoreSchema: DynamicSchema {
|
||||
return entityDescription
|
||||
}
|
||||
|
||||
private static func secondPassConnectRelationshipAttributes(for entityDescriptionsByEntity: [AnyEntity: NSEntityDescription]) {
|
||||
private static func secondPassConnectRelationshipAttributes(for entityDescriptionsByEntity: [DynamicEntity: NSEntityDescription]) {
|
||||
|
||||
var relationshipsByNameByEntity: [AnyEntity: [String: NSRelationshipDescription]] = [:]
|
||||
var relationshipsByNameByEntity: [DynamicEntity: [String: NSRelationshipDescription]] = [:]
|
||||
for (entity, entityDescription) in entityDescriptionsByEntity {
|
||||
|
||||
relationshipsByNameByEntity[entity] = entityDescription.relationshipsByName
|
||||
}
|
||||
func findEntity(for type: CoreStoreObject.Type) -> AnyEntity {
|
||||
func findEntity(for type: CoreStoreObject.Type) -> DynamicEntity {
|
||||
|
||||
var matchedEntities: Set<AnyEntity> = []
|
||||
var matchedEntities: Set<DynamicEntity> = []
|
||||
for (entity, _) in entityDescriptionsByEntity where entity.type == type {
|
||||
|
||||
matchedEntities.insert(entity)
|
||||
@@ -392,7 +339,7 @@ public final class CoreStoreSchema: DynamicSchema {
|
||||
}
|
||||
}
|
||||
|
||||
func findInverseRelationshipMatching(destinationEntity: AnyEntity, destinationKeyPath: String) -> NSRelationshipDescription {
|
||||
func findInverseRelationshipMatching(destinationEntity: DynamicEntity, destinationKeyPath: String) -> NSRelationshipDescription {
|
||||
|
||||
for case (destinationKeyPath, let relationshipDescription) in relationshipsByNameByEntity[destinationEntity]! {
|
||||
|
||||
@@ -451,7 +398,7 @@ public final class CoreStoreSchema: DynamicSchema {
|
||||
}
|
||||
}
|
||||
|
||||
private static func thirdPassConnectInheritanceTree(for entityDescriptionsByEntity: [AnyEntity: NSEntityDescription]) {
|
||||
private static func thirdPassConnectInheritanceTree(for entityDescriptionsByEntity: [DynamicEntity: NSEntityDescription]) {
|
||||
|
||||
func connectBaseEntity(mirror: Mirror, entityDescription: NSEntityDescription) {
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ import Foundation
|
||||
// MARK: - DynamicSchema
|
||||
|
||||
/**
|
||||
`DynamicSchema` are types that provide `NSManagedObjectModel` instances for a particular model version. CoreStore currently supports the following concrete types:
|
||||
`DynamicSchema` are types that provide `NSManagedObjectModel` instances for a single model version. CoreStore currently supports the following concrete types:
|
||||
- `XcodeDataModelSchema`: describes models loaded from a .xcdatamodeld file.
|
||||
- `LegacyXcodeDataModelSchema`: describes models loaded directly from an existing `NSManagedObjectModel`. It is not advisable to continue using this model as its metadata are not available to CoreStore.
|
||||
- `CoreStoreSchema`: describes models written for `CoreStoreObject` Swift class declarations.
|
||||
|
||||
@@ -29,8 +29,21 @@ import Foundation
|
||||
|
||||
// MARK: - LegacyXcodeDataModelSchema
|
||||
|
||||
/**
|
||||
The `LegacyXcodeDataModelSchema` describes models loaded directly from an existing `NSManagedObjectModel`. It is not advisable to continue using this model as its metadata are not available to CoreStore.
|
||||
*/
|
||||
public final class LegacyXcodeDataModelSchema: DynamicSchema {
|
||||
|
||||
/**
|
||||
Initializes a `LegacyXcodeDataModelSchema` from an `NSManagedObjectModel`.
|
||||
```
|
||||
CoreStore.defaultStack = DataStack(
|
||||
LegacyXcodeDataModelSchema(modelName: "MyAppV1", model: model)
|
||||
)
|
||||
```
|
||||
- parameter modelName: the model version, typically the file name of an *.xcdatamodeld file (without the file extension)
|
||||
- parameter model: the `NSManagedObjectModel`
|
||||
*/
|
||||
public required init(modelName: ModelVersion, model: NSManagedObjectModel) {
|
||||
|
||||
self.modelVersion = modelName
|
||||
|
||||
@@ -29,16 +29,60 @@ import Foundation
|
||||
|
||||
// MARK: - XcodeDataModelSchema
|
||||
|
||||
/**
|
||||
The `XcodeDataModelSchema` describes a model version declared in a single *.xcdatamodeld file.
|
||||
```
|
||||
CoreStore.defaultStack = DataStack(
|
||||
XcodeDataModelSchema(modelName: "MyAppV1", bundle: .main)
|
||||
)
|
||||
```
|
||||
*/
|
||||
public final class XcodeDataModelSchema: DynamicSchema {
|
||||
|
||||
public required init(modelVersion: ModelVersion, modelVersionFileURL: URL) {
|
||||
/**
|
||||
Initializes an `XcodeDataModelSchema` from an *.xcdatamodeld version name and its containing `Bundle`.
|
||||
```
|
||||
CoreStore.defaultStack = DataStack(
|
||||
XcodeDataModelSchema(modelName: "MyAppV1", bundle: .main)
|
||||
)
|
||||
```
|
||||
- parameter modelName: the model version, typically the file name of an *.xcdatamodeld file (without the file extension)
|
||||
- parameter bundle: the `Bundle` that contains the .xcdatamodeld's "momd" file. If not specified, the `Bundle.main` will be searched.
|
||||
*/
|
||||
public convenience init(modelName: ModelVersion, bundle: Bundle = Bundle.main) {
|
||||
|
||||
guard let modelFilePath = bundle.path(forResource: modelName, ofType: "momd") else {
|
||||
|
||||
// For users migrating from very old Xcode versions: Old xcdatamodel files are not contained inside xcdatamodeld (with a "d"), and will thus fail this check. If that was the case, create a new xcdatamodeld file and copy all contents into the new model.
|
||||
let foundModels = bundle
|
||||
.paths(forResourcesOfType: "momd", inDirectory: nil)
|
||||
.map({ ($0 as NSString).lastPathComponent })
|
||||
CoreStore.abort("Could not find \"\(modelName).momd\" from the bundle \"\(bundle.bundleIdentifier ?? "<nil>")\". Other model files in bundle: \(foundModels.coreStoreDumpString)")
|
||||
}
|
||||
|
||||
let modelFileURL = URL(fileURLWithPath: modelFilePath)
|
||||
let fileURL = modelFileURL.appendingPathComponent("\(modelName).mom", isDirectory: false)
|
||||
self.init(modelName: modelName, modelVersionFileURL: fileURL)
|
||||
}
|
||||
|
||||
/**
|
||||
Initializes an `XcodeDataModelSchema` from an *.xcdatamodeld file URL.
|
||||
```
|
||||
CoreStore.defaultStack = DataStack(
|
||||
XcodeDataModelSchema(modelName: "MyAppV1", modelVersionFileURL: fileURL)
|
||||
)
|
||||
```
|
||||
- parameter modelName: the model version, typically the file name of an *.xcdatamodeld file (without the file extension)
|
||||
- parameter modelVersionFileURL: the file URL that points to the .xcdatamodeld's "momd" file.
|
||||
*/
|
||||
public required init(modelName: ModelVersion, modelVersionFileURL: URL) {
|
||||
|
||||
CoreStore.assert(
|
||||
NSManagedObjectModel(contentsOf: modelVersionFileURL) != nil,
|
||||
"Could not find the \"\(modelVersion).mom\" version file for the model at URL \"\(modelVersionFileURL)\"."
|
||||
"Could not find the \"\(modelName).mom\" version file for the model at URL \"\(modelVersionFileURL)\"."
|
||||
)
|
||||
|
||||
self.modelVersion = modelVersion
|
||||
self.modelVersion = modelName
|
||||
self.modelVersionFileURL = modelVersionFileURL
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user