> On Apr 1, 2017, at 5:56 PM, Karl Wagner via swift-evolution 
> <[email protected]> wrote:
> 
>> let isPuppyQualifier = Pet.type.equals(.dog).and(Pet.age.lessThan(12))
>> let familyQualifier = Family.pets.hasAtLeastOne(satisfying: isPuppyQualifier)
>> let familiesWithPuppies = Family.fetch(editingContext, familyQualifier)
>> 
>> For those unfamiliar with EOF, the editingContext in the code above is an 
>> EOEditingContext which is analogous to NSManagedObjectContext. 
> 
> Theoretically, you could do something like that with this proposal...
> 
> struct UnaryPredicate<Parameter, Result> {
>     let evaluate: (Parameter) -> Result
> }
> struct BinaryPredicate<Left, Right, Result> {
>     let evaluate: (Left, Right) -> Result
> }
> 
> extension KeyPath where Value: Equatable {
>     func equals(_ value: Value) -> UnaryPredicate<Root, Bool> {
>         return UnaryPredicate { $0[keyPath: self] == value }
>     }
>     func equals<KP: KeyPath>(_ other: KP) -> BinaryPredicate<Root, KP.Root, 
> Bool> where KP.Value == Value {
>         return BinaryPredicate { $0[keyPath: self] == $1[keyPath: other] }
>     }
> }
> 
> let isDog = #keypath(Pet, .type).equals(.dog) // UnaryPredicate<Pet, Bool>
> if isDog.evaluate(somePet) {
>     print(“It’s a dog”)
> }
> 
> let areSameLength = #keypath(Array<Int>, 
> .count).equals(#keypath(Array<String>, .count))
> // BinaryPredicate<Array<Int>, Array<String>, Bool>
> if areSameLength.evaluate([1,2,3], [“a”, “b”, “c”]) {
>     print(“same lengths”)
> }


You guys aren't thinking big enough.

        // This implementation is closure-based because it's too complex for an 
email even *with* 
        // generics system upgrades. Without type system upgrades, things get 
*really* complicated, 
        // though probably still tractable.
        typealias Predicate<Element> = (Element) -> Bool
        
        func == <Root, Value: Equatable> (lhs: KeyPath<Root, Value>, rhs: 
Value) -> Predicate<Root> {
                return { $0[keyPath: lhs] == rhs }
        }
        
        func < <Root, Value: Comparable> (lhs: KeyPath<Root, Value>, rhs: 
Value) -> Predicate<Root> {
                return { $0[keyPath: lhs] < rhs }
        }

        func && <Root>(lhs: Predicate<Root>, rhs: Predicate<Root>) -> 
Predicate<Root> {
                return { lhs($0) && rhs($0) }
        }

        extension KeyPath where Value: Collection {
                func contains(where predicate: Predicate<Value.Element>) -> 
Predicate<Value> {
                        return { $0.contains(where: predicate) }
                }
        }

That gives you:

        let isPuppyQualifier = #keyPath(Pet, .type) == .dog && #keyPath(Pet, 
.age) < 12
        let familyQualifier = #keyPath(Family, .pets).contains(where: 
isPuppyQualifier)
        let familiesWithPuppies = Family.fetch(editingContext, familyQualifier)

Or, in one line with a more sugary syntax:

        let familiesWithPuppies = Family.fetch(editingContext, 
(.pets).contains(where: .type == .dog && .age < 12))

-- 
Brent Royal-Gordon
Architechies

_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to