Skip to content

Commit ce56391

Browse files
committed
Addressing comments #1
1 parent ac15477 commit ce56391

File tree

8 files changed

+81
-65
lines changed

8 files changed

+81
-65
lines changed

Firestore/Protos/nanopb/google/firestore/v1/document.nanopb.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ const pb_field_t google_firestore_v1_Document_fields[5] = {
3333
PB_FIELD( 1, BYTES , SINGULAR, POINTER , FIRST, google_firestore_v1_Document, name, name, 0),
3434
PB_FIELD( 2, MESSAGE , REPEATED, POINTER , OTHER, google_firestore_v1_Document, fields, name, &google_firestore_v1_Document_FieldsEntry_fields),
3535
PB_FIELD( 3, MESSAGE , SINGULAR, STATIC , OTHER, google_firestore_v1_Document, create_time, fields, &google_protobuf_Timestamp_fields),
36-
PB_FIELD( 4, MESSAGE , SINGULAR, STATIC , OTHER, google_firestore_v1_Document, update_time, create_time, &google_protobuf_Timestamp_fields),
36+
PB_FIELD( 4, MESSAGE , OPTIONAL, STATIC , OTHER, google_firestore_v1_Document, update_time, create_time, &google_protobuf_Timestamp_fields),
3737
PB_LAST_FIELD
3838
};
3939

Firestore/Protos/nanopb/google/firestore/v1/document.nanopb.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ typedef struct _google_firestore_v1_Document {
5656
pb_size_t fields_count;
5757
struct _google_firestore_v1_Document_FieldsEntry *fields;
5858
google_protobuf_Timestamp create_time;
59+
bool has_update_time;
5960
google_protobuf_Timestamp update_time;
6061
/* @@protoc_insertion_point(struct:google_firestore_v1_Document) */
6162
} google_firestore_v1_Document;
@@ -93,13 +94,13 @@ typedef struct _google_firestore_v1_MapValue_FieldsEntry {
9394
/* Default values for struct fields */
9495

9596
/* Initializer values for message structs */
96-
#define google_firestore_v1_Document_init_default {NULL, 0, NULL, google_protobuf_Timestamp_init_default, google_protobuf_Timestamp_init_default}
97+
#define google_firestore_v1_Document_init_default {NULL, 0, NULL, google_protobuf_Timestamp_init_default, false, google_protobuf_Timestamp_init_default}
9798
#define google_firestore_v1_Document_FieldsEntry_init_default {NULL, google_firestore_v1_Value_init_default}
9899
#define google_firestore_v1_Value_init_default {0, {0}}
99100
#define google_firestore_v1_ArrayValue_init_default {0, NULL}
100101
#define google_firestore_v1_MapValue_init_default {0, NULL}
101102
#define google_firestore_v1_MapValue_FieldsEntry_init_default {NULL, google_firestore_v1_Value_init_default}
102-
#define google_firestore_v1_Document_init_zero {NULL, 0, NULL, google_protobuf_Timestamp_init_zero, google_protobuf_Timestamp_init_zero}
103+
#define google_firestore_v1_Document_init_zero {NULL, 0, NULL, google_protobuf_Timestamp_init_zero, false, google_protobuf_Timestamp_init_zero}
103104
#define google_firestore_v1_Document_FieldsEntry_init_zero {NULL, google_firestore_v1_Value_init_zero}
104105
#define google_firestore_v1_Value_init_zero {0, {0}}
105106
#define google_firestore_v1_ArrayValue_init_zero {0, NULL}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Copyright 2019 Google
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
#
15+
16+
# In proto3 mode, Nanopb doesn't allow distinguishing between unset fields and
17+
# fields having default values, even for non-primitive types. Using the
18+
# workaround suggested in
19+
# https://github.com/nanopb/nanopb/issues/255#issuecomment-291842903
20+
21+
# Serializer needs to verify update_time is set.
22+
google.firestore.v1.Document.update_time proto3:false

Firestore/Protos/protos/google/firestore/v1/firestore.options

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,6 @@
1818
# workaround suggested in
1919
# https://github.com/nanopb/nanopb/issues/255#issuecomment-291842903
2020

21-
# cause is not set if everything is OK, serializer need to be able to tell
21+
# cause is not set if everything is OK, serializer needs to be able to tell
2222
# that is the case.
2323
google.firestore.v1.TargetChange.cause proto3:false

Firestore/core/src/firebase/firestore/local/local_serializer.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ google_firestore_v1_Document LocalSerializer::EncodeDocument(
142142
}
143143

144144
result.update_time = rpc_serializer_.EncodeVersion(doc.version());
145-
145+
result.has_update_time = true;
146146
// Ignore Document.create_time. (We don't use this in our on-disk protos.)
147147

148148
return result;

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

+36-42
Original file line numberDiff line numberDiff line change
@@ -1496,6 +1496,7 @@ MutationResult Serializer::DecodeMutationResult(
14961496
write_result.has_update_time
14971497
? DecodeSnapshotVersion(reader, write_result.update_time)
14981498
: commit_version;
1499+
14991500
absl::optional<std::vector<FieldValue>> transform_results;
15001501
if (write_result.transform_results_count > 0) {
15011502
transform_results = std::vector<FieldValue>{};
@@ -1504,17 +1505,19 @@ MutationResult Serializer::DecodeMutationResult(
15041505
DecodeFieldValue(reader, write_result.transform_results[i]));
15051506
}
15061507
}
1507-
return MutationResult(std::move(version), std::move(transform_results));
1508+
1509+
return MutationResult(version, std::move(transform_results));
15081510
}
15091511

