Write amazing, strong-typed and easy-to-read NSPredicate. This library allows you to write flowable NSPredicate, without guessing attribution names, predicate operation or writing wrong arguments type.
- iOS 9.0+
- macOS 10.9+
- tvOS 9.0+
- watchOS 2.0+
CocoaPods is actually the only way to install it.
CocoaPods 0.39.0+ is required to build this library
- 
Add pod 'PredicateFlow'to your Podfile and runpod install
- 
In Xcode, click on your project in the file list, choose your target under TARGETS, click theBuild Phasestab and add aNew Run Script Phaseby clicking the plus icon in the top left
- 
Drag the new Run Scriptphase above theCompile Sourcesphase and belowCheck Pods Manifest.lock, expand it and paste the following script:"$PODS_ROOT/Sourcery/bin/sourcery" --sources "$PODS_ROOT/PredicateFlow/PredicateFlow/Classes/Utils/" --sources "$SRCROOT" --templates "$PODS_ROOT/PredicateFlow/PredicateFlow/Templates/PredicateFlow.stencil" --output "$SRCROOT/PredicateFlow.generated.swift"In case you are using PredicateFlow-Realm, past the following script instead of the above one: "$PODS_ROOT/Sourcery/bin/sourcery" --sources "$PODS_ROOT/PredicateFlow/PredicateFlow/Classes/Utils/" --sources "$SRCROOT" --sources "$PODS_ROOT/RealmSwift" --templates "$PODS_ROOT/PredicateFlow/PredicateFlow/Templates/PredicateFlow-Realm.stencil" --output "$SRCROOT/PredicateFlow.generated.swift"For Xcode 10 only, add a new Output Filesand paste the following:$SRCROOT/PredicateFlow.generated.swift
- 
Build your project. In Finder you will now see a PredicateFlow.generated.swiftin the$SRCROOT-folder, drag thePredicateFlow.generated.swiftfiles into your project and uncheckCopy items if needed
Tip: Add the *.generated.swift pattern to your .gitignore file to prevent unnecessary conflicts.
Define a class/struct with its own attributes, which implements PredicateSchema:
import PredicateFlow
class Dog: PredicateSchema {
	
	private var name: String = ""
	private var age: Int = 0
	private var isHungry: Bool = false
	private var owner: Person?
}
class Person: PredicateSchema {
	
	enum Sex {
		case male
		case female
	}
	
	private var name: String = ""
	private var birth: Date?
	private var sex: Sex!
	private var dogs: [Dog] = []
}Build the project. PredicateFlow will autogenerate attributes references to build predicates, putting them in structures.
// Generated using Sourcery 0.10.0 — https://github.com/krzysztofzablocki/Sourcery
// DO NOT EDIT
import PredicateFlow
/// The "Dog" Predicate Schema
internal struct DogSchema: GeneratedPredicateSchema {
    private var compoundFieldBuilder: CompoundFieldBuilder
    /// DO NOT USE THIS INIT DIRECTLY!
    internal init(compoundFieldBuilder: CompoundFieldBuilder) {
        self.compoundFieldBuilder = compoundFieldBuilder
    }
    /// "name" property
    internal var name: StringPredicateProperty { return builder.string("name") }
    /// "name" property for static access
    internal static var name: StringPredicateProperty { return DogSchema().name }
    
    // Other properties of Dog class autogenerated...
}
/// The "Person" Predicate Schema
internal struct PersonSchema: GeneratedPredicateSchema {
    private var compoundFieldBuilder: CompoundFieldBuilder
    /// DO NOT USE THIS INIT DIRECTLY!
    internal init(compoundFieldBuilder: CompoundFieldBuilder) {
        self.compoundFieldBuilder = compoundFieldBuilder
    }
    /// "name" property
    internal var name: StringPredicateProperty { return builder.string("name") }
    /// "name" property for static access
    internal static var name: StringPredicateProperty { return PersonSchema().name }
    
    // Other properties of Person class autogenerated...
}To type a floawable NSPredicate, just write:
DogSchema.age.isEqual(10).query()
// or
// Vanilla mode: 
// NSPredicate("age == %@", 10)You can also write compound predicate, and use deeper fields:
PredicateBuilder(DogSchema.age > 10)
    .and(DogSchema.isHungry.isTrue)
    .and(DogSchema.age.between(1, 10))
    .and(DogSchema.owner.element().name == "Foo")
    .or(DogSchema.owner.element().dogs.maxElements().age > 10)
    .or(DogSchema.owner.element().dogs.anyElements().name == "Foo")
    .build()
    
// Vanilla mode: 
// NSPredicate("age > %@ AND isHungry == %@ AND age BETWEEN %@ AND owner.name == %@ OR [email protected] > %@ OR ANY owner.dogs.name == %@", 10, true, [1, 10], "Foo", 10, "Foo")PredicateFlow can also build KeyPaths, and you can use it to get a strong-typed one.
DogSchema.age.keyPath()
DogSchema.owner.element().dogs.keyPath()
// Vanilla mode:
// "age"
// "owner.dogs"If you want to use flowable and strong-typed queries in Realm, add both pod 'PredicateFlow' and pod 'PredicateFlow/Realm' to your Podfile and run pod install.
let realm = try! Realm()
realm.objects(Dog.self)
    .filter(DogSchema.age.isGreater(than: 10))
    .filter(DogSchema.isHungry.isTrue)
    .sorted(DogSchema.age.ascending())
    
// Vanilla mode:
realm.objects(Dog.self)
    .filter("age > %@", 10)
    .filter("isHungry == %@", true)
    .sorted("age", ascending: true)PredicateFlow is an open source project, so feel free to contribute. You can open an issue for problems or suggestions, and you can propose your own fixes by opening a pull request with the changes.
PredicateFlow is available under the MIT license. See the LICENSE file for more info.
This library is powered by Sourcery.
Andrea Del Fante, [email protected]