def commit(self): """Commits the transaction. This is called automatically upon exiting a with statement, however it can be called explicitly if you don't want to use a context manager. This method has necessary side-effects: - Sets the current connection's transaction reference to None. - Sets the current transaction's ID to None. - Updates paths for any keys that needed an automatically generated ID. """ # It's possible that they called commit() already, in which case # we shouldn't do any committing of our own. if self.connection().transaction(): result = self.connection().commit(self.dataset().id(), self.mutation()) # For any of the auto-id entities, make sure we update their keys. for i, entity in enumerate(self._auto_id_entities): key_pb = result.insert_auto_id_key[i] key = Key.from_protobuf(key_pb) entity.key(entity.key().path(key.path())) # Tell the connection that the transaction is over. self.connection().transaction(None) # Clear our own ID in case this gets accidentally reused. self._id = None
def save(self): """Save the entity in the Cloud Datastore. :rtype: :class:`gcloud.datastore.entity.Entity` :returns: The entity with a possibly updated Key. """ # pylint: disable=maybe-no-member key_pb = self.dataset().connection().save_entity( dataset_id=self.dataset().id(), key_pb=self.key().to_protobuf(), properties=dict(self)) # pylint: enable=maybe-no-member # If we are in a transaction and the current entity needs an # automatically assigned ID, tell the transaction where to put that. transaction = self.dataset().connection().transaction() # pylint: disable=maybe-no-member if transaction and self.key().is_partial(): transaction.add_auto_id_entity(self) # pylint: enable=maybe-no-member if isinstance(key_pb, datastore_pb.Key): updated_key = Key.from_protobuf(key_pb) # Update the path (which may have been altered). # pylint: disable=maybe-no-member key = self.key().path(updated_key.path()) # pylint: enable=maybe-no-member self.key(key) return self
def _get_value_from_protobuf(pb): """Given a protobuf for a Property, get the correct value. The Cloud Datastore Protobuf API returns a Property Protobuf which has one value set and the rest blank. This function retrieves the the one value provided. Some work is done to coerce the return value into a more useful type (particularly in the case of a timestamp value, or a key value). :type pb: :class:`gcloud.datastore.datastore_v1_pb2.Property` :param pb: The Property Protobuf. :returns: The value provided by the Protobuf. """ if pb.value.HasField('timestamp_microseconds_value'): microseconds = pb.value.timestamp_microseconds_value naive = (datetime.utcfromtimestamp(0) + timedelta(microseconds=microseconds)) return naive.replace(tzinfo=pytz.utc) elif pb.value.HasField('key_value'): return Key.from_protobuf(pb.value.key_value) elif pb.value.HasField('boolean_value'): return pb.value.boolean_value elif pb.value.HasField('double_value'): return pb.value.double_value elif pb.value.HasField('integer_value'): return pb.value.integer_value elif pb.value.HasField('string_value'): return pb.value.string_value elif pb.value.HasField('entity_value'): return Entity.from_protobuf(pb.value.entity_value) else: return None
def from_protobuf(cls, pb, dataset=None): """Factory method for creating an entity based on a protobuf. The protobuf should be one returned from the Cloud Datastore Protobuf API. :type key: :class:`gcloud.datastore.datastore_v1_pb2.Entity` :param key: The Protobuf representing the entity. :returns: The :class:`Entity` derived from the :class:`gcloud.datastore.datastore_v1_pb2.Entity`. """ # This is here to avoid circular imports. from gcloud.datastore import helpers key = Key.from_protobuf(pb.key, dataset=dataset) entity = cls.from_key(key) for property_pb in pb.property: value = helpers.get_value_from_protobuf(property_pb) entity[property_pb.name] = value return entity
def get_value_from_protobuf(pb): """Given a protobuf for a Property, get the correct value. The Cloud Datastore Protobuf API returns a Property Protobuf which has one value set and the rest blank. This method retrieves the the one value provided. Some work is done to coerce the return value into a more useful type (particularly in the case of a timestamp value, or a key value). :type pb: :class:`gcloud.datastore.datastore_v1_pb2.Property` :param pb: The Property Protobuf. :returns: The value provided by the Protobuf. """ if pb.value.HasField('timestamp_microseconds_value'): microseconds = pb.value.timestamp_microseconds_value return (datetime.utcfromtimestamp(0) + timedelta(microseconds=microseconds)) elif pb.value.HasField('key_value'): return Key.from_protobuf(pb.value.key_value) elif pb.value.HasField('boolean_value'): return pb.value.boolean_value elif pb.value.HasField('double_value'): return pb.value.double_value elif pb.value.HasField('integer_value'): return pb.value.integer_value elif pb.value.HasField('string_value'): return pb.value.string_value else: # TODO(jjg): Should we raise a ValueError here? return None
def save(self): """Save the entity in the Cloud Datastore. :rtype: :class:`gcloud.datastore.entity.Entity` :returns: The entity with a possibly updated Key. """ key_pb = self.dataset().connection().save_entity( dataset_id=self.dataset().id(), key_pb=self.key().to_protobuf(), properties=dict(self)) # If we are in a transaction and the current entity needs an # automatically assigned ID, tell the transaction where to put that. transaction = self.dataset().connection().transaction() if transaction and self.key().is_partial(): transaction.add_auto_id_entity(self) if isinstance(key_pb, datastore_pb.Key): updated_key = Key.from_protobuf(key_pb) # Update the path (which may have been altered). key = self.key().path(updated_key.path()) self.key(key) return self