17
17
#include " Firestore/core/src/model/value_util.h"
18
18
19
19
#include < algorithm>
20
+ #include < cmath>
21
+ #include < limits>
20
22
#include < memory>
21
23
#include < vector>
22
24
25
+ #include " Firestore/core/src/model/database_id.h"
26
+ #include " Firestore/core/src/model/document_key.h"
23
27
#include " Firestore/core/src/model/server_timestamp_util.h"
24
28
#include " Firestore/core/src/nanopb/nanopb_util.h"
25
29
#include " Firestore/core/src/util/comparison.h"
@@ -123,9 +127,10 @@ ComparisonResult CompareBlobs(const google_firestore_v1_Value& left,
123
127
? util::ComparisonResultFromInt (cmp)
124
128
: util::Compare (left.bytes_value ->size , right.bytes_value ->size );
125
129
} else {
126
- // An empty blob is represented by a nullptr
127
- return util::Compare (left.bytes_value != nullptr ,
128
- right.bytes_value != nullptr );
130
+ // An empty blob is represented by a nullptr (or an empty byte array)
131
+ return util::Compare (
132
+ !(left.bytes_value == nullptr || left.bytes_value ->size == 0 ),
133
+ !(right.bytes_value == nullptr || right.bytes_value ->size == 0 ));
129
134
}
130
135
}
131
136
@@ -247,8 +252,8 @@ ComparisonResult Compare(const google_firestore_v1_Value& left,
247
252
}
248
253
}
249
254
250
- bool NumberEquals (const firebase::firestore:: google_firestore_v1_Value& left,
251
- const firebase::firestore:: google_firestore_v1_Value& right) {
255
+ bool NumberEquals (const google_firestore_v1_Value& left,
256
+ const google_firestore_v1_Value& right) {
252
257
if (left.which_value_type == google_firestore_v1_Value_integer_value_tag &&
253
258
right.which_value_type == google_firestore_v1_Value_integer_value_tag) {
254
259
return left.integer_value == right.integer_value ;
@@ -261,42 +266,36 @@ bool NumberEquals(const firebase::firestore::google_firestore_v1_Value& left,
261
266
return false ;
262
267
}
263
268
264
- bool ArrayEquals (const firebase::firestore::google_firestore_v1_Value& left,
265
- const firebase::firestore::google_firestore_v1_Value& right) {
266
- const google_firestore_v1_ArrayValue& left_array = left.array_value ;
267
- const google_firestore_v1_ArrayValue& right_array = right.array_value ;
268
-
269
- if (left_array.values_count != right_array.values_count ) {
269
+ bool ArrayEquals (const google_firestore_v1_ArrayValue& left,
270
+ const google_firestore_v1_ArrayValue& right) {
271
+ if (left.values_count != right.values_count ) {
270
272
return false ;
271
273
}
272
274
273
- for (size_t i = 0 ; i < left_array .values_count ; ++i) {
274
- if (left_array .values [i] != right_array .values [i]) {
275
+ for (size_t i = 0 ; i < left .values_count ; ++i) {
276
+ if (left .values [i] != right .values [i]) {
275
277
return false ;
276
278
}
277
279
}
278
280
279
281
return true ;
280
282
}
281
283
282
- bool ObjectEquals (const firebase::firestore::google_firestore_v1_Value& left,
283
- const firebase::firestore::google_firestore_v1_Value& right) {
284
- google_firestore_v1_MapValue left_map = left.map_value ;
285
- google_firestore_v1_MapValue right_map = right.map_value ;
286
-
287
- if (left_map.fields_count != right_map.fields_count ) {
284
+ bool ObjectEquals (const google_firestore_v1_MapValue& left,
285
+ const google_firestore_v1_MapValue& right) {
286
+ if (left.fields_count != right.fields_count ) {
288
287
return false ;
289
288
}
290
289
291
290
// Porting Note: MapValues in iOS are always kept in sorted order. We
292
291
// therefore do no need to sort them before comparing.
293
- for (size_t i = 0 ; i < right_map .fields_count ; ++i) {
294
- if (nanopb::MakeStringView (left_map .fields [i].key ) !=
295
- nanopb::MakeStringView (right_map .fields [i].key )) {
292
+ for (size_t i = 0 ; i < right .fields_count ; ++i) {
293
+ if (nanopb::MakeStringView (left .fields [i].key ) !=
294
+ nanopb::MakeStringView (right .fields [i].key )) {
296
295
return false ;
297
296
}
298
297
299
- if (left_map .fields [i].value != right_map .fields [i].value ) {
298
+ if (left .fields [i].value != right .fields [i].value ) {
300
299
return false ;
301
300
}
302
301
}
@@ -349,16 +348,21 @@ bool Equals(const google_firestore_v1_Value& lhs,
349
348
lhs.geo_point_value .longitude == rhs.geo_point_value .longitude ;
350
349
351
350
case TypeOrder::kArray :
352
- return ArrayEquals (lhs, rhs);
351
+ return ArrayEquals (lhs. array_value , rhs. array_value );
353
352
354
353
case TypeOrder::kMap :
355
- return ObjectEquals (lhs, rhs);
354
+ return ObjectEquals (lhs. map_value , rhs. map_value );
356
355
357
356
default :
358
357
HARD_FAIL (" Invalid type value: %s" , left_type);
359
358
}
360
359
}
361
360
361
+ bool Equals (const google_firestore_v1_ArrayValue& lhs,
362
+ const google_firestore_v1_ArrayValue& rhs) {
363
+ return ArrayEquals (lhs, rhs);
364
+ }
365
+
362
366
std::string CanonifyTimestamp (const google_firestore_v1_Value& value) {
363
367
return absl::StrFormat (" time(%d,%d)" , value.timestamp_value .seconds ,
364
368
value.timestamp_value .nanos );
@@ -381,13 +385,11 @@ std::string CanonifyGeoPoint(const google_firestore_v1_Value& value) {
381
385
value.geo_point_value .longitude );
382
386
}
383
387
384
- std::string CanonifyArray (const google_firestore_v1_Value& value) {
385
- const auto & array = value.array_value ;
386
-
388
+ std::string CanonifyArray (const google_firestore_v1_ArrayValue& array_value) {
387
389
std::string result = " [" ;
388
- for (size_t i = 0 ; i < array .values_count ; ++i) {
389
- absl::StrAppend (&result, CanonicalId (array .values [i]));
390
- if (i != array .values_count - 1 ) {
390
+ for (size_t i = 0 ; i < array_value .values_count ; ++i) {
391
+ absl::StrAppend (&result, CanonicalId (array_value .values [i]));
392
+ if (i != array_value .values_count - 1 ) {
391
393
absl::StrAppend (&result, " ," );
392
394
}
393
395
}
@@ -444,7 +446,7 @@ std::string CanonicalId(const google_firestore_v1_Value& value) {
444
446
return CanonifyGeoPoint (value);
445
447
446
448
case google_firestore_v1_Value_array_value_tag:
447
- return CanonifyArray (value);
449
+ return CanonifyArray (value. array_value );
448
450
449
451
case google_firestore_v1_Value_map_value_tag: {
450
452
return CanonifyObject (value);
@@ -455,12 +457,61 @@ std::string CanonicalId(const google_firestore_v1_Value& value) {
455
457
}
456
458
}
457
459
458
- google_firestore_v1_Value DeepClone (google_firestore_v1_Value source) {
460
+ std::string CanonicalId (const google_firestore_v1_ArrayValue& value) {
461
+ return CanonifyArray (value);
462
+ }
463
+
464
+ bool Contains (google_firestore_v1_ArrayValue haystack,
465
+ google_firestore_v1_Value needle) {
466
+ for (pb_size_t i = 0 ; i < haystack.values_count ; ++i) {
467
+ if (Equals (haystack.values [i], needle)) {
468
+ return true ;
469
+ }
470
+ }
471
+ return false ;
472
+ }
473
+
474
+ google_firestore_v1_Value NullValue () {
475
+ google_firestore_v1_Value null_value{};
476
+ null_value.which_value_type = google_firestore_v1_Value_null_value_tag;
477
+ return null_value;
478
+ }
479
+
480
+ bool IsNullValue (const google_firestore_v1_Value& value) {
481
+ return value.which_value_type == google_firestore_v1_Value_null_value_tag;
482
+ }
483
+
484
+ google_firestore_v1_Value NaNValue () {
485
+ google_firestore_v1_Value nan_value{};
486
+ nan_value.which_value_type = google_firestore_v1_Value_double_value_tag;
487
+ nan_value.double_value = std::numeric_limits<double >::quiet_NaN ();
488
+ return nan_value;
489
+ }
490
+
491
+ bool IsNaNValue (const google_firestore_v1_Value& value) {
492
+ return value.which_value_type == google_firestore_v1_Value_double_value_tag &&
493
+ isnan (value.double_value );
494
+ }
495
+
496
+ google_firestore_v1_Value RefValue (const model::DatabaseId& database_id,
497
+ const model::DocumentKey& document_key) {
498
+ google_firestore_v1_Value result{};
499
+ result.which_value_type = google_firestore_v1_Value_reference_value_tag;
500
+ result.string_value = nanopb::MakeBytesArray (util::StringFormat (
501
+ " projects/%s/databases/%s/documents/%s" , database_id.project_id (),
502
+ database_id.database_id (), document_key.ToString ()));
503
+ return result;
504
+ }
505
+
506
+ google_firestore_v1_Value DeepClone (const google_firestore_v1_Value& source) {
459
507
google_firestore_v1_Value target = source;
460
508
switch (source.which_value_type ) {
461
509
case google_firestore_v1_Value_string_value_tag:
462
- target.string_value = nanopb::MakeBytesArray (source.string_value ->bytes ,
463
- source.string_value ->size );
510
+ target.string_value =
511
+ source.string_value
512
+ ? nanopb::MakeBytesArray (source.string_value ->bytes ,
513
+ source.string_value ->size )
514
+ : nullptr ;
464
515
break ;
465
516
466
517
case google_firestore_v1_Value_reference_value_tag:
@@ -469,8 +520,10 @@ google_firestore_v1_Value DeepClone(google_firestore_v1_Value source) {
469
520
break ;
470
521
471
522
case google_firestore_v1_Value_bytes_value_tag:
472
- target.bytes_value = nanopb::MakeBytesArray (source.bytes_value ->bytes ,
473
- source.bytes_value ->size );
523
+ target.bytes_value =
524
+ source.bytes_value ? nanopb::MakeBytesArray (source.bytes_value ->bytes ,
525
+ source.bytes_value ->size )
526
+ : nullptr ;
474
527
break ;
475
528
476
529
case google_firestore_v1_Value_array_value_tag:
@@ -499,6 +552,18 @@ google_firestore_v1_Value DeepClone(google_firestore_v1_Value source) {
499
552
return target;
500
553
}
501
554
555
+ google_firestore_v1_ArrayValue DeepClone (
556
+ const google_firestore_v1_ArrayValue& source) {
557
+ google_firestore_v1_ArrayValue target = source;
558
+ target.values_count = source.values_count ;
559
+ target.values =
560
+ nanopb::MakeArray<google_firestore_v1_Value>(source.values_count );
561
+ for (pb_size_t i = 0 ; i < source.values_count ; ++i) {
562
+ target.values [i] = DeepClone (source.values [i]);
563
+ }
564
+ return target;
565
+ }
566
+
502
567
} // namespace model
503
568
} // namespace firestore
504
569
} // namespace firebase
0 commit comments