def test_success(self): from google.cloud.firestore_v1beta1.gapic import enums from google.cloud.firestore_v1beta1.proto import query_pb2 from google.cloud.firestore_v1beta1 import _helpers field_path1 = 'a' field_path2 = 'a.b' field_path3 = 'x' direction1 = enums.StructuredQuery.Direction.DESCENDING direction2 = enums.StructuredQuery.Direction.ASCENDING direction3 = enums.StructuredQuery.Direction.ASCENDING orders = ( _make_order_pb(field_path1, direction1), _make_order_pb(field_path2, direction2), _make_order_pb(field_path3, direction3), ) data = { 'a': { 'b': 10, 'c': 1.5, }, 'x': True, } cursor_pair = data, True cursor_pb = self._call_fut(cursor_pair, orders) expected_pb = query_pb2.Cursor( values=[ _helpers.encode_value(data['a']), _helpers.encode_value(data['a']['b']), _helpers.encode_value(data['x']), ], before=True, ) self.assertEqual(cursor_pb, expected_pb)
def _comparator(self, doc1, doc2): _orders = self._orders # Add implicit sorting by name, using the last specified direction. if len(_orders) == 0: lastDirection = Query.ASCENDING else: if _orders[-1].direction == 1: lastDirection = Query.ASCENDING else: lastDirection = Query.DESCENDING orderBys = list(_orders) order_pb = query_pb2.StructuredQuery.Order( field=query_pb2.StructuredQuery.FieldReference(field_path="id"), direction=_enum_from_direction(lastDirection), ) orderBys.append(order_pb) for orderBy in orderBys: if orderBy.field.field_path == "id": # If ordering by docuent id, compare resource paths. comp = Order()._compare_to(doc1.reference._path, doc2.reference._path) else: if ( orderBy.field.field_path not in doc1._data or orderBy.field.field_path not in doc2._data ): raise ValueError( "Can only compare fields that exist in the " "DocumentSnapshot. Please include the fields you are " "ordering on in your select() call." ) v1 = doc1._data[orderBy.field.field_path] v2 = doc2._data[orderBy.field.field_path] encoded_v1 = _helpers.encode_value(v1) encoded_v2 = _helpers.encode_value(v2) comp = Order().compare(encoded_v1, encoded_v2) if comp != 0: # 1 == Ascending, -1 == Descending return orderBy.direction * comp return 0
def _make_field_filter_pb(field_path, op_string, value): from google.cloud.firestore_v1beta1.proto import query_pb2 from google.cloud.firestore_v1beta1 import _helpers from google.cloud.firestore_v1beta1.query import _enum_from_op_string return query_pb2.StructuredQuery.FieldFilter( field=query_pb2.StructuredQuery.FieldReference(field_path=field_path), op=_enum_from_op_string(op_string), value=_helpers.encode_value(value), )
def _make_field_filter_pb(field_path, op_string, value): from google.cloud.firestore_v1beta1.proto import query_pb2 from google.cloud.firestore_v1beta1 import _helpers from google.cloud.firestore_v1beta1.query import _enum_from_op_string return query_pb2.StructuredQuery.FieldFilter( field=query_pb2.StructuredQuery.FieldReference( field_path=field_path), op=_enum_from_op_string(op_string), value=_helpers.encode_value(value), )
def _cursor_pb(cursor_pair, orders): """Convert a cursor pair to a protobuf. If ``cursor_pair`` is :data:`None`, just returns :data:`None`. Args: cursor_pair (Optional[Tuple[dict, bool]]): Two-tuple of * a mapping of fields. Any field that is present in this mapping must also be present in ``orders`` * a ``before`` flag orders (Tuple[google.cloud.proto.firestore.v1beta1.\ query_pb2.StructuredQuery.Order, ...]]): The "order by" entries to use for a query. (We use this rather than a list of field path strings just because it is how a query stores calls to ``order_by``.) Returns: Optional[google.cloud.firestore_v1beta1.types.Cursor]: A protobuf cursor corresponding to the values. Raises: ValueError: If ``cursor_pair`` is not :data:`None`, but there are no ``orders``. ValueError: If one of the field paths in ``orders`` is not contained in the ``data`` (i.e. the first component of ``cursor_pair``). """ if cursor_pair is None: return None if len(orders) == 0: raise ValueError(_NO_ORDERS_FOR_CURSOR) data, before = cursor_pair value_pbs = [] for order in orders: field_path = order.field.field_path try: value = _helpers.get_nested_value(field_path, data) except KeyError: msg = _MISSING_ORDER_BY.format(field_path, data) raise ValueError(msg) value_pb = _helpers.encode_value(value) value_pbs.append(value_pb) return query_pb2.Cursor(values=value_pbs, before=before)
def _cursor_pb(cursor_pair): """Convert a cursor pair to a protobuf. If ``cursor_pair`` is :data:`None`, just returns :data:`None`. Args: cursor_pair (Optional[Tuple[list, bool]]): Two-tuple of * a list of field values. * a ``before`` flag Returns: Optional[google.cloud.firestore_v1beta1.types.Cursor]: A protobuf cursor corresponding to the values. """ if cursor_pair is not None: data, before = cursor_pair value_pbs = [_helpers.encode_value(value) for value in data] return query_pb2.Cursor(values=value_pbs, before=before)
def _boolean_value(b): return encode_value(b)
def _object_value(keysAndValues): return encode_value(keysAndValues)
def _array_value(values=[]): return encode_value(values)
def _geoPoint_value(latitude, longitude): return encode_value(GeoPoint(latitude, longitude))
def nullValue(): return encode_value(None)
def _int_value(value): return encode_value(value)
def where(self, field_path, op_string, value): """Filter the query on a field. See :meth:`~google.cloud.firestore_v1beta1.client.Client.field_path` for more information on **field paths**. Returns a new :class:`~google.cloud.firestore_v1beta1.query.Query` that filters on a specific field path, according to an operation (e.g. ``==`` or "equals") and a particular value to be paired with that operation. Args: field_path (str): A field path (``.``-delimited list of field names) for the field to filter on. op_string (str): A comparison operation in the form of a string. Acceptable values are ``<``, ``<=``, ``==``, ``>=`` and ``>``. value (Any): The value to compare the field against in the filter. If ``value`` is :data:`None` or a NaN, then ``==`` is the only allowed operation. Returns: ~.firestore_v1beta1.query.Query: A filtered query. Acts as a copy of the current query, modified with the newly added filter. Raises: ValueError: If ``field_path`` is invalid. ValueError: If ``value`` is a NaN or :data:`None` and ``op_string`` is not ``==``. """ field_path_module.split_field_path(field_path) # raises if value is None: if op_string != _EQ_OP: raise ValueError(_BAD_OP_NAN_NULL) filter_pb = query_pb2.StructuredQuery.UnaryFilter( field=query_pb2.StructuredQuery.FieldReference(field_path=field_path), op=enums.StructuredQuery.UnaryFilter.Operator.IS_NULL, ) elif _isnan(value): if op_string != _EQ_OP: raise ValueError(_BAD_OP_NAN_NULL) filter_pb = query_pb2.StructuredQuery.UnaryFilter( field=query_pb2.StructuredQuery.FieldReference(field_path=field_path), op=enums.StructuredQuery.UnaryFilter.Operator.IS_NAN, ) elif isinstance(value, (transforms.Sentinel, transforms._ValueList)): raise ValueError(_INVALID_WHERE_TRANSFORM) else: filter_pb = query_pb2.StructuredQuery.FieldFilter( field=query_pb2.StructuredQuery.FieldReference(field_path=field_path), op=_enum_from_op_string(op_string), value=_helpers.encode_value(value), ) new_filters = self._field_filters + (filter_pb,) return self.__class__( self._parent, projection=self._projection, field_filters=new_filters, orders=self._orders, limit=self._limit, offset=self._offset, start_at=self._start_at, end_at=self._end_at, )
def _string_value(s): if not isinstance(s, six.text_type): s = six.u(s) return encode_value(s)
def _double_value(d): return encode_value(d)
def where(self, field_path, op_string, value): """Filter the query on a field. See :meth:`~.firestore_v1beta1.client.Client.field_path` for more information on **field paths**. Returns a new :class:`~.firestore_v1beta1.query.Query` that filters on a specific field path, according to an operation (e.g. ``==`` or "equals") and a particular value to be paired with that operation. Args: field_path (str): A field path (``.``-delimited list of field names) for the field to filter on. op_string (str): A comparison operation in the form of a string. Acceptable values are ``<``, ``<=``, ``==``, ``>=`` and ``>``. value (Any): The value to compare the field against in the filter. If ``value`` is :data:`None` or a NaN, then ``==`` is the only allowed operation. Returns: ~.firestore_v1beta1.query.Query: A filtered query. Acts as a copy of the current query, modified with the newly added filter. Raises: ValueError: If ``value`` is a NaN or :data:`None` and ``op_string`` is not ``==``. """ if value is None: if op_string != _EQ_OP: raise ValueError(_BAD_OP_NAN_NULL) filter_pb = query_pb2.StructuredQuery.UnaryFilter( field=query_pb2.StructuredQuery.FieldReference( field_path=field_path, ), op=enums.StructuredQuery.UnaryFilter.Operator.IS_NULL, ) elif _isnan(value): if op_string != _EQ_OP: raise ValueError(_BAD_OP_NAN_NULL) filter_pb = query_pb2.StructuredQuery.UnaryFilter( field=query_pb2.StructuredQuery.FieldReference( field_path=field_path, ), op=enums.StructuredQuery.UnaryFilter.Operator.IS_NAN, ) else: filter_pb = query_pb2.StructuredQuery.FieldFilter( field=query_pb2.StructuredQuery.FieldReference( field_path=field_path, ), op=_enum_from_op_string(op_string), value=_helpers.encode_value(value), ) new_filters = self._field_filters + (filter_pb, ) return self.__class__( self._parent, projection=self._projection, field_filters=new_filters, orders=self._orders, limit=self._limit, offset=self._offset, start_at=self._start_at, end_at=self._end_at, )
def _int_value(l): return encode_value(l)
def _blob_value(b): return encode_value(b)
def _call_fut(value): from google.cloud.firestore_v1beta1._helpers import encode_value return encode_value(value)