mirror of
https://github.com/JohnEstropia/CoreStore.git
synced 2026-03-30 14:21:49 +02:00
WIP: documentation
This commit is contained in:
@@ -40,19 +40,19 @@ class Dog: Animal {
|
|||||||
let nickname = Value.Optional<String>("nickname")
|
let nickname = Value.Optional<String>("nickname")
|
||||||
let age = Value.Required<Int>("age", default: 1)
|
let age = Value.Required<Int>("age", default: 1)
|
||||||
let friends = Relationship.ToManyOrdered<Dog>("friends")
|
let friends = Relationship.ToManyOrdered<Dog>("friends")
|
||||||
let friends2 = Relationship.ToManyUnordered<Dog>("friends2", inverse: { $0.friends })
|
let friendedBy = Relationship.ToManyUnordered<Dog>("friendedBy", inverse: { $0.friends })
|
||||||
}
|
}
|
||||||
|
|
||||||
class Person: CoreStoreObject {
|
class Person: CoreStoreObject {
|
||||||
|
let title = Value.Required<String>("title", default: "Mr.")
|
||||||
let name = Value.Required<String>(
|
let name = Value.Required<String>(
|
||||||
"name",
|
"name",
|
||||||
customGetter: { (`self`, getValue) in
|
customGetter: { (`self`, getValue) in
|
||||||
|
|
||||||
return "Mr. \(getValue())"
|
return "\(self.title.value) \(getValue())"
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
let pet = Relationship.ToOne<Animal>("pet", inverse: { $0.master })
|
let pets = Relationship.ToManyUnordered<Animal>("pets", inverse: { $0.master })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -69,12 +69,12 @@ class DynamicModelTests: BaseTestDataTestCase {
|
|||||||
Entity<Animal>("Animal"),
|
Entity<Animal>("Animal"),
|
||||||
Entity<Dog>("Dog"),
|
Entity<Dog>("Dog"),
|
||||||
Entity<Person>("Person")
|
Entity<Person>("Person")
|
||||||
],
|
]/*,
|
||||||
versionLock: [
|
versionLock: [
|
||||||
"Animal": [0x2698c812ebbc3b97, 0x751e3fa3f04cf9, 0x51fd460d3babc82, 0x92b4ba735b5a3053],
|
"Animal": [0x2698c812ebbc3b97, 0x751e3fa3f04cf9, 0x51fd460d3babc82, 0x92b4ba735b5a3053],
|
||||||
"Dog": [0x5285f8e3aff69199, 0x62c3291b59f2ec7c, 0xbe5a571397a4117b, 0x97fb40f5b79ffbdc],
|
"Dog": [0x5285f8e3aff69199, 0x62c3291b59f2ec7c, 0xbe5a571397a4117b, 0x97fb40f5b79ffbdc],
|
||||||
"Person": [0xae4060a59f990ef0, 0x8ac83a6e1411c130, 0xa29fea58e2e38ab6, 0x2071bb7e33d77887]
|
"Person": [0xae4060a59f990ef0, 0x8ac83a6e1411c130, 0xa29fea58e2e38ab6, 0x2071bb7e33d77887]
|
||||||
]
|
]*/
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
self.prepareStack(dataStack, configurations: [nil]) { (stack) in
|
self.prepareStack(dataStack, configurations: [nil]) { (stack) in
|
||||||
@@ -112,16 +112,20 @@ class DynamicModelTests: BaseTestDataTestCase {
|
|||||||
XCTAssertEqual(dog.nickname.value, "Spot")
|
XCTAssertEqual(dog.nickname.value, "Spot")
|
||||||
|
|
||||||
let person = transaction.create(Into<Person>())
|
let person = transaction.create(Into<Person>())
|
||||||
XCTAssertNil(person.pet.value)
|
XCTAssertTrue(person.pets.value.isEmpty)
|
||||||
|
|
||||||
person.name .= "John"
|
person.name .= "John"
|
||||||
XCTAssertEqual(person.name.value, "Mr. John") // Custom getter
|
XCTAssertEqual(person.name.value, "Mr. John") // Custom getter
|
||||||
|
|
||||||
person.pet .= dog
|
person.title .= "Sir"
|
||||||
XCTAssertEqual(person.pet.value, dog)
|
XCTAssertEqual(person.name.value, "Sir John")
|
||||||
XCTAssertEqual(person.pet.value?.master.value, person)
|
|
||||||
|
person.pets.value.insert(dog)
|
||||||
|
XCTAssertEqual(person.pets.count, 1)
|
||||||
|
XCTAssertEqual(person.pets.value.first, dog)
|
||||||
|
XCTAssertEqual(person.pets.value.first?.master.value, person)
|
||||||
XCTAssertEqual(dog.master.value, person)
|
XCTAssertEqual(dog.master.value, person)
|
||||||
XCTAssertEqual(dog.master.value?.pet.value, dog)
|
XCTAssertEqual(dog.master.value?.pets.value.first, dog)
|
||||||
},
|
},
|
||||||
success: {
|
success: {
|
||||||
|
|
||||||
@@ -152,7 +156,7 @@ class DynamicModelTests: BaseTestDataTestCase {
|
|||||||
|
|
||||||
let person = transaction.fetchOne(From<Person>())
|
let person = transaction.fetchOne(From<Person>())
|
||||||
XCTAssertNotNil(person)
|
XCTAssertNotNil(person)
|
||||||
XCTAssertEqual(person!.pet.value, dog)
|
XCTAssertEqual(person!.pets.value.first, dog)
|
||||||
|
|
||||||
let p3 = Dog.where({ $0.age == 10 })
|
let p3 = Dog.where({ $0.age == 10 })
|
||||||
XCTAssertEqual(p3.predicate, NSPredicate(format: "%K == %d", "age", 10))
|
XCTAssertEqual(p3.predicate, NSPredicate(format: "%K == %d", "age", 10))
|
||||||
|
|||||||
@@ -150,8 +150,6 @@ public enum RelationshipContainer<O: CoreStoreObject> {
|
|||||||
|
|
||||||
public final class ToManyOrdered<D: CoreStoreObject>: RelationshipProtocol {
|
public final class ToManyOrdered<D: CoreStoreObject>: RelationshipProtocol {
|
||||||
|
|
||||||
// MARK: -
|
|
||||||
|
|
||||||
public static func .= (_ relationship: RelationshipContainer<O>.ToManyOrdered<D>, _ value: [D]) {
|
public static func .= (_ relationship: RelationshipContainer<O>.ToManyOrdered<D>, _ value: [D]) {
|
||||||
|
|
||||||
relationship.value = value
|
relationship.value = value
|
||||||
@@ -187,45 +185,15 @@ public enum RelationshipContainer<O: CoreStoreObject> {
|
|||||||
self.init(keyPath: keyPath, inverseKeyPath: { inverse(D.meta).keyPath }, deleteRule: deleteRule, minCount: minCount, maxCount: maxCount, versionHashModifier: versionHashModifier, renamingIdentifier: renamingIdentifier)
|
self.init(keyPath: keyPath, inverseKeyPath: { inverse(D.meta).keyPath }, deleteRule: deleteRule, minCount: minCount, maxCount: maxCount, versionHashModifier: versionHashModifier, renamingIdentifier: renamingIdentifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: add subscripts, indexed operations for more performant single updates
|
|
||||||
|
|
||||||
public var value: [D] {
|
public var value: [D] {
|
||||||
|
|
||||||
get {
|
get {
|
||||||
|
|
||||||
let object = self.parentObject() as! O
|
return self.nativeValue.map({ D.cs_fromRaw(object: $0 as! NSManagedObject) })
|
||||||
CoreStore.assert(
|
|
||||||
object.rawObject!.isRunningInAllowedQueue() == true,
|
|
||||||
"Attempted to access \(cs_typeName(O.self))'s value outside it's designated queue."
|
|
||||||
)
|
|
||||||
return object.rawObject!.getValue(
|
|
||||||
forKvcKey: self.keyPath,
|
|
||||||
didGetValue: {
|
|
||||||
|
|
||||||
guard let orderedSet = $0 as! NSOrderedSet? else {
|
|
||||||
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
return orderedSet.map({ D.cs_fromRaw(object: $0 as! NSManagedObject) })
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
set {
|
set {
|
||||||
|
|
||||||
let object = self.parentObject() as! O
|
self.nativeValue = NSOrderedSet(array: newValue.map({ $0.rawObject! }))
|
||||||
CoreStore.assert(
|
|
||||||
object.rawObject!.isRunningInAllowedQueue() == true,
|
|
||||||
"Attempted to access \(cs_typeName(O.self))'s value outside it's designated queue."
|
|
||||||
)
|
|
||||||
CoreStore.assert(
|
|
||||||
object.rawObject!.isEditableInContext() == true,
|
|
||||||
"Attempted to update a \(cs_typeName(O.self))'s value from outside a transaction."
|
|
||||||
)
|
|
||||||
object.rawObject!.setValue(
|
|
||||||
newValue,
|
|
||||||
forKvcKey: self.keyPath,
|
|
||||||
willSetValue: { NSOrderedSet(array: $0.map({ $0.rawObject! })) }
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -249,6 +217,38 @@ public enum RelationshipContainer<O: CoreStoreObject> {
|
|||||||
CoreStore.abort("Attempted to access values from a \(cs_typeName(O.self)) meta object. Meta objects are only used for querying keyPaths and infering types.")
|
CoreStore.abort("Attempted to access values from a \(cs_typeName(O.self)) meta object. Meta objects are only used for querying keyPaths and infering types.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal var nativeValue: NSOrderedSet {
|
||||||
|
|
||||||
|
get {
|
||||||
|
|
||||||
|
let object = self.parentObject() as! O
|
||||||
|
CoreStore.assert(
|
||||||
|
object.rawObject!.isRunningInAllowedQueue() == true,
|
||||||
|
"Attempted to access \(cs_typeName(O.self))'s value outside it's designated queue."
|
||||||
|
)
|
||||||
|
return object.rawObject!.getValue(
|
||||||
|
forKvcKey: self.keyPath,
|
||||||
|
didGetValue: { ($0 as! NSOrderedSet?) ?? [] }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
|
||||||
|
let object = self.parentObject() as! O
|
||||||
|
CoreStore.assert(
|
||||||
|
object.rawObject!.isRunningInAllowedQueue() == true,
|
||||||
|
"Attempted to access \(cs_typeName(O.self))'s value outside it's designated queue."
|
||||||
|
)
|
||||||
|
CoreStore.assert(
|
||||||
|
object.rawObject!.isEditableInContext() == true,
|
||||||
|
"Attempted to update a \(cs_typeName(O.self))'s value from outside a transaction."
|
||||||
|
)
|
||||||
|
object.rawObject!.setValue(
|
||||||
|
newValue,
|
||||||
|
forKvcKey: self.keyPath
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// MARK: Private
|
// MARK: Private
|
||||||
|
|
||||||
@@ -260,7 +260,7 @@ public enum RelationshipContainer<O: CoreStoreObject> {
|
|||||||
self.versionHashModifier = versionHashModifier
|
self.versionHashModifier = versionHashModifier
|
||||||
self.renamingIdentifier = renamingIdentifier
|
self.renamingIdentifier = renamingIdentifier
|
||||||
|
|
||||||
let range = (max(0, minCount) ... maxCount)
|
let range = (Swift.max(0, minCount) ... maxCount)
|
||||||
self.minCount = range.lowerBound
|
self.minCount = range.lowerBound
|
||||||
self.maxCount = range.upperBound
|
self.maxCount = range.upperBound
|
||||||
}
|
}
|
||||||
@@ -313,10 +313,40 @@ public enum RelationshipContainer<O: CoreStoreObject> {
|
|||||||
self.init(keyPath: keyPath, inverseKeyPath: { inverse(D.meta).keyPath }, deleteRule: deleteRule, minCount: minCount, maxCount: maxCount, versionHashModifier: versionHashModifier, renamingIdentifier: renamingIdentifier)
|
self.init(keyPath: keyPath, inverseKeyPath: { inverse(D.meta).keyPath }, deleteRule: deleteRule, minCount: minCount, maxCount: maxCount, versionHashModifier: versionHashModifier, renamingIdentifier: renamingIdentifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: add subscripts, indexed operations for more performant single updates
|
|
||||||
|
|
||||||
public var value: Set<D> {
|
public var value: Set<D> {
|
||||||
|
|
||||||
|
get {
|
||||||
|
|
||||||
|
return Set(self.nativeValue.map({ D.cs_fromRaw(object: $0 as! NSManagedObject) }))
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
|
||||||
|
self.nativeValue = NSSet(array: newValue.map({ $0.rawObject! }))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: RelationshipProtocol
|
||||||
|
|
||||||
|
public let keyPath: KeyPath
|
||||||
|
|
||||||
|
internal let isToMany = true
|
||||||
|
internal let isOptional = true
|
||||||
|
internal let isOrdered = false
|
||||||
|
internal let deleteRule: NSDeleteRule
|
||||||
|
internal let minCount: Int
|
||||||
|
internal let maxCount: Int
|
||||||
|
internal let inverse: (type: CoreStoreObject.Type, keyPath: () -> KeyPath?)
|
||||||
|
internal let versionHashModifier: String?
|
||||||
|
internal let renamingIdentifier: String?
|
||||||
|
|
||||||
|
internal var parentObject: () -> CoreStoreObject = {
|
||||||
|
|
||||||
|
CoreStore.abort("Attempted to access values from a \(cs_typeName(O.self)) meta object. Meta objects are only used for querying keyPaths and infering types.")
|
||||||
|
}
|
||||||
|
|
||||||
|
internal var nativeValue: NSSet {
|
||||||
|
|
||||||
get {
|
get {
|
||||||
|
|
||||||
let object = self.parentObject() as! O
|
let object = self.parentObject() as! O
|
||||||
@@ -326,14 +356,7 @@ public enum RelationshipContainer<O: CoreStoreObject> {
|
|||||||
)
|
)
|
||||||
return object.rawObject!.getValue(
|
return object.rawObject!.getValue(
|
||||||
forKvcKey: self.keyPath,
|
forKvcKey: self.keyPath,
|
||||||
didGetValue: {
|
didGetValue: { ($0 as! NSSet?) ?? [] }
|
||||||
|
|
||||||
guard let set = $0 as! NSSet? else {
|
|
||||||
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
return Set(set.map({ D.cs_fromRaw(object: $0 as! NSManagedObject) }))
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
set {
|
set {
|
||||||
@@ -349,33 +372,12 @@ public enum RelationshipContainer<O: CoreStoreObject> {
|
|||||||
)
|
)
|
||||||
object.rawObject!.setValue(
|
object.rawObject!.setValue(
|
||||||
newValue,
|
newValue,
|
||||||
forKvcKey: self.keyPath,
|
forKvcKey: self.keyPath
|
||||||
willSetValue: { NSSet(array: $0.map({ $0.rawObject! })) }
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// MARK: RelationshipProtocol
|
|
||||||
|
|
||||||
public let keyPath: KeyPath
|
|
||||||
|
|
||||||
internal let isToMany = true
|
|
||||||
internal let isOptional = true
|
|
||||||
internal let isOrdered = true
|
|
||||||
internal let deleteRule: NSDeleteRule
|
|
||||||
internal let minCount: Int
|
|
||||||
internal let maxCount: Int
|
|
||||||
internal let inverse: (type: CoreStoreObject.Type, keyPath: () -> KeyPath?)
|
|
||||||
internal let versionHashModifier: String?
|
|
||||||
internal let renamingIdentifier: String?
|
|
||||||
|
|
||||||
internal var parentObject: () -> CoreStoreObject = {
|
|
||||||
|
|
||||||
CoreStore.abort("Attempted to access values from a \(cs_typeName(O.self)) meta object. Meta objects are only used for querying keyPaths and infering types.")
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: Private
|
// MARK: Private
|
||||||
|
|
||||||
private init(keyPath: KeyPath, inverseKeyPath: @escaping () -> KeyPath?, deleteRule: DeleteRule, minCount: Int, maxCount: Int, versionHashModifier: String?, renamingIdentifier: String?) {
|
private init(keyPath: KeyPath, inverseKeyPath: @escaping () -> KeyPath?, deleteRule: DeleteRule, minCount: Int, maxCount: Int, versionHashModifier: String?, renamingIdentifier: String?) {
|
||||||
@@ -386,7 +388,7 @@ public enum RelationshipContainer<O: CoreStoreObject> {
|
|||||||
self.versionHashModifier = versionHashModifier
|
self.versionHashModifier = versionHashModifier
|
||||||
self.renamingIdentifier = renamingIdentifier
|
self.renamingIdentifier = renamingIdentifier
|
||||||
|
|
||||||
let range = (max(0, minCount) ... maxCount)
|
let range = (Swift.max(0, minCount) ... maxCount)
|
||||||
self.minCount = range.lowerBound
|
self.minCount = range.lowerBound
|
||||||
self.maxCount = range.upperBound
|
self.maxCount = range.upperBound
|
||||||
}
|
}
|
||||||
@@ -414,6 +416,74 @@ public enum RelationshipContainer<O: CoreStoreObject> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: RelationshipContainer.ToManyOrdered: RandomAccessCollection
|
||||||
|
|
||||||
|
extension RelationshipContainer.ToManyOrdered: RandomAccessCollection {
|
||||||
|
|
||||||
|
// MARK: Sequence
|
||||||
|
|
||||||
|
public typealias Iterator = AnyIterator<D>
|
||||||
|
|
||||||
|
public func makeIterator() -> Iterator {
|
||||||
|
|
||||||
|
let iterator = self.nativeValue.makeIterator()
|
||||||
|
return AnyIterator({ D.cs_fromRaw(object: iterator.next() as! NSManagedObject) })
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: Collection
|
||||||
|
|
||||||
|
public typealias Index = Int
|
||||||
|
|
||||||
|
public var startIndex: Index {
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
public var endIndex: Index {
|
||||||
|
|
||||||
|
return self.nativeValue.count
|
||||||
|
}
|
||||||
|
|
||||||
|
public subscript(position: Index) -> Iterator.Element {
|
||||||
|
|
||||||
|
return D.cs_fromRaw(object: self.nativeValue[position] as! NSManagedObject)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func index(after i: Index) -> Index {
|
||||||
|
|
||||||
|
return i + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: RelationshipContainer.ToManyUnordered: Sequence
|
||||||
|
|
||||||
|
extension RelationshipContainer.ToManyUnordered: Sequence {
|
||||||
|
|
||||||
|
public var count: Int {
|
||||||
|
|
||||||
|
return self.nativeValue.count
|
||||||
|
}
|
||||||
|
|
||||||
|
public var isEmpty: Bool {
|
||||||
|
|
||||||
|
return self.nativeValue.count == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: Sequence
|
||||||
|
|
||||||
|
public typealias Iterator = AnyIterator<D>
|
||||||
|
|
||||||
|
public func makeIterator() -> Iterator {
|
||||||
|
|
||||||
|
let iterator = self.nativeValue.makeIterator()
|
||||||
|
return AnyIterator({ D.cs_fromRaw(object: iterator.next() as! NSManagedObject) })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// MARK: - RelationshipProtocol
|
// MARK: - RelationshipProtocol
|
||||||
|
|
||||||
internal protocol RelationshipProtocol: class {
|
internal protocol RelationshipProtocol: class {
|
||||||
|
|||||||
Reference in New Issue
Block a user