Skip to content

Conversation

zxu123
Copy link
Contributor

@zxu123 zxu123 commented Dec 5, 2017

Discussion

API change proposal, http://go/firestore-nspredicate-based-query

Testing

New test is added to cover the new function and all tests pass.

API Changes

API change proposal, http://go/firestore-nspredicate-based-query

… vars.

*   add queryByRemovingFilters() in FSTQuery and test case;
*   add property usePredicate in FIRQuery and update old APIs queryWhereField/Path;
*   add a no-op queryFilteredUsingPredicate() skeleton in FIRQuery.

All tests pass.
*   implement queryFilteredUsingPredicate in FIRQuery;
*   add new unit test skeleton FIRQueryTests.m;
*   reverts last change on adding usePredicate as we are now allowing mix usage of two types of query filtering APIs.
*   add unit test and integration test;
*   revert a few irrelevant line-change in last commit in project.pbxproj.
@zxu123 zxu123 requested a review from wilhuff December 5, 2017 16:07
rename queryFilteredUsingPredicate to queryWherePredicate
raise assertion in the particular case of NSBlockPredicate.
Copy link
Contributor

@wilhuff wilhuff left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change is definitely on the right track.

@@ -0,0 +1,72 @@
/*
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please put this file in the location that parallels the implementation: under API as a peer of FIRGeoPointTests.m.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

* limitations under the License.
*/

#import "FirebaseFirestore/FIRFirestore.h"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the public surface area of Firestore, please just @import the module, like so:

@import FirebaseFirestore;

That gets both the FIRFirestore.h and FIRQuery.h headers.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

id value = nil;
if (comparison.leftExpression.keyPath == nil &&
comparison.rightExpression.keyPath == nil) {
FSTThrowInvalidArgument(@"Invalid query. Predicate comparison must have "
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This error message is more specific than it needs to be and could be simplified. Maybe:

Predicate comparisons must include a key path.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

}
NSString *path;
id value = nil;
if (comparison.leftExpression.keyPath == nil &&
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This logic doesn't handle the case where both sides are keyPaths. Is that possible?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactored the logic, now only keypath = constant and constant = keypath are allowed comparison through type check.

comparison.rightExpression.keyPath == nil) {
FSTThrowInvalidArgument(@"Invalid query. Predicate comparison must have "
"a key path on either side of its expression.");
} else if (comparison.leftExpression.keyPath == nil) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: This could be clearer if you tested that the key path was non-nil then used it in the immediately following block.

As it stands you're comparing against leftExpression.keyPath then using the rightExpression.keyPath right below.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done, refactored

^BOOL(id obj, NSDictionary *bindings) { return true; }] class]]) {
FSTThrowInvalidArgument(@"Invalid query. Block-based predicates are not "
"supported. Please use predicateWithFormat to "
"construct predicate instead.");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Construct" is a C++ and Java-ism that's not native to Objective-C (where objects are created or initialized). Also "predicate" should be pluralized.

Please use predicateWithFormat to create predicates instead.

Here and below.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

* Creates and returns a new `FIRQuery` with the additional filter that documents must
* satisfy the specified predicate.
*
* @param predicate The predicate the document must satisfy. Can be either comparison
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should specifically mention that block-based predicates are not supported

value:value];
}

