def _compare(self, other): """Compare this result to another result for sorting. Args: other (_Result): The other result to compare to. Returns: int: :data:`-1` if this result should come before `other`, :data:`0` if this result is equivalent to `other` for sorting purposes, or :data:`1` if this result should come after `other`. Raises: NotImplemented: If `order_by` was not passed to constructor or is :data:`None` or is empty. NotImplemented: If `other` is not a `_Result`. """ if not self.order_by: raise NotImplementedError("Can't sort result set without order_by") if not isinstance(other, _Result): return NotImplemented for order in self.order_by: if order.name == "__key__": this_value = helpers.key_from_protobuf( self.result_pb.entity.key).flat_path other_value = helpers.key_from_protobuf( other.result_pb.entity.key).flat_path else: this_value_pb = self.result_pb.entity.properties[order.name] this_value = helpers._get_value_from_value_pb(this_value_pb) other_value_pb = other.result_pb.entity.properties[order.name] other_value = helpers._get_value_from_value_pb(other_value_pb) # Compare key paths if ordering by key property if isinstance(this_value, Key): this_value = this_value.flat_path if isinstance(other_value, Key): other_value = other_value.flat_path direction = -1 if order.reverse else 1 if this_value < other_value: return -direction elif this_value > other_value: return direction return 0
def entity(self): """Get an entity for an entity result. Args: projection (Optional[Sequence[str]]): Sequence of property names to be projected in the query results. Returns: Union[model.Model, key.Key]: The processed result. """ if self.result_type == RESULT_TYPE_FULL: entity = model._entity_from_protobuf(self.result_pb.entity) return entity elif self.result_type == RESULT_TYPE_PROJECTION: entity = model._entity_from_protobuf(self.result_pb.entity) projection = tuple(self.result_pb.entity.properties.keys()) entity._set_projection(projection) return entity elif self.result_type == RESULT_TYPE_KEY_ONLY: key_pb = self.result_pb.entity.key ds_key = helpers.key_from_protobuf(key_pb) key = key_module.Key._from_ds_key(ds_key) return key raise NotImplementedError( "Got unexpected entity result type for query.")
def get_multi(self, keys, missing=None, deferred=None, transaction=None): """Retrieve entities, along with their attributes. :type keys: list of :class:`google.cloud.datastore.key.Key` :param keys: The keys to be retrieved from the datastore. :type missing: list :param missing: (Optional) If a list is passed, the key-only entities returned by the backend as "missing" will be copied into it. If the list is not empty, an error will occur. :type deferred: list :param deferred: (Optional) If a list is passed, the keys returned by the backend as "deferred" will be copied into it. If the list is not empty, an error will occur. :type transaction: :class:`~.transaction.Transaction` :param transaction: (Optional) Transaction to use for read consistency. If not passed, uses current transaction, if set. :rtype: list of :class:`google.cloud.datastore.entity.Entity` :returns: The requested entities. :raises: :class:`ValueError` if one or more of ``keys`` has a project which does not match our project. """ if not keys: return [] ids = set(key.project for key in keys) for current_id in ids: if current_id != self.project: raise ValueError('Keys do not match project') if transaction is None: transaction = self.current_transaction entity_pbs = _extended_lookup( connection=self.connection, project=self.project, key_pbs=[k.to_protobuf() for k in keys], missing=missing, deferred=deferred, transaction_id=transaction and transaction.id, ) if missing is not None: missing[:] = [ helpers.entity_from_protobuf(missed_pb) for missed_pb in missing ] if deferred is not None: deferred[:] = [ helpers.key_from_protobuf(deferred_pb) for deferred_pb in deferred ] return [ helpers.entity_from_protobuf(entity_pb) for entity_pb in entity_pbs ]
def put(entity, options): """Store an entity in datastore. The entity can be a new entity to be saved for the first time or an existing entity that has been updated. Args: entity_pb (datastore.Entity): The entity to be stored. options (_options.Options): Options for this request. Returns: tasklets.Future: Result will be completed datastore key (datastore.Key) for the entity. """ context = context_module.get_context() use_global_cache = context._use_global_cache(entity.key, options) use_datastore = context._use_datastore(entity.key, options) if not (use_global_cache or use_datastore): raise TypeError("use_global_cache and use_datastore can't both be False") if not use_datastore and entity.key.is_partial: raise TypeError("Can't store partial keys when use_datastore is False") lock = None entity_pb = helpers.entity_to_protobuf(entity) cache_key = _cache.global_cache_key(entity.key) if use_global_cache and not entity.key.is_partial: if use_datastore: lock = yield _cache.global_lock_for_write(cache_key) else: expires = context._global_cache_timeout(entity.key, options) cache_value = entity_pb.SerializeToString() yield _cache.global_set(cache_key, cache_value, expires=expires) if use_datastore: transaction = context.transaction if transaction: batch = _get_commit_batch(transaction, options) else: batch = _batch.get_batch(_NonTransactionalCommitBatch, options) key_pb = yield batch.put(entity_pb) if key_pb: key = helpers.key_from_protobuf(key_pb) else: key = None if lock: if transaction: def callback(): _cache.global_unlock_for_write(cache_key, lock).result() context.call_on_transaction_complete(callback) else: yield _cache.global_unlock_for_write(cache_key, lock) raise tasklets.Return(key)
def get_multi(self, keys, missing=None, deferred=None, transaction=None): """Retrieve entities, along with their attributes. :type keys: list of :class:`google.cloud.datastore.key.Key` :param keys: The keys to be retrieved from the datastore. :type missing: list :param missing: (Optional) If a list is passed, the key-only entities returned by the backend as "missing" will be copied into it. If the list is not empty, an error will occur. :type deferred: list :param deferred: (Optional) If a list is passed, the keys returned by the backend as "deferred" will be copied into it. If the list is not empty, an error will occur. :type transaction: :class:`~.transaction.Transaction` :param transaction: (Optional) Transaction to use for read consistency. If not passed, uses current transaction, if set. :rtype: list of :class:`google.cloud.datastore.entity.Entity` :returns: The requested entities. :raises: :class:`ValueError` if one or more of ``keys`` has a project which does not match our project. """ if not keys: return [] ids = set(key.project for key in keys) for current_id in ids: if current_id != self.project: raise ValueError('Keys do not match project') if transaction is None: transaction = self.current_transaction entity_pbs = _extended_lookup( connection=self.connection, project=self.project, key_pbs=[k.to_protobuf() for k in keys], missing=missing, deferred=deferred, transaction_id=transaction and transaction.id, ) if missing is not None: missing[:] = [ helpers.entity_from_protobuf(missed_pb) for missed_pb in missing] if deferred is not None: deferred[:] = [ helpers.key_from_protobuf(deferred_pb) for deferred_pb in deferred] return [helpers.entity_from_protobuf(entity_pb) for entity_pb in entity_pbs]
def entity(self): """Get an entity for an entity result. Use the cache if available. Args: projection (Optional[Sequence[str]]): Sequence of property names to be projected in the query results. Returns: Union[model.Model, key.Key]: The processed result. """ if self.result_type == RESULT_TYPE_FULL: # First check the cache. context = context_module.get_context() key_pb = self.result_pb.entity.key ds_key = helpers.key_from_protobuf(key_pb) key = key_module.Key._from_ds_key(ds_key) entity = _KEY_NOT_IN_CACHE use_cache = context._use_cache(key) if use_cache: try: entity = context.cache.get_and_validate(key) except KeyError: pass if entity is _KEY_NOT_IN_CACHE: # entity not in cache, create one. entity = model._entity_from_protobuf(self.result_pb.entity) return entity elif self.result_type == RESULT_TYPE_PROJECTION: entity = model._entity_from_protobuf(self.result_pb.entity) projection = tuple(self.result_pb.entity.properties.keys()) entity._set_projection(projection) return entity elif self.result_type == RESULT_TYPE_KEY_ONLY: key_pb = self.result_pb.entity.key ds_key = helpers.key_from_protobuf(key_pb) key = key_module.Key._from_ds_key(ds_key) return key raise NotImplementedError( "Got unexpected entity result type for query.")
def key(self): """Construct the key for this result. Returns: key.Key: The key. """ if self._key is None: key_pb = self.result_pb.entity.key ds_key = helpers.key_from_protobuf(key_pb) self._key = key_module.Key._from_ds_key(ds_key) return self._key
def _call_fut(self, val): from google.cloud.datastore.helpers import key_from_protobuf return key_from_protobuf(val)
def get_multi( self, keys, missing=None, deferred=None, transaction=None, eventual=False, retry=None, timeout=None, ): """Retrieve entities, along with their attributes. :type keys: list of :class:`google.cloud.datastore.key.Key` :param keys: The keys to be retrieved from the datastore. :type missing: list :param missing: (Optional) If a list is passed, the key-only entities returned by the backend as "missing" will be copied into it. If the list is not empty, an error will occur. :type deferred: list :param deferred: (Optional) If a list is passed, the keys returned by the backend as "deferred" will be copied into it. If the list is not empty, an error will occur. :type transaction: :class:`~google.cloud.datastore.transaction.Transaction` :param transaction: (Optional) Transaction to use for read consistency. If not passed, uses current transaction, if set. :type eventual: bool :param eventual: (Optional) Defaults to strongly consistent (False). Setting True will use eventual consistency, but cannot be used inside a transaction or will raise ValueError. :type retry: :class:`google.api_core.retry.Retry` :param retry: A retry object used to retry requests. If ``None`` is specified, requests will be retried using a default configuration. :type timeout: float :param timeout: Time, in seconds, to wait for the request to complete. Note that if ``retry`` is specified, the timeout applies to each individual attempt. :rtype: list of :class:`google.cloud.datastore.entity.Entity` :returns: The requested entities. :raises: :class:`ValueError` if one or more of ``keys`` has a project which does not match our project. :raises: :class:`ValueError` if eventual is True and in a transaction. """ if not keys: return [] ids = set(key.project for key in keys) for current_id in ids: if current_id != self.project: raise ValueError("Keys do not match project") if transaction is None: transaction = self.current_transaction entity_pbs = _extended_lookup( datastore_api=self._datastore_api, project=self.project, key_pbs=[key.to_protobuf() for key in keys], eventual=eventual, missing=missing, deferred=deferred, transaction_id=transaction and transaction.id, retry=retry, timeout=timeout, ) if missing is not None: missing[:] = [ helpers.entity_from_protobuf(missed_pb) for missed_pb in missing ] if deferred is not None: deferred[:] = [ helpers.key_from_protobuf(deferred_pb) for deferred_pb in deferred ] return [ helpers.entity_from_protobuf(entity_pb._pb) for entity_pb in entity_pbs ]