def filter(self, expression, value): 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 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:`gclouddatastore.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 save_entity(self, entity): # Create a non-transactional commit request. commit_request = datastore_pb.CommitRequest() commit_request.mode = datastore_pb.CommitRequest.NON_TRANSACTIONAL mutation = commit_request.mutation.insert_auto_id.add() # First set the (partial) key. mutation.key.CopyFrom(entity.key().to_protobuf()) for name, value in entity.iteritems(): prop = mutation.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) response = self._rpc('commit', commit_request, datastore_pb.CommitResponse) return response.mutation_result.insert_auto_id_key[0]