mirror of
https://github.com/JohnEstropia/CoreStore.git
synced 2026-01-11 20:00:30 +01:00
support compound indexes and unique constraints on CoreStore properties
This commit is contained in:
@@ -35,7 +35,6 @@ internal protocol AttributeProtocol: class {
|
||||
|
||||
var keyPath: KeyPathString { get }
|
||||
var isOptional: Bool { get }
|
||||
var isIndexed: Bool { get }
|
||||
var isTransient: Bool { get }
|
||||
var allowsExternalBinaryDataStorage: Bool { get }
|
||||
var versionHashModifier: () -> String? { get }
|
||||
|
||||
@@ -1177,7 +1177,6 @@ extension NSAttributeDescription: CoreStoreDebugStringConvertible {
|
||||
("isOptional", self.isOptional),
|
||||
("isTransient", self.isTransient),
|
||||
("userInfo", self.userInfo as Any),
|
||||
("isIndexed", self.isIndexed),
|
||||
("versionHash", self.versionHash),
|
||||
("versionHashModifier", self.versionHashModifier as Any),
|
||||
("isIndexedBySpotlight", self.isIndexedBySpotlight),
|
||||
@@ -1248,13 +1247,17 @@ extension NSEntityDescription: CoreStoreDebugStringConvertible {
|
||||
("userInfo", self.userInfo as Any),
|
||||
("versionHash", self.versionHash),
|
||||
("versionHashModifier", self.versionHashModifier as Any),
|
||||
("renamingIdentifier", self.renamingIdentifier as Any),
|
||||
("compoundIndexes", self.compoundIndexes)
|
||||
("renamingIdentifier", self.renamingIdentifier as Any)
|
||||
]
|
||||
if #available(iOS 9.0, OSXApplicationExtension 10.11, OSX 10.11, *) {
|
||||
if #available(iOS 11.0, OSX 10.13, watchOS 4.0, tvOS 11.0, *) {
|
||||
|
||||
info.append(("uniquenessConstraints", self.uniquenessConstraints))
|
||||
info.append(("indexes", self.indexes))
|
||||
}
|
||||
else {
|
||||
|
||||
info.append(("compoundIndexes", self.compoundIndexes))
|
||||
}
|
||||
info.append(("uniquenessConstraints", self.uniquenessConstraints))
|
||||
return createFormattedString(
|
||||
"(", ")",
|
||||
info
|
||||
|
||||
@@ -292,7 +292,6 @@ public final class CoreStoreSchema: DynamicSchema {
|
||||
description.name = attribute.keyPath
|
||||
description.attributeType = Swift.type(of: attribute).attributeType
|
||||
description.isOptional = attribute.isOptional
|
||||
description.isIndexed = attribute.isIndexed
|
||||
description.defaultValue = attribute.defaultValue()
|
||||
description.isTransient = attribute.isTransient
|
||||
description.allowsExternalBinaryDataStorage = attribute.allowsExternalBinaryDataStorage
|
||||
@@ -442,6 +441,53 @@ public final class CoreStoreSchema: DynamicSchema {
|
||||
entityDescription: entityDescription
|
||||
)
|
||||
}
|
||||
for (entity, entityDescription) in entityDescriptionsByEntity {
|
||||
|
||||
let uniqueConstraints = entity.uniqueConstraints.filter({ !$0.isEmpty })
|
||||
if !uniqueConstraints.isEmpty {
|
||||
|
||||
CoreStore.assert(
|
||||
entityDescription.superentity == nil,
|
||||
"Uniqueness constraints must be defined at the highest level possible."
|
||||
)
|
||||
entityDescription.uniquenessConstraints = entity.uniqueConstraints.map { $0.map { $0 as NSString } }
|
||||
}
|
||||
guard !entity.indexes.isEmpty else {
|
||||
|
||||
continue
|
||||
}
|
||||
defer {
|
||||
|
||||
entityDescription.coreStoreEntity = entity // reserialize
|
||||
}
|
||||
let attributesByName = entityDescription.attributesByName
|
||||
if #available(iOS 11.0, OSX 10.13, watchOS 4.0, tvOS 11.0, *) {
|
||||
|
||||
entityDescription.indexes = entity.indexes.map { (compoundIndexes) in
|
||||
|
||||
return NSFetchIndexDescription.init(
|
||||
name: "_CoreStoreSchema_indexes_\(entityDescription.name!)_\(compoundIndexes.joined(separator: "-"))",
|
||||
elements: compoundIndexes.map { (keyPath) in
|
||||
|
||||
return NSFetchIndexElementDescription(
|
||||
property: attributesByName[keyPath]!,
|
||||
collationType: .binary
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
entityDescription.compoundIndexes = entity.indexes.map { (compoundIndexes) in
|
||||
|
||||
return compoundIndexes.map { (keyPath) in
|
||||
|
||||
return attributesByName[keyPath]!
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static func fourthPassSynthesizeManagedObjectClasses(for entityDescriptionsByEntity: [DynamicEntity: NSEntityDescription], allCustomGettersSetters: [DynamicEntity: [KeyPathString: CoreStoreManagedObject.CustomGetterSetter]]) {
|
||||
|
||||
@@ -26,12 +26,23 @@
|
||||
import Foundation
|
||||
|
||||
|
||||
// MARK: - AnyDynamicKeyPath
|
||||
|
||||
public protocol AnyDynamicKeyPath {
|
||||
|
||||
/**
|
||||
The keyPath string
|
||||
*/
|
||||
var cs_keyPathString: String { get }
|
||||
}
|
||||
|
||||
|
||||
// MARK: - DynamicKeyPath
|
||||
|
||||
/**
|
||||
Used only for utility methods.
|
||||
*/
|
||||
public protocol DynamicKeyPath {
|
||||
public protocol DynamicKeyPath: AnyDynamicKeyPath {
|
||||
|
||||
/**
|
||||
The DynamicObject type
|
||||
@@ -42,11 +53,6 @@ public protocol DynamicKeyPath {
|
||||
The Value type
|
||||
*/
|
||||
associatedtype ValueType
|
||||
|
||||
/**
|
||||
The keyPath string
|
||||
*/
|
||||
var cs_keyPathString: String { get }
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -181,7 +181,6 @@ public extension DynamicSchema {
|
||||
default:
|
||||
fatalError("Unsupported attribute type: \(attribute.attributeType.rawValue)")
|
||||
}
|
||||
let indexedString = attribute.isIndexed ? ", isIndexed: true" : ""
|
||||
let transientString = attribute.isTransient ? ", isTransient: true" : ""
|
||||
// TODO: escape strings
|
||||
let versionHashModifierString = attribute.versionHashModifier
|
||||
@@ -189,7 +188,7 @@ public extension DynamicSchema {
|
||||
// TODO: escape strings
|
||||
let renamingIdentifierString = attribute.renamingIdentifier
|
||||
.flatMap({ ($0 == attributeName ? "" : ", renamingIdentifier: \"\($0)\"") as String }) ?? ""
|
||||
output.append(" let \(attributeName) = \(containerType)<\(String(describing: valueType))>(\"\(attributeName)\"\(indexedString)\(defaultString)\(transientString)\(versionHashModifierString)\(renamingIdentifierString))\n")
|
||||
output.append(" let \(attributeName) = \(containerType)<\(String(describing: valueType))>(\"\(attributeName)\"\(defaultString)\(transientString)\(versionHashModifierString)\(renamingIdentifierString))\n")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ import ObjectiveC
|
||||
- SeeAlso: CoreStoreSchema
|
||||
- SeeAlso: CoreStoreObject
|
||||
*/
|
||||
public final class Entity<O: DynamicObject>: DynamicEntity {
|
||||
public final class Entity<O: CoreStoreObject>: DynamicEntity {
|
||||
|
||||
/**
|
||||
Initializes an `Entity`. Always provide a concrete generic type to `Entity`.
|
||||
@@ -66,11 +66,20 @@ public final class Entity<O: DynamicObject>: DynamicEntity {
|
||||
```
|
||||
- parameter entityName: the `NSEntityDescription` name to use for the entity
|
||||
- parameter isAbstract: set to `true` if the entity is meant to be an abstract class and can only be initialized with subclass types.
|
||||
- parameter versionHashModifier: The version hash modifier for the entity. Used to mark or denote an entity as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where, for example, the structure of an entity is unchanged but the format or content of data has changed.)
|
||||
- parameter versionHashModifier: the version hash modifier for the entity. Used to mark or denote an entity as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where, for example, the structure of an entity is unchanged but the format or content of data has changed.)
|
||||
- parameter indexes: the compound indexes for the entity as an array of arrays. The arrays contained in the returned array contain `KeyPath`s to properties of the entity.
|
||||
- parameter uniqueConstraints: sets uniqueness constraints for the entity. A uniqueness constraint is a set of one or more `KeyPath`s whose value must be unique over the set of instances of that entity. This value forms part of the entity's version hash. Uniqueness constraint violations can be computationally expensive to handle. It is highly suggested that there be only one uniqueness constraint per entity hierarchy. Uniqueness constraints must be defined at the highest level possible, and CoreStore will raise an assertion failure if unique constraints are added to a sub entity.
|
||||
*/
|
||||
public convenience init(_ entityName: String, isAbstract: Bool = false, versionHashModifier: String? = nil) {
|
||||
public convenience init(_ entityName: String, isAbstract: Bool = false, versionHashModifier: String? = nil, indexes: [[PartialKeyPath<O>]] = [], uniqueConstraints: [[PartialKeyPath<O>]] = []) {
|
||||
|
||||
self.init(O.self, entityName, isAbstract: isAbstract, versionHashModifier: versionHashModifier)
|
||||
self.init(
|
||||
O.self,
|
||||
entityName,
|
||||
isAbstract: isAbstract,
|
||||
versionHashModifier: versionHashModifier,
|
||||
indexes: indexes,
|
||||
uniqueConstraints: uniqueConstraints
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -81,11 +90,28 @@ public final class Entity<O: DynamicObject>: DynamicEntity {
|
||||
- parameter type: the `DynamicObject` type associated with the entity
|
||||
- parameter entityName: the `NSEntityDescription` name to use for the entity
|
||||
- parameter isAbstract: set to `true` if the entity is meant to be an abstract class and can only be initialized with subclass types.
|
||||
- parameter versionHashModifier: The version hash modifier for the entity. Used to mark or denote an entity as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where, for example, the structure of an entity is unchanged but the format or content of data has changed.)
|
||||
- parameter versionHashModifier: the version hash modifier for the entity. Used to mark or denote an entity as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where, for example, the structure of an entity is unchanged but the format or content of data has changed.)
|
||||
- parameter indexes: the compound indexes for the entity as an array of arrays. The arrays contained in the returned array contain KeyPath's to properties of the entity.
|
||||
- parameter uniqueConstraints: sets uniqueness constraints for the entity. A uniqueness constraint is a set of one or more `KeyPath`s whose value must be unique over the set of instances of that entity. This value forms part of the entity's version hash. Uniqueness constraint violations can be computationally expensive to handle. It is highly suggested that there be only one uniqueness constraint per entity hierarchy. Uniqueness constraints must be defined at the highest level possible, and CoreStore will raise an assertion failure if unique constraints are added to a sub entity.
|
||||
*/
|
||||
public init(_ type: O.Type, _ entityName: String, isAbstract: Bool = false, versionHashModifier: String? = nil) {
|
||||
public init(_ type: O.Type, _ entityName: String, isAbstract: Bool = false, versionHashModifier: String? = nil, indexes: [[PartialKeyPath<O>]] = [], uniqueConstraints: [[PartialKeyPath<O>]] = []) {
|
||||
|
||||
super.init(type: type, entityName: entityName, isAbstract: isAbstract, versionHashModifier: versionHashModifier)
|
||||
let meta = O.meta
|
||||
let toStringArray: ([PartialKeyPath<O>]) -> [KeyPathString] = {
|
||||
|
||||
return $0.map {
|
||||
|
||||
return (meta[keyPath: $0] as! AnyDynamicKeyPath).cs_keyPathString
|
||||
}
|
||||
}
|
||||
super.init(
|
||||
type: type,
|
||||
entityName: entityName,
|
||||
isAbstract: isAbstract,
|
||||
versionHashModifier: versionHashModifier,
|
||||
indexes: indexes.map(toStringArray),
|
||||
uniqueConstraints: uniqueConstraints.map(toStringArray)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,6 +143,16 @@ public /*abstract*/ class DynamicEntity: Hashable {
|
||||
*/
|
||||
public let versionHashModifier: String?
|
||||
|
||||
/**
|
||||
Do not use directly.
|
||||
*/
|
||||
public let indexes: [[KeyPathString]]
|
||||
|
||||
/**
|
||||
Do not use directly.
|
||||
*/
|
||||
public let uniqueConstraints: [[KeyPathString]]
|
||||
|
||||
|
||||
// MARK: Equatable
|
||||
|
||||
@@ -126,6 +162,8 @@ public /*abstract*/ class DynamicEntity: Hashable {
|
||||
&& lhs.entityName == rhs.entityName
|
||||
&& lhs.isAbstract == rhs.isAbstract
|
||||
&& lhs.versionHashModifier == rhs.versionHashModifier
|
||||
&& lhs.indexes == rhs.indexes
|
||||
&& lhs.uniqueConstraints == rhs.uniqueConstraints
|
||||
}
|
||||
|
||||
// MARK: Hashable
|
||||
@@ -136,16 +174,20 @@ public /*abstract*/ class DynamicEntity: Hashable {
|
||||
^ self.entityName.hashValue
|
||||
^ self.isAbstract.hashValue
|
||||
^ (self.versionHashModifier ?? "").hashValue
|
||||
// ^ self.indexes.hashValue
|
||||
// ^ self.uniqueConstraints.hashValue
|
||||
}
|
||||
|
||||
|
||||
// MARK: Internal
|
||||
|
||||
internal init(type: DynamicObject.Type, entityName: String, isAbstract: Bool = false, versionHashModifier: String?) {
|
||||
internal init(type: DynamicObject.Type, entityName: String, isAbstract: Bool, versionHashModifier: String?, indexes: [[KeyPathString]], uniqueConstraints: [[KeyPathString]]) {
|
||||
|
||||
self.type = type
|
||||
self.entityName = entityName
|
||||
self.isAbstract = isAbstract
|
||||
self.versionHashModifier = versionHashModifier
|
||||
self.indexes = indexes
|
||||
self.uniqueConstraints = uniqueConstraints
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,9 @@ internal extension NSEntityDescription {
|
||||
guard let userInfo = self.userInfo,
|
||||
let typeName = userInfo[UserInfoKey.CoreStoreManagedObjectTypeName] as! String?,
|
||||
let entityName = userInfo[UserInfoKey.CoreStoreManagedObjectEntityName] as! String?,
|
||||
let isAbstract = userInfo[UserInfoKey.CoreStoreManagedObjectIsAbstract] as! Bool? else {
|
||||
let isAbstract = userInfo[UserInfoKey.CoreStoreManagedObjectIsAbstract] as! Bool?,
|
||||
let indexes = userInfo[UserInfoKey.CoreStoreManagedObjectIndexes] as! [[KeyPathString]]?,
|
||||
let uniqueConstraints = userInfo[UserInfoKey.CoreStoreManagedObjectUniqueConstraints] as! [[KeyPathString]]? else {
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -58,7 +60,9 @@ internal extension NSEntityDescription {
|
||||
type: NSClassFromString(typeName) as! CoreStoreObject.Type,
|
||||
entityName: entityName,
|
||||
isAbstract: isAbstract,
|
||||
versionHashModifier: userInfo[UserInfoKey.CoreStoreManagedObjectVersionHashModifier] as! String?
|
||||
versionHashModifier: userInfo[UserInfoKey.CoreStoreManagedObjectVersionHashModifier] as! String?,
|
||||
indexes: indexes,
|
||||
uniqueConstraints: uniqueConstraints
|
||||
)
|
||||
}
|
||||
set {
|
||||
@@ -71,6 +75,8 @@ internal extension NSEntityDescription {
|
||||
userInfo[UserInfoKey.CoreStoreManagedObjectEntityName] = newValue.entityName
|
||||
userInfo[UserInfoKey.CoreStoreManagedObjectIsAbstract] = newValue.isAbstract
|
||||
userInfo[UserInfoKey.CoreStoreManagedObjectVersionHashModifier] = newValue.versionHashModifier
|
||||
userInfo[UserInfoKey.CoreStoreManagedObjectIndexes] = newValue.indexes
|
||||
userInfo[UserInfoKey.CoreStoreManagedObjectUniqueConstraints] = newValue.uniqueConstraints
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -81,6 +87,8 @@ internal extension NSEntityDescription {
|
||||
userInfo[UserInfoKey.CoreStoreManagedObjectEntityName] = nil
|
||||
userInfo[UserInfoKey.CoreStoreManagedObjectIsAbstract] = nil
|
||||
userInfo[UserInfoKey.CoreStoreManagedObjectVersionHashModifier] = nil
|
||||
userInfo[UserInfoKey.CoreStoreManagedObjectIndexes] = nil
|
||||
userInfo[UserInfoKey.CoreStoreManagedObjectUniqueConstraints] = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -139,6 +147,8 @@ internal extension NSEntityDescription {
|
||||
fileprivate static let CoreStoreManagedObjectEntityName = "CoreStoreManagedObjectEntityName"
|
||||
fileprivate static let CoreStoreManagedObjectIsAbstract = "CoreStoreManagedObjectIsAbstract"
|
||||
fileprivate static let CoreStoreManagedObjectVersionHashModifier = "CoreStoreManagedObjectVersionHashModifier"
|
||||
fileprivate static let CoreStoreManagedObjectIndexes = "CoreStoreManagedObjectIndexes"
|
||||
fileprivate static let CoreStoreManagedObjectUniqueConstraints = "CoreStoreManagedObjectUniqueConstraints"
|
||||
|
||||
fileprivate static let CoreStoreManagedObjectKeyPathsByAffectedKeyPaths = "CoreStoreManagedObjectKeyPathsByAffectedKeyPaths"
|
||||
fileprivate static let CoreStoreManagedObjectCustomGetterSetterByKeyPaths = "CoreStoreManagedObjectCustomGetterSetterByKeyPaths"
|
||||
|
||||
@@ -107,7 +107,6 @@ public enum TransformableContainer<O: CoreStoreObject> {
|
||||
```
|
||||
- parameter keyPath: the permanent attribute name for this property.
|
||||
- parameter initial: the initial value for the property when the object is first created. Defaults to the `ImportableAttributeType`'s empty value if not specified.
|
||||
- parameter isIndexed: `true` if the property should be indexed for searching, otherwise `false`. Defaults to `false` if not specified.
|
||||
- parameter isTransient: `true` if the property is transient, otherwise `false`. Defaults to `false` if not specified. The transient flag specifies whether or not a property's value is ignored when an object is saved to a persistent store. Transient properties are not saved to the persistent store, but are still managed for undo, redo, validation, and so on.
|
||||
- parameter allowsExternalBinaryDataStorage: `true` if the attribute allows external binary storage, otherwise `false`.
|
||||
- parameter versionHashModifier: used to mark or denote a property as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where the properties are unchanged but the format or content of its data are changed.)
|
||||
@@ -119,7 +118,6 @@ public enum TransformableContainer<O: CoreStoreObject> {
|
||||
public init(
|
||||
_ keyPath: KeyPathString,
|
||||
initial: @autoclosure @escaping () -> V,
|
||||
isIndexed: Bool = false,
|
||||
isTransient: Bool = false,
|
||||
allowsExternalBinaryDataStorage: Bool = false,
|
||||
versionHashModifier: @autoclosure @escaping () -> String? = nil,
|
||||
@@ -130,7 +128,6 @@ public enum TransformableContainer<O: CoreStoreObject> {
|
||||
|
||||
self.keyPath = keyPath
|
||||
self.defaultValue = initial
|
||||
self.isIndexed = isIndexed
|
||||
self.isTransient = isTransient
|
||||
self.allowsExternalBinaryDataStorage = allowsExternalBinaryDataStorage
|
||||
self.versionHashModifier = versionHashModifier
|
||||
@@ -202,7 +199,6 @@ public enum TransformableContainer<O: CoreStoreObject> {
|
||||
|
||||
internal let keyPath: KeyPathString
|
||||
internal let isOptional = false
|
||||
internal let isIndexed: Bool
|
||||
internal let isTransient: Bool
|
||||
internal let allowsExternalBinaryDataStorage: Bool
|
||||
internal let versionHashModifier: () -> String?
|
||||
@@ -258,15 +254,15 @@ public enum TransformableContainer<O: CoreStoreObject> {
|
||||
|
||||
private let customGetter: ((_ partialObject: PartialObject<O>) -> V)?
|
||||
private let customSetter: ((_ partialObject: PartialObject<O>, _ newValue: V) -> Void)?
|
||||
|
||||
|
||||
|
||||
|
||||
// MARK: Deprecated
|
||||
|
||||
@available(*, deprecated: 3.2, renamed: "init(_:initial:isIndexed:isTransient:versionHashModifier:renamingIdentifier:customGetter:customSetter:affectedByKeyPaths:)")
|
||||
|
||||
@available(*, unavailable, message: "Indexes are now set through the Entity<T> initializer, which now supports compound indexes.")
|
||||
public convenience init(
|
||||
_ keyPath: KeyPathString,
|
||||
`default`: @autoclosure @escaping () -> V,
|
||||
isIndexed: Bool = false,
|
||||
initial: @autoclosure @escaping () -> V,
|
||||
isIndexed: Bool,
|
||||
isTransient: Bool = false,
|
||||
allowsExternalBinaryDataStorage: Bool = false,
|
||||
versionHashModifier: @autoclosure @escaping () -> String? = nil,
|
||||
@@ -274,18 +270,8 @@ public enum TransformableContainer<O: CoreStoreObject> {
|
||||
customGetter: ((_ partialObject: PartialObject<O>) -> V)? = nil,
|
||||
customSetter: ((_ partialObject: PartialObject<O>, _ newValue: V) -> Void)? = nil,
|
||||
affectedByKeyPaths: @autoclosure @escaping () -> Set<String> = []) {
|
||||
|
||||
self.init(
|
||||
keyPath,
|
||||
initial: `default`,
|
||||
isIndexed: isIndexed,
|
||||
isTransient: isTransient,
|
||||
versionHashModifier: versionHashModifier,
|
||||
renamingIdentifier: renamingIdentifier,
|
||||
customGetter: customGetter,
|
||||
customSetter: customSetter,
|
||||
affectedByKeyPaths: affectedByKeyPaths
|
||||
)
|
||||
|
||||
fatalError()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -334,8 +320,8 @@ public enum TransformableContainer<O: CoreStoreObject> {
|
||||
```
|
||||
- parameter keyPath: the permanent attribute name for this property.
|
||||
- parameter initial: the initial value for the property when the object is first created. Defaults to the `ImportableAttributeType`'s empty value if not specified.
|
||||
- parameter isIndexed: `true` if the property should be indexed for searching, otherwise `false`. Defaults to `false` if not specified.
|
||||
- parameter isTransient: `true` if the property is transient, otherwise `false`. Defaults to `false` if not specified. The transient flag specifies whether or not a property's value is ignored when an object is saved to a persistent store. Transient properties are not saved to the persistent store, but are still managed for undo, redo, validation, and so on.
|
||||
- parameter allowsExternalBinaryDataStorage: `true` if the attribute allows external binary storage, otherwise `false`.
|
||||
- parameter versionHashModifier: used to mark or denote a property as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where the properties are unchanged but the format or content of its data are changed.)
|
||||
- parameter renamingIdentifier: used to resolve naming conflicts between models. When creating an entity mapping between entities in two managed object models, a source entity property and a destination entity property that share the same identifier indicate that a property mapping should be configured to migrate from the source to the destination. If unset, the identifier will be the property's name.
|
||||
- parameter customGetter: use this closure as an "override" for the default property getter. The closure receives a `PartialObject<O>`, which acts as a fast, type-safe KVC interface for `CoreStoreObject`. The reason a `CoreStoreObject` instance is not passed directly is because the Core Data runtime is not aware of `CoreStoreObject` properties' static typing, and so loading those info everytime KVO invokes this accessor method incurs a cumulative performance hit (especially in KVO-heavy operations such as `ListMonitor` observing.) When accessing the property value from `PartialObject<O>`, make sure to use `PartialObject<O>.primitiveValue(for:)` instead of `PartialObject<O>.value(for:)`, which would unintentionally execute the same closure again recursively.
|
||||
@@ -345,8 +331,8 @@ public enum TransformableContainer<O: CoreStoreObject> {
|
||||
public init(
|
||||
_ keyPath: KeyPathString,
|
||||
initial: @autoclosure @escaping () -> V? = nil,
|
||||
isIndexed: Bool = false,
|
||||
isTransient: Bool = false,
|
||||
allowsExternalBinaryDataStorage: Bool = false,
|
||||
versionHashModifier: @autoclosure @escaping () -> String? = nil,
|
||||
renamingIdentifier: @autoclosure @escaping () -> String? = nil,
|
||||
customGetter: ((_ partialObject: PartialObject<O>) -> V?)? = nil,
|
||||
@@ -355,8 +341,8 @@ public enum TransformableContainer<O: CoreStoreObject> {
|
||||
|
||||
self.keyPath = keyPath
|
||||
self.defaultValue = initial
|
||||
self.isIndexed = isIndexed
|
||||
self.isTransient = isTransient
|
||||
self.allowsExternalBinaryDataStorage = allowsExternalBinaryDataStorage
|
||||
self.versionHashModifier = versionHashModifier
|
||||
self.renamingIdentifier = renamingIdentifier
|
||||
self.customGetter = customGetter
|
||||
@@ -426,8 +412,8 @@ public enum TransformableContainer<O: CoreStoreObject> {
|
||||
|
||||
internal let keyPath: KeyPathString
|
||||
internal let isOptional = true
|
||||
internal let isIndexed: Bool
|
||||
internal let isTransient: Bool
|
||||
internal let allowsExternalBinaryDataStorage: Bool
|
||||
internal let versionHashModifier: () -> String?
|
||||
internal let renamingIdentifier: () -> String?
|
||||
internal let defaultValue: () -> Any?
|
||||
@@ -481,33 +467,24 @@ public enum TransformableContainer<O: CoreStoreObject> {
|
||||
|
||||
private let customGetter: ((_ partialObject: PartialObject<O>) -> V?)?
|
||||
private let customSetter: ((_ partialObject: PartialObject<O>, _ newValue: V?) -> Void)?
|
||||
|
||||
|
||||
|
||||
|
||||
// MARK: Deprecated
|
||||
|
||||
@available(*, deprecated: 3.2, renamed: "init(_:initial:isIndexed:isTransient:versionHashModifier:renamingIdentifier:customGetter:customSetter:affectedByKeyPaths:)")
|
||||
|
||||
@available(*, unavailable, message: "Indexes are now set through the Entity<T> initializer, which now supports compound indexes.")
|
||||
public convenience init(
|
||||
_ keyPath: KeyPathString,
|
||||
`default`: @autoclosure @escaping () -> V? = nil,
|
||||
isIndexed: Bool = false,
|
||||
initial: @autoclosure @escaping () -> V? = nil,
|
||||
isIndexed: Bool,
|
||||
isTransient: Bool = false,
|
||||
allowsExternalBinaryDataStorage: Bool = false,
|
||||
versionHashModifier: @autoclosure @escaping () -> String? = nil,
|
||||
renamingIdentifier: @autoclosure @escaping () -> String? = nil,
|
||||
customGetter: ((_ partialObject: PartialObject<O>) -> V?)? = nil,
|
||||
customSetter: ((_ partialObject: PartialObject<O>, _ newValue: V?) -> Void)? = nil,
|
||||
affectedByKeyPaths: @autoclosure @escaping () -> Set<String> = []) {
|
||||
|
||||
self.init(
|
||||
keyPath,
|
||||
initial: `default`,
|
||||
isIndexed: isIndexed,
|
||||
isTransient: isTransient,
|
||||
versionHashModifier: versionHashModifier,
|
||||
renamingIdentifier: renamingIdentifier,
|
||||
customGetter: customGetter,
|
||||
customSetter: customSetter,
|
||||
affectedByKeyPaths: affectedByKeyPaths
|
||||
)
|
||||
|
||||
fatalError()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,7 +103,6 @@ public enum ValueContainer<O: CoreStoreObject> {
|
||||
```
|
||||
- parameter keyPath: the permanent attribute name for this property.
|
||||
- parameter initial: the initial value for the property when the object is first created
|
||||
- parameter isIndexed: `true` if the property should be indexed for searching, otherwise `false`. Defaults to `false` if not specified.
|
||||
- parameter isTransient: `true` if the property is transient, otherwise `false`. Defaults to `false` if not specified. The transient flag specifies whether or not a property's value is ignored when an object is saved to a persistent store. Transient properties are not saved to the persistent store, but are still managed for undo, redo, validation, and so on.
|
||||
- parameter versionHashModifier: used to mark or denote a property as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where the properties are unchanged but the format or content of its data are changed.)
|
||||
- parameter renamingIdentifier: used to resolve naming conflicts between models. When creating an entity mapping between entities in two managed object models, a source entity property and a destination entity property that share the same identifier indicate that a property mapping should be configured to migrate from the source to the destination. If unset, the identifier will be the property's name.
|
||||
@@ -114,7 +113,6 @@ public enum ValueContainer<O: CoreStoreObject> {
|
||||
public init(
|
||||
_ keyPath: KeyPathString,
|
||||
initial: @autoclosure @escaping () -> V,
|
||||
isIndexed: Bool = false,
|
||||
isTransient: Bool = false,
|
||||
versionHashModifier: @autoclosure @escaping () -> String? = nil,
|
||||
renamingIdentifier: @autoclosure @escaping () -> String? = nil,
|
||||
@@ -123,7 +121,6 @@ public enum ValueContainer<O: CoreStoreObject> {
|
||||
affectedByKeyPaths: @autoclosure @escaping () -> Set<String> = []) {
|
||||
|
||||
self.keyPath = keyPath
|
||||
self.isIndexed = isIndexed
|
||||
self.isTransient = isTransient
|
||||
self.defaultValue = { initial().cs_toQueryableNativeType() }
|
||||
self.versionHashModifier = versionHashModifier
|
||||
@@ -197,7 +194,6 @@ public enum ValueContainer<O: CoreStoreObject> {
|
||||
|
||||
internal let keyPath: KeyPathString
|
||||
internal let isOptional = false
|
||||
internal let isIndexed: Bool
|
||||
internal let isTransient: Bool
|
||||
internal let allowsExternalBinaryDataStorage = false
|
||||
internal let versionHashModifier: () -> String?
|
||||
@@ -257,11 +253,11 @@ public enum ValueContainer<O: CoreStoreObject> {
|
||||
|
||||
// MARK: Deprecated
|
||||
|
||||
@available(*, deprecated: 3.2, renamed: "init(_:initial:isIndexed:isTransient:versionHashModifier:renamingIdentifier:customGetter:customSetter:affectedByKeyPaths:)")
|
||||
@available(*, unavailable, message: "Indexes are now set through the Entity<T> initializer, which now supports compound indexes.")
|
||||
public convenience init(
|
||||
_ keyPath: KeyPathString,
|
||||
`default`: @autoclosure @escaping () -> V,
|
||||
isIndexed: Bool = false,
|
||||
initial: @autoclosure @escaping () -> V,
|
||||
isIndexed: Bool,
|
||||
isTransient: Bool = false,
|
||||
versionHashModifier: @autoclosure @escaping () -> String? = nil,
|
||||
renamingIdentifier: @autoclosure @escaping () -> String? = nil,
|
||||
@@ -269,17 +265,7 @@ public enum ValueContainer<O: CoreStoreObject> {
|
||||
customSetter: ((_ partialObject: PartialObject<O>, _ newValue: V) -> Void)? = nil,
|
||||
affectedByKeyPaths: @autoclosure @escaping () -> Set<String> = []) {
|
||||
|
||||
self.init(
|
||||
keyPath,
|
||||
initial: `default`,
|
||||
isIndexed: isIndexed,
|
||||
isTransient: isTransient,
|
||||
versionHashModifier: versionHashModifier,
|
||||
renamingIdentifier: renamingIdentifier,
|
||||
customGetter: customGetter,
|
||||
customSetter: customSetter,
|
||||
affectedByKeyPaths: affectedByKeyPaths
|
||||
)
|
||||
fatalError()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,7 +311,6 @@ public enum ValueContainer<O: CoreStoreObject> {
|
||||
```
|
||||
- parameter keyPath: the permanent attribute name for this property.
|
||||
- parameter initial: the initial value for the property when the object is first created. Defaults to `nil` if not specified.
|
||||
- parameter isIndexed: `true` if the property should be indexed for searching, otherwise `false`. Defaults to `false` if not specified.
|
||||
- parameter isTransient: `true` if the property is transient, otherwise `false`. Defaults to `false` if not specified. The transient flag specifies whether or not a property's value is ignored when an object is saved to a persistent store. Transient properties are not saved to the persistent store, but are still managed for undo, redo, validation, and so on.
|
||||
- parameter versionHashModifier: used to mark or denote a property as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where the properties are unchanged but the format or content of its data are changed.)
|
||||
- parameter renamingIdentifier: used to resolve naming conflicts between models. When creating an entity mapping between entities in two managed object models, a source entity property and a destination entity property that share the same identifier indicate that a property mapping should be configured to migrate from the source to the destination. If unset, the identifier will be the property's name.
|
||||
@@ -341,7 +326,6 @@ public enum ValueContainer<O: CoreStoreObject> {
|
||||
public init(
|
||||
_ keyPath: KeyPathString,
|
||||
initial: @autoclosure @escaping () -> V? = nil,
|
||||
isIndexed: Bool = false,
|
||||
isTransient: Bool = false,
|
||||
versionHashModifier: @autoclosure @escaping () -> String? = nil,
|
||||
renamingIdentifier: @autoclosure @escaping () -> String? = nil,
|
||||
@@ -350,7 +334,6 @@ public enum ValueContainer<O: CoreStoreObject> {
|
||||
affectedByKeyPaths: @autoclosure @escaping () -> Set<String> = []) {
|
||||
|
||||
self.keyPath = keyPath
|
||||
self.isIndexed = isIndexed
|
||||
self.isTransient = isTransient
|
||||
self.defaultValue = { initial()?.cs_toQueryableNativeType() }
|
||||
self.versionHashModifier = versionHashModifier
|
||||
@@ -423,7 +406,6 @@ public enum ValueContainer<O: CoreStoreObject> {
|
||||
|
||||
internal let keyPath: KeyPathString
|
||||
internal let isOptional = true
|
||||
internal let isIndexed: Bool
|
||||
internal let isTransient: Bool
|
||||
internal let allowsExternalBinaryDataStorage = false
|
||||
internal let versionHashModifier: () -> String?
|
||||
@@ -483,11 +465,11 @@ public enum ValueContainer<O: CoreStoreObject> {
|
||||
|
||||
// MARK: Deprecated
|
||||
|
||||
@available(*, deprecated: 3.2, renamed: "init(_:initial:isIndexed:isTransient:versionHashModifier:renamingIdentifier:customGetter:customSetter:affectedByKeyPaths:)")
|
||||
@available(*, unavailable, message: "Indexes are now set through the Entity<T> initializer, which now supports compound indexes.")
|
||||
public convenience init(
|
||||
_ keyPath: KeyPathString,
|
||||
`default`: @autoclosure @escaping () -> V? = nil,
|
||||
isIndexed: Bool = false,
|
||||
initial: @autoclosure @escaping () -> V? = nil,
|
||||
isIndexed: Bool,
|
||||
isTransient: Bool = false,
|
||||
versionHashModifier: @autoclosure @escaping () -> String? = nil,
|
||||
renamingIdentifier: @autoclosure @escaping () -> String? = nil,
|
||||
@@ -495,17 +477,7 @@ public enum ValueContainer<O: CoreStoreObject> {
|
||||
customSetter: ((_ partialObject: PartialObject<O>, _ newValue: V?) -> Void)? = nil,
|
||||
affectedByKeyPaths: @autoclosure @escaping () -> Set<String> = []) {
|
||||
|
||||
self.init(
|
||||
keyPath,
|
||||
initial: `default`,
|
||||
isIndexed: isIndexed,
|
||||
isTransient: isTransient,
|
||||
versionHashModifier: versionHashModifier,
|
||||
renamingIdentifier: renamingIdentifier,
|
||||
customGetter: customGetter,
|
||||
customSetter: customSetter,
|
||||
affectedByKeyPaths: affectedByKeyPaths
|
||||
)
|
||||
fatalError()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user