Skip to content

Commit 583d266

Browse files
authored
feat: Add support for PFQuery.explain and PFQuery.hint (#1723)
1 parent af750cf commit 583d266

File tree

12 files changed

+139
-4
lines changed

12 files changed

+139
-4
lines changed

Parse/Parse/Internal/Commands/PFRESTQueryCommand.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ NS_ASSUME_NONNULL_BEGIN
3030
includedKeys:(nullable NSSet *)includedKeys
3131
limit:(NSInteger)limit
3232
skip:(NSInteger)skip
33+
explain:(BOOL)explain
34+
hint:(NSString *)hint
3335
extraOptions:(nullable NSDictionary *)extraOptions
3436
tracingEnabled:(BOOL)trace
3537
sessionToken:(nullable NSString *)sessionToken
@@ -54,6 +56,8 @@ NS_ASSUME_NONNULL_BEGIN
5456
includedKeys:(nullable NSSet *)includedKeys
5557
limit:(NSInteger)limit
5658
skip:(NSInteger)skip
59+
explain:(BOOL)explain
60+
hint:(NSString *)hint
5761
extraOptions:(nullable NSDictionary *)extraOptions
5862
tracingEnabled:(BOOL)trace
5963
error:(NSError **)error;

Parse/Parse/Internal/Commands/PFRESTQueryCommand.m

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ + (nullable instancetype)findCommandForClassWithName:(NSString *)className
3838
includedKeys:(NSSet *)includedKeys
3939
limit:(NSInteger)limit
4040
skip:(NSInteger)skip
41+
explain:(BOOL)explain
42+
hint:(NSString *)hint
4143
extraOptions:(NSDictionary *)extraOptions
4244
tracingEnabled:(BOOL)trace
4345
sessionToken:(NSString *)sessionToken
@@ -48,6 +50,8 @@ + (nullable instancetype)findCommandForClassWithName:(NSString *)className
4850
includedKeys:includedKeys
4951
limit:limit
5052
skip:skip
53+
explain:explain
54+
hint:hint
5155
extraOptions:extraOptions
5256
tracingEnabled:trace
5357
error:error];
@@ -100,6 +104,8 @@ + (nullable NSDictionary *)findCommandParametersForQueryState:(PFQueryState *)qu
100104
includedKeys:queryState.includedKeys
101105
limit:queryState.limit
102106
skip:queryState.skip
107+
explain:queryState.explain
108+
hint:queryState.hint
103109
extraOptions:queryState.extraOptions
104110
tracingEnabled:queryState.trace
105111
error:error];
@@ -111,6 +117,8 @@ + (nullable NSDictionary *)findCommandParametersWithOrder:(NSString *)order
111117
includedKeys:(NSSet *)includedKeys
112118
limit:(NSInteger)limit
113119
skip:(NSInteger)skip
120+
explain:(BOOL)explain
121+
hint:(NSString *)hint
114122
extraOptions:(NSDictionary *)extraOptions
115123
tracingEnabled:(BOOL)trace
116124
error:(NSError **)error {
@@ -139,6 +147,12 @@ + (nullable NSDictionary *)findCommandParametersWithOrder:(NSString *)order
139147
// TODO: (nlutsenko) Double check that tracing still works. Maybe create test for it.
140148
parameters[@"trace"] = @"1";
141149
}
150+
if (explain) {
151+
parameters[@"explain"] = @"1";
152+
}
153+
if (hint != nil) {
154+
parameters[@"hint"] = hint;
155+
}
142156
[extraOptions enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
143157
parameters[key] = obj;
144158
}];
@@ -165,6 +179,8 @@ + (nullable NSDictionary *)findCommandParametersWithOrder:(NSString *)order
165179
includedKeys:subquery.state.includedKeys
166180
limit:subquery.state.limit
167181
skip:subquery.state.skip
182+
explain:subquery.state.explain
183+
hint:subquery.state.hint
168184
extraOptions:nil
169185
tracingEnabled:NO
170186
error:&encodingError];
@@ -224,8 +240,10 @@ + (nullable id)_encodeSubqueryIfNeeded:(id)object error:(NSError * __autoreleasi
224240
conditions:subquery.state.conditions
225241
selectedKeys:subquery.state.selectedKeys
226242
includedKeys:subquery.state.includedKeys
227-
limit:subquery.state.limit
243+
limit:subquery.state.limit
228244
skip:subquery.state.skip
245+
explain:subquery.state.explain
246+
hint:subquery.state.hint
229247
extraOptions:subquery.state.extraOptions
230248
tracingEnabled:NO
231249
error:&encodingError];

Parse/Parse/Internal/Query/Controller/PFQueryController.m

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,9 @@ - (BFTask *)findObjectsAsyncForQueryState:(PFQueryState *)queryState
7777
PFCommandResult *result = task.result;
7878
NSDate *queryReceived = (queryState.trace ? [NSDate date] : nil);
7979

