19
19
import static com .google .firebase .firestore .testutil .IntegrationTestUtil .testCollectionWithDocsOnNightly ;
20
20
import static com .google .firebase .firestore .testutil .IntegrationTestUtil .waitFor ;
21
21
import static com .google .firebase .firestore .testutil .TestUtil .map ;
22
+ import static java .lang .Double .NaN ;
23
+ import static java .lang .Double .POSITIVE_INFINITY ;
22
24
import static org .junit .Assert .assertEquals ;
23
25
import static org .junit .Assert .assertNotNull ;
24
26
import static org .junit .Assert .assertNull ;
@@ -54,6 +56,7 @@ public void writeAndReadBsonTypes() throws ExecutionException, InterruptedExcept
54
56
"bsonTimestamp" , new BsonTimestamp (1 , 2 ),
55
57
"bsonBinary" , BsonBinaryData .fromBytes (1 , new byte [] {1 , 2 , 3 }),
56
58
"int32" , new Int32Value (1 ),
59
+ "decimal128" , new Decimal128Value ("1.2e3" ),
57
60
"minKey" , MinKey .instance (),
58
61
"maxKey" , MaxKey .instance ())));
59
62
@@ -75,6 +78,7 @@ public void writeAndReadBsonTypes() throws ExecutionException, InterruptedExcept
75
78
expected .put ("bsonTimestamp" , new BsonTimestamp (1 , 3 ));
76
79
expected .put ("bsonBinary" , BsonBinaryData .fromBytes (1 , new byte [] {1 , 2 , 3 }));
77
80
expected .put ("int32" , new Int32Value (2 ));
81
+ expected .put ("decimal128" , new Decimal128Value ("1.2e3" ));
78
82
expected .put ("minKey" , MinKey .instance ());
79
83
expected .put ("maxKey" , MaxKey .instance ());
80
84
@@ -85,6 +89,7 @@ public void writeAndReadBsonTypes() throws ExecutionException, InterruptedExcept
85
89
assertTrue (actual .get ("bsonTimestamp" ) instanceof BsonTimestamp );
86
90
assertTrue (actual .get ("bsonBinary" ) instanceof BsonBinaryData );
87
91
assertTrue (actual .get ("int32" ) instanceof Int32Value );
92
+ assertTrue (actual .get ("decimal128" ) instanceof Decimal128Value );
88
93
assertTrue (actual .get ("minKey" ) instanceof MinKey );
89
94
assertTrue (actual .get ("maxKey" ) instanceof MaxKey );
90
95
assertEquals (expected , actual .getData ());
@@ -101,13 +106,22 @@ public void writeAndReadBsonTypeOffline() throws ExecutionException, Interrupted
101
106
Map <String , Object > expected = new HashMap <>();
102
107
docRef .set (
103
108
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 ()));
111
125
112
126
docRef .update (
113
127
map (
@@ -123,6 +137,7 @@ public void writeAndReadBsonTypeOffline() throws ExecutionException, Interrupted
123
137
expected .put ("bsonTimestamp" , new BsonTimestamp (1 , 3 ));
124
138
expected .put ("bsonBinary" , BsonBinaryData .fromBytes (1 , new byte [] {1 , 2 , 3 }));
125
139
expected .put ("int32" , new Int32Value (1 ));
140
+ expected .put ("decimal128" , new Decimal128Value ("1.2e3" ));
126
141
expected .put ("minKey" , MinKey .instance ());
127
142
expected .put ("maxKey" , MaxKey .instance ());
128
143
@@ -133,6 +148,7 @@ public void writeAndReadBsonTypeOffline() throws ExecutionException, Interrupted
133
148
assertTrue (actual .get ("bsonTimestamp" ) instanceof BsonTimestamp );
134
149
assertTrue (actual .get ("bsonBinary" ) instanceof BsonBinaryData );
135
150
assertTrue (actual .get ("int32" ) instanceof Int32Value );
151
+ assertTrue (actual .get ("decimal128" ) instanceof Decimal128Value );
136
152
assertTrue (actual .get ("minKey" ) instanceof MinKey );
137
153
assertTrue (actual .get ("maxKey" ) instanceof MaxKey );
138
154
assertEquals (expected , actual .getData ());
@@ -174,6 +190,8 @@ public void listenToDocumentsWithBsonTypes() throws Throwable {
174
190
BsonBinaryData .fromBytes (1 , new byte [] {1 , 2 , 3 }),
175
191
"int32" ,
176
192
new Int32Value (1 ),
193
+ "decimal128" ,
194
+ new Decimal128Value ("1.2e3" ),
177
195
"minKey" ,
178
196
MinKey .instance (),
179
197
"maxKey" ,
@@ -192,6 +210,9 @@ public void listenToDocumentsWithBsonTypes() throws Throwable {
192
210
assertEquals (
193
211
docSnap .getBsonTimestamp ("bsonTimestamp" ), new BsonTimestamp (1 , 2 ));
194
212
assertEquals (docSnap .getInt32Value ("int32" ), new Int32Value (1 ));
213
+ assertEquals (
214
+ docSnap .getDecimal128Value ("decimal128" ),
215
+ new Decimal128Value ("1.2e3" ));
195
216
assertEquals (docSnap .getMinKey ("minKey" ), MinKey .instance ());
196
217
assertEquals (docSnap .getMaxKey ("maxKey" ), MaxKey .instance ());
197
218
@@ -266,15 +287,13 @@ public void filterAndOrderBsonObjectIds() throws Exception {
266
287
randomColl
267
288
.orderBy ("key" , Direction .DESCENDING )
268
289
.whereGreaterThan ("key" , new BsonObjectId ("507f191e810c19729de860ea" ));
269
-
270
290
assertSDKQueryResultsConsistentWithBackend (
271
291
randomColl , orderedQuery , docs , Arrays .asList ("c" , "b" ));
272
292
273
293
orderedQuery =
274
294
randomColl
275
295
.orderBy ("key" , Direction .DESCENDING )
276
296
.whereNotEqualTo ("key" , new BsonObjectId ("507f191e810c19729de860eb" ));
277
-
278
297
assertSDKQueryResultsConsistentWithBackend (
279
298
randomColl , orderedQuery , docs , Arrays .asList ("c" , "a" ));
280
299
}
@@ -385,6 +404,80 @@ public void filterAndOrderInt32() throws Exception {
385
404
randomColl , orderedQuery , docs , Arrays .asList ("c" , "a" ));
386
405
}
387
406
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
+ // Pre-populate the cache with all docs
426
+ waitFor (randomColl .get ());
427
+
428
+ Query orderedQuery =
429
+ randomColl
430
+ .orderBy ("key" , Direction .DESCENDING )
431
+ .whereGreaterThan ("key" , new Decimal128Value ("-1.2e3" ));
432
+ assertSDKQueryResultsConsistentWithBackend (
433
+ randomColl , orderedQuery , docs , Arrays .asList ("f" , "c" , "b" ));
434
+
435
+ orderedQuery =
436
+ randomColl
437
+ .orderBy ("key" , Direction .DESCENDING )
438
+ .whereGreaterThan ("key" , new Decimal128Value ("-1.2e-3" ));
439
+ assertSDKQueryResultsConsistentWithBackend (
440
+ randomColl , orderedQuery , docs , Arrays .asList ("f" , "c" , "b" ));
441
+
442
+ orderedQuery =
443
+ randomColl
444
+ .orderBy ("key" , Direction .DESCENDING )
445
+ .whereNotEqualTo ("key" , new Decimal128Value ("0.0" ));
446
+ assertSDKQueryResultsConsistentWithBackend (
447
+ randomColl , orderedQuery , docs , Arrays .asList ("f" , "c" , "a" , "e" , "d" ));
448
+
449
+ orderedQuery = randomColl .whereNotEqualTo ("key" , new Decimal128Value ("NaN" ));
450
+ assertSDKQueryResultsConsistentWithBackend (
451
+ randomColl , orderedQuery , docs , Arrays .asList ("e" , "a" , "b" , "c" , "f" ));
452
+
453
+ orderedQuery =
454
+ randomColl
455
+ .orderBy ("key" , Direction .DESCENDING )
456
+ .whereEqualTo ("key" , new Decimal128Value ("1.2e3" ));
457
+ assertSDKQueryResultsConsistentWithBackend (randomColl , orderedQuery , docs , Arrays .asList ("c" ));
458
+
459
+ orderedQuery =
460
+ randomColl
461
+ .orderBy ("key" , Direction .DESCENDING )
462
+ .whereNotEqualTo ("key" , new Decimal128Value ("1.2e3" ));
463
+ assertSDKQueryResultsConsistentWithBackend (
464
+ randomColl , orderedQuery , docs , Arrays .asList ("f" , "b" , "a" , "e" , "d" ));
465
+
466
+ // Note: server is sending NaN incorrectly, but the SDK NotInFilter.matches gracefully handles
467
+ // it and removes the incorrect doc "d".
468
+ orderedQuery =
469
+ randomColl
470
+ .orderBy ("key" , Direction .DESCENDING )
471
+ .whereNotIn (
472
+ "key" ,
473
+ Arrays .asList (
474
+ new Decimal128Value ("1.2e3" ),
475
+ new Decimal128Value ("Infinity" ),
476
+ new Decimal128Value ("NaN" )));
477
+ assertSDKQueryResultsConsistentWithBackend (
478
+ randomColl , orderedQuery , docs , Arrays .asList ("b" , "a" , "e" ));
479
+ }
480
+
388
481
@ Test
389
482
public void filterAndOrderMinKey () throws Exception {
390
483
Map <String , Map <String , Object >> docs =
@@ -478,6 +571,108 @@ public void filterNullValueWithBsonTypes() throws Exception {
478
571
randomColl , query , docs , Arrays .asList ("a" , "d" , "e" ));
479
572
}
480
573
574
+ @ Test
575
+ public void filterAndOrderNumericalValues () throws Exception {
576
+ Map <String , Map <String , Object >> docs =
577
+ map (
578
+ "a" ,
579
+ map ("key" , new Decimal128Value ("-1.2e3" )), // -1200
580
+ "b" ,
581
+ map ("key" , new Int32Value (0 )),
582
+ "c" ,
583
+ map ("key" , new Decimal128Value ("1" )),
584
+ "d" ,
585
+ map ("key" , new Int32Value (1 )),
586
+ "e" ,
587
+ map ("key" , 1L ),
588
+ "f" ,
589
+ map ("key" , 1.0 ),
590
+ "g" ,
591
+ map ("key" , new Decimal128Value ("1.2e-3" )), // 0.0012
592
+ "h" ,
593
+ map ("key" , new Int32Value (2 )),
594
+ "i" ,
595
+ map ("key" , new Decimal128Value ("NaN" )),
596
+ "j" ,
597
+ map ("key" , new Decimal128Value ("-Infinity" )),
598
+ "k" ,
599
+ map ("key" , NaN ),
600
+ "l" ,
601
+ map ("key" , POSITIVE_INFINITY ));
602
+ CollectionReference randomColl = testCollectionWithDocsOnNightly (docs );
603
+
604
+ // Pre-populate the cache with all docs
605
+ waitFor (randomColl .get ());
606
+
607
+ Query orderedQuery = randomColl .orderBy ("key" , Direction .DESCENDING );
608
+ assertSDKQueryResultsConsistentWithBackend (
609
+ randomColl ,
610
+ orderedQuery ,
611
+ docs ,
612
+ Arrays .asList (
613
+ "l" , // Infinity
614
+ "h" , // 2
615
+ "f" , // 1.0
616
+ "e" , // 1
617
+ "d" , // 1
618
+ "c" , // 1
619
+ "g" , // 0.0012
620
+ "b" , // 0
621
+ "a" , // -1200
622
+ "j" , // -Infinity
623
+ "k" , // NaN
624
+ "i" // NaN
625
+ ));
626
+
627
+ orderedQuery =
628
+ randomColl
629
+ .orderBy ("key" , Direction .DESCENDING )
630
+ .whereNotEqualTo ("key" , new Decimal128Value ("1.0" ));
631
+ assertSDKQueryResultsConsistentWithBackend (
632
+ randomColl , orderedQuery , docs , Arrays .asList ("l" , "h" , "g" , "b" , "a" , "j" , "k" , "i" ));
633
+
634
+ orderedQuery = randomColl .orderBy ("key" , Direction .DESCENDING ).whereEqualTo ("key" , 1 );
635
+ assertSDKQueryResultsConsistentWithBackend (
636
+ randomColl , orderedQuery , docs , Arrays .asList ("f" , "e" , "d" , "c" ));
637
+ }
638
+
639
+ @ Test
640
+ public void decimal128ValuesWithNo2sComplementRepresentation () throws Exception {
641
+ // For decimal128 values with no 2's complement representation, it is considered not equal to
642
+ // a double with the same value, e.g, 1.1.
643
+ Map <String , Map <String , Object >> docs =
644
+ map (
645
+ "a" ,
646
+ map ("key" , new Decimal128Value ("-1.1e-3" )), // -0.0011
647
+ "b" ,
648
+ map ("key" , new Decimal128Value ("1.1" )),
649
+ "c" ,
650
+ map ("key" , 1.1 ),
651
+ "d" ,
652
+ map ("key" , 1.0 ),
653
+ "e" ,
654
+ map ("key" , new Decimal128Value ("1.1e-3" )) // 0.0011
655
+ );
656
+ CollectionReference randomColl = testCollectionWithDocsOnNightly (docs );
657
+
658
+ // Pre-populate the cache with all docs
659
+ waitFor (randomColl .get ());
660
+
661
+ Query orderedQuery = randomColl .whereEqualTo ("key" , new Decimal128Value ("1.1" ));
662
+ assertSDKQueryResultsConsistentWithBackend (randomColl , orderedQuery , docs , Arrays .asList ("b" ));
663
+
664
+ orderedQuery = randomColl .whereNotEqualTo ("key" , new Decimal128Value ("1.1" ));
665
+ assertSDKQueryResultsConsistentWithBackend (
666
+ randomColl , orderedQuery , docs , Arrays .asList ("a" , "e" , "d" , "c" ));
667
+
668
+ orderedQuery = randomColl .whereEqualTo ("key" , 1.1 );
669
+ assertSDKQueryResultsConsistentWithBackend (randomColl , orderedQuery , docs , Arrays .asList ("c" ));
670
+
671
+ orderedQuery = randomColl .whereNotEqualTo ("key" , 1.1 );
672
+ assertSDKQueryResultsConsistentWithBackend (
673
+ randomColl , orderedQuery , docs , Arrays .asList ("a" , "e" , "d" , "b" ));
674
+ }
675
+
481
676
@ Test
482
677
public void orderBsonTypesTogether () throws Exception {
483
678
Map <String , Map <String , Object >> docs =
@@ -512,6 +707,12 @@ public void orderBsonTypesTogether() throws Exception {
512
707
map ("key" , new Int32Value (1 )),
513
708
"int32Value3" ,
514
709
map ("key" , new Int32Value (0 )),
710
+ "decimal128Value1" ,
711
+ map ("key" , new Decimal128Value ("-1.2e3" )),
712
+ "decimal128Value2" ,
713
+ map ("key" , new Decimal128Value ("-0.0" )),
714
+ "decimal128Value3" ,
715
+ map ("key" , new Decimal128Value ("1.2e3" )),
515
716
"minKey1" ,
516
717
map ("key" , MinKey .instance ()),
517
718
"minKey2" ,
@@ -539,9 +740,15 @@ public void orderBsonTypesTogether() throws Exception {
539
740
"bsonTimestamp1" ,
540
741
"bsonTimestamp2" ,
541
742
"bsonTimestamp3" ,
743
+ // Int32Value and Decimal128Value are sorted together
744
+ "decimal128Value3" ,
542
745
"int32Value2" ,
746
+ // Int32Value of 0 equals to Decimal128Value of 0, and falls to document key as second
747
+ // order
543
748
"int32Value3" ,
749
+ "decimal128Value2" ,
544
750
"int32Value1" ,
751
+ "decimal128Value1" ,
545
752
"minKey2" ,
546
753
"minKey1" );
547
754
0 commit comments