1919import static com .google .firebase .firestore .testutil .IntegrationTestUtil .testCollectionWithDocsOnNightly ;
2020import static com .google .firebase .firestore .testutil .IntegrationTestUtil .waitFor ;
2121import static com .google .firebase .firestore .testutil .TestUtil .map ;
22+ import static java .lang .Double .NaN ;
23+ import static java .lang .Double .POSITIVE_INFINITY ;
2224import static org .junit .Assert .assertEquals ;
2325import static org .junit .Assert .assertNotNull ;
2426import static org .junit .Assert .assertNull ;
@@ -54,6 +56,7 @@ public void writeAndReadBsonTypes() throws ExecutionException, InterruptedExcept
5456 "bsonTimestamp" , new BsonTimestamp (1 , 2 ),
5557 "bsonBinary" , BsonBinaryData .fromBytes (1 , new byte [] {1 , 2 , 3 }),
5658 "int32" , new Int32Value (1 ),
59+ "decimal128" , new Decimal128Value ("1.2e3" ),
5760 "minKey" , MinKey .instance (),
5861 "maxKey" , MaxKey .instance ())));
5962
@@ -75,6 +78,7 @@ public void writeAndReadBsonTypes() throws ExecutionException, InterruptedExcept
7578 expected .put ("bsonTimestamp" , new BsonTimestamp (1 , 3 ));
7679 expected .put ("bsonBinary" , BsonBinaryData .fromBytes (1 , new byte [] {1 , 2 , 3 }));
7780 expected .put ("int32" , new Int32Value (2 ));
81+ expected .put ("decimal128" , new Decimal128Value ("1.2e3" ));
7882 expected .put ("minKey" , MinKey .instance ());
7983 expected .put ("maxKey" , MaxKey .instance ());
8084
@@ -85,6 +89,7 @@ public void writeAndReadBsonTypes() throws ExecutionException, InterruptedExcept
8589 assertTrue (actual .get ("bsonTimestamp" ) instanceof BsonTimestamp );
8690 assertTrue (actual .get ("bsonBinary" ) instanceof BsonBinaryData );
8791 assertTrue (actual .get ("int32" ) instanceof Int32Value );
92+ assertTrue (actual .get ("decimal128" ) instanceof Decimal128Value );
8893 assertTrue (actual .get ("minKey" ) instanceof MinKey );
8994 assertTrue (actual .get ("maxKey" ) instanceof MaxKey );
9095 assertEquals (expected , actual .getData ());
@@ -101,13 +106,22 @@ public void writeAndReadBsonTypeOffline() throws ExecutionException, Interrupted
101106 Map <String , Object > expected = new HashMap <>();
102107 docRef .set (
103108 map (
104- "bsonObjectId" , new BsonObjectId ("507f191e810c19729de860ea" ),
105- "regex" , new RegexValue ("^foo" , "i" ),
106- "bsonTimestamp" , new BsonTimestamp (1 , 2 ),
107- "bsonBinary" , BsonBinaryData .fromBytes (1 , new byte [] {1 , 2 , 3 }),
108- "int32" , new Int32Value (1 ),
109- "minKey" , MinKey .instance (),
110- "maxKey" , MaxKey .instance ()));
109+ "bsonObjectId" ,
110+ new BsonObjectId ("507f191e810c19729de860ea" ),
111+ "regex" ,
112+ new RegexValue ("^foo" , "i" ),
113+ "bsonTimestamp" ,
114+ new BsonTimestamp (1 , 2 ),
115+ "bsonBinary" ,
116+ BsonBinaryData .fromBytes (1 , new byte [] {1 , 2 , 3 }),
117+ "int32" ,
118+ new Int32Value (1 ),
119+ "decimal128" ,
120+ new Decimal128Value ("1.2e3" ),
121+ "minKey" ,
122+ MinKey .instance (),
123+ "maxKey" ,
124+ MaxKey .instance ()));
111125
112126 docRef .update (
113127 map (
@@ -123,6 +137,7 @@ public void writeAndReadBsonTypeOffline() throws ExecutionException, Interrupted
123137 expected .put ("bsonTimestamp" , new BsonTimestamp (1 , 3 ));
124138 expected .put ("bsonBinary" , BsonBinaryData .fromBytes (1 , new byte [] {1 , 2 , 3 }));
125139 expected .put ("int32" , new Int32Value (1 ));
140+ expected .put ("decimal128" , new Decimal128Value ("1.2e3" ));
126141 expected .put ("minKey" , MinKey .instance ());
127142 expected .put ("maxKey" , MaxKey .instance ());
128143
@@ -133,6 +148,7 @@ public void writeAndReadBsonTypeOffline() throws ExecutionException, Interrupted
133148 assertTrue (actual .get ("bsonTimestamp" ) instanceof BsonTimestamp );
134149 assertTrue (actual .get ("bsonBinary" ) instanceof BsonBinaryData );
135150 assertTrue (actual .get ("int32" ) instanceof Int32Value );
151+ assertTrue (actual .get ("decimal128" ) instanceof Decimal128Value );
136152 assertTrue (actual .get ("minKey" ) instanceof MinKey );
137153 assertTrue (actual .get ("maxKey" ) instanceof MaxKey );
138154 assertEquals (expected , actual .getData ());
@@ -174,6 +190,8 @@ public void listenToDocumentsWithBsonTypes() throws Throwable {
174190 BsonBinaryData .fromBytes (1 , new byte [] {1 , 2 , 3 }),
175191 "int32" ,
176192 new Int32Value (1 ),
193+ "decimal128" ,
194+ new Decimal128Value ("1.2e3" ),
177195 "minKey" ,
178196 MinKey .instance (),
179197 "maxKey" ,
@@ -192,6 +210,9 @@ public void listenToDocumentsWithBsonTypes() throws Throwable {
192210 assertEquals (
193211 docSnap .getBsonTimestamp ("bsonTimestamp" ), new BsonTimestamp (1 , 2 ));
194212 assertEquals (docSnap .getInt32Value ("int32" ), new Int32Value (1 ));
213+ assertEquals (
214+ docSnap .getDecimal128Value ("decimal128" ),
215+ new Decimal128Value ("1.2e3" ));
195216 assertEquals (docSnap .getMinKey ("minKey" ), MinKey .instance ());
196217 assertEquals (docSnap .getMaxKey ("maxKey" ), MaxKey .instance ());
197218
@@ -266,15 +287,13 @@ public void filterAndOrderBsonObjectIds() throws Exception {
266287 randomColl
267288 .orderBy ("key" , Direction .DESCENDING )
268289 .whereGreaterThan ("key" , new BsonObjectId ("507f191e810c19729de860ea" ));
269-
270290 assertSDKQueryResultsConsistentWithBackend (
271291 randomColl , orderedQuery , docs , Arrays .asList ("c" , "b" ));
272292
273293 orderedQuery =
274294 randomColl
275295 .orderBy ("key" , Direction .DESCENDING )
276296 .whereNotEqualTo ("key" , new BsonObjectId ("507f191e810c19729de860eb" ));
277-
278297 assertSDKQueryResultsConsistentWithBackend (
279298 randomColl , orderedQuery , docs , Arrays .asList ("c" , "a" ));
280299 }
@@ -385,6 +404,77 @@ public void filterAndOrderInt32() throws Exception {
385404 randomColl , orderedQuery , docs , Arrays .asList ("c" , "a" ));
386405 }
387406
407+ @ Test
408+ public void filterAndOrderDecimal128 () throws Exception {
409+ Map <String , Map <String , Object >> docs =
410+ map (
411+ "a" ,
412+ map ("key" , new Decimal128Value ("-1.2e3" )),
413+ "b" ,
414+ map ("key" , new Decimal128Value ("0" )),
415+ "c" ,
416+ map ("key" , new Decimal128Value ("1.2e3" )),
417+ "d" ,
418+ map ("key" , new Decimal128Value ("NaN" )),
419+ "e" ,
420+ map ("key" , new Decimal128Value ("-Infinity" )),
421+ "f" ,
422+ map ("key" , new Decimal128Value ("Infinity" )));
423+ CollectionReference randomColl = testCollectionWithDocsOnNightly (docs );
424+
425+ Query orderedQuery =
426+ randomColl
427+ .orderBy ("key" , Direction .DESCENDING )
428+ .whereGreaterThan ("key" , new Decimal128Value ("-1.2e3" ));
429+ assertSDKQueryResultsConsistentWithBackend (
430+ randomColl , orderedQuery , docs , Arrays .asList ("f" , "c" , "b" ));
431+
432+ orderedQuery =
433+ randomColl
434+ .orderBy ("key" , Direction .DESCENDING )
435+ .whereGreaterThan ("key" , new Decimal128Value ("-1.2e-3" ));
436+ assertSDKQueryResultsConsistentWithBackend (
437+ randomColl , orderedQuery , docs , Arrays .asList ("f" , "c" , "b" ));
438+
439+ orderedQuery =
440+ randomColl
441+ .orderBy ("key" , Direction .DESCENDING )
442+ .whereNotEqualTo ("key" , new Decimal128Value ("0.0" ));
443+ assertSDKQueryResultsConsistentWithBackend (
444+ randomColl , orderedQuery , docs , Arrays .asList ("f" , "c" , "a" , "e" , "d" ));
445+
446+ orderedQuery = randomColl .whereNotEqualTo ("key" , new Decimal128Value ("NaN" ));
447+ assertSDKQueryResultsConsistentWithBackend (
448+ randomColl , orderedQuery , docs , Arrays .asList ("e" , "a" , "b" , "c" , "f" ));
449+
450+ orderedQuery =
451+ randomColl
452+ .orderBy ("key" , Direction .DESCENDING )
453+ .whereEqualTo ("key" , new Decimal128Value ("1.2e3" ));
454+ assertSDKQueryResultsConsistentWithBackend (randomColl , orderedQuery , docs , Arrays .asList ("c" ));
455+
456+ orderedQuery =
457+ randomColl
458+ .orderBy ("key" , Direction .DESCENDING )
459+ .whereNotEqualTo ("key" , new Decimal128Value ("1.2e3" ));
460+ assertSDKQueryResultsConsistentWithBackend (
461+ randomColl , orderedQuery , docs , Arrays .asList ("f" , "b" , "a" , "e" , "d" ));
462+
463+ // Note: server is sending NaN incorrectly, but the SDK NotInFilter.matches gracefully handles
464+ // it and removes the incorrect doc "d".
465+ orderedQuery =
466+ randomColl
467+ .orderBy ("key" , Direction .DESCENDING )
468+ .whereNotIn (
469+ "key" ,
470+ Arrays .asList (
471+ new Decimal128Value ("1.2e3" ),
472+ new Decimal128Value ("Infinity" ),
473+ new Decimal128Value ("NaN" )));
474+ assertSDKQueryResultsConsistentWithBackend (
475+ randomColl , orderedQuery , docs , Arrays .asList ("b" , "a" , "e" ));
476+ }
477+
388478 @ Test
389479 public void filterAndOrderMinKey () throws Exception {
390480 Map <String , Map <String , Object >> docs =
@@ -478,6 +568,102 @@ public void filterNullValueWithBsonTypes() throws Exception {
478568 randomColl , query , docs , Arrays .asList ("a" , "d" , "e" ));
479569 }
480570
571+ @ Test
572+ public void filterAndOrderNumericalValues () throws Exception {
573+ Map <String , Map <String , Object >> docs =
574+ map (
575+ "a" ,
576+ map ("key" , new Decimal128Value ("-1.2e3" )), // -1200
577+ "b" ,
578+ map ("key" , new Int32Value (0 )),
579+ "c" ,
580+ map ("key" , new Decimal128Value ("1" )),
581+ "d" ,
582+ map ("key" , new Int32Value (1 )),
583+ "e" ,
584+ map ("key" , 1L ),
585+ "f" ,
586+ map ("key" , 1.0 ),
587+ "g" ,
588+ map ("key" , new Decimal128Value ("1.2e-3" )), // 0.0012
589+ "h" ,
590+ map ("key" , new Int32Value (2 )),
591+ "i" ,
592+ map ("key" , new Decimal128Value ("NaN" )),
593+ "j" ,
594+ map ("key" , new Decimal128Value ("-Infinity" )),
595+ "k" ,
596+ map ("key" , NaN ),
597+ "l" ,
598+ map ("key" , POSITIVE_INFINITY ));
599+ CollectionReference randomColl = testCollectionWithDocsOnNightly (docs );
600+
601+ Query orderedQuery = randomColl .orderBy ("key" , Direction .DESCENDING );
602+ assertSDKQueryResultsConsistentWithBackend (
603+ randomColl ,
604+ orderedQuery ,
605+ docs ,
606+ Arrays .asList (
607+ "l" , // Infinity
608+ "h" , // 2
609+ "f" , // 1.0
610+ "e" , // 1
611+ "d" , // 1
612+ "c" , // 1
613+ "g" , // 0.0012
614+ "b" , // 0
615+ "a" , // -1200
616+ "j" , // -Infinity
617+ "k" , // NaN
618+ "i" // NaN
619+ ));
620+
621+ orderedQuery =
622+ randomColl
623+ .orderBy ("key" , Direction .DESCENDING )
624+ .whereNotEqualTo ("key" , new Decimal128Value ("1.0" ));
625+ assertSDKQueryResultsConsistentWithBackend (
626+ randomColl , orderedQuery , docs , Arrays .asList ("l" , "h" , "g" , "b" , "a" , "j" , "k" , "i" ));
627+
628+ orderedQuery = randomColl .orderBy ("key" , Direction .DESCENDING ).whereEqualTo ("key" , 1 );
629+ assertSDKQueryResultsConsistentWithBackend (
630+ randomColl , orderedQuery , docs , Arrays .asList ("f" , "e" , "d" , "c" ));
631+ }
632+
633+ @ Test
634+ public void decimal128ValuesWithNo2sComplementRepresentation () throws Exception {
635+ // For decimal128 values with no 2's complement representation, it is considered not equal to
636+ // a double with the same value, e.g, 1.1.
637+ Map <String , Map <String , Object >> docs =
638+ map (
639+ "a" ,
640+ map ("key" , new Decimal128Value ("-1.1e-3" )), // -0.0011
641+ "b" ,
642+ map ("key" , new Decimal128Value ("1.1" )),
643+ "c" ,
644+ map ("key" , 1.1 ),
645+ "d" ,
646+ map ("key" , 1.0 ),
647+ "e" ,
648+ map ("key" , new Decimal128Value ("1.1e-3" )) // 0.0011
649+ );
650+ CollectionReference randomColl = testCollectionWithDocsOnNightly (docs );
651+
652+ Query orderedQuery = randomColl .whereEqualTo ("key" , new Decimal128Value ("1.1" ));
653+ assertSDKQueryResultsConsistentWithBackend (randomColl , orderedQuery , docs , Arrays .asList ("b" ));
654+
655+ orderedQuery = randomColl .whereNotEqualTo ("key" , new Decimal128Value ("1.1" ));
656+ assertSDKQueryResultsConsistentWithBackend (
657+ randomColl , orderedQuery , docs , Arrays .asList ("a" , "e" , "d" , "c" ));
658+
659+ orderedQuery = randomColl .whereEqualTo ("key" , 1.1 );
660+ assertSDKQueryResultsConsistentWithBackend (randomColl , orderedQuery , docs , Arrays .asList ("c" ));
661+
662+ orderedQuery = randomColl .whereNotEqualTo ("key" , 1.1 );
663+ assertSDKQueryResultsConsistentWithBackend (
664+ randomColl , orderedQuery , docs , Arrays .asList ("a" , "e" , "d" , "b" ));
665+ }
666+
481667 @ Test
482668 public void orderBsonTypesTogether () throws Exception {
483669 Map <String , Map <String , Object >> docs =
@@ -512,6 +698,12 @@ public void orderBsonTypesTogether() throws Exception {
512698 map ("key" , new Int32Value (1 )),
513699 "int32Value3" ,
514700 map ("key" , new Int32Value (0 )),
701+ "decimal128Value1" ,
702+ map ("key" , new Decimal128Value ("-1.2e3" )),
703+ "decimal128Value2" ,
704+ map ("key" , new Decimal128Value ("-0.0" )),
705+ "decimal128Value3" ,
706+ map ("key" , new Decimal128Value ("1.2e3" )),
515707 "minKey1" ,
516708 map ("key" , MinKey .instance ()),
517709 "minKey2" ,
@@ -539,9 +731,15 @@ public void orderBsonTypesTogether() throws Exception {
539731 "bsonTimestamp1" ,
540732 "bsonTimestamp2" ,
541733 "bsonTimestamp3" ,
734+ // Int32Value and Decimal128Value are sorted together
735+ "decimal128Value3" ,
542736 "int32Value2" ,
737+ // Int32Value of 0 equals to Decimal128Value of 0, and falls to document key as second
738+ // order
543739 "int32Value3" ,
740+ "decimal128Value2" ,
544741 "int32Value1" ,
742+ "decimal128Value1" ,
545743 "minKey2" ,
546744 "minKey1" );
547745
0 commit comments