mirror of
https://github.com/JohnEstropia/CoreStore.git
synced 2026-01-18 23:17:02 +01:00
trials
This commit is contained in:
@@ -94,13 +94,14 @@ extension CoreStoreError: CustomDebugStringConvertible, CoreStoreDebugStringConv
|
||||
firstLine = ".progressiveMigrationRequired"
|
||||
info.append(("localStoreURL", localStoreURL))
|
||||
|
||||
case .asynchronousMigrationRequired(let localStoreURL):
|
||||
case .asynchronousMigrationRequired(let localStoreURL, let nsError):
|
||||
firstLine = ".asynchronousMigrationRequired"
|
||||
info.append(("localStoreURL", localStoreURL))
|
||||
info.append(("NSError", nsError))
|
||||
|
||||
case .internalError(let NSError):
|
||||
case .internalError(let nsError):
|
||||
firstLine = ".internalError"
|
||||
info.append(("NSError", NSError))
|
||||
info.append(("NSError", nsError))
|
||||
|
||||
case .userError(error: let error):
|
||||
firstLine = ".userError"
|
||||
|
||||
@@ -197,14 +197,7 @@ public enum CoreStoreError: Error, CustomNSError, Hashable {
|
||||
return NSError1.isEqual(NSError2)
|
||||
|
||||
case (.userError(let error1), .userError(let error2)):
|
||||
switch (error1, error2) {
|
||||
|
||||
case (let error1 as AnyHashable, let error2 as AnyHashable):
|
||||
return error1 == error2
|
||||
|
||||
case (let error1 as NSError, let error2 as NSError):
|
||||
return error1.isEqual(error2)
|
||||
}
|
||||
return error1.bridgeToSwift == error2.bridgeToSwift
|
||||
|
||||
case (.userCancelled, .userCancelled):
|
||||
return true
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
//
|
||||
// CoreStoreObject+DataSources.swift
|
||||
// CoreStore iOS
|
||||
//
|
||||
// Created by John Estropia on 2019/10/04.
|
||||
// Copyright © 2019 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
#if canImport(UIKit) || canImport(AppKit)
|
||||
|
||||
#if canImport(Combine)
|
||||
import Combine
|
||||
|
||||
// MARK: - ListPublisher: ObservableObject
|
||||
|
||||
@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *)
|
||||
extension CoreStoreObject: ObservableObject {
|
||||
|
||||
// MARK: ObservableObject
|
||||
|
||||
public var objectWillChange: ObservableObjectPublisher {
|
||||
|
||||
return self.cs_toRaw().objectWillChange
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -106,47 +106,47 @@ extension Int64: AllowedObjectiveCKeyPathValue {
|
||||
|
||||
extension NSData: AllowedOptionalObjectiveCKeyPathValue {
|
||||
|
||||
public typealias DestinationValueType = Self
|
||||
public typealias DestinationValueType = NSData
|
||||
}
|
||||
|
||||
extension NSDate: AllowedOptionalObjectiveCKeyPathValue {
|
||||
|
||||
public typealias DestinationValueType = Self
|
||||
public typealias DestinationValueType = NSDate
|
||||
}
|
||||
|
||||
extension NSManagedObject: AllowedOptionalObjectiveCKeyPathValue {
|
||||
|
||||
public typealias DestinationValueType = Self
|
||||
public typealias DestinationValueType = NSManagedObject
|
||||
}
|
||||
|
||||
extension NSNumber: AllowedOptionalObjectiveCKeyPathValue {
|
||||
|
||||
public typealias DestinationValueType = Self
|
||||
public typealias DestinationValueType = NSNumber
|
||||
}
|
||||
|
||||
extension NSString: AllowedOptionalObjectiveCKeyPathValue {
|
||||
|
||||
public typealias DestinationValueType = Self
|
||||
public typealias DestinationValueType = NSString
|
||||
}
|
||||
|
||||
extension NSSet: AllowedOptionalObjectiveCKeyPathValue {
|
||||
|
||||
public typealias DestinationValueType = Self
|
||||
public typealias DestinationValueType = NSSet
|
||||
}
|
||||
|
||||
extension NSOrderedSet: AllowedOptionalObjectiveCKeyPathValue {
|
||||
|
||||
public typealias DestinationValueType = Self
|
||||
public typealias DestinationValueType = NSOrderedSet
|
||||
}
|
||||
|
||||
extension NSURL: AllowedOptionalObjectiveCKeyPathValue {
|
||||
|
||||
public typealias DestinationValueType = Self
|
||||
public typealias DestinationValueType = NSURL
|
||||
}
|
||||
|
||||
extension NSUUID: AllowedOptionalObjectiveCKeyPathValue {
|
||||
|
||||
public typealias DestinationValueType = Self
|
||||
public typealias DestinationValueType = NSUUID
|
||||
}
|
||||
|
||||
extension String: AllowedOptionalObjectiveCKeyPathValue {
|
||||
@@ -240,32 +240,32 @@ extension Int64: AllowedObjectiveCAttributeKeyPathValue {
|
||||
|
||||
extension NSData: AllowedObjectiveCAttributeKeyPathValue {
|
||||
|
||||
public typealias ReturnValueType = Self
|
||||
public typealias ReturnValueType = NSData
|
||||
}
|
||||
|
||||
extension NSDate: AllowedObjectiveCAttributeKeyPathValue {
|
||||
|
||||
public typealias ReturnValueType = Self
|
||||
public typealias ReturnValueType = NSDate
|
||||
}
|
||||
|
||||
extension NSNumber: AllowedObjectiveCAttributeKeyPathValue {
|
||||
|
||||
public typealias ReturnValueType = Self
|
||||
public typealias ReturnValueType = NSNumber
|
||||
}
|
||||
|
||||
extension NSString: AllowedObjectiveCAttributeKeyPathValue {
|
||||
|
||||
public typealias ReturnValueType = Self
|
||||
public typealias ReturnValueType = NSString
|
||||
}
|
||||
|
||||
extension NSURL: AllowedObjectiveCAttributeKeyPathValue {
|
||||
|
||||
public typealias ReturnValueType = Self
|
||||
public typealias ReturnValueType = NSURL
|
||||
}
|
||||
|
||||
extension NSUUID: AllowedObjectiveCAttributeKeyPathValue {
|
||||
|
||||
public typealias ReturnValueType = Self
|
||||
public typealias ReturnValueType = NSUUID
|
||||
}
|
||||
|
||||
extension String: AllowedObjectiveCAttributeKeyPathValue {
|
||||
|
||||
@@ -73,6 +73,7 @@ public enum ValueContainer<O: CoreStoreObject> {
|
||||
```
|
||||
- Important: `Value.Required` properties are required to be stored properties. Computed properties will be ignored, including `lazy` and `weak` properties.
|
||||
*/
|
||||
@propertyWrapper
|
||||
public final class Required<V: ImportableAttributeType>: AttributeKeyPathStringConvertible, AttributeProtocol {
|
||||
|
||||
/**
|
||||
@@ -110,7 +111,7 @@ public enum ValueContainer<O: CoreStoreObject> {
|
||||
- parameter customSetter: use this closure as an "override" for the default property setter. 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>.setPrimitiveValue(_:for:)` instead of `PartialObject<O>.setValue(_:for:)`, which would unintentionally execute the same closure again recursively.
|
||||
- parameter affectedByKeyPaths: a set of key paths for properties whose values affect the value of the receiver. This is similar to `NSManagedObject.keyPathsForValuesAffectingValue(forKey:)`.
|
||||
*/
|
||||
public init(
|
||||
public convenience init(
|
||||
_ keyPath: KeyPathString,
|
||||
initial: @autoclosure @escaping () -> V,
|
||||
isTransient: Bool = false,
|
||||
@@ -119,15 +120,17 @@ public enum ValueContainer<O: CoreStoreObject> {
|
||||
customGetter: ((_ partialObject: PartialObject<O>) -> V)? = nil,
|
||||
customSetter: ((_ partialObject: PartialObject<O>, _ newValue: V) -> Void)? = nil,
|
||||
affectedByKeyPaths: @autoclosure @escaping () -> Set<String> = []) {
|
||||
|
||||
self.keyPath = keyPath
|
||||
self.isTransient = isTransient
|
||||
self.defaultValue = { initial().cs_toQueryableNativeType() }
|
||||
self.versionHashModifier = versionHashModifier
|
||||
self.renamingIdentifier = renamingIdentifier
|
||||
self.customGetter = customGetter
|
||||
self.customSetter = customSetter
|
||||
self.affectedByKeyPaths = affectedByKeyPaths
|
||||
|
||||
self.init(
|
||||
wrappedValue: initial(),
|
||||
keyPath,
|
||||
isTransient: isTransient,
|
||||
versionHashModifier: versionHashModifier(),
|
||||
renamingIdentifier: renamingIdentifier(),
|
||||
customGetter: customGetter,
|
||||
customSetter: customSetter,
|
||||
affectedByKeyPaths: affectedByKeyPaths()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -135,24 +138,59 @@ public enum ValueContainer<O: CoreStoreObject> {
|
||||
*/
|
||||
public var value: ReturnValueType {
|
||||
|
||||
get {
|
||||
|
||||
return self.wrappedValue
|
||||
}
|
||||
set {
|
||||
|
||||
self.wrappedValue = newValue
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: @propertyWrapper
|
||||
|
||||
public init(
|
||||
wrappedValue initialValue: @autoclosure @escaping () -> V,
|
||||
_ keyPath: KeyPathString,
|
||||
isTransient: 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.keyPath = keyPath
|
||||
self.isTransient = isTransient
|
||||
self.defaultValue = { initialValue().cs_toQueryableNativeType() }
|
||||
self.versionHashModifier = versionHashModifier
|
||||
self.renamingIdentifier = renamingIdentifier
|
||||
self.customGetter = customGetter
|
||||
self.customSetter = customSetter
|
||||
self.affectedByKeyPaths = affectedByKeyPaths
|
||||
}
|
||||
|
||||
public var wrappedValue: V {
|
||||
|
||||
get {
|
||||
|
||||
Internals.assert(
|
||||
self.rawObject != nil,
|
||||
"Attempted to access values from a \(Internals.typeName(O.self)) meta object. Meta objects are only used for querying keyPaths and infering types."
|
||||
)
|
||||
return withExtendedLifetime(self.rawObject!) { (object) in
|
||||
|
||||
return withExtendedLifetime(self.rawObject!) { (rawObject) in
|
||||
|
||||
Internals.assert(
|
||||
object.isRunningInAllowedQueue() == true,
|
||||
rawObject.isRunningInAllowedQueue() == true,
|
||||
"Attempted to access \(Internals.typeName(O.self))'s value outside it's designated queue."
|
||||
)
|
||||
if let customGetter = self.customGetter {
|
||||
|
||||
return customGetter(PartialObject<O>(object))
|
||||
|
||||
return customGetter(PartialObject<O>(rawObject))
|
||||
}
|
||||
return V.cs_fromQueryableNativeType(
|
||||
object.value(forKey: self.keyPath)! as! V.QueryableNativeType
|
||||
rawObject.value(forKey: self.keyPath)! as! V.QueryableNativeType
|
||||
)!
|
||||
}
|
||||
}
|
||||
@@ -162,27 +200,32 @@ public enum ValueContainer<O: CoreStoreObject> {
|
||||
self.rawObject != nil,
|
||||
"Attempted to access values from a \(Internals.typeName(O.self)) meta object. Meta objects are only used for querying keyPaths and infering types."
|
||||
)
|
||||
return withExtendedLifetime(self.rawObject!) { (object) in
|
||||
|
||||
return withExtendedLifetime(self.rawObject!) { (rawObject) in
|
||||
|
||||
Internals.assert(
|
||||
object.isRunningInAllowedQueue() == true,
|
||||
rawObject.isRunningInAllowedQueue() == true,
|
||||
"Attempted to access \(Internals.typeName(O.self))'s value outside it's designated queue."
|
||||
)
|
||||
Internals.assert(
|
||||
object.isEditableInContext() == true,
|
||||
rawObject.isEditableInContext() == true,
|
||||
"Attempted to update a \(Internals.typeName(O.self))'s value from outside a transaction."
|
||||
)
|
||||
if let customSetter = self.customSetter {
|
||||
|
||||
return customSetter(PartialObject<O>(object), newValue)
|
||||
|
||||
return customSetter(PartialObject<O>(rawObject), newValue)
|
||||
}
|
||||
return object.setValue(
|
||||
return rawObject.setValue(
|
||||
newValue.cs_toQueryableNativeType(),
|
||||
forKey: self.keyPath
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public var projectedValue: ValueContainer<O>.Required<V> {
|
||||
|
||||
return self
|
||||
}
|
||||
|
||||
|
||||
// MARK: AnyKeyPathStringConvertible
|
||||
@@ -293,6 +336,7 @@ public enum ValueContainer<O: CoreStoreObject> {
|
||||
```
|
||||
- Important: `Value.Optional` properties are required to be stored properties. Computed properties will be ignored, including `lazy` and `weak` properties.
|
||||
*/
|
||||
@propertyWrapper
|
||||
public final class Optional<V: ImportableAttributeType>: AttributeKeyPathStringConvertible, AttributeProtocol {
|
||||
|
||||
/**
|
||||
@@ -333,7 +377,7 @@ public enum ValueContainer<O: CoreStoreObject> {
|
||||
- parameter originalNewValue: the original new value
|
||||
- parameter affectedByKeyPaths: a set of key paths for properties whose values affect the value of the receiver. This is similar to `NSManagedObject.keyPathsForValuesAffectingValue(forKey:)`.
|
||||
*/
|
||||
public init(
|
||||
public convenience init(
|
||||
_ keyPath: KeyPathString,
|
||||
initial: @autoclosure @escaping () -> V? = nil,
|
||||
isTransient: Bool = false,
|
||||
@@ -343,14 +387,16 @@ public enum ValueContainer<O: CoreStoreObject> {
|
||||
customSetter: ((_ partialObject: PartialObject<O>, _ newValue: V?) -> Void)? = nil,
|
||||
affectedByKeyPaths: @autoclosure @escaping () -> Set<String> = []) {
|
||||
|
||||
self.keyPath = keyPath
|
||||
self.isTransient = isTransient
|
||||
self.defaultValue = { initial()?.cs_toQueryableNativeType() }
|
||||
self.versionHashModifier = versionHashModifier
|
||||
self.renamingIdentifier = renamingIdentifier
|
||||
self.customGetter = customGetter
|
||||
self.customSetter = customSetter
|
||||
self.affectedByKeyPaths = affectedByKeyPaths
|
||||
self.init(
|
||||
wrappedValue: initial(),
|
||||
keyPath,
|
||||
isTransient: isTransient,
|
||||
versionHashModifier: versionHashModifier(),
|
||||
renamingIdentifier: renamingIdentifier(),
|
||||
customGetter: customGetter,
|
||||
customSetter: customSetter,
|
||||
affectedByKeyPaths: affectedByKeyPaths()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -358,23 +404,58 @@ public enum ValueContainer<O: CoreStoreObject> {
|
||||
*/
|
||||
public var value: ReturnValueType {
|
||||
|
||||
get {
|
||||
|
||||
return self.wrappedValue
|
||||
}
|
||||
set {
|
||||
|
||||
self.wrappedValue = newValue
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: @propertyWrapper
|
||||
|
||||
public init(
|
||||
wrappedValue initialValue: @autoclosure @escaping () -> V?,
|
||||
_ keyPath: KeyPathString,
|
||||
isTransient: 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.keyPath = keyPath
|
||||
self.isTransient = isTransient
|
||||
self.defaultValue = { initialValue()?.cs_toQueryableNativeType() }
|
||||
self.versionHashModifier = versionHashModifier
|
||||
self.renamingIdentifier = renamingIdentifier
|
||||
self.customGetter = customGetter
|
||||
self.customSetter = customSetter
|
||||
self.affectedByKeyPaths = affectedByKeyPaths
|
||||
}
|
||||
|
||||
public var wrappedValue: V? {
|
||||
|
||||
get {
|
||||
|
||||
Internals.assert(
|
||||
self.rawObject != nil,
|
||||
"Attempted to access values from a \(Internals.typeName(O.self)) meta object. Meta objects are only used for querying keyPaths and infering types."
|
||||
)
|
||||
return withExtendedLifetime(self.rawObject!) { (object) in
|
||||
return withExtendedLifetime(self.rawObject!) { (rawObject) in
|
||||
|
||||
Internals.assert(
|
||||
object.isRunningInAllowedQueue() == true,
|
||||
rawObject.isRunningInAllowedQueue() == true,
|
||||
"Attempted to access \(Internals.typeName(O.self))'s value outside it's designated queue."
|
||||
)
|
||||
if let customGetter = self.customGetter {
|
||||
|
||||
return customGetter(PartialObject<O>(object))
|
||||
return customGetter(PartialObject<O>(rawObject))
|
||||
}
|
||||
return (object.value(forKey: self.keyPath) as! V.QueryableNativeType?)
|
||||
return (rawObject.value(forKey: self.keyPath) as! V.QueryableNativeType?)
|
||||
.flatMap(V.cs_fromQueryableNativeType)
|
||||
}
|
||||
}
|
||||
@@ -384,27 +465,32 @@ public enum ValueContainer<O: CoreStoreObject> {
|
||||
self.rawObject != nil,
|
||||
"Attempted to access values from a \(Internals.typeName(O.self)) meta object. Meta objects are only used for querying keyPaths and infering types."
|
||||
)
|
||||
return withExtendedLifetime(self.rawObject!) { (object) in
|
||||
return withExtendedLifetime(self.rawObject!) { (rawObject) in
|
||||
|
||||
Internals.assert(
|
||||
object.isRunningInAllowedQueue() == true,
|
||||
rawObject.isRunningInAllowedQueue() == true,
|
||||
"Attempted to access \(Internals.typeName(O.self))'s value outside it's designated queue."
|
||||
)
|
||||
Internals.assert(
|
||||
object.isEditableInContext() == true,
|
||||
rawObject.isEditableInContext() == true,
|
||||
"Attempted to update a \(Internals.typeName(O.self))'s value from outside a transaction."
|
||||
)
|
||||
if let customSetter = self.customSetter {
|
||||
|
||||
return customSetter(PartialObject<O>(object), newValue)
|
||||
return customSetter(PartialObject<O>(rawObject), newValue)
|
||||
}
|
||||
object.setValue(
|
||||
rawObject.setValue(
|
||||
newValue?.cs_toQueryableNativeType(),
|
||||
forKey: self.keyPath
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public var projectedValue: ValueContainer<O>.Optional<V> {
|
||||
|
||||
return self
|
||||
}
|
||||
|
||||
|
||||
// MARK: AnyKeyPathStringConvertible
|
||||
|
||||
Reference in New Issue
Block a user