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 owner.dogs.@max.age > %@ 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, andreadelfante94@gmail.com