@@ -36,6 +36,13 @@ using nanopb::ByteString;
3636
3737using Type = FieldValue::Type;
3838
39+ FIRESTORE_ATTRIBUTE_NORETURN
40+ void ThrowInvalidData (const ParseContext& context, const std::string& message) {
41+ std::string full_message =
42+ " Invalid data. " + message + context.FieldDescription ();
43+ SimpleThrowInvalidArgument (full_message);
44+ }
45+
3946void ParseDelete (ParseContext&& context) {
4047 if (context.data_source () == UserDataSource::MergeSet) {
4148 // No transform to add for a delete, but we need to add it to our field mask
@@ -49,32 +56,16 @@ void ParseDelete(ParseContext&& context) {
4956 !context.path ()->empty (),
5057 " FieldValue.Delete() at the top level should have already been "
5158 " handled." );
52- // TODO(b/147444199): use string formatting.
53- // ThrowInvalidArgument(
54- // "FieldValue::Delete() can only appear at the top level of your "
55- // "update data%s",
56- // context.FieldDescription());
57- auto message =
58- std::string (
59- " FieldValue::Delete() can only appear at the top level of your "
60- " update data" ) +
61- context.FieldDescription ();
62- SimpleThrowInvalidArgument (message);
59+ ThrowInvalidData (context,
60+ " FieldValue::Delete() can only appear at the top level of "
61+ " your update data" );
6362 }
6463
6564 // We shouldn't encounter delete sentinels for queries or non-merge `Set`
6665 // calls.
67- // TODO(b/147444199): use string formatting.
68- // ThrowInvalidArgument(
69- // "FieldValue::Delete() can only be used with Update() and Set() with "
70- // "merge == true%s",
71- // context.FieldDescription());
72- auto message =
73- std::string (
74- " FieldValue::Delete() can only be used with Update() and Set() with "
75- " merge == true" ) +
76- context.FieldDescription ();
77- SimpleThrowInvalidArgument (message);
66+ ThrowInvalidData (context,
67+ " FieldValue::Delete() can only be used with Update() and "
68+ " Set() with merge == true" );
7869}
7970
8071void ParseServerTimestamp (ParseContext&& context) {
@@ -143,7 +134,7 @@ FieldMask CreateFieldMask(const ParseAccumulator& accumulator,
143134 // path.CanonicalString());
144135 auto message =
145136 std::string (" Field '" ) + path.CanonicalString () +
146- " ' is specified in your field mask but missing from your input data." ;
137+ " ' is specified in your field mask but not in your input data." ;
147138 SimpleThrowInvalidArgument (message);
148139 }
149140
@@ -276,7 +267,7 @@ model::FieldValue::Array UserDataConverter::ParseArray(
276267 // disable this validation.
277268 if (context.array_element () &&
278269 context.data_source () != core::UserDataSource::ArrayArgument) {
279- SimpleThrowInvalidArgument ( " Nested arrays are not supported" );
270+ ThrowInvalidData (context, " Nested arrays are not supported" );
280271 }
281272
282273 model::FieldValue::Array result;
@@ -323,21 +314,21 @@ void UserDataConverter::ParseSentinel(const FieldValue& value,
323314 // Sentinels are only supported with writes, and not within arrays.
324315 if (!context.write ()) {
325316 // TODO(b/147444199): use string formatting.
326- // ThrowInvalidArgument("%s can only be used with Update() and Set()%s",
327- // Describe(value.type()), context.FieldDescription());
328- auto message = Describe (value.type ()) +
329- " can only be used with Update() and Set() " +
330- context. FieldDescription () ;
331- SimpleThrowInvalidArgument ( message);
317+ // ThrowInvalidData(
318+ // context, "%s can only be used with Update() and Set()%s",
319+ // Describe(value.type()), context.FieldDescription());
320+ auto message =
321+ Describe (value. type ()) + " can only be used with Update() and Set() " ;
322+ ThrowInvalidData (context, message);
332323 }
333324
334325 if (!context.path ()) {
335326 // TODO(b/147444199): use string formatting.
336- // ThrowInvalidArgument( "%s is not currently supported inside arrays",
337- // Describe(value.type()));
327+ // ThrowInvalidData(context, "%s is not currently supported inside arrays",
328+ // Describe(value.type()));
338329 auto message =
339330 Describe (value.type ()) + " is not currently supported inside arrays" ;
340- SimpleThrowInvalidArgument ( message);
331+ ThrowInvalidData (context, message);
341332 }
342333
343334 switch (value.type ()) {
@@ -406,7 +397,8 @@ model::FieldValue UserDataConverter::ParseScalar(const FieldValue& value,
406397 GetInternal (reference.firestore ())->database_id ();
407398 if (other != *database_id_) {
408399 // TODO(b/147444199): use string formatting.
409- // ThrowInvalidArgument(
400+ // ThrowInvalidData(
401+ // context,
410402 // "DocumentReference is for database %s/%s but should be for "
411403 // "database %s/%s%s",
412404 // other.project_id(), other.database_id(),
@@ -415,10 +407,9 @@ model::FieldValue UserDataConverter::ParseScalar(const FieldValue& value,
415407 auto actual_db = other.project_id () + " /" + other.database_id ();
416408 auto expected_db =
417409 database_id_->project_id () + " /" + database_id_->database_id ();
418- auto message = std::string (" DocumentReference is for database " ) +
419- actual_db + " but should be for database " +
420- expected_db + context.FieldDescription ();
421- SimpleThrowInvalidArgument (message);
410+ auto message = std::string (" Document reference is for database " ) +
411+ actual_db + " but should be for database " + expected_db;
412+ ThrowInvalidData (context, message);
422413 }
423414
424415 const model::DocumentKey& key = GetInternal (&reference)->key ();
0 commit comments