15101512
std::unordered_map<std::string, std::string>
15111513
Serializer::EncodeListenRequestLabels(const QueryData& query_data) const {
15121514
auto value = EncodeLabel(query_data.purpose());
1513-
1514-
std::unordered_map<std::string, std::string> result(1);
1515-
if (!value.empty()) {
1516-
result["goog-listen-tags"] = value;
1515+
if (value.empty()) {
1516+
return {};
15171517
}
1518+
1519+
std::unordered_map<std::string, std::string> result;
1520+
result["goog-listen-tags"] = std::move(value);
15181521
return result;
15191522
}
15201523

@@ -1526,9 +1529,8 @@ std::string Serializer::EncodeLabel(QueryPurpose purpose) const {
15261529
return "existence-filter-mismatch";
15271530
case QueryPurpose::LimboResolution:
15281531
return "limbo-document";
1529-
default:
1530-
HARD_FAIL("Unrecognized query purpose: %s", purpose);
15311532
}
1533+
UNREACHABLE();
15321534
}
15331535

15341536
std::unique_ptr<WatchChange> Serializer::DecodeWatchChange(
@@ -1549,11 +1551,8 @@ std::unique_ptr<WatchChange> Serializer::DecodeWatchChange(
15491551

15501552
case google_firestore_v1_ListenResponse_filter_tag:
15511553
return DecodeExistenceFilterWatchChange(reader, watch_change.filter);
1552-
1553-
default:
1554-
HARD_FAIL("Unknown WatchChange.changeType %s",
1555-
watch_change.which_response_type);
15561554
}
1555+
UNREACHABLE();
15571556
}
15581557

15591558
SnapshotVersion Serializer::DecodeVersion(
@@ -1569,28 +1568,18 @@ SnapshotVersion Serializer::DecodeVersion(
15691568
if (listen_response.target_change.target_ids_count != 0) {
15701569
return SnapshotVersion::None();
15711570
}
1572-
return DecodeSnapshotVersion(reader, listen_response.target_change.read_time);
1573-
}
1574-
1575-
std::vector<TargetId> Serializer::DecodeTargetIdArray(nanopb::Reader* reader,
1576-
int32_t* array,
1577-
pb_size_t size) const {
1578-
std::vector<TargetId> target_ids;
15791571

1580-
for (pb_size_t i = 0; i < size; i++) {
1581-
target_ids.push_back(array[i]);
1582-
}
1583-
return target_ids;
1572+
return DecodeSnapshotVersion(reader, listen_response.target_change.read_time);
15841573
}
15851574

15861575
std::unique_ptr<WatchChange> Serializer::DecodeTargetChange(
15871576
nanopb::Reader* reader,
15881577
const google_firestore_v1_TargetChange& change) const {
15891578
WatchTargetChangeState state =
15901579
DecodeTargetChangeState(reader, change.target_change_type);
1591-
auto target_ids =
1592-
DecodeTargetIdArray(reader, change.target_ids, change.target_ids_count);
1593-
ByteString resume_token = ByteString(change.resume_token);
1580+
std::vector<TargetId> target_ids(change.target_ids,
1581+
change.target_ids + change.target_ids_count);
1582+
ByteString resume_token(change.resume_token);
15941583

15951584
util::Status cause;
15961585
if (change.has_cause) {
@@ -1616,9 +1605,8 @@ WatchTargetChangeState Serializer::DecodeTargetChangeState(
16161605
return WatchTargetChangeState::Current;
16171606
case google_firestore_v1_TargetChange_TargetChangeType_RESET:
16181607
return WatchTargetChangeState::Reset;
1619-
default:
1620-
HARD_FAIL("Unexpected TargetChange.state: %s", state);
16211608
}
1609+
UNREACHABLE();
16221610
}
16231611

16241612
std::unique_ptr<WatchChange> Serializer::DecodeDocumentChange(
@@ -1627,19 +1615,23 @@ std::unique_ptr<WatchChange> Serializer::DecodeDocumentChange(
16271615
ObjectValue value = ObjectValue::FromMap(DecodeFields(
16281616
reader, change.document.fields_count, change.document.fields));
16291617
DocumentKey key = DecodeKey(reader, change.document.name);
1618+
1619+
HARD_ASSERT(change.document.has_update_time,
1620+
"Got a document change with no snapshot version");
16301621
SnapshotVersion version =
16311622
DecodeSnapshotVersion(reader, change.document.update_time);
1632-
HARD_ASSERT(version != SnapshotVersion::None(),
1633-
"Got a document change with no snapshot version");
1634-
// The document may soon be re-serialized back to protos in order to store it
1635-
// in local persistence. Memoize the encoded form to avoid encoding it again.
1636-
Document document(std::move(value), key, version, DocumentState::kSynced,
1637-
change.document);
16381623

1639-
auto updated_target_ids =
1640-
DecodeTargetIdArray(reader, change.target_ids, change.target_ids_count);
1641-
auto removed_target_ids = DecodeTargetIdArray(
1642-
reader, change.removed_target_ids, change.removed_target_ids_count);
1624+
// TODO(wuandy): Originally `document` is constructed with `change.document`
1625+
// as last argument, such that it does not have to encode the proto again
1626+
// when saving it. It's dangerous because last argument is an `any` type.
1627+
// Revisit this when porting local serializer to see if we can do it safely.
1628+
Document document(std::move(value), key, version, DocumentState::kSynced);
1629+
1630+
std::vector<TargetId> updated_target_ids(
1631+
change.target_ids, change.target_ids + change.target_ids_count);
1632+
std::vector<TargetId> removed_target_ids(
1633+
change.removed_target_ids,
1634+
change.removed_target_ids + change.removed_target_ids_count);
16431635

16441636
return absl::make_unique<DocumentWatchChange>(
16451637
std::move(updated_target_ids), std::move(removed_target_ids),
@@ -1651,14 +1643,15 @@ std::unique_ptr<WatchChange> Serializer::DecodeDocumentDelete(
16511643
const google_firestore_v1_DocumentDelete& change) const {
16521644
DocumentKey key = DecodeKey(reader, change.document);
16531645
// Note that version might be unset in which case we use
1654-
// SnapshotVersion::None()
1646+
// SnapshotVersion::None().
16551647
SnapshotVersion version =
16561648
change.has_read_time ? DecodeSnapshotVersion(reader, change.read_time)
16571649
: SnapshotVersion::None();
16581650
NoDocument document(key, version, /* has_committed_mutations= */ false);
16591651

1660-
std::vector<TargetId> removed_target_ids = DecodeTargetIdArray(
1661-
reader, change.removed_target_ids, change.removed_target_ids_count);
1652+
std::vector<TargetId> removed_target_ids(
1653+
change.removed_target_ids,
1654+
change.removed_target_ids + change.removed_target_ids_count);
16621655

16631656
return absl::make_unique<DocumentWatchChange>(
16641657
std::vector<TargetId>{}, std::move(removed_target_ids), std::move(key),
@@ -1669,8 +1662,9 @@ std::unique_ptr<WatchChange> Serializer::DecodeDocumentRemove(
16691662
nanopb::Reader* reader,
16701663
const google_firestore_v1_DocumentRemove& change) const {
16711664
DocumentKey key = DecodeKey(reader, change.document);
1672-
std::vector<TargetId> removed_target_ids = DecodeTargetIdArray(
1673-
reader, change.removed_target_ids, change.removed_target_ids_count);
1665+
std::vector<TargetId> removed_target_ids(
1666+
change.removed_target_ids,
1667+
change.removed_target_ids + change.removed_target_ids_count);
16741668

16751669
return absl::make_unique<DocumentWatchChange>(std::vector<TargetId>{},
16761670
std::move(removed_target_ids),

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

-3
Original file line numberDiff line numberDiff line change
@@ -349,9 +349,6 @@ class Serializer {
349349
std::unique_ptr<remote::WatchChange> DecodeDocumentChange(
350350
nanopb::Reader* reader,
351351
const google_firestore_v1_DocumentChange& change) const;
352-
std::vector<model::TargetId> DecodeTargetIdArray(nanopb::Reader* reader,
353-
int32_t* array,
354-
pb_size_t size) const;
355352
std::unique_ptr<remote::WatchChange> DecodeDocumentDelete(
356353
nanopb::Reader* reader,
357354
const google_firestore_v1_DocumentDelete& change) const;

Firestore/core/test/firebase/firestore/remote/serializer_test.cc

+17-15
Original file line numberDiff line numberDiff line change
@@ -120,23 +120,26 @@ QueryData CreateQueryData(absl::string_view str) {
120120
return CreateQueryData(Query(str));
121121
}
122122

123+
template <typename T>
124+
bool Equals(const WatchChange& lhs, const WatchChange& rhs) {
125+
return static_cast<const T&>(lhs) == static_cast<const T&>(rhs);
126+
}
127+
128+
// Compares two `WatchChange`s taking into account their actual derived type.
123129
bool operator==(const WatchChange& lhs, const WatchChange& rhs) {
124130
if (lhs.type() != rhs.type()) {
125131
return false;
126132
}
133+
127134
switch (lhs.type()) {
128135
case WatchChange::Type::Document:
129-
return static_cast<const DocumentWatchChange&>(lhs) ==
130-
static_cast<const DocumentWatchChange&>(rhs);
131-
case WatchChange::Type::TargetChange:
132-
return static_cast<const WatchTargetChange&>(lhs) ==
133-
static_cast<const WatchTargetChange&>(rhs);
136+
return Equals<DocumentWatchChange>(lhs, rhs);
134137
case WatchChange::Type::ExistenceFilter:
135-
return static_cast<const ExistenceFilterWatchChange&>(lhs) ==
136-
static_cast<const ExistenceFilterWatchChange&>(rhs);
137-
default:
138-
HARD_FAIL("Unknown WatchChange.type() %s", lhs.type());
138+
return Equals<ExistenceFilterWatchChange>(lhs, rhs);
139+
case WatchChange::Type::TargetChange:
140+
return Equals<WatchTargetChange>(lhs, rhs);
139141
}
142+
UNREACHABLE();
140143
}
141144

142145
} // namespace
@@ -498,7 +501,7 @@ class SerializerTest : public ::testing::Test {
498501
google_firestore_v1_ListenResponse_fields,
499502
std::mem_fn(&Serializer::DecodeWatchChange), proto);
500503

501-
ASSERT_TRUE(model == *actual_model);
504+
EXPECT_TRUE(model == *actual_model);
502505
}
503506

504507
template <typename T>
@@ -1468,18 +1471,17 @@ TEST_F(SerializerTest, EncodesResumeTokens) {
14681471
TEST_F(SerializerTest, EncodesListenRequestLabels) {
14691472
core::Query q = Query("docs");
14701473

1471-
std::vector<
1472-
std::pair<QueryPurpose, std::unordered_map<std::string, std::string>>>
1473-
purposeToLabel = {
1474+
std::map<QueryPurpose, std::unordered_map<std::string, std::string>>
1475+
purpose_to_label = {
14741476
{QueryPurpose::Listen, {}},
14751477
{QueryPurpose::LimboResolution,
14761478
{{"goog-listen-tags", "limbo-document"}}},
14771479
{QueryPurpose::ExistenceFilterMismatch,
14781480
{{"goog-listen-tags", "existence-filter-mismatch"}}},
14791481
};
14801482

1481-
for (const auto& p : purposeToLabel) {
1482-
QueryData model(q, 1, 0, p.first, SnapshotVersion::None(), Bytes(1, 2, 3));
1483+
for (const auto& p : purpose_to_label) {
1484+
QueryData model(q, 1, 0, p.first);
14831485

14841486
auto result = serializer.EncodeListenRequestLabels(model);
14851487
EXPECT_EQ(result, p.second);

0 commit comments

Comments
 (0)