add comparison operators for Where.Expression

This commit is contained in:
John Estropia
2019-02-08 17:16:56 +09:00
parent db4426e6b9
commit 635201868a
2 changed files with 154 additions and 24 deletions

View File

@@ -66,14 +66,17 @@ final class WhereTests: XCTestCase {
XCTAssertEqual( XCTAssertEqual(
#keyPath(TestEntity1.testToOne.testEntityID), #keyPath(TestEntity1.testToOne.testEntityID),
(\TestEntity1.testToOne ~ \.testEntityID).description,
String(keyPath: \TestEntity1.testToOne ~ \.testEntityID) String(keyPath: \TestEntity1.testToOne ~ \.testEntityID)
) )
XCTAssertEqual( XCTAssertEqual(
#keyPath(TestEntity1.testToOne.testToOne.testToManyUnordered), #keyPath(TestEntity1.testToOne.testToOne.testToManyUnordered),
(\TestEntity1.testToOne ~ \.testToOne ~ \.testToManyUnordered).description,
String(keyPath: \TestEntity1.testToOne ~ \.testToOne ~ \.testToManyUnordered) String(keyPath: \TestEntity1.testToOne ~ \.testToOne ~ \.testToManyUnordered)
) )
XCTAssertEqual( XCTAssertEqual(
#keyPath(TestEntity2.testToOne.testToOne.testToManyOrdered), #keyPath(TestEntity2.testToOne.testToOne.testToManyOrdered),
(\TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered).description,
String(keyPath: \TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered) String(keyPath: \TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered)
) )
} }
@@ -81,14 +84,17 @@ final class WhereTests: XCTestCase {
XCTAssertEqual( XCTAssertEqual(
"master.pets", "master.pets",
(\Animal.master ~ \.pets).description,
String(keyPath: \Animal.master ~ \.pets) String(keyPath: \Animal.master ~ \.pets)
) )
XCTAssertEqual( XCTAssertEqual(
"master.pets.species", "master.pets.species",
(\Animal.master ~ \.pets ~ \.species).description,
String(keyPath: \Animal.master ~ \.pets ~ \.species) String(keyPath: \Animal.master ~ \.pets ~ \.species)
) )
XCTAssertEqual( XCTAssertEqual(
"master.pets.master", "master.pets.master",
(\Animal.master ~ \.pets ~ \.master).description,
String(keyPath: \Animal.master ~ \.pets ~ \.master) String(keyPath: \Animal.master ~ \.pets ~ \.master)
) )
} }
@@ -96,84 +102,99 @@ final class WhereTests: XCTestCase {
XCTAssertEqual( XCTAssertEqual(
#keyPath(TestEntity1.testToOne.testToManyUnordered) + ".@count", #keyPath(TestEntity1.testToOne.testToManyUnordered) + ".@count",
(\TestEntity1.testToOne ~ \.testToManyUnordered).count().description (\TestEntity1.testToOne ~ \.testToManyUnordered).count().description,
String(keyPath: (\TestEntity1.testToOne ~ \.testToManyUnordered).count())
) )
XCTAssertEqual( XCTAssertEqual(
#keyPath(TestEntity2.testToOne.testToOne.testToManyOrdered) + ".@count", #keyPath(TestEntity2.testToOne.testToOne.testToManyOrdered) + ".@count",
(\TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered).count().description (\TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered).count().description,
String(keyPath: (\TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered).count())
) )
} }
do { do {
XCTAssertEqual( XCTAssertEqual(
"master.pets.@count", "master.pets.@count",
(\Animal.master ~ \.pets).count().description (\Animal.master ~ \.pets).count().description,
String(keyPath: (\Animal.master ~ \.pets).count())
) )
} }
do { do {
XCTAssertEqual( XCTAssertEqual(
"ANY " + #keyPath(TestEntity1.testToOne.testToManyUnordered), "ANY " + #keyPath(TestEntity1.testToOne.testToManyUnordered),
(\TestEntity1.testToOne ~ \.testToManyUnordered).any().description (\TestEntity1.testToOne ~ \.testToManyUnordered).any().description,
String(keyPath: (\TestEntity1.testToOne ~ \.testToManyUnordered).any())
) )
XCTAssertEqual( XCTAssertEqual(
"ANY " + #keyPath(TestEntity2.testToOne.testToOne.testToManyOrdered), "ANY " + #keyPath(TestEntity2.testToOne.testToOne.testToManyOrdered),
(\TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered).any().description (\TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered).any().description,
String(keyPath: (\TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered).any())
) )
} }
do { do {
XCTAssertEqual( XCTAssertEqual(
"ANY master.pets", "ANY master.pets",
(\Animal.master ~ \.pets).any().description (\Animal.master ~ \.pets).any().description,
String(keyPath: (\Animal.master ~ \.pets).any())
) )
XCTAssertEqual( XCTAssertEqual(
"ANY master.pets.species", "ANY master.pets.species",
(\Animal.master ~ \.pets ~ \.species).any().description (\Animal.master ~ \.pets ~ \.species).any().description,
String(keyPath: (\Animal.master ~ \.pets ~ \.species).any())
) )
} }
do { do {
XCTAssertEqual( XCTAssertEqual(
"ALL " + #keyPath(TestEntity1.testToOne.testToManyUnordered), "ALL " + #keyPath(TestEntity1.testToOne.testToManyUnordered),
(\TestEntity1.testToOne ~ \.testToManyUnordered).all().description (\TestEntity1.testToOne ~ \.testToManyUnordered).all().description,
String(keyPath: (\TestEntity1.testToOne ~ \.testToManyUnordered).all())
) )
XCTAssertEqual( XCTAssertEqual(
"ALL " + #keyPath(TestEntity2.testToOne.testToOne.testToManyOrdered), "ALL " + #keyPath(TestEntity2.testToOne.testToOne.testToManyOrdered),
(\TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered).all().description (\TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered).all().description,
String(keyPath: (\TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered).all())
) )
} }
do { do {
XCTAssertEqual( XCTAssertEqual(
"ALL master.pets", "ALL master.pets",
(\Animal.master ~ \.pets).all().description (\Animal.master ~ \.pets).all().description,
String(keyPath: (\Animal.master ~ \.pets).all())
) )
XCTAssertEqual( XCTAssertEqual(
"ALL master.pets.species", "ALL master.pets.species",
(\Animal.master ~ \.pets ~ \.species).all().description (\Animal.master ~ \.pets ~ \.species).all().description,
String(keyPath: (\Animal.master ~ \.pets ~ \.species).all())
) )
} }
do { do {
XCTAssertEqual( XCTAssertEqual(
"NONE " + #keyPath(TestEntity1.testToOne.testToManyUnordered), "NONE " + #keyPath(TestEntity1.testToOne.testToManyUnordered),
(\TestEntity1.testToOne ~ \.testToManyUnordered).none().description (\TestEntity1.testToOne ~ \.testToManyUnordered).none().description,
String(keyPath: (\TestEntity1.testToOne ~ \.testToManyUnordered).none())
) )
XCTAssertEqual( XCTAssertEqual(
"NONE " + #keyPath(TestEntity2.testToOne.testToOne.testToManyOrdered), "NONE " + #keyPath(TestEntity2.testToOne.testToOne.testToManyOrdered),
(\TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered).none().description (\TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered).none().description,
String(keyPath: (\TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered).none())
) )
} }
do { do {
XCTAssertEqual( XCTAssertEqual(
"NONE master.pets", "NONE master.pets",
(\Animal.master ~ \.pets).none().description (\Animal.master ~ \.pets).none().description,
String(keyPath: (\Animal.master ~ \.pets).none())
) )
XCTAssertEqual( XCTAssertEqual(
"NONE master.pets.species", "NONE master.pets.species",
(\Animal.master ~ \.pets ~ \.species).none().description (\Animal.master ~ \.pets ~ \.species).none().description,
String(keyPath: (\Animal.master ~ \.pets ~ \.species).none())
) )
} }
} }