- (FIRQuery *)queryWherePredicate:(NSPredicate *)predicate {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method is very large. Consider breaking it down into a few smaller pieces.

For example, you could make queryWherePredicate: do the instanceof checks and then delegate to strongly-typed single-purpose methods like queryWhereComparisonPredicate: and queryWhereCompoundPredicate.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

"not supported.");
break;
default:
FSTThrowInvalidArgument(@"Invalid query. Predicate does not support "
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This "Predicate does not support" phrasing isn't quite right. NSPredicate does support these things and this phrasing seems to suggest that the predicate itself doesn't support these.

The other phrasing just above is much better: "Custom predicate filters are not supported" is a better example.

Maybe this one could be

Operator type %lu is not supported.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

NSCompoundPredicate *compound = (NSCompoundPredicate *)predicate;
if (compound.compoundPredicateType != NSAndPredicateType ||
compound.subpredicates.count == 0) {
FSTThrowInvalidArgument(@"Invalid query. Predicate only supports "
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to above, this would be better phrased as:

Only compound queries using AND are supported.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@wilhuff
Copy link
Contributor

wilhuff commented Dec 5, 2017

Also, please add an entry to Firestore/CHANGELOG.md describing what was done. Something like:

[feature] Queries can now be created from an NSPredicate.

revert name queryWherePredicate() back to queryFilteredUsingPredicate().
*   improve docs / assertion message;
*   fix a bug where transposed comparison is not treated correctly; also add unit test to cover that case.
project change of adding the FIRQueryTests.m file
XCTAssertEqualObjects(FIRQuerySnapshotGetIDs(snapshot), (@[ @"b", @"a" ]));
}

- (void)testQueryWithPredicate {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please fix the trailing space travis failure -

$ ! git grep -I ' $'
Firestore/Example/Tests/Integration/API/FIRQueryTests.m:
The command "! git grep -I ' $'" exited with 1.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

*   refactoring to split logic into two helpers;
*   update change log.
Copy link
Contributor Author

@zxu123 zxu123 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated. PTAL.

@@ -0,0 +1,72 @@
/*
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

* Creates and returns a new `FIRQuery` with the additional filter that documents must
* satisfy the specified predicate.
*
* @param predicate The predicate the document must satisfy. Can be either comparison
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added in @param part

* limitations under the License.
*/

#import "FirebaseFirestore/FIRFirestore.h"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

}
NSString *path;
id value = nil;
if (comparison.leftExpression.keyPath == nil &&
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactored the logic, now only keypath = constant and constant = keypath are allowed comparison through type check.

id value = nil;
if (comparison.leftExpression.keyPath == nil &&
comparison.rightExpression.keyPath == nil) {
FSTThrowInvalidArgument(@"Invalid query. Predicate comparison must have "
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

"not supported.");
break;
default:
FSTThrowInvalidArgument(@"Invalid query. Predicate does not support "
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

NSCompoundPredicate *compound = (NSCompoundPredicate *)predicate;
if (compound.compoundPredicateType != NSAndPredicateType ||
compound.subpredicates.count == 0) {
FSTThrowInvalidArgument(@"Invalid query. Predicate only supports "
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

^BOOL(id obj, NSDictionary *bindings) { return true; }] class]]) {
FSTThrowInvalidArgument(@"Invalid query. Block-based predicates are not "
"supported. Please use predicateWithFormat to "
"construct predicate instead.");
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

XCTAssertEqualObjects(FIRQuerySnapshotGetIDs(snapshot), (@[ @"b", @"a" ]));
}

- (void)testQueryWithPredicate {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

value:value];
}

- (FIRQuery *)queryWherePredicate:(NSPredicate *)predicate {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

remove trailing space
@wilhuff wilhuff changed the base branch from master to firestore-api-changes December 6, 2017 23:45
Copy link
Contributor

@wilhuff wilhuff left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pretty much LGTM except one (minor) question.

Note that I've changed this to target the firestore-api-changes branch so that we can release all of these API changes at once.

* @return The created `FIRQuery`.
*/
// clang-format off
- (FIRQuery *)queryFilteredUsingPredicate:(NSPredicate *)predicate NS_SWIFT_NAME(filter(using:));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this NS_SWIFT_NAME be filtered(using:)? Mentioned this in the API proposal.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, changed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm really sorry to have pointed this out because I was totally wrong :-(.

@mikelehen points out that the other swift names are things like orderBy rather than orderedBy so this really should be filter(using:).

Again I'm super sorry to have caused you extra work like this and I've reverted that change here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no problem, fellow. I like discussions, which is the only way great idea comes from.

@zxu123
Copy link
Contributor Author

zxu123 commented Dec 7, 2017

please advise when it is OK to merge.

zxu123 and others added 2 commits December 6, 2017 21:46
swift name filter -> filtered
This reverts commit 5585202.
Copy link
Contributor

@wilhuff wilhuff left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM to squash and merge into firestore-api-changes.

@zxu123 zxu123 merged commit 5da88e4 into firestore-api-changes Dec 7, 2017
@zxu123 zxu123 deleted the zxu/predquery branch December 7, 2017 20:36
minafarid pushed a commit to minafarid/firebase-ios-sdk that referenced this pull request Jun 6, 2018
*   implement queryFilteredUsingPredicate in FIRQuery;
*   add unit test and integration test for queryFilteredUsingPredicate;
*   project change of adding the FIRQueryTests.m file;
*   refactoring queryFilteredUsingPredicate to split logic into two helpers;
@firebase firebase locked and limited conversation to collaborators Nov 10, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants