bundle_serializer.cc 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695
  1. /*
  2. * Copyright 2021 Google LLC
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include "Firestore/core/src/bundle/bundle_serializer.h"
  17. #include <memory>
  18. #include <vector>
  19. #include "Firestore/core/src/core/bound.h"
  20. #include "Firestore/core/src/core/direction.h"
  21. #include "Firestore/core/src/core/field_filter.h"
  22. #include "Firestore/core/src/core/filter.h"
  23. #include "Firestore/core/src/core/order_by.h"
  24. #include "Firestore/core/src/core/query.h"
  25. #include "Firestore/core/src/core/target.h"
  26. #include "Firestore/core/src/model/field_path.h"
  27. #include "Firestore/core/src/model/mutable_document.h"
  28. #include "Firestore/core/src/model/resource_path.h"
  29. #include "Firestore/core/src/model/value_util.h"
  30. #include "Firestore/core/src/nanopb/byte_string.h"
  31. #include "Firestore/core/src/nanopb/message.h"
  32. #include "Firestore/core/src/nanopb/nanopb_util.h"
  33. #include "Firestore/core/src/timestamp_internal.h"
  34. #include "Firestore/core/src/util/no_destructor.h"
  35. #include "Firestore/core/src/util/statusor.h"
  36. #include "Firestore/core/src/util/string_format.h"
  37. #include "Firestore/core/src/util/string_util.h"
  38. #include "absl/strings/escaping.h"
  39. #include "absl/strings/numbers.h"
  40. #include "absl/time/time.h"
  41. namespace firebase {
  42. namespace firestore {
  43. namespace bundle {
  44. using absl::Time;
  45. using core::Bound;
  46. using core::Direction;
  47. using core::FieldFilter;
  48. using core::Filter;
  49. using core::LimitType;
  50. using core::OrderBy;
  51. using core::Query;
  52. using core::Target;
  53. using model::DeepClone;
  54. using model::Document;
  55. using model::DocumentKey;
  56. using model::FieldPath;
  57. using model::MutableDocument;
  58. using model::NaNValue;
  59. using model::NullValue;
  60. using model::ObjectValue;
  61. using model::ResourcePath;
  62. using model::SnapshotVersion;
  63. using nanopb::ByteString;
  64. using nanopb::MakeSharedMessage;
  65. using nanopb::Message;
  66. using nanopb::SetRepeatedField;
  67. using nanopb::SharedMessage;
  68. using nlohmann::json;
  69. using util::JsonReader;
  70. using util::NoDestructor;
  71. using util::StatusOr;
  72. using util::StringFormat;
  73. using Operator = FieldFilter::Operator;
  74. namespace {
  75. const NoDestructor<Bound> kDefaultBound{Bound::FromValue(
  76. MakeSharedMessage<google_firestore_v1_ArrayValue>({}), false)};
  77. Timestamp DecodeTimestamp(JsonReader& reader, const json& version) {
  78. StatusOr<Timestamp> decoded;
  79. if (version.is_string()) {
  80. Time time;
  81. std::string err;
  82. bool ok = absl::ParseTime(
  83. absl::RFC3339_full, version.get_ref<const std::string&>(), &time, &err);
  84. if (ok) {
  85. decoded = TimestampInternal::FromUntrustedTime(time);
  86. } else {
  87. reader.Fail("Parsing timestamp failed with error: " + err);
  88. return {};
  89. }
  90. } else {
  91. decoded = TimestampInternal::FromUntrustedSecondsAndNanos(
  92. reader.OptionalInt<int64_t>("seconds", version, 0),
  93. reader.OptionalInt<int32_t>("nanos", version, 0));
  94. }
  95. if (!decoded.ok()) {
  96. reader.Fail(
  97. "Failed to decode json into valid protobuf Timestamp with error '%s'",
  98. decoded.status().error_message());
  99. return {};
  100. }
  101. return decoded.ConsumeValueOrDie();
  102. }
  103. SnapshotVersion DecodeSnapshotVersion(JsonReader& reader, const json& version) {
  104. return SnapshotVersion(DecodeTimestamp(reader, version));
  105. }
  106. void VerifyStructuredQuery(JsonReader& reader, const json& query) {
  107. if (!query.is_object()) {
  108. reader.Fail("'structuredQuery' is not an object as expected.");
  109. return;
  110. }
  111. if (query.contains("select")) {
  112. reader.Fail(
  113. "Queries with 'select' statements are not supported in bundles");
  114. return;
  115. }
  116. if (!query.contains("from")) {
  117. reader.Fail("Query does not have a 'from' collection");
  118. return;
  119. }
  120. if (query.contains("offset")) {
  121. reader.Fail("Queries with 'offset' are not supported in bundles");
  122. return;
  123. }
  124. }
  125. /**
  126. * Decodes a json object into the given `parent` and `group` reference.
  127. *
  128. * Specifically, if the given `from_json` is for a collection group query, its
  129. * collection id will be decoded into `group`; otherwise, the collection id will
  130. * be appended to `parent`.
  131. */
  132. void DecodeCollectionSource(JsonReader& reader,
  133. const json& from_json,
  134. ResourcePath& parent,
  135. std::string& group) {
  136. const auto& from = from_json.get_ref<const std::vector<json>&>();
  137. if (from.size() != 1) {
  138. reader.Fail(
  139. "Only queries with a single 'from' clause are supported by the SDK");
  140. return;
  141. }
  142. const auto& collection_selector = from.at(0);
  143. const auto& collection_id =
  144. reader.RequiredString("collectionId", collection_selector);
  145. bool all_descendants =
  146. reader.OptionalBool("allDescendants", collection_selector);
  147. if (all_descendants) {
  148. group = collection_id;
  149. } else {
  150. parent = parent.Append(collection_id);
  151. }
  152. }
  153. FieldPath DecodeFieldReference(JsonReader& reader, const json& field) {
  154. if (!field.is_object()) {
  155. reader.Fail("'field' should be an json object, but it is not");
  156. return {};
  157. }
  158. const auto& field_path = reader.RequiredString("fieldPath", field);
  159. auto result = FieldPath::FromServerFormat(field_path);
  160. if (!result.ok()) {
  161. reader.set_status(result.status());
  162. return {};
  163. } else {
  164. return result.ConsumeValueOrDie();
  165. }
  166. }
  167. Operator DecodeFieldFilterOperator(JsonReader& reader, const std::string& op) {
  168. if (op == "LESS_THAN") {
  169. return Operator::LessThan;
  170. } else if (op == "LESS_THAN_OR_EQUAL") {
  171. return Operator::LessThanOrEqual;
  172. } else if (op == "EQUAL") {
  173. return Operator::Equal;
  174. } else if (op == "NOT_EQUAL") {
  175. return Operator::NotEqual;
  176. } else if (op == "GREATER_THAN") {
  177. return Operator::GreaterThan;
  178. } else if (op == "GREATER_THAN_OR_EQUAL") {
  179. return Operator::GreaterThanOrEqual;
  180. } else if (op == "ARRAY_CONTAINS") {
  181. return Operator::ArrayContains;
  182. } else if (op == "IN") {
  183. return Operator::In;
  184. } else if (op == "ARRAY_CONTAINS_ANY") {
  185. return Operator::ArrayContainsAny;
  186. } else if (op == "NOT_IN") {
  187. return Operator::NotIn;
  188. } else {
  189. reader.Fail("Operator in filter is not valid: " + op);
  190. // We have to return something.
  191. return Operator::Equal;
  192. }
  193. }
  194. Filter InvalidFilter() {
  195. // The exact value doesn't matter. Note that there's no way to create the base
  196. // class `Filter`, so it has to be one of the derived classes.
  197. return FieldFilter::Create({}, {},
  198. MakeSharedMessage(google_firestore_v1_Value{}));
  199. }
  200. Filter DecodeUnaryFilter(JsonReader& reader, const json& filter) {
  201. FieldPath path =
  202. DecodeFieldReference(reader, reader.RequiredObject("field", filter));
  203. std::string op = reader.RequiredString("op", filter);
  204. // Return early if !ok(), because `FieldFilter::Create` will abort with
  205. // invalid inputs.
  206. if (!reader.ok()) {
  207. return InvalidFilter();
  208. }
  209. if (op == "IS_NAN") {
  210. return FieldFilter::Create(path, Operator::Equal, DeepClone(NaNValue()));
  211. } else if (op == "IS_NULL") {
  212. return FieldFilter::Create(path, Operator::Equal, DeepClone(NullValue()));
  213. } else if (op == "IS_NOT_NAN") {
  214. return FieldFilter::Create(path, Operator::NotEqual, DeepClone(NaNValue()));
  215. } else if (op == "IS_NOT_NULL") {
  216. return FieldFilter::Create(path, Operator::NotEqual,
  217. DeepClone(NullValue()));
  218. }
  219. reader.Fail("Unexpected unary filter operator: " + op);
  220. return InvalidFilter();
  221. }
  222. std::vector<OrderBy> DecodeOrderBy(JsonReader& reader, const json& query) {
  223. std::vector<OrderBy> result;
  224. std::vector<json> default_order_by;
  225. for (const auto& order_by :
  226. reader.OptionalArray("orderBy", query, default_order_by)) {
  227. FieldPath path =
  228. DecodeFieldReference(reader, reader.RequiredObject("field", order_by));
  229. std::string direction_string =
  230. reader.OptionalString("direction", order_by, "ASCENDING");
  231. if (direction_string != "DESCENDING" && direction_string != "ASCENDING") {
  232. reader.Fail("'direction' value is invalid: " + direction_string);
  233. return {};
  234. }
  235. Direction direction = direction_string == "ASCENDING"
  236. ? Direction::Ascending
  237. : Direction::Descending;
  238. result.emplace_back(std::move(path), direction);
  239. }
  240. return result;
  241. }
  242. int32_t DecodeLimit(JsonReader& reader, const json& query) {
  243. int32_t limit = Target::kNoLimit;
  244. if (query.contains("limit")) {
  245. const auto& limit_object = query.at("limit");
  246. // "limit" can be encoded as integer or "{"value": integer}".
  247. if (limit_object.is_number_integer()) {
  248. return limit_object.get<int32_t>();
  249. } else if (limit_object.is_object()) {
  250. if (limit_object.at("value").is_number_integer()) {
  251. return limit_object.at("value").get<int32_t>();
  252. }
  253. }
  254. reader.Fail("'limit' is not encoded as a valid integer");
  255. return limit;
  256. }
  257. return limit;
  258. }
  259. LimitType DecodeLimitType(JsonReader& reader, const json& query) {
  260. std::string limit_type = reader.OptionalString("limitType", query, "FIRST");
  261. if (limit_type == "FIRST") {
  262. return LimitType::First;
  263. } else if (limit_type == "LAST") {
  264. return LimitType::Last;
  265. } else {
  266. reader.Fail("'limitType' is not encoded as a recognizable value");
  267. return LimitType::None;
  268. }
  269. }
  270. google_type_LatLng DecodeGeoPointValue(JsonReader& reader,
  271. const json& geo_json) {
  272. google_type_LatLng result{};
  273. result.latitude = reader.OptionalDouble("latitude", geo_json, 0.0);
  274. result.longitude = reader.OptionalDouble("longitude", geo_json, 0.0);
  275. return result;
  276. }
  277. pb_bytes_array_t* DecodeBytesValue(JsonReader& reader,
  278. const std::string& bytes_string) {
  279. std::string decoded;
  280. if (!absl::Base64Unescape(bytes_string, &decoded)) {
  281. reader.Fail("Failed to decode bytesValue string into binary form");
  282. return {};
  283. }
  284. return nanopb::MakeBytesArray(decoded);
  285. }
  286. } // namespace
  287. BundleMetadata BundleSerializer::DecodeBundleMetadata(
  288. JsonReader& reader, const json& metadata) const {
  289. return BundleMetadata(
  290. reader.RequiredString("id", metadata),
  291. reader.RequiredInt<uint32_t>("version", metadata),
  292. DecodeSnapshotVersion(reader,
  293. reader.RequiredObject("createTime", metadata)),
  294. reader.OptionalInt<uint32_t>("totalDocuments", metadata, 0),
  295. reader.OptionalInt<uint64_t>("totalBytes", metadata, 0));
  296. }
  297. NamedQuery BundleSerializer::DecodeNamedQuery(JsonReader& reader,
  298. const json& named_query) const {
  299. return NamedQuery(
  300. reader.RequiredString("name", named_query),
  301. DecodeBundledQuery(reader,
  302. reader.RequiredObject("bundledQuery", named_query)),
  303. DecodeSnapshotVersion(reader,
  304. reader.RequiredObject("readTime", named_query)));
  305. }
  306. BundledQuery BundleSerializer::DecodeBundledQuery(
  307. JsonReader& reader, const nlohmann::json& query) const {
  308. const json& structured_query =
  309. reader.RequiredObject("structuredQuery", query);
  310. VerifyStructuredQuery(reader, structured_query);
  311. if (!reader.ok()) {
  312. return {};
  313. }
  314. ResourcePath parent =
  315. DecodeName(reader, reader.RequiredObject("parent", query));
  316. std::string collection_group_string;
  317. DecodeCollectionSource(reader, structured_query.at("from"), parent,
  318. collection_group_string);
  319. std::shared_ptr<std::string> collection_group;
  320. if (!collection_group_string.empty()) {
  321. collection_group = std::make_shared<std::string>(collection_group_string);
  322. }
  323. auto filters = DecodeWhere(reader, structured_query);
  324. auto order_bys = DecodeOrderBy(reader, structured_query);
  325. auto start_at_bound = DecodeStartAtBound(reader, structured_query);
  326. absl::optional<Bound> start_at;
  327. if (start_at_bound.position()->values_count > 0) {
  328. start_at = std::move(start_at_bound);
  329. }
  330. auto end_at_bound = DecodeEndAtBound(reader, structured_query);
  331. absl::optional<Bound> end_at;
  332. if (end_at_bound.position()->values_count > 0) {
  333. end_at = std::move(end_at_bound);
  334. }
  335. int32_t limit = DecodeLimit(reader, structured_query);
  336. LimitType limit_type = DecodeLimitType(reader, query);
  337. if (!reader.ok()) {
  338. return {};
  339. }
  340. return BundledQuery(
  341. Query(std::move(parent), std::move(collection_group), std::move(filters),
  342. std::move(order_bys), limit,
  343. // Not using `limit_type` because bundled queries are what the
  344. // backend sees, and there is no limit_to_last for the backend.
  345. // Limit type is applied when the query is read back instead.
  346. LimitType::None, std::move(start_at), std::move(end_at))
  347. .ToTarget(),
  348. limit_type);
  349. }
  350. ResourcePath BundleSerializer::DecodeName(JsonReader& reader,
  351. const json& document_name) const {
  352. if (!document_name.is_string()) {
  353. reader.Fail("Document name is not a string.");
  354. return {};
  355. }
  356. auto path =
  357. ResourcePath::FromString(document_name.get_ref<const std::string&>());
  358. if (!rpc_serializer_.IsLocalResourceName(path)) {
  359. reader.Fail("Resource name is not valid for current instance: " +
  360. path.CanonicalString());
  361. return {};
  362. }
  363. return path.PopFirst(5);
  364. }
  365. std::vector<Filter> BundleSerializer::DecodeWhere(JsonReader& reader,
  366. const json& query) const {
  367. // Absent 'where' is a valid case.
  368. if (!query.contains("where")) {
  369. return {};
  370. }
  371. const auto& where = query.at("where");
  372. if (!where.is_object()) {
  373. reader.Fail("Query's 'where' clause is not a json object.");
  374. return {};
  375. }
  376. if (where.contains("compositeFilter")) {
  377. return DecodeCompositeFilter(reader, where.at("compositeFilter"));
  378. } else if (where.contains("fieldFilter")) {
  379. return {DecodeFieldFilter(reader, where.at("fieldFilter"))};
  380. } else if (where.contains("unaryFilter")) {
  381. return {DecodeUnaryFilter(reader, where.at("unaryFilter"))};
  382. } else {
  383. reader.Fail("'where' does not have valid filter");
  384. return {};
  385. }
  386. }
  387. Filter BundleSerializer::DecodeFieldFilter(JsonReader& reader,
  388. const json& filter) const {
  389. FieldPath path =
  390. DecodeFieldReference(reader, reader.RequiredObject("field", filter));
  391. const auto& op_string = reader.RequiredString("op", filter);
  392. auto op = DecodeFieldFilterOperator(reader, op_string);
  393. Message<google_firestore_v1_Value> value =
  394. DecodeValue(reader, reader.RequiredObject("value", filter));
  395. // Return early if !ok(), because `FieldFilter::Create` will abort with
  396. // invalid inputs.
  397. if (!reader.ok()) {
  398. return InvalidFilter();
  399. }
  400. return FieldFilter::Create(path, op, std::move(value));
  401. }
  402. std::vector<Filter> BundleSerializer::DecodeCompositeFilter(
  403. JsonReader& reader, const json& filter) const {
  404. if (reader.RequiredString("op", filter) != "AND") {
  405. reader.Fail("The SDK only supports composite filters of type 'AND'");
  406. return {};
  407. }
  408. const std::vector<json> default_filters;
  409. const auto& filters =
  410. reader.OptionalArray("filters", filter, default_filters);
  411. const json default_objects;
  412. std::vector<Filter> result;
  413. for (const auto& f : filters) {
  414. const json& field_filter =
  415. reader.OptionalObject("fieldFilter", f, default_objects);
  416. if (!field_filter.empty()) {
  417. result.push_back(DecodeFieldFilter(reader, field_filter));
  418. } else {
  419. result.push_back(DecodeUnaryFilter(
  420. reader, reader.OptionalObject("unaryFilter", f, default_objects)));
  421. }
  422. if (!reader.ok()) {
  423. return {};
  424. }
  425. }
  426. return result;
  427. }
  428. Bound BundleSerializer::DecodeStartAtBound(JsonReader& reader,
  429. const json& query) const {
  430. if (!query.contains("startAt")) {
  431. return *kDefaultBound;
  432. }
  433. auto result =
  434. DecodeBoundFields(reader, reader.RequiredObject("startAt", query));
  435. return Bound::FromValue(std::move(result.second), result.first);
  436. }
  437. Bound BundleSerializer::DecodeEndAtBound(JsonReader& reader,
  438. const json& query) const {
  439. if (!query.contains("endAt")) {
  440. return *kDefaultBound;
  441. }
  442. auto result =
  443. DecodeBoundFields(reader, reader.RequiredObject("endAt", query));
  444. return Bound::FromValue(std::move(result.second), !result.first);
  445. }
  446. std::pair<bool, nanopb::SharedMessage<google_firestore_v1_ArrayValue>>
  447. BundleSerializer::DecodeBoundFields(JsonReader& reader,
  448. const nlohmann::json& bound_json) const {
  449. bool before = reader.OptionalBool("before", bound_json);
  450. std::vector<json> default_values;
  451. std::vector<json> values =
  452. reader.OptionalArray("values", bound_json, default_values);
  453. auto positions = MakeSharedMessage<google_firestore_v1_ArrayValue>({});
  454. SetRepeatedField(
  455. &positions->values, &positions->values_count, values,
  456. [&](const json& j) { return *DecodeValue(reader, j).release(); });
  457. return {before, std::move(positions)};
  458. }
  459. Message<google_firestore_v1_Value> BundleSerializer::DecodeValue(
  460. JsonReader& reader, const json& value) const {
  461. if (!value.is_object()) {
  462. reader.Fail("'value' is not encoded as JSON object");
  463. return {};
  464. }
  465. Message<google_firestore_v1_Value> result;
  466. if (value.contains("nullValue")) {
  467. result->which_value_type = google_firestore_v1_Value_null_value_tag;
  468. result->null_value = {};
  469. } else if (value.contains("booleanValue")) {
  470. result->which_value_type = google_firestore_v1_Value_boolean_value_tag;
  471. auto val = value.at("booleanValue");
  472. if (!val.is_boolean()) {
  473. reader.Fail("'booleanValue' is not encoded as a valid boolean");
  474. return {};
  475. }
  476. result->boolean_value = val.get<bool>();
  477. } else if (value.contains("integerValue")) {
  478. result->which_value_type = google_firestore_v1_Value_integer_value_tag;
  479. result->integer_value = reader.RequiredInt<int64_t>("integerValue", value);
  480. } else if (value.contains("doubleValue")) {
  481. result->which_value_type = google_firestore_v1_Value_double_value_tag;
  482. result->double_value = reader.RequiredDouble("doubleValue", value);
  483. } else if (value.contains("timestampValue")) {
  484. auto val = DecodeTimestamp(reader, value.at("timestampValue"));
  485. result->which_value_type = google_firestore_v1_Value_timestamp_value_tag;
  486. result->timestamp_value.seconds = val.seconds();
  487. result->timestamp_value.nanos = val.nanoseconds();
  488. } else if (value.contains("stringValue")) {
  489. result->which_value_type = google_firestore_v1_Value_string_value_tag;
  490. result->string_value =
  491. nanopb::MakeBytesArray(reader.RequiredString("stringValue", value));
  492. } else if (value.contains("bytesValue")) {
  493. result->which_value_type = google_firestore_v1_Value_bytes_value_tag;
  494. result->bytes_value =
  495. DecodeBytesValue(reader, reader.RequiredString("bytesValue", value));
  496. } else if (value.contains("referenceValue")) {
  497. result->which_value_type = google_firestore_v1_Value_reference_value_tag;
  498. result->reference_value = DecodeReferenceValue(
  499. reader, reader.RequiredString("referenceValue", value));
  500. } else if (value.contains("geoPointValue")) {
  501. result->which_value_type = google_firestore_v1_Value_geo_point_value_tag;
  502. result->geo_point_value =
  503. DecodeGeoPointValue(reader, value.at("geoPointValue"));
  504. } else if (value.contains("arrayValue")) {
  505. result->which_value_type = google_firestore_v1_Value_array_value_tag;
  506. result->array_value =
  507. *DecodeArrayValue(reader, value.at("arrayValue")).release();
  508. } else if (value.contains("mapValue")) {
  509. result->which_value_type = google_firestore_v1_Value_map_value_tag;
  510. result->map_value = *DecodeMapValue(reader, value.at("mapValue")).release();
  511. } else {
  512. reader.Fail("Failed to decode value, no type is recognized");
  513. return {};
  514. }
  515. return result;
  516. }
  517. Message<google_firestore_v1_MapValue> BundleSerializer::DecodeMapValue(
  518. JsonReader& reader, const json& map_json) const {
  519. if (!map_json.is_object()) {
  520. reader.Fail("mapValue is not a valid object");
  521. return {};
  522. }
  523. // Empty map doesn't have `fields` field.
  524. if (!map_json.contains("fields")) {
  525. return {};
  526. }
  527. const auto& fields = map_json.at("fields");
  528. if (!fields.is_object()) {
  529. reader.Fail("mapValue's 'field' is not a valid map");
  530. return {};
  531. }
  532. // Fill the map array. Note that we can't use SetRepeatedField here since the
  533. // JSON map doesn't currently work with SetRepeatedField.
  534. Message<google_firestore_v1_MapValue> map_value;
  535. map_value->fields_count = nanopb::CheckedSize(fields.size());
  536. map_value->fields =
  537. nanopb::MakeArray<google_firestore_v1_MapValue_FieldsEntry>(
  538. map_value->fields_count);
  539. pb_size_t i = 0;
  540. for (const auto& entry : fields.items()) {
  541. map_value->fields[i] = {nanopb::MakeBytesArray(entry.key()),
  542. *DecodeValue(reader, entry.value()).release()};
  543. ++i;
  544. }
  545. return map_value;
  546. }
  547. Message<google_firestore_v1_ArrayValue> BundleSerializer::DecodeArrayValue(
  548. JsonReader& reader, const json& array_json) const {
  549. std::vector<json> default_values;
  550. const auto& values =
  551. reader.OptionalArray("values", array_json, default_values);
  552. Message<google_firestore_v1_ArrayValue> array_value;
  553. SetRepeatedField(
  554. &array_value->values, &array_value->values_count, values,
  555. [&](const json& j) { return *DecodeValue(reader, j).release(); });
  556. return array_value;
  557. }
  558. pb_bytes_array_t* BundleSerializer::DecodeReferenceValue(
  559. JsonReader& reader, const std::string& ref_string) const {
  560. if (reader.ok() && !rpc_serializer_.IsLocalDocumentKey(ref_string)) {
  561. reader.Fail(
  562. StringFormat("Tried to deserialize an invalid key: %s", ref_string));
  563. }
  564. return nanopb::MakeBytesArray(ref_string);
  565. }
  566. BundledDocumentMetadata BundleSerializer::DecodeDocumentMetadata(
  567. JsonReader& reader, const json& document_metadata) const {
  568. ResourcePath path =
  569. DecodeName(reader, reader.RequiredObject("name", document_metadata));
  570. // Return early if !ok(), `DocumentKey` aborts with invalid inputs.
  571. if (!reader.ok()) {
  572. return {};
  573. }
  574. DocumentKey key = DocumentKey(path);
  575. SnapshotVersion read_time = DecodeSnapshotVersion(
  576. reader, reader.RequiredObject("readTime", document_metadata));
  577. bool exists = reader.OptionalBool("exists", document_metadata);
  578. std::vector<std::string> queries;
  579. std::vector<json> default_queries;
  580. for (const json& query :
  581. reader.OptionalArray("queries", document_metadata, default_queries)) {
  582. if (!query.is_string()) {
  583. reader.Fail("Query name should be encoded as string");
  584. return {};
  585. }
  586. queries.push_back(query.get<std::string>());
  587. }
  588. return BundledDocumentMetadata(std::move(key), read_time, exists,
  589. std::move(queries));
  590. }
  591. BundleDocument BundleSerializer::DecodeDocument(JsonReader& reader,
  592. const json& document) const {
  593. ResourcePath path =
  594. DecodeName(reader, reader.RequiredObject("name", document));
  595. // Return early if !ok(), `DocumentKey` aborts with invalid inputs.
  596. if (!reader.ok()) {
  597. return {};
  598. }
  599. DocumentKey key = DocumentKey(path);
  600. SnapshotVersion update_time = DecodeSnapshotVersion(
  601. reader, reader.RequiredObject("updateTime", document));
  602. auto map_value = DecodeMapValue(reader, document);
  603. return BundleDocument(MutableDocument::FoundDocument(
  604. std::move(key), update_time,
  605. ObjectValue::FromMapValue(std::move(map_value))));
  606. }
  607. } // namespace bundle
  608. } // namespace firestore
  609. } // namespace firebase