FIRQueryTests.mm 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. /*
  2. * Copyright 2017 Google
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #import <FirebaseFirestore/FirebaseFirestore.h>
  17. #import <XCTest/XCTest.h>
  18. #import "Firestore/Source/API/FIRFilter+Internal.h"
  19. #import "Firestore/Source/API/FIRQuery+Internal.h"
  20. #import "Firestore/Example/Tests/Util/FSTEventAccumulator.h"
  21. #import "Firestore/Example/Tests/Util/FSTHelpers.h"
  22. #import "Firestore/Example/Tests/Util/FSTIntegrationTestCase.h"
  23. @interface FIRQueryTests : FSTIntegrationTestCase
  24. @end
  25. @implementation FIRQueryTests
  26. /**
  27. * Checks that running the query while online (against the backend/emulator) results in the same
  28. * documents as running the query while offline. It also checks that both online and offline
  29. * query result is equal to the expected documents.
  30. *
  31. * @param query The query to check.
  32. * @param expectedDocs Array of document keys that are expected to match the query.
  33. */
  34. - (void)checkOnlineAndOfflineQuery:(FIRQuery *)query matchesResult:(NSArray *)expectedDocs {
  35. FIRQuerySnapshot *docsFromServer = [self readDocumentSetForRef:query
  36. source:FIRFirestoreSourceServer];
  37. FIRQuerySnapshot *docsFromCache = [self readDocumentSetForRef:query
  38. source:FIRFirestoreSourceCache];
  39. XCTAssertEqualObjects(FIRQuerySnapshotGetIDs(docsFromServer),
  40. FIRQuerySnapshotGetIDs(docsFromCache));
  41. XCTAssertEqualObjects(FIRQuerySnapshotGetIDs(docsFromCache), expectedDocs);
  42. }
  43. - (void)testLimitQueries {
  44. FIRCollectionReference *collRef = [self collectionRefWithDocuments:@{
  45. @"a" : @{@"k" : @"a"},
  46. @"b" : @{@"k" : @"b"},
  47. @"c" : @{@"k" : @"c"}
  48. }];
  49. FIRQuerySnapshot *snapshot = [self readDocumentSetForRef:[collRef queryLimitedTo:2]];
  50. XCTAssertEqualObjects(FIRQuerySnapshotGetData(snapshot), (@[ @{@"k" : @"a"}, @{@"k" : @"b"} ]));
  51. }
  52. - (void)testLimitQueriesWithDescendingSortOrder {
  53. FIRCollectionReference *collRef = [self collectionRefWithDocuments:@{
  54. @"a" : @{@"k" : @"a", @"sort" : @0},
  55. @"b" : @{@"k" : @"b", @"sort" : @1},
  56. @"c" : @{@"k" : @"c", @"sort" : @1},
  57. @"d" : @{@"k" : @"d", @"sort" : @2},
  58. }];
  59. FIRQuerySnapshot *snapshot =
  60. [self readDocumentSetForRef:[[collRef queryOrderedByField:@"sort"
  61. descending:YES] queryLimitedTo:2]];
  62. XCTAssertEqualObjects(FIRQuerySnapshotGetData(snapshot),
  63. (@[ @{@"k" : @"d", @"sort" : @2}, @{@"k" : @"c", @"sort" : @1} ]));
  64. }
  65. - (void)testLimitToLastMustAlsoHaveExplicitOrderBy {
  66. FIRCollectionReference *collRef = [self collectionRefWithDocuments:@{}];
  67. FIRQuery *query = [collRef queryLimitedToLast:2];
  68. FSTAssertThrows([query getDocumentsWithCompletion:^(FIRQuerySnapshot *, NSError *){
  69. }],
  70. @"limit(toLast:) queries require specifying at least one OrderBy() clause.");
  71. }
  72. // Two queries that mapped to the same target ID are referred to as
  73. // "mirror queries". An example for a mirror query is a limitToLast()
  74. // query and a limit() query that share the same backend Target ID.
  75. // Since limitToLast() queries are sent to the backend with a modified
  76. // orderBy() clause, they can map to the same target representation as
  77. // limit() query, even if both queries appear separate to the user.
  78. - (void)testListenUnlistenRelistenSequenceOfMirrorQueries {
  79. FIRCollectionReference *collRef = [self collectionRefWithDocuments:@{
  80. @"a" : @{@"k" : @"a", @"sort" : @0},
  81. @"b" : @{@"k" : @"b", @"sort" : @1},
  82. @"c" : @{@"k" : @"c", @"sort" : @1},
  83. @"d" : @{@"k" : @"d", @"sort" : @2},
  84. }];
  85. // Setup a `limit` query.
  86. FIRQuery *limit = [[collRef queryOrderedByField:@"sort" descending:NO] queryLimitedTo:2];
  87. FSTEventAccumulator *limitAccumulator = [FSTEventAccumulator accumulatorForTest:self];
  88. id<FIRListenerRegistration> limitRegistration =
  89. [limit addSnapshotListener:limitAccumulator.valueEventHandler];
  90. // Setup a mirroring `limitToLast` query.
  91. FIRQuery *limitToLast = [[collRef queryOrderedByField:@"sort"
  92. descending:YES] queryLimitedToLast:2];
  93. FSTEventAccumulator *limitToLastAccumulator = [FSTEventAccumulator accumulatorForTest:self];
  94. id<FIRListenerRegistration> limitToLastRegistration =
  95. [limitToLast addSnapshotListener:limitToLastAccumulator.valueEventHandler];
  96. // Verify both queries get expected result.
  97. FIRQuerySnapshot *snapshot = [limitAccumulator awaitEventWithName:@"Snapshot"];
  98. NSArray *expected = @[ @{@"k" : @"a", @"sort" : @0}, @{@"k" : @"b", @"sort" : @1} ];
  99. XCTAssertEqualObjects(FIRQuerySnapshotGetData(snapshot), expected);
  100. snapshot = [limitToLastAccumulator awaitEventWithName:@"Snapshot"];
  101. expected = @[ @{@"k" : @"b", @"sort" : @1}, @{@"k" : @"a", @"sort" : @0} ];
  102. XCTAssertEqualObjects(FIRQuerySnapshotGetData(snapshot), expected);
  103. // Unlisten then re-listen limit query.
  104. [limitRegistration remove];
  105. [limit addSnapshotListener:[limitAccumulator valueEventHandler]];
  106. // Verify limit query still works.
  107. snapshot = [limitAccumulator awaitEventWithName:@"Snapshot"];
  108. expected = @[ @{@"k" : @"a", @"sort" : @0}, @{@"k" : @"b", @"sort" : @1} ];
  109. XCTAssertEqualObjects(FIRQuerySnapshotGetData(snapshot), expected);
  110. // Add a document that would change the result set.
  111. [self addDocumentRef:collRef data:@{@"k" : @"e", @"sort" : @-1}];
  112. // Verify both queries get expected result.
  113. snapshot = [limitAccumulator awaitEventWithName:@"Snapshot"];
  114. expected = @[ @{@"k" : @"e", @"sort" : @-1}, @{@"k" : @"a", @"sort" : @0} ];
  115. XCTAssertEqualObjects(FIRQuerySnapshotGetData(snapshot), expected);
  116. snapshot = [limitToLastAccumulator awaitEventWithName:@"Snapshot"];
  117. expected = @[ @{@"k" : @"a", @"sort" : @0}, @{@"k" : @"e", @"sort" : @-1} ];
  118. XCTAssertEqualObjects(FIRQuerySnapshotGetData(snapshot), expected);
  119. // Unlisten to limitToLast, update a doc, then relisten to limitToLast
  120. [limitToLastRegistration remove];
  121. [self updateDocumentRef:[collRef documentWithPath:@"a"] data:@{@"k" : @"a", @"sort" : @-2}];
  122. [limitToLast addSnapshotListener:[limitToLastAccumulator valueEventHandler]];
  123. // Verify both queries get expected result.
  124. snapshot = [limitAccumulator awaitEventWithName:@"Snapshot"];
  125. expected = @[ @{@"k" : @"a", @"sort" : @-2}, @{@"k" : @"e", @"sort" : @-1} ];
  126. XCTAssertEqualObjects(FIRQuerySnapshotGetData(snapshot), expected);
  127. snapshot = [limitToLastAccumulator awaitEventWithName:@"Snapshot"];
  128. expected = @[ @{@"k" : @"e", @"sort" : @-1}, @{@"k" : @"a", @"sort" : @-2} ];
  129. XCTAssertEqualObjects(FIRQuerySnapshotGetData(snapshot), expected);
  130. }
  131. - (void)testUnaryFilterQueries {
  132. FIRCollectionReference *collRef = [self collectionRefWithDocuments:@{
  133. @"a" : @{@"null" : [NSNull null], @"nan" : @(NAN)},
  134. @"b" : @{@"null" : [NSNull null], @"nan" : @0},
  135. @"c" : @{@"null" : @NO, @"nan" : @(NAN)}
  136. }];
  137. FIRQuerySnapshot *results =
  138. [self readDocumentSetForRef:[[collRef queryWhereField:@"null"
  139. isEqualTo:[NSNull null]] queryWhereField:@"nan"
  140. isEqualTo:@(NAN)]];
  141. XCTAssertEqualObjects(FIRQuerySnapshotGetData(results),
  142. (@[ @{@"null" : [NSNull null], @"nan" : @(NAN)} ]));
  143. }
  144. - (void)testQueryWithFieldPaths {
  145. FIRCollectionReference *collRef = [self
  146. collectionRefWithDocuments:@{@"a" : @{@"a" : @1}, @"b" : @{@"a" : @2}, @"c" : @{@"a" : @3}}];
  147. FIRQuery *query = [collRef queryWhereFieldPath:[[FIRFieldPath alloc] initWithFields:@[ @"a" ]]
  148. isLessThan:@3];
  149. query = [query queryOrderedByFieldPath:[[FIRFieldPath alloc] initWithFields:@[ @"a" ]]
  150. descending:YES];
  151. FIRQuerySnapshot *snapshot = [self readDocumentSetForRef:query];
  152. XCTAssertEqualObjects(FIRQuerySnapshotGetIDs(snapshot), (@[ @"b", @"a" ]));
  153. }
  154. - (void)testQueryWithPredicate {
  155. FIRCollectionReference *collRef = [self
  156. collectionRefWithDocuments:@{@"a" : @{@"a" : @1}, @"b" : @{@"a" : @2}, @"c" : @{@"a" : @3}}];
  157. NSPredicate *predicate = [NSPredicate predicateWithFormat:@"a < 3"];
  158. FIRQuery *query = [collRef queryFilteredUsingPredicate:predicate];
  159. query = [query queryOrderedByFieldPath:[[FIRFieldPath alloc] initWithFields:@[ @"a" ]]
  160. descending:YES];
  161. FIRQuerySnapshot *snapshot = [self readDocumentSetForRef:query];
  162. XCTAssertEqualObjects(FIRQuerySnapshotGetIDs(snapshot), (@[ @"b", @"a" ]));
  163. }
  164. - (void)testFilterOnInfinity {
  165. FIRCollectionReference *collRef = [self collectionRefWithDocuments:@{
  166. @"a" : @{@"inf" : @(INFINITY)},
  167. @"b" : @{@"inf" : @(-INFINITY)}
  168. }];
  169. FIRQuerySnapshot *results = [self readDocumentSetForRef:[collRef queryWhereField:@"inf"
  170. isEqualTo:@(INFINITY)]];
  171. XCTAssertEqualObjects(FIRQuerySnapshotGetData(results), (@[ @{@"inf" : @(INFINITY)} ]));
  172. }
  173. @end