def filter(self, expression, value): """Filter the query based on an expression and a value. This will return a clone of the current :class:`Query` filtered by the expression and value provided. Expressions take the form of:: .filter('<property> <operator>', <value>) where property is a property stored on the entity in the datastore and operator is one of ``OPERATORS`` (ie, ``=``, ``<``, ``<=``, ``>``, ``>=``):: >>> query = Query('Person') >>> filtered_query = query.filter('name =', 'James') >>> filtered_query = query.filter('age >', 50) Because each call to ``.filter()`` returns a cloned ``Query`` object we are able to string these together:: >>> query = Query('Person').filter('name =', 'James').filter('age >', 50) :type expression: string :param expression: An expression of a property and an operator (ie, ``=``). :type value: integer, string, boolean, float, None, datetime :param value: The value to filter on. :rtype: :class:`Query` :returns: A Query filtered by the expression and value provided. """ clone = self._clone() # Take an expression like 'property >=', and parse it into useful pieces. property_name, operator = None, None expression = expression.strip() for operator_string in self.OPERATORS: if expression.endswith(operator_string): operator = self.OPERATORS[operator_string] property_name = expression[0:-len(operator_string)].strip() if not operator or not property_name: raise ValueError('Invalid expression: "%s"' % expression) # Build a composite filter AND'd together. composite_filter = clone._pb.filter.composite_filter composite_filter.operator = datastore_pb.CompositeFilter.AND # Add the specific filter property_filter = composite_filter.filter.add().property_filter property_filter.property.name = property_name property_filter.operator = operator # Set the value to filter on based on the type. attr_name, pb_value = helpers.get_protobuf_attribute_and_value(value) setattr(property_filter.value, attr_name, pb_value) return clone
def save_entity(self, dataset_id, key_pb, properties): """Save an entity to the Cloud Datastore with the provided properties. :type dataset_id: string :param dataset_id: The dataset in which to save the entity. :type key_pb: :class:`gcloud.datastore.datastore_v1_pb2.Key` :param key_pb: The complete or partial key for the entity. :type properties: dict :param properties: The properties to store on the entity. """ # TODO: Is this the right method name? # TODO: How do you delete properties? Set them to None? mutation = self.mutation() # If the Key is complete, we should upsert # instead of using insert_auto_id. path = key_pb.path_element[-1] auto_id = not (path.HasField('id') or path.HasField('name')) if auto_id: insert = mutation.insert_auto_id.add() else: insert = mutation.upsert.add() insert.key.CopyFrom(key_pb) for name, value in properties.iteritems(): prop = insert.property.add() # Set the name of the property. prop.name = name # Set the appropriate value. pb_attr, pb_value = helpers.get_protobuf_attribute_and_value(value) setattr(prop.value, pb_attr, pb_value) # If this is in a transaction, we should just return True. The transaction # will handle assigning any keys as necessary. if self.transaction(): return True result = self.commit(dataset_id, mutation) # If this was an auto-assigned ID, return the new Key. if auto_id: return result.insert_auto_id_key[0] return True
def test_get_protobuf_attribute(self): mapping = ( (str(), 'string_value'), (unicode(), 'string_value'), (int(), 'integer_value'), (long(), 'integer_value'), (float(), 'double_value'), (bool(), 'boolean_value'), (datetime.now(), 'timestamp_microseconds_value'), (Key(), 'key_value'), ) for test_value, expected_name in mapping: actual_name, _ = helpers.get_protobuf_attribute_and_value(test_value) self.assertEqual(expected_name, actual_name, 'Test value "%s" expected %s, got %s' % ( test_value, expected_name, actual_name))
def test_get_protobuf_value(self): now = datetime.utcnow() mapping = ( (str('string'), 'string'), (unicode('string'), 'string'), (int(), int()), (long(), int()), (float(), float()), (bool(), bool()), (now, long(calendar.timegm(now.timetuple()) * 1e6 + now.microsecond)), (Key(), Key().to_protobuf()), ) for test_value, expected_value in mapping: _, actual_value = helpers.get_protobuf_attribute_and_value(test_value) self.assertEqual(expected_value, actual_value, 'Test value "%s" expected %s, got %s.' % ( test_value, expected_value, actual_value))
def test_get_protobuf_attribute(self): mapping = ( (str(), 'string_value'), (unicode(), 'string_value'), (int(), 'integer_value'), (long(), 'integer_value'), (float(), 'double_value'), (bool(), 'boolean_value'), (datetime.now(), 'timestamp_microseconds_value'), (Key(), 'key_value'), ) for test_value, expected_name in mapping: actual_name, _ = helpers.get_protobuf_attribute_and_value( test_value) self.assertEqual( expected_name, actual_name, 'Test value "%s" expected %s, got %s' % (test_value, expected_name, actual_name))
def test_get_protobuf_value(self): now = datetime.utcnow() mapping = ( (str('string'), 'string'), (unicode('string'), 'string'), (int(), int()), (long(), int()), (float(), float()), (bool(), bool()), (now, long(calendar.timegm(now.timetuple()) * 1e6 + now.microsecond)), (Key(), Key().to_protobuf()), ) for test_value, expected_value in mapping: _, actual_value = helpers.get_protobuf_attribute_and_value( test_value) self.assertEqual( expected_value, actual_value, 'Test value "%s" expected %s, got %s.' % (test_value, expected_value, actual_value))
def _callFUT(self, val): from gcloud.datastore.helpers import get_protobuf_attribute_and_value return get_protobuf_attribute_and_value(val)