View File

@@ -91,7 +91,7 @@ extension Where {
} }
// MARK: - ~ Operator (Where.Expression Creation Operators) // MARK: - ~ (Where.Expression Creation Operators)
// MARK: ~ where D: NSManagedObject // MARK: ~ where D: NSManagedObject
@@ -218,6 +218,29 @@ public func ~= <D, T, V: QueryableAttributeType, S: Sequence>(_ sequence: S, _ e
} }
// MARK: - Where.Expression where V: QueryableAttributeType & Comparable
public func < <D, T, V: QueryableAttributeType & Comparable>(_ lhs: Where<D>.Expression<T, V>, _ rhs: V) -> Where<D> {
return Where<D>(expression: lhs, function: "<", operand: rhs)
}
public func <= <D, T, V: QueryableAttributeType & Comparable>(_ lhs: Where<D>.Expression<T, V>, _ rhs: V) -> Where<D> {
return Where<D>(expression: lhs, function: "<=", operand: rhs)
}
public func > <D, T, V: QueryableAttributeType & Comparable>(_ lhs: Where<D>.Expression<T, V>, _ rhs: V) -> Where<D> {
return Where<D>(expression: lhs, function: ">", operand: rhs)
}
public func >= <D, T, V: QueryableAttributeType & Comparable>(_ lhs: Where<D>.Expression<T, V>, _ rhs: V) -> Where<D> {
return Where<D>(expression: lhs, function: ">=", operand: rhs)
}
// MARK: - Where.Expression where V: Optional<QueryableAttributeType> // MARK: - Where.Expression where V: Optional<QueryableAttributeType>
public func == <D, T, V: QueryableAttributeType>(_ lhs: Where<D>.Expression<T, V?>, _ rhs: V) -> Where<D> { public func == <D, T, V: QueryableAttributeType>(_ lhs: Where<D>.Expression<T, V?>, _ rhs: V) -> Where<D> {
@@ -246,11 +269,44 @@ public func ~= <D, T, V: QueryableAttributeType, S: Sequence>(_ sequence: S, _ e
} }
// MARK: - Where.Expression where V: Optional<QueryableAttributeType & Comparable>
public func < <D, T, V: QueryableAttributeType & Comparable>(_ lhs: Where<D>.Expression<T, V?>, _ rhs: V) -> Where<D> {
return Where<D>(expression: lhs, function: "<", operand: rhs)
}
public func <= <D, T, V: QueryableAttributeType & Comparable>(_ lhs: Where<D>.Expression<T, V?>, _ rhs: V?) -> Where<D> {
return Where<D>(expression: lhs, function: "<=", operand: rhs)
}
public func > <D, T, V: QueryableAttributeType & Comparable>(_ lhs: Where<D>.Expression<T, V?>, _ rhs: V) -> Where<D> {
return Where<D>(expression: lhs, function: ">", operand: rhs)
}
public func >= <D, T, V: QueryableAttributeType & Comparable>(_ lhs: Where<D>.Expression<T, V?>, _ rhs: V?) -> Where<D> {
return Where<D>(expression: lhs, function: ">=", operand: rhs)
}
// MARK: - KeyPath where Root: NSManagedObject, Value: AllowedObjectiveCCollectionKeyPathValue
extension KeyPath where Root: NSManagedObject, Value: AllowedObjectiveCCollectionKeyPathValue {
public func count() -> Where<Root>.Expression<Where<Root>.CollectionTarget, Int> {
return .init(self.cs_keyPathString, "@count")
}
}
// MARK: - Where.Expression where D: NSManagedObject, T == Where<D>.CollectionTarget, V: AllowedObjectiveCCollectionKeyPathValue // MARK: - Where.Expression where D: NSManagedObject, T == Where<D>.CollectionTarget, V: AllowedObjectiveCCollectionKeyPathValue
extension Where.Expression where D: NSManagedObject, T == Where<D>.CollectionTarget, V: AllowedObjectiveCCollectionKeyPathValue { extension Where.Expression where D: NSManagedObject, T == Where<D>.CollectionTarget, V: AllowedObjectiveCCollectionKeyPathValue {
public func count() -> Where<D>.Expression<Where<D>.CollectionTarget, Int> { public func count() -> Where<D>.Expression<T, Int> {
return .init(self.cs_keyPathString, "@count") return .init(self.cs_keyPathString, "@count")
} }
@@ -261,44 +317,97 @@ extension Where.Expression where D: NSManagedObject, T == Where<D>.CollectionTar
extension Where.Expression where D: NSManagedObject, T == Where<D>.CollectionTarget, V: AllowedObjectiveCKeyPathValue { extension Where.Expression where D: NSManagedObject, T == Where<D>.CollectionTarget, V: AllowedObjectiveCKeyPathValue {
public func any() -> Where<D>.Expression<Where<D>.CollectionTarget, V> { public func any() -> Where<D>.Expression<T, V> {
return .init("ANY " + self.cs_keyPathString) return .init("ANY " + self.cs_keyPathString)
} }
public func all() -> Where<D>.Expression<Where<D>.CollectionTarget, V> { public func all() -> Where<D>.Expression<T, V> {
return .init("ALL " + self.cs_keyPathString) return .init("ALL " + self.cs_keyPathString)
} }
public func none() -> Where<D>.Expression<Where<D>.CollectionTarget, V> { public func none() -> Where<D>.Expression<T, V> {
return .init("NONE " + self.cs_keyPathString) return .init("NONE " + self.cs_keyPathString)
} }
} }
// MARK: - KeyPath where Root: CoreStoreObject, Value: AllowedObjectiveCCollectionKeyPathValue
extension KeyPath where Root: CoreStoreObject, Value: AllowedCoreStoreObjectCollectionKeyPathValue {
public func count() -> Where<Root>.Expression<Where<Root>.CollectionTarget, Int> {
return .init(Root.meta[keyPath: self].cs_keyPathString, "@count")
}
}
// MARK: - Where.Expression where D: CoreStoreObject, T == Where<D>.CollectionTarget // MARK: - Where.Expression where D: CoreStoreObject, T == Where<D>.CollectionTarget
extension Where.Expression where D: CoreStoreObject, T == Where<D>.CollectionTarget { extension Where.Expression where D: CoreStoreObject, T == Where<D>.CollectionTarget {
public func count() -> Where<D>.Expression<Where<D>.CollectionTarget, Int> { public func count() -> Where<D>.Expression<T, Int> {
return .init(self.cs_keyPathString, "@count") return .init(self.cs_keyPathString, "@count")
} }
public func any() -> Where<D>.Expression<Where<D>.CollectionTarget, V> { public func any() -> Where<D>.Expression<T, V> {
return .init("ANY " + self.cs_keyPathString) return .init("ANY " + self.cs_keyPathString)
} }
public func all() -> Where<D>.Expression<Where<D>.CollectionTarget, V> { public func all() -> Where<D>.Expression<T, V> {
return .init("ALL " + self.cs_keyPathString) return .init("ALL " + self.cs_keyPathString)
} }
public func none() -> Where<D>.Expression<Where<D>.CollectionTarget, V> { public func none() -> Where<D>.Expression<T, V> {
return .init("NONE " + self.cs_keyPathString) return .init("NONE " + self.cs_keyPathString)
} }
} }
// MARK: - Where
extension Where {
// MARK: FilePrivate
fileprivate init<T, V: QueryableAttributeType & Comparable>(expression: Where<D>.Expression<T, V>, function: String, operand: V) {
self.init("\(expression.cs_keyPathString) \(function) %@", operand.cs_toQueryableNativeType())
}
fileprivate init<T, V: QueryableAttributeType & Comparable>(expression: Where<D>.Expression<T, V?>, function: String, operand: V) {
self.init("\(expression.cs_keyPathString) \(function) %@", operand.cs_toQueryableNativeType())
}
fileprivate init<T, V: QueryableAttributeType & Comparable>(expression: Where<D>.Expression<T, V>, function: String, operand: V?) {
if let operand = operand {
self.init("\(expression.cs_keyPathString) \(function) %@", operand.cs_toQueryableNativeType())
}
else {
self.init("\(expression.cs_keyPathString) \(function) nil")
}
}
fileprivate init<T, V: QueryableAttributeType & Comparable>(expression: Where<D>.Expression<T, V?>, function: String, operand: V?) {
if let operand = operand {
self.init("\(expression.cs_keyPathString) \(function) %@", operand.cs_toQueryableNativeType())
}
else {
self.init("\(expression.cs_keyPathString) \(function) nil")
}
}
}