Skip to content

Commit

Permalink
feat: Add support for PFQuery.explain and PFQuery.hint (#1723)
Browse files Browse the repository at this point in the history
  • Loading branch information
dplewis authored Mar 10, 2023
1 parent af750cf commit 583d266
Show file tree
Hide file tree
Showing 12 changed files with 139 additions and 4 deletions.
4 changes: 4 additions & 0 deletions Parse/Parse/Internal/Commands/PFRESTQueryCommand.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ NS_ASSUME_NONNULL_BEGIN
includedKeys:(nullable NSSet *)includedKeys
limit:(NSInteger)limit
skip:(NSInteger)skip
explain:(BOOL)explain
hint:(NSString *)hint
extraOptions:(nullable NSDictionary *)extraOptions
tracingEnabled:(BOOL)trace
sessionToken:(nullable NSString *)sessionToken
Expand All @@ -54,6 +56,8 @@ NS_ASSUME_NONNULL_BEGIN
includedKeys:(nullable NSSet *)includedKeys
limit:(NSInteger)limit
skip:(NSInteger)skip
explain:(BOOL)explain
hint:(NSString *)hint
extraOptions:(nullable NSDictionary *)extraOptions
tracingEnabled:(BOOL)trace
error:(NSError **)error;
Expand Down
20 changes: 19 additions & 1 deletion Parse/Parse/Internal/Commands/PFRESTQueryCommand.m
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ + (nullable instancetype)findCommandForClassWithName:(NSString *)className
includedKeys:(NSSet *)includedKeys
limit:(NSInteger)limit
skip:(NSInteger)skip
explain:(BOOL)explain
hint:(NSString *)hint
extraOptions:(NSDictionary *)extraOptions
tracingEnabled:(BOOL)trace
sessionToken:(NSString *)sessionToken
Expand All @@ -48,6 +50,8 @@ + (nullable instancetype)findCommandForClassWithName:(NSString *)className
includedKeys:includedKeys
limit:limit
skip:skip
explain:explain
hint:hint
extraOptions:extraOptions
tracingEnabled:trace
error:error];
Expand Down Expand Up @@ -100,6 +104,8 @@ + (nullable NSDictionary *)findCommandParametersForQueryState:(PFQueryState *)qu
includedKeys:queryState.includedKeys
limit:queryState.limit
skip:queryState.skip
explain:queryState.explain
hint:queryState.hint
extraOptions:queryState.extraOptions
tracingEnabled:queryState.trace
error:error];
Expand All @@ -111,6 +117,8 @@ + (nullable NSDictionary *)findCommandParametersWithOrder:(NSString *)order
includedKeys:(NSSet *)includedKeys
limit:(NSInteger)limit
skip:(NSInteger)skip
explain:(BOOL)explain
hint:(NSString *)hint
extraOptions:(NSDictionary *)extraOptions
tracingEnabled:(BOOL)trace
error:(NSError **)error {
Expand Down Expand Up @@ -139,6 +147,12 @@ + (nullable NSDictionary *)findCommandParametersWithOrder:(NSString *)order
// TODO: (nlutsenko) Double check that tracing still works. Maybe create test for it.
parameters[@"trace"] = @"1";
}
if (explain) {
parameters[@"explain"] = @"1";
}
if (hint != nil) {
parameters[@"hint"] = hint;
}
[extraOptions enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
parameters[key] = obj;
}];
Expand All @@ -165,6 +179,8 @@ + (nullable NSDictionary *)findCommandParametersWithOrder:(NSString *)order
includedKeys:subquery.state.includedKeys
limit:subquery.state.limit
skip:subquery.state.skip
explain:subquery.state.explain
hint:subquery.state.hint
extraOptions:nil
tracingEnabled:NO
error:&encodingError];
Expand Down Expand Up @@ -224,8 +240,10 @@ + (nullable id)_encodeSubqueryIfNeeded:(id)object error:(NSError * __autoreleasi
conditions:subquery.state.conditions
selectedKeys:subquery.state.selectedKeys
includedKeys:subquery.state.includedKeys
limit:subquery.state.limit
limit:subquery.state.limit
skip:subquery.state.skip
explain:subquery.state.explain
hint:subquery.state.hint
extraOptions:subquery.state.extraOptions
tracingEnabled:NO
error:&encodingError];
Expand Down
3 changes: 3 additions & 0 deletions Parse/Parse/Internal/Query/Controller/PFQueryController.m
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ - (BFTask *)findObjectsAsyncForQueryState:(PFQueryState *)queryState
PFCommandResult *result = task.result;
NSDate *queryReceived = (queryState.trace ? [NSDate date] : nil);

