Skip to content

Commit e551423

Browse files
authored
Firestore: test document update w/ integer ids (#5895)
Attempt to reproduce issue #5489: the new system tests both pass.
1 parent a78af51 commit e551423

3 files changed

Lines changed: 111 additions & 42 deletions

File tree

firestore/google/cloud/firestore_v1beta1/_helpers.py

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -833,15 +833,18 @@ def process_server_timestamp(document_data, split_on_dots=True):
833833
(for updates only).
834834
835835
Returns:
836-
Tuple[List[str, ...], Dict[str, Any]]: A two-tuple of
836+
List[List[str, ...], Dict[str, Any]], List[List[str, ...]: A
837+
three-tuple of:
837838
838839
* A list of all transform paths that use the server timestamp sentinel
839840
* The remaining keys in ``document_data`` after removing the
840841
server timestamp sentinels
842+
* A list of all field paths that do not use the server timestamp
843+
sentinel
841844
"""
842-
field_paths = []
843845
transform_paths = []
844846
actual_data = {}
847+
field_paths = []
845848
for field_name, value in six.iteritems(document_data):
846849
if split_on_dots:
847850
top_level_path = FieldPath(*field_name.split("."))
@@ -872,6 +875,26 @@ def process_server_timestamp(document_data, split_on_dots=True):
872875
return transform_paths, actual_data, field_paths
873876

874877

878+
def canonicalize_field_paths(field_paths):
879+
"""Converts non-simple field paths to quoted field paths
880+
881+
Args:
882+
field_paths (Sequence[str]): A list of field paths
883+
884+
Returns:
885+
Sequence[str]:
886+
The same list of field paths except non-simple field names
887+
in the `.` delimited field path have been converted
888+
into quoted unicode field paths. Simple field paths match
889+
the regex ^[_a-zA-Z][_a-zA-Z0-9]*$. See `Document`_ page for
890+
more information.
891+
892+
.. _Document: https://cloud.google.com/firestore/docs/reference/rpc/google.firestore.v1beta1#google.firestore.v1beta1.Document # NOQA
893+
"""
894+
field_paths = [path.to_api_repr() for path in field_paths]
895+
return sorted(field_paths) # for testing purposes
896+
897+
875898
def get_transform_pb(document_path, transform_paths):
876899
"""Get a ``Write`` protobuf for performing a document transform.
877900
@@ -946,26 +969,6 @@ def pbs_for_set(document_path, document_data, merge=False, exists=None):
946969
return write_pbs
947970

948971

949-
def canonicalize_field_paths(field_paths):
950-
"""Converts non-simple field paths to quoted field paths
951-
952-
Args:
953-
field_paths (Sequence[str]): A list of field paths
954-
955-
Returns:
956-
Sequence[str]:
957-
The same list of field paths except non-simple field names
958-
in the `.` delimited field path have been converted
959-
into quoted unicode field paths. Simple field paths match
960-
the regex ^[_a-zA-Z][_a-zA-Z0-9]*$. See `Document`_ page for
961-
more information.
962-
963-
.. _Document: https://cloud.google.com/firestore/docs/reference/rpc/google.firestore.v1beta1#google.firestore.v1beta1.Document # NOQA
964-
"""
965-
field_paths = [path.to_api_repr() for path in field_paths]
966-
return sorted(field_paths) # for testing purposes
967-
968-
969972
def pbs_for_update(client, document_path, field_updates, option):
970973
"""Make ``Write`` protobufs for ``update()`` methods.
971974

firestore/tests/system.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,55 @@ def test_document_set_merge(client, cleanup):
248248
assert snapshot2.update_time == write_result2.update_time
249249

250250

251+
def test_document_set_w_int_field(client, cleanup):
252+
document_id = 'set-int-key' + unique_resource_id('-')
253+
document = client.document('i-did-it', document_id)
254+
# Add to clean-up before API request (in case ``set()`` fails).
255+
cleanup(document)
256+
257+
# 0. Make sure the document doesn't exist yet
258+
snapshot = document.get()
259+
assert not snapshot.exists
260+
261+
# 1. Use ``create()`` to create the document.
262+
before = {'testing': '1'}
263+
document.create(before)
264+
265+
# 2. Replace using ``set()``.
266+
data = {'14': {'status': 'active'}}
267+
document.set(data)
268+
269+
# 3. Verify replaced data.
270+
snapshot1 = document.get()
271+
assert snapshot1.to_dict() == data
272+
273+
274+
def test_document_update_w_int_field(client, cleanup):
275+
# Attempt to reproduce #5489.
276+
document_id = 'update-int-key' + unique_resource_id('-')
277+
document = client.document('i-did-it', document_id)
278+
# Add to clean-up before API request (in case ``set()`` fails).
279+
cleanup(document)
280+
281+
# 0. Make sure the document doesn't exist yet
282+
snapshot = document.get()
283+
assert not snapshot.exists
284+
285+
# 1. Use ``create()`` to create the document.
286+
before = {'testing': '1'}
287+
document.create(before)
288+
289+
# 2. Add values using ``update()``.
290+
data = {'14': {'status': 'active'}}
291+
document.update(data)
292+
293+
# 3. Verify updated data.
294+
expected = before.copy()
295+
expected.update(data)
296+
snapshot1 = document.get()
297+
assert snapshot1.to_dict() == expected
298+
299+
251300
def test_update_document(client, cleanup):
252301
document_id = 'for-update' + unique_resource_id('-')
253302
document = client.document('made', document_id)

firestore/tests/unit/test__helpers.py

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ def test_invalid_chars_in_constructor(self):
122122

123123
def test_component(self):
124124
field_path = self._make_one('a..b')
125-
self.assertEquals(field_path.parts, ('a..b',))
125+
self.assertEqual(field_path.parts, ('a..b',))
126126

127127
def test_constructor_iterable(self):
128128
field_path = self._make_one('a', 'b', 'c')
@@ -140,7 +140,7 @@ def test_to_api_repr_a(self):
140140
def test_to_api_repr_backtick(self):
141141
parts = '`'
142142
field_path = self._make_one(parts)
143-
self.assertEqual(field_path.to_api_repr(), '`\``')
143+
self.assertEqual(field_path.to_api_repr(), r'`\``')
144144

145145
def test_to_api_repr_dot(self):
146146
parts = '.'
@@ -1378,6 +1378,41 @@ def test_field_updates(self):
13781378
self.assertEqual(actual_data, expected_data)
13791379

13801380

1381+
class Test_canonicalize_field_paths(unittest.TestCase):
1382+
1383+
@staticmethod
1384+
def _call_fut(field_paths):
1385+
from google.cloud.firestore_v1beta1 import _helpers
1386+
1387+
return _helpers.canonicalize_field_paths(field_paths)
1388+
1389+
def _test_helper(self, to_convert):
1390+
from google.cloud.firestore_v1beta1 import _helpers
1391+
1392+
paths = [
1393+
_helpers.FieldPath.from_string(path) for path in to_convert
1394+
]
1395+
found = self._call_fut(paths)
1396+
1397+
self.assertEqual(found, sorted(to_convert.values()))
1398+
1399+
def test_w_native_strings(self):
1400+
to_convert = {
1401+
'0abc.deq': '`0abc`.deq',
1402+
'abc.654': 'abc.`654`',
1403+
'321.0deq._321': '`321`.`0deq`._321',
1404+
}
1405+
self._test_helper(to_convert)
1406+
1407+
def test_w_unicode(self):
1408+
to_convert = {
1409+
u'0abc.deq': '`0abc`.deq',
1410+
u'abc.654': 'abc.`654`',
1411+
u'321.0deq._321': '`321`.`0deq`._321',
1412+
}
1413+
self._test_helper(to_convert)
1414+
1415+
13811416
class Test_get_transform_pb(unittest.TestCase):
13821417

13831418
@staticmethod
@@ -1498,24 +1533,6 @@ def test_update_and_transform(self):
14981533
self._helper(do_transform=True)
14991534

15001535

1501-
class Test_canonicalize_field_paths(unittest.TestCase):
1502-
1503-
def test_canonicalize_field_paths(self):
1504-
from google.cloud.firestore_v1beta1 import _helpers
1505-
1506-
field_paths = ['0abc.deq', 'abc.654', '321.0deq._321',
1507-
u'0abc.deq', u'abc.654', u'321.0deq._321']
1508-
field_paths = [
1509-
_helpers.FieldPath.from_string(path) for path in field_paths]
1510-
convert = _helpers.canonicalize_field_paths(field_paths)
1511-
self.assertListEqual(
1512-
convert,
1513-
sorted([
1514-
'`0abc`.deq', 'abc.`654`', '`321`.`0deq`._321',
1515-
'`0abc`.deq', 'abc.`654`', '`321`.`0deq`._321'])
1516-
)
1517-
1518-
15191536
class Test_pbs_for_update(unittest.TestCase):
15201537

15211538
@staticmethod

0 commit comments

Comments
 (0)