80+
if (queryState.explain) {
81+
return result.result[@"results"];
82+
}
8083
NSArray *resultObjects = result.result[@"results"];
8184
NSMutableArray *foundObjects = [NSMutableArray arrayWithCapacity:resultObjects.count];
8285
if (resultObjects != nil) {

Parse/Parse/Internal/Query/State/PFMutableQueryState.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616
@property (nonatomic, assign, readwrite) NSInteger limit;
1717
@property (nonatomic, assign, readwrite) NSInteger skip;
1818

19+
@property (nonatomic, assign, readwrite) BOOL explain;
20+
@property (nonatomic, copy, readwrite) NSString *hint;
21+
1922
///--------------------------------------
2023
#pragma mark - Remote + Caching Options
2124
///--------------------------------------

Parse/Parse/Internal/Query/State/PFMutableQueryState.m

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ @implementation PFMutableQueryState
3636
@dynamic cachePolicy;
3737
@dynamic maxCacheAge;
3838
@dynamic trace;
39+
@dynamic explain;
40+
@dynamic hint;
3941
@dynamic shouldIgnoreACLs;
4042
@dynamic shouldIncludeDeletingEventually;
4143
@dynamic queriesLocalDatastore;

Parse/Parse/Internal/Query/State/PFQueryState.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@
2929
@property (nonatomic, assign, readonly) NSInteger limit;
3030
@property (nonatomic, assign, readonly) NSInteger skip;
3131

32+
@property (nonatomic, assign, readonly) BOOL explain;
33+
@property (nonatomic, copy, readonly) NSString *hint;
34+
3235
///--------------------------------------
3336
#pragma mark - Remote + Caching Options
3437
///--------------------------------------

Parse/Parse/Internal/Query/State/PFQueryState.m

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,10 @@ + (NSDictionary *)propertyAttributes {
3838
PFQueryStatePropertyName(shouldIgnoreACLs): [PFPropertyAttributes attributes],
3939
PFQueryStatePropertyName(shouldIncludeDeletingEventually): [PFPropertyAttributes attributes],
4040
PFQueryStatePropertyName(queriesLocalDatastore): [PFPropertyAttributes attributes],
41-
42-
PFQueryStatePropertyName(localDatastorePinName): [PFPropertyAttributes attributesWithAssociationType:PFPropertyInfoAssociationTypeCopy]
41+
PFQueryStatePropertyName(localDatastorePinName): [PFPropertyAttributes attributesWithAssociationType:PFPropertyInfoAssociationTypeCopy],
42+
43+
PFQueryStatePropertyName(explain): [PFPropertyAttributes attributes],
44+
PFQueryStatePropertyName(hint): [PFPropertyAttributes attributesWithAssociationType:PFPropertyInfoAssociationTypeCopy]
4345
};
4446
}
4547

Parse/Parse/Internal/Query/State/PFQueryState_Private.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@
3939
NSTimeInterval _maxCacheAge;
4040

4141
BOOL _trace;
42+
43+
BOOL _explain;
44+
NSString *_hint;
4245

4346
BOOL _shouldIgnoreACLs;
4447
BOOL _shouldIncludeDeletingEventually;
@@ -51,6 +54,9 @@
5154
@property (nonatomic, assign, readwrite) NSInteger limit;
5255
@property (nonatomic, assign, readwrite) NSInteger skip;
5356

57+
@property (nonatomic, assign, readwrite) BOOL explain;
58+
@property (nonatomic, copy, readwrite) NSString *hint;
59+
5460
///--------------------------------------
5561
#pragma mark - Remote + Caching Options
5662
///--------------------------------------

