WIP: documentation

This commit is contained in:
John Rommel Estropia
2017-05-10 02:00:47 +09:00
parent 19abedfa9f
commit 8ff163af30
10 changed files with 230 additions and 112 deletions

View File

@@ -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) {

View File

@@ -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.

View File

@@ -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

View File

@@ -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
}