def _ValidateQuery(self, query, query_info): """Ensure that the given query matches the query_info. Args: query: datastore_pb.Query instance we are chacking query_info: datastore_pb.Query instance we want to match Raises BadRequestError on failure. """ error_msg = 'Cursor does not match query: %s' if query_info.filter_list() != query.filter_list(): raise BadRequestError(error_msg % 'filters do not match') if query_info.order_list() != query.order_list(): raise BadRequestError(error_msg % 'orders do not match') for attr in ('ancestor', 'kind', 'name_space', 'search_query'): query_info_has_attr = getattr(query_info, 'has_%s' % attr) query_info_attr = getattr(query_info, attr) query_has_attr = getattr(query, 'has_%s' % attr) query_attr = getattr(query, attr) if query_info_has_attr(): if not query_has_attr() or query_info_attr() != query_attr(): raise BadRequestError(error_msg % ('%s does not match' % attr)) elif query_has_attr(): raise BadRequestError(error_msg % ('%s does not match' % attr))
def ParsePropertyQuery(query, filters, orders): """Parse __property__ queries. Raises exceptions for illegal queries. Args: query: A Query PB. filters: the normalized filters from query. orders: the normalized orders from query. Returns: The kind range (a ValueRange over (kind, property) pairs) requested in the query. """ if query.has_transaction(): raise BadRequestError( 'transactional queries on __property__ not allowed') key_range = ParseKeyFilteredQuery(filters, orders) key_range.Remap(lambda x: _PropertyKeyToString(x, '')) if query.has_ancestor(): ancestor = datastore_types.Key._FromPb(query.ancestor()) ancestor_kind, ancestor_property = _PropertyKeyToString(ancestor, None) if ancestor_property is not None: key_range.Update(datastore_pb.Query_Filter.EQUAL, (ancestor_kind, ancestor_property)) else: key_range.Update(datastore_pb.Query_Filter.GREATER_THAN_OR_EQUAL, (ancestor_kind, '')) key_range.Update(datastore_pb.Query_Filter.LESS_THAN_OR_EQUAL, (ancestor_kind + '\0', '')) query.clear_ancestor() return key_range
def ParseKeyFilteredQuery(filters, orders): """Parse queries which only allow filters and ascending-orders on __key__. Raises exceptions for illegal queries. Args: filters: the normalized filters of a query. orders: the normalized orders of a query. Returns: The key range (a ValueRange over datastore_types.Key) requested in the query. """ remaining_filters = [] key_range = ValueRange() key_prop = datastore_types._KEY_SPECIAL_PROPERTY for f in filters: op = f.op() if not (f.property_size() == 1 and f.property(0).name() == key_prop and not (op == datastore_pb.Query_Filter.IN or op == datastore_pb.Query_Filter.EXISTS)): remaining_filters.append(f) continue val = f.property(0).value() if not val.has_referencevalue(): raise BadRequestError('__key__ kind must be compared to a key') limit = datastore_types.FromReferenceProperty(val) key_range.Update(op, limit) remaining_orders = [] for o in orders: if not (o.direction() == datastore_pb.Query_Order.ASCENDING and o.property() == datastore_types._KEY_SPECIAL_PROPERTY): remaining_orders.append(o) else: break if remaining_filters: raise BadRequestError('Only comparison filters on ' + key_prop + ' supported') if remaining_orders: raise BadRequestError('Only ascending order on ' + key_prop + ' supported') return key_range
def _KindKeyToString(key): """Extract kind name from __kind__ key. Raises an ApplicationError if the key is not of the form '__kind__'/name. Args: key: a key for a __kind__ instance. Returns: kind specified by key. """ key_path = key.to_path() if (len(key_path) == 2 and key_path[0] == '__kind__' and isinstance(key_path[1], basestring)): return key_path[1] raise BadRequestError('invalid Key for __kind__ table')
def _NamespaceKeyToString(key): """Extract namespace name from __namespace__ key. Raises an ApplicationError if the key is not of the form '__namespace__'/name or '__namespace__'/_EMPTY_NAMESPACE_ID. Args: key: a key for a __namespace__ instance. Returns: namespace specified by key. """ key_path = key.to_path() if len(key_path) == 2 and key_path[0] == '__namespace__': if key_path[1] == datastore_types._EMPTY_NAMESPACE_ID: return '' if isinstance(key_path[1], basestring): return key_path[1] raise BadRequestError('invalid Key for __namespace__ table')
def ParseNamespaceQuery(query, filters, orders): """Parse __namespace__ queries. Raises exceptions for illegal queries. Args: query: A Query PB. filters: the normalized filters from query. orders: the normalized orders from query. Returns: The kind range (a ValueRange over string) requested in the query. """ if query.has_ancestor(): raise BadRequestError('ancestor queries on __namespace__ not allowed') key_range = ParseKeyFilteredQuery(filters, orders) key_range.Remap(_NamespaceKeyToString) return key_range
def _PropertyKeyToString(key, default_property): """Extract property name from __property__ key. Raises an ApplicationError if the key is not of the form '__kind__'/kind, '__property__'/property or '__kind__'/kind Args: key: a key for a __property__ instance. default_property: property value to return when key only has a kind. Returns: kind, property if key = '__kind__'/kind, '__property__'/property kind, default_property if key = '__kind__'/kind """ key_path = key.to_path() if (len(key_path) == 2 and key_path[0] == '__kind__' and isinstance(key_path[1], basestring)): return (key_path[1], default_property) if (len(key_path) == 4 and key_path[0] == '__kind__' and isinstance(key_path[1], basestring) and key_path[2] == '__property__' and isinstance(key_path[3], basestring)): return (key_path[1], key_path[3]) raise BadRequestError('invalid Key for __property__ table')