From 6ed6c5cb3b372b4d73d1b19c04c2c49ef0447cd0 Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Thu, 29 Nov 2018 17:00:45 -0500 Subject: [PATCH] Prevent use of transforms as cursor values. Closes #6704. --- .../google/cloud/firestore_v1beta1/query.py | 8 ++++ firestore/tests/unit/test_query.py | 40 +++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/firestore/google/cloud/firestore_v1beta1/query.py b/firestore/google/cloud/firestore_v1beta1/query.py index fefd7647a079..29a0b7260ad5 100644 --- a/firestore/google/cloud/firestore_v1beta1/query.py +++ b/firestore/google/cloud/firestore_v1beta1/query.py @@ -27,6 +27,7 @@ from google.cloud.firestore_v1beta1 import _helpers from google.cloud.firestore_v1beta1 import document +from google.cloud.firestore_v1beta1 import transforms from google.cloud.firestore_v1beta1.gapic import enums from google.cloud.firestore_v1beta1.proto import query_pb2 from google.cloud.firestore_v1beta1.order import Order @@ -46,6 +47,7 @@ _BAD_OP_NAN_NULL = ( 'Only an equality filter ("==") can be used with None or NaN values') _BAD_DIR_STRING = 'Invalid direction {!r}. Must be one of {!r} or {!r}.' +_INVALID_CURSOR_TRANSFORM = 'Transforms cannot be used as cursor values.' _MISSING_ORDER_BY = ( 'The "order by" field path {!r} is not present in the cursor data {!r}. ' 'All fields sent to ``order_by()`` must be present in the fields ' @@ -563,6 +565,12 @@ def _normalize_cursor(cursor, orders): document_fields, order_keys) raise ValueError(msg) + _transform_bases = (transforms.Sentinel, transforms._ValueList) + for field in document_fields: + if isinstance(field, _transform_bases): + msg = _INVALID_CURSOR_TRANSFORM + raise ValueError(msg) + return document_fields, before def _to_protobuf(self): diff --git a/firestore/tests/unit/test_query.py b/firestore/tests/unit/test_query.py index 10ecef10e170..9e35e5af4afe 100644 --- a/firestore/tests/unit/test_query.py +++ b/firestore/tests/unit/test_query.py @@ -503,6 +503,46 @@ def test__normalize_cursor_as_dict_mismatched_order(self): with self.assertRaises(ValueError): query._normalize_cursor(cursor, query._orders) + def test__normalize_cursor_w_delete(self): + from google.cloud.firestore_v1beta1 import DELETE_FIELD + + cursor = ([DELETE_FIELD], True) + query = self._make_one( + mock.sentinel.parent).order_by('b', 'ASCENDING') + + with self.assertRaises(ValueError): + query._normalize_cursor(cursor, query._orders) + + def test__normalize_cursor_w_server_timestamp(self): + from google.cloud.firestore_v1beta1 import SERVER_TIMESTAMP + + cursor = ([SERVER_TIMESTAMP], True) + query = self._make_one( + mock.sentinel.parent).order_by('b', 'ASCENDING') + + with self.assertRaises(ValueError): + query._normalize_cursor(cursor, query._orders) + + def test__normalize_cursor_w_array_remove(self): + from google.cloud.firestore_v1beta1 import ArrayRemove + + cursor = ([ArrayRemove([1, 3, 5])], True) + query = self._make_one( + mock.sentinel.parent).order_by('b', 'ASCENDING') + + with self.assertRaises(ValueError): + query._normalize_cursor(cursor, query._orders) + + def test__normalize_cursor_w_array_union(self): + from google.cloud.firestore_v1beta1 import ArrayUnion + + cursor = ([ArrayUnion([2, 4, 8])], True) + query = self._make_one( + mock.sentinel.parent).order_by('b', 'ASCENDING') + + with self.assertRaises(ValueError): + query._normalize_cursor(cursor, query._orders) + def test__normalize_cursor_as_list_hit(self): cursor = ([1], True) query = self._make_one(