Parse/Parse/Source/PFQuery.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -762,6 +762,23 @@ typedef void (^PFQueryArrayResultBlock)(NSArray<PFGenericObject> *_Nullable obje
762762
*/
763763
- (instancetype)ignoreACLs;
764764

765+
/**
766+
Change the source of this query to investigate the query execution plan. Useful for optimizing queries.
767+
768+
@param explain Used to toggle the information on the query plan.
769+
*/
770+
- (void)setExplain:(BOOL)explain;
771+
772+
/**
773+
Change the source of this query to force an index selection.
774+
775+
@param hint The index name that should be used when executing query.
776+
*/
777+
- (void)setHint:(nullable NSString *)hint;
778+
779+
@property (nonatomic, copy) NSString *hint;
780+
@property (nonatomic, assign) BOOL explain;
781+
765782
///--------------------------------------
766783
#pragma mark - Advanced Settings
767784
///--------------------------------------

Parse/Parse/Source/PFQuery.m

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,26 @@ - (BOOL)trace {
183183
return self.state.trace;
184184
}
185185

186+
#pragma mark Hint
187+
188+
- (void)setHint:(NSString *)hint {
189+
self.state.hint = hint;
190+
}
191+
192+
- (NSString *)hint {
193+
return self.state.hint;
194+
}
195+
196+
#pragma mark Explain
197+
198+
- (void)setExplain:(BOOL)explain {
199+
self.state.explain = explain;
200+
}
201+
202+
- (BOOL)explain {
203+
return self.state.explain;
204+
}
205+
186206
///--------------------------------------
187207
#pragma mark - Order
188208
///--------------------------------------
@@ -990,6 +1010,18 @@ - (instancetype)ignoreACLs {
9901010
return self;
9911011
}
9921012

1013+
- (instancetype)explain:(BOOL)explain {
1014+
[self checkIfCommandIsRunning];
1015+
self.state.explain = explain;
1016+
return self;
1017+
}
1018+
1019+
- (instancetype)hint:(NSString *)indexName {
1020+
[self checkIfCommandIsRunning];
1021+
self.state.hint = [indexName copy];
1022+
return self;
1023+
}
1024+
9931025
///--------------------------------------
9941026
#pragma mark - Query State
9951027
///--------------------------------------

Parse/Tests/Unit/QueryStateUnitTests.m

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ - (PFQueryState *)sampleQueryState {
2828
state.cachePolicy = kPFCachePolicyCacheOnly;
2929
state.maxCacheAge = 100500.0;
3030
state.trace = YES;
31+
state.hint = @"_id_";
32+
state.explain = YES;
3133
state.shouldIgnoreACLs = YES;
3234
state.shouldIncludeDeletingEventually = YES;
3335
state.queriesLocalDatastore = YES;
@@ -64,6 +66,8 @@ - (void)assertQueryState:(PFQueryState *)state equalToState:(PFQueryState *)diff
6466
XCTAssertEqualObjects(state.extraOptions, differentState.extraOptions);
6567

6668
XCTAssertEqualObjects(state.localDatastorePinName, differentState.localDatastorePinName);
69+
XCTAssertEqualObjects(state.hint, differentState.hint);
70+
XCTAssertEqual(state.explain, differentState.explain);
6771
}
6872

6973
///--------------------------------------

Parse/Tests/Unit/QueryUnitTests.m

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,43 @@ - (void)testTrace {
213213
XCTAssertTrue(query.state.trace);
214214
}
215215

216+
- (void)testExplain {
217+
PFQuery *query = [PFQuery queryWithClassName:@"a"];
218+
query.explain = YES;
219+
XCTAssertTrue(query.explain);
220+
XCTAssertTrue(query.state.explain);
221+
222+
[query setExplain:NO];
223+
XCTAssertFalse(query.explain);
224+
XCTAssertFalse(query.state.explain);
225+
}
226+
227+
- (void)testFindWithExplain {
228+
PFQuery *query = [PFQuery queryWithClassName:@"a"];
229+
[query setExplain:YES];
230+
231+
[self mockQueryControllerFindObjectsForQueryState:query.state withResult:@[ @"yolo" ] error:nil];
232+
233+
XCTestExpectation *expectation = [self currentSelectorTestExpectation];
234+
[[query findObjectsInBackground] continueWithSuccessBlock:^id(BFTask *task) {
235+
XCTAssertEqualObjects(task.result, @[ @"yolo" ]);
236+
[expectation fulfill];
237+
return nil;
238+
}];
239+
[self waitForTestExpectations];
240+
}
241+
242+
- (void)testHint {
243+
PFQuery *query = [PFQuery queryWithClassName:@"a"];
244+
query.hint = @"_id_";
245+
XCTAssertEqualObjects(query.hint, @"_id_");
246+
XCTAssertEqualObjects(query.state.hint, @"_id_");
247+
248+
[query setHint:nil];
249+
XCTAssertNil(query.hint);
250+
XCTAssertNil(query.state.hint);
251+
}
252+
216253
- (void)testIncludeKey {
217254
PFQuery *query = [PFQuery queryWithClassName:@"a"];
218255
[query includeKey:@"yolo"];
@@ -1287,7 +1324,8 @@ - (void)testNSCopying {
12871324

12881325
query.limit = 10;
12891326
query.skip = 20;
1290-
1327+
query.explain = YES;
1328+
query.hint = @"_id_";
12911329
query.cachePolicy = kPFCachePolicyIgnoreCache;
12921330
query.maxCacheAge = 30.0;
12931331

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

13131351
XCTAssertEqual(queryCopy.trace, query.trace);
1352+
1353+
XCTAssertEqual(queryCopy.explain, query.explain);
1354+
XCTAssertEqualObjects(queryCopy.hint, query.hint);
13141355
}
13151356

13161357
#pragma mark Predicates

0 commit comments

Comments
 (0)