Build Status CocoaPods Compatible Platform contributions welcome License
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 Phases
tab and add aNew Run Script Phase
by clicking the plus icon in the top left -
Drag the new
Run Script
phase above theCompile Sources
phase 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 Files
and paste the following:$SRCROOT/PredicateFlow.generated.swift
-
Build your project. In Finder you will now see a
PredicateFlow.generated.swift
in the$SRCROOT
-folder, drag thePredicateFlow.generated.swift
files 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