diff --git a/packages/google-cloud-firestore/google/cloud/firestore_v1/field_path.py b/packages/google-cloud-firestore/google/cloud/firestore_v1/field_path.py index 45931e9efdad..e14de997e1d0 100644 --- a/packages/google-cloud-firestore/google/cloud/firestore_v1/field_path.py +++ b/packages/google-cloud-firestore/google/cloud/firestore_v1/field_path.py @@ -36,7 +36,7 @@ _LEADING_ALPHA_INVALID = re.compile(r"^[_a-zA-Z][_a-zA-Z0-9]*[~*/\[\]]") PATH_ELEMENT_TOKENS = [ ("SIMPLE", r"[_a-zA-Z][_a-zA-Z0-9]*"), # unquoted elements - ("QUOTED", r"`(?:\\`|[^`])*?`"), # quoted elements, unquoted + ("QUOTED", r"`(?:\\.|[^`\\])*`"), # quoted elements, unquoted ("DOT", r"\."), # separator ] TOKENS_PATTERN = "|".join("(?P<{}>{})".format(*pair) for pair in PATH_ELEMENT_TOKENS) diff --git a/packages/google-cloud-firestore/tests/unit/v1/test_field_path.py b/packages/google-cloud-firestore/tests/unit/v1/test_field_path.py index 5efbadbd3a6e..13659dea10af 100644 --- a/packages/google-cloud-firestore/tests/unit/v1/test_field_path.py +++ b/packages/google-cloud-firestore/tests/unit/v1/test_field_path.py @@ -59,6 +59,10 @@ def test__tokenize_field_path_w_dotted_escaped(): _expect_tokenize_field_path("_0.`1`.`+2`", ["_0", ".", "`1`", ".", "`+2`"]) +def test__tokenize_field_path_w_quoted_trailing_escaped_backslash(): + _expect_tokenize_field_path(r"`a\\`.`b c`", [r"`a\\`", ".", "`b c`"]) + + def test__tokenize_field_path_w_unconsumed_characters(): from google.cloud.firestore_v1 import field_path @@ -150,6 +154,12 @@ def test_parse_field_path_w_escaped_backslash(): assert field_path.parse_field_path("`a\\\\b`.c.d") == ["a\\b", "c", "d"] +def test_parse_field_path_w_trailing_escaped_backslash(): + from google.cloud.firestore_v1 import field_path + + assert field_path.parse_field_path("`a\\\\`.`b c`") == ["a\\", "b c"] + + def test_parse_field_path_w_first_name_escaped_wo_closing_backtick(): from google.cloud.firestore_v1 import field_path @@ -451,6 +461,14 @@ def test_fieldpath_from_string_w_non_ascii_dotted(): assert field_path.parts == ("a", "δΈ€") +def test_fieldpath_from_string_w_trailing_escaped_backslash(): + from google.cloud.firestore_v1 import field_path + + path_string = field_path.FieldPath("a\\", "b c").to_api_repr() + field_path = field_path.FieldPath.from_string(path_string) + assert field_path.parts == ("a\\", "b c") + + def test_fieldpath___hash___w_single_part(): field_path = _make_field_path("a") assert hash(field_path) == hash("a")