Skip to content

Commit 331f651

Browse files
authored
Add serializer support for transform mutations (#3642)
* Rename Encode/DecodeDocumentMask to *FieldMask to name after the model type * Add Serializer::{Encode,Decode}FieldPath * Avoid passing Serializer* everywhere in serializer_test. * Add support for serializing TransformMutations
1 parent c42bf81 commit 331f651

File tree

4 files changed

+185
-86
lines changed

4 files changed

+185
-86
lines changed

Firestore/core/src/firebase/firestore/remote/serializer.cc

Lines changed: 130 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -547,29 +547,28 @@ google_firestore_v1_Write Serializer::EncodeMutation(
547547
result.which_operation = google_firestore_v1_Write_update_tag;
548548
auto patch_mutation = static_cast<const PatchMutation&>(mutation);
549549
result.update = EncodeDocument(mutation.key(), patch_mutation.value());
550-
result.update_mask = EncodeDocumentMask(patch_mutation.mask());
550+
result.update_mask = EncodeFieldMask(patch_mutation.mask());
551551
return result;
552552
}
553553

554554
case Mutation::Type::Transform: {
555-
// TODO(rsgowman): Implement transform mutations. Probably like this:
556-
abort();
557-
/*
558-
result.which_operation = google_firestore_v1_Write_transform_tag;
559-
auto transform = static_cast<const TransformMutation&>(mutation);
560-
result.transform.document = EncodeKey(transform.key());
561-
562-
size_t count = transform.field_transforms.size();
563-
result.transform.field_transforms_count = count;
564-
result.transform.field_transforms =
565-
MakeArray<google_firestore_v1_DocumentTransform_FieldTransform>(count);
566-
int i = 0;
567-
for (const FieldTransform& field_transform :
568-
transform.field_transforms()) { result.transform.field_transforms[i] =
569-
EncodeFieldTransform(field_transform); i++;
570-
}
571-
return result;
572-
*/
555+
result.which_operation = google_firestore_v1_Write_transform_tag;
556+
auto transform = static_cast<const TransformMutation&>(mutation);
557+
result.transform.document = EncodeString(EncodeKey(transform.key()));
558+
559+
pb_size_t count = CheckedSize(transform.field_transforms().size());
560+
result.transform.field_transforms_count = count;
561+
result.transform.field_transforms =
562+
MakeArray<google_firestore_v1_DocumentTransform_FieldTransform>(
563+
count);
564+
int i = 0;
565+
for (const FieldTransform& field_transform :
566+
transform.field_transforms()) {
567+
result.transform.field_transforms[i] =
568+
EncodeFieldTransform(field_transform);
569+
i++;
570+
}
571+
return result;
573572
}
574573

575574
case Mutation::Type::Delete: {
@@ -592,7 +591,7 @@ Mutation Serializer::DecodeMutation(
592591
DocumentKey key = DecodeKey(reader, DecodeString(mutation.update.name));
593592
ObjectValue value = ObjectValue::FromMap(DecodeFields(
594593
reader, mutation.update.fields_count, mutation.update.fields));
595-
FieldMask mask = DecodeDocumentMask(mutation.update_mask);
594+
FieldMask mask = DecodeFieldMask(mutation.update_mask);
596595
if (mask.size() > 0) {
597596
return PatchMutation(std::move(key), std::move(value), std::move(mask),
598597
std::move(precondition));
@@ -606,22 +605,21 @@ Mutation Serializer::DecodeMutation(
606605
return DeleteMutation(DecodeKey(reader, DecodeString(mutation.delete_)),
607606
std::move(precondition));
608607

609-
// TODO(rsgowman): Implement transform. Probably like this:
610-
/*
611-
case google_firestore_v1_Write_transform_tag:
612-
std::vector<FieldTransform> field_transforms;
613-
for (size_t i = 0; i<mutation.transform.field_transforms_count; i++) {
614-
field_transforms.push_back(DecodeFieldTransform(mutation.transform.field_transforms[i]));
615-
}
608+
case google_firestore_v1_Write_transform_tag: {
609+
std::vector<FieldTransform> field_transforms;
610+
for (size_t i = 0; i < mutation.transform.field_transforms_count; i++) {
611+
field_transforms.push_back(DecodeFieldTransform(
612+
reader, mutation.transform.field_transforms[i]));
613+
}
616614

617-
HARD_ASSERT(precondition.type() == Precondition::Type::Exists &&
618-
precondition.exists(), "Transforms only support precondition \"exists ==
619-
true\"");
615+
HARD_ASSERT(precondition.type() == Precondition::Type::Exists &&
616+
precondition.exists(),
617+
"Transforms only support precondition \"exists == true\"");
620618

621-
return absl::make_unique<TransformMutation>(
622-
DecodeKey(reader, mutation.transform.document),
623-
field_transforms);
624-
*/
619+
return TransformMutation(
620+
DecodeKey(reader, MakeStringView(mutation.transform.document)),
621+
field_transforms);
622+
}
625623

626624
default:
627625
reader->Fail(StringFormat("Unknown mutation operation: %s",
@@ -687,7 +685,7 @@ Precondition Serializer::DecodePrecondition(
687685
}
688686

689687
/* static */
690-
google_firestore_v1_DocumentMask Serializer::EncodeDocumentMask(
688+
google_firestore_v1_DocumentMask Serializer::EncodeFieldMask(
691689
const FieldMask& mask) {
692690
google_firestore_v1_DocumentMask result{};
693691

@@ -697,22 +695,114 @@ google_firestore_v1_DocumentMask Serializer::EncodeDocumentMask(
697695

698696
int i = 0;
699697
for (const FieldPath& path : mask) {
700-
result.field_paths[i] = EncodeString(path.CanonicalString());
698+
result.field_paths[i] = EncodeFieldPath(path);
701699
i++;
702700
}
703701

704702
return result;
705703
}
706704

707705
/* static */
708-
model::FieldMask Serializer::DecodeDocumentMask(
706+
FieldMask Serializer::DecodeFieldMask(
709707
const google_firestore_v1_DocumentMask& mask) {
710708
std::set<FieldPath> fields;
711709
for (size_t i = 0; i < mask.field_paths_count; i++) {
712-
auto path = DecodeString(mask.field_paths[i]);
713-
fields.insert(FieldPath::FromServerFormat(path));
710+
fields.insert(DecodeFieldPath(mask.field_paths[i]));
711+
}
712+
return FieldMask(std::move(fields));
713+
}
714+
715+
/* static */
716+
google_firestore_v1_DocumentTransform_FieldTransform
717+
Serializer::EncodeFieldTransform(const FieldTransform& field_transform) {
718+
using Type = TransformOperation::Type;
719+
720+
google_firestore_v1_DocumentTransform_FieldTransform proto{};
721+
proto.field_path = EncodeFieldPath(field_transform.path());
722+
723+
switch (field_transform.transformation().type()) {
724+
case Type::ServerTimestamp:
725+
proto.which_transform_type =
726+
google_firestore_v1_DocumentTransform_FieldTransform_set_to_server_value_tag; // NOLINT
727+
proto.set_to_server_value =
728+
google_firestore_v1_DocumentTransform_FieldTransform_ServerValue_REQUEST_TIME; // NOLINT
729+
return proto;
730+
731+
case Type::ArrayUnion:
732+
proto.which_transform_type =
733+
google_firestore_v1_DocumentTransform_FieldTransform_append_missing_elements_tag; // NOLINT
734+
proto.append_missing_elements = EncodeArray(
735+
ArrayTransform(field_transform.transformation()).elements());
736+
return proto;
737+
738+
case Type::ArrayRemove:
739+
proto.which_transform_type =
740+
google_firestore_v1_DocumentTransform_FieldTransform_remove_all_from_array_tag; // NOLINT
741+
proto.remove_all_from_array = EncodeArray(
742+
ArrayTransform(field_transform.transformation()).elements());
743+
return proto;
744+
745+
case Type::Increment: {
746+
const auto& increment = static_cast<const NumericIncrementTransform&>(
747+
field_transform.transformation());
748+
proto.increment = EncodeFieldValue(increment.operand());
749+
return proto;
750+
}
714751
}
715-
return model::FieldMask(std::move(fields));
752+
753+
UNREACHABLE();
754+
}
755+
756+
/* static */ FieldTransform Serializer::DecodeFieldTransform(
757+
nanopb::Reader* reader,
758+
const google_firestore_v1_DocumentTransform_FieldTransform& proto) {
759+
switch (proto.which_transform_type) {
760+
case google_firestore_v1_DocumentTransform_FieldTransform_set_to_server_value_tag: { // NOLINT
761+
HARD_ASSERT(
762+
proto.set_to_server_value ==
763+
google_firestore_v1_DocumentTransform_FieldTransform_ServerValue_REQUEST_TIME, // NOLINT
764+
"Unknown transform setToServerValue: %s", proto.set_to_server_value);
765+
766+
return FieldTransform(DecodeFieldPath(proto.field_path),
767+
ServerTimestampTransform());
768+
}
769+
770+
case google_firestore_v1_DocumentTransform_FieldTransform_append_missing_elements_tag: { // NOLINT
771+
std::vector<FieldValue> elements =
772+
DecodeArray(reader, proto.append_missing_elements);
773+
return FieldTransform(DecodeFieldPath(proto.field_path),
774+
ArrayTransform(TransformOperation::Type::ArrayUnion,
775+
std::move(elements)));
776+
}
777+
778+
case google_firestore_v1_DocumentTransform_FieldTransform_remove_all_from_array_tag: { // NOLINT
779+
std::vector<FieldValue> elements =
780+
DecodeArray(reader, proto.remove_all_from_array);
781+
return FieldTransform(
782+
DecodeFieldPath(proto.field_path),
783+
ArrayTransform(TransformOperation::Type::ArrayRemove,
784+
std::move(elements)));
785+
}
786+
787+
case google_firestore_v1_DocumentTransform_FieldTransform_increment_tag: {
788+
FieldValue operand = DecodeFieldValue(reader, proto.increment);
789+
return FieldTransform(DecodeFieldPath(proto.field_path),
790+
NumericIncrementTransform(std::move(operand)));
791+
}
792+
}
793+
794+
UNREACHABLE();
795+
}
796+
797+
/* static */
798+
pb_bytes_array_t* Serializer::EncodeFieldPath(const FieldPath& field_path) {
799+
return EncodeString(field_path.CanonicalString());
800+
}
801+
802+
/* static */
803+
FieldPath Serializer::DecodeFieldPath(const pb_bytes_array_t* field_path) {
804+
absl::string_view str = MakeStringView(field_path);
805+
return FieldPath::FromServerFormat(str);
716806
}
717807

718808
google_firestore_v1_Target_QueryTarget Serializer::EncodeQueryTarget(

Firestore/core/src/firebase/firestore/remote/serializer.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,11 +175,20 @@ class Serializer {
175175
nanopb::Reader* reader,
176176
const google_firestore_v1_Precondition& precondition);
177177

178-
static google_firestore_v1_DocumentMask EncodeDocumentMask(
178+
static google_firestore_v1_DocumentMask EncodeFieldMask(
179179
const model::FieldMask& mask);
180-
static model::FieldMask DecodeDocumentMask(
180+
static model::FieldMask DecodeFieldMask(
181181
const google_firestore_v1_DocumentMask& mask);
182182

183+
static google_firestore_v1_DocumentTransform_FieldTransform
184+
EncodeFieldTransform(const model::FieldTransform& field_transform);
185+
static model::FieldTransform DecodeFieldTransform(
186+
nanopb::Reader* reader,
187+
const google_firestore_v1_DocumentTransform_FieldTransform& proto);
188+
189+
static pb_bytes_array_t* EncodeFieldPath(const model::FieldPath& field_path);
190+
static model::FieldPath DecodeFieldPath(const pb_bytes_array_t* field_path);
191+
183192
/**
184193
* @brief Converts the Query into bytes, representing a
185194
* firestore::v1::Target::QueryTarget.

0 commit comments

Comments
 (0)