if (queryState.explain) {
return result.result[@"results"];
}
NSArray *resultObjects = result.result[@"results"];
NSMutableArray *foundObjects = [NSMutableArray arrayWithCapacity:resultObjects.count];
if (resultObjects != nil) {
Expand Down
3 changes: 3 additions & 0 deletions Parse/Parse/Internal/Query/State/PFMutableQueryState.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
@property (nonatomic, assign, readwrite) NSInteger limit;
@property (nonatomic, assign, readwrite) NSInteger skip;

@property (nonatomic, assign, readwrite) BOOL explain;
@property (nonatomic, copy, readwrite) NSString *hint;

///--------------------------------------
#pragma mark - Remote + Caching Options
///--------------------------------------
Expand Down
2 changes: 2 additions & 0 deletions Parse/Parse/Internal/Query/State/PFMutableQueryState.m
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ @implementation PFMutableQueryState
@dynamic cachePolicy;
@dynamic maxCacheAge;
@dynamic trace;
@dynamic explain;
@dynamic hint;
@dynamic shouldIgnoreACLs;
@dynamic shouldIncludeDeletingEventually;
@dynamic queriesLocalDatastore;
Expand Down
3 changes: 3 additions & 0 deletions Parse/Parse/Internal/Query/State/PFQueryState.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@
@property (nonatomic, assign, readonly) NSInteger limit;
@property (nonatomic, assign, readonly) NSInteger skip;

@property (nonatomic, assign, readonly) BOOL explain;
@property (nonatomic, copy, readonly) NSString *hint;

///--------------------------------------
#pragma mark - Remote + Caching Options
///--------------------------------------
Expand Down
6 changes: 4 additions & 2 deletions Parse/Parse/Internal/Query/State/PFQueryState.m
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,10 @@ + (NSDictionary *)propertyAttributes {
PFQueryStatePropertyName(shouldIgnoreACLs): [PFPropertyAttributes attributes],
PFQueryStatePropertyName(shouldIncludeDeletingEventually): [PFPropertyAttributes attributes],
PFQueryStatePropertyName(queriesLocalDatastore): [PFPropertyAttributes attributes],

PFQueryStatePropertyName(localDatastorePinName): [PFPropertyAttributes attributesWithAssociationType:PFPropertyInfoAssociationTypeCopy]
PFQueryStatePropertyName(localDatastorePinName): [PFPropertyAttributes attributesWithAssociationType:PFPropertyInfoAssociationTypeCopy],

PFQueryStatePropertyName(explain): [PFPropertyAttributes attributes],
PFQueryStatePropertyName(hint): [PFPropertyAttributes attributesWithAssociationType:PFPropertyInfoAssociationTypeCopy]
};
}

Expand Down
6 changes: 6 additions & 0 deletions Parse/Parse/Internal/Query/State/PFQueryState_Private.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@
NSTimeInterval _maxCacheAge;

BOOL _trace;

BOOL _explain;
NSString *_hint;

BOOL _shouldIgnoreACLs;
BOOL _shouldIncludeDeletingEventually;
Expand All @@ -51,6 +54,9 @@
@property (nonatomic, assign, readwrite) NSInteger limit;
@property (nonatomic, assign, readwrite) NSInteger skip;

@property (nonatomic, assign, readwrite) BOOL explain;
@property (nonatomic, copy, readwrite) NSString *hint;

///--------------------------------------
#pragma mark - Remote + Caching Options
///--------------------------------------
Expand Down
17 changes: 17 additions & 0 deletions Parse/Parse/Source/PFQuery.h
Original file line number Diff line number Diff line change
Expand Up @@ -762,6 +762,23 @@ typedef void (^PFQueryArrayResultBlock)(NSArray<PFGenericObject> *_Nullable obje
*/
- (instancetype)ignoreACLs;

/**
Change the source of this query to investigate the query execution plan. Useful for optimizing queries.
@param explain Used to toggle the information on the query plan.
*/
- (void)setExplain:(BOOL)explain;

/**
Change the source of this query to force an index selection.
@param hint The index name that should be used when executing query.
*/
- (void)setHint:(nullable NSString *)hint;

@property (nonatomic, copy) NSString *hint;
@property (nonatomic, assign) BOOL explain;

///--------------------------------------
#pragma mark - Advanced Settings
///--------------------------------------
Expand Down
32 changes: 32 additions & 0 deletions Parse/Parse/Source/PFQuery.m
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,26 @@ - (BOOL)trace {
return self.state.trace;
}

#pragma mark Hint

- (void)setHint:(NSString *)hint {
self.state.hint = hint;
}

- (NSString *)hint {
return self.state.hint;
}

#pragma mark Explain

- (void)setExplain:(BOOL)explain {
self.state.explain = explain;
}

- (BOOL)explain {
return self.state.explain;
}

///--------------------------------------
#pragma mark - Order
///--------------------------------------
Expand Down Expand Up @@ -990,6 +1010,18 @@ - (instancetype)ignoreACLs {
return self;
}

- (instancetype)explain:(BOOL)explain {
[self checkIfCommandIsRunning];
self.state.explain = explain;
return self;
}

- (instancetype)hint:(NSString *)indexName {
[self checkIfCommandIsRunning];
self.state.hint = [indexName copy];
return self;
}

///--------------------------------------
#pragma mark - Query State
///--------------------------------------
Expand Down
4 changes: 4 additions & 0 deletions Parse/Tests/Unit/QueryStateUnitTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ - (PFQueryState *)sampleQueryState {
state.cachePolicy = kPFCachePolicyCacheOnly;
state.maxCacheAge = 100500.0;
state.trace = YES;
state.hint = @"_id_";
state.explain = YES;
state.shouldIgnoreACLs = YES;
state.shouldIncludeDeletingEventually = YES;
state.queriesLocalDatastore = YES;
Expand Down Expand Up @@ -64,6 +66,8 @@ - (void)assertQueryState:(PFQueryState *)state equalToState:(PFQueryState *)diff
XCTAssertEqualObjects(state.extraOptions, differentState.extraOptions);

XCTAssertEqualObjects(state.localDatastorePinName, differentState.localDatastorePinName);
XCTAssertEqualObjects(state.hint, differentState.hint);
XCTAssertEqual(state.explain, differentState.explain);
}

///--------------------------------------
Expand Down
43 changes: 42 additions & 1 deletion Parse/Tests/Unit/QueryUnitTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,43 @@ - (void)testTrace {
XCTAssertTrue(query.state.trace);
}

- (void)testExplain {
PFQuery *query = [PFQuery queryWithClassName:@"a"];
query.explain = YES;
XCTAssertTrue(query.explain);
XCTAssertTrue(query.state.explain);

[query setExplain:NO];
XCTAssertFalse(query.explain);
XCTAssertFalse(query.state.explain);
}

- (void)testFindWithExplain {
PFQuery *query = [PFQuery queryWithClassName:@"a"];
[query setExplain:YES];

[self mockQueryControllerFindObjectsForQueryState:query.state withResult:@[ @"yolo" ] error:nil];

XCTestExpectation *expectation = [self currentSelectorTestExpectation];
[[query findObjectsInBackground] continueWithSuccessBlock:^id(BFTask *task) {
XCTAssertEqualObjects(task.result, @[ @"yolo" ]);
[expectation fulfill];
return nil;
}];
[self waitForTestExpectations];
}

- (void)testHint {
PFQuery *query = [PFQuery queryWithClassName:@"a"];
query.hint = @"_id_";
XCTAssertEqualObjects(query.hint, @"_id_");
XCTAssertEqualObjects(query.state.hint, @"_id_");

[query setHint:nil];
XCTAssertNil(query.hint);
XCTAssertNil(query.state.hint);
}

- (void)testIncludeKey {
PFQuery *query = [PFQuery queryWithClassName:@"a"];
[query includeKey:@"yolo"];
Expand Down Expand Up @@ -1287,7 +1324,8 @@ - (void)testNSCopying {

query.limit = 10;
query.skip = 20;

query.explain = YES;
query.hint = @"_id_";
query.cachePolicy = kPFCachePolicyIgnoreCache;
query.maxCacheAge = 30.0;

Expand All @@ -1311,6 +1349,9 @@ - (void)testNSCopying {
XCTAssertEqual(queryCopy.maxCacheAge, query.maxCacheAge);

XCTAssertEqual(queryCopy.trace, query.trace);

XCTAssertEqual(queryCopy.explain, query.explain);
XCTAssertEqualObjects(queryCopy.hint, query.hint);
}

#pragma mark Predicates
Expand Down

0 comments on commit 583d266

Please sign in to comment.