Beispiel #1
0
    def _callFUT(self, val, dataset=_MARKER):
        from gcloud.datastore.helpers import entity_from_protobuf

        if dataset is self._MARKER:
            return entity_from_protobuf(val)

        return entity_from_protobuf(val, dataset)
Beispiel #2
0
    def _callFUT(self, val, dataset=_MARKER):
        from gcloud.datastore.helpers import entity_from_protobuf

        if dataset is self._MARKER:
            return entity_from_protobuf(val)

        return entity_from_protobuf(val, dataset)
Beispiel #3
0
    def get_multi(self, keys, missing=None, deferred=None, transaction=None):
        """Retrieve entities, along with their attributes.

        :type keys: list of :class:`gcloud.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:`gcloud.datastore.transaction.Transaction`
        :param transaction: (Optional) Transaction to use for read consistency.
                            If not passed, uses current transaction, if set.

        :rtype: list of :class:`gcloud.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
        ]
Beispiel #4
0
    def get_multi(self, keys, missing=None, deferred=None, transaction=None):
        """Retrieve entities, along with their attributes.

        :type keys: list of :class:`gcloud.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:`gcloud.datastore.transaction.Transaction`
        :param transaction: (Optional) Transaction to use for read consistency.
                            If not passed, uses current transaction, if set.

        :rtype: list of :class:`gcloud.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]
Beispiel #5
0
    def get_multi(self, keys, missing=None, deferred=None):
        """Retrieve entities, along with their attributes.

        :type keys: list of :class:`gcloud.datastore.key.Key`
        :param keys: The keys to be retrieved from the datastore.

        :type missing: an empty list or None.
        :param missing: If a list is passed, the key-only entities returned
                        by the backend as "missing" will be copied into it.
                        Use only as a keyword param.

        :type deferred: an empty list or None.
        :param deferred: If a list is passed, the keys returned
                         by the backend as "deferred" will be copied into it.
                         Use only as a keyword param.

        :rtype: list of :class:`gcloud.datastore.entity.Entity`
        :returns: The requested entities.
        :raises: ValueError if one or more of ``keys`` has a dataset ID which
                 does not match our dataset ID.
        """
        if not keys:
            return []

        ids = list(set([key.dataset_id for key in keys]))
        if ids != [self.dataset_id]:
            raise ValueError('Keys do not match dataset ID')

        transaction = self.current_transaction

        entity_pbs = _extended_lookup(
            connection=self.connection,
            dataset_id=self.dataset_id,
            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
        ]
Beispiel #6
0
    def get_multi(self, keys, missing=None, deferred=None):
        """Retrieve entities, along with their attributes.

        :type keys: list of :class:`gcloud.datastore.key.Key`
        :param keys: The keys to be retrieved from the datastore.

        :type missing: an empty list or None.
        :param missing: If a list is passed, the key-only entities returned
                        by the backend as "missing" will be copied into it.
                        Use only as a keyword param.

        :type deferred: an empty list or None.
        :param deferred: If a list is passed, the keys returned
                         by the backend as "deferred" will be copied into it.
                         Use only as a keyword param.

        :rtype: list of :class:`gcloud.datastore.entity.Entity`
        :returns: The requested entities.
        :raises: ValueError if one or more of ``keys`` has a dataset ID which
                 does not match our dataset ID.
        """
        if not keys:
            return []

        ids = set(key.dataset_id for key in keys)
        for current_id in ids:
            if not _dataset_ids_equal(current_id, self.dataset_id):
                raise ValueError('Keys do not match dataset ID')

        transaction = self.current_transaction

        entity_pbs = _extended_lookup(
            connection=self.connection,
            dataset_id=self.dataset_id,
            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]
Beispiel #7
0
def get(keys, missing=None, deferred=None, connection=None):
    """Retrieves entities, along with their attributes.

    :type keys: list of :class:`gcloud.datastore.key.Key`
    :param keys: The keys to be retrieved from the datastore.

    :type missing: an empty list or None.
    :param missing: If a list is passed, the key-only entities returned
                    by the backend as "missing" will be copied into it.
                    Use only as a keyword param.

    :type deferred: an empty list or None.
    :param deferred: If a list is passed, the keys returned
                     by the backend as "deferred" will be copied into it.
                     Use only as a keyword param.

    :type connection: :class:`gcloud.datastore.connection.Connection`
    :param connection: Optional. The connection used to connect to datastore.

    :rtype: list of :class:`gcloud.datastore.entity.Entity`
    :returns: The requested entities.
    """
    if not keys:
        return []

    connection = _require_connection(connection)
    dataset_id = _get_dataset_id_from_keys(keys)

    transaction = Transaction.current()

    entity_pbs = connection.lookup(
        dataset_id=dataset_id,
        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]

    entities = []
    for entity_pb in entity_pbs:
        entities.append(helpers.entity_from_protobuf(entity_pb))

    return entities
Beispiel #8
0
    def next_page(self):
        """Fetch a single "page" of query results.

        Low-level API for fine control:  the more convenient API is
        to iterate on the current Iterator.

        :rtype: tuple, (entities, more_results, cursor)
        """
        pb = _pb_from_query(self._query)

        start_cursor = self._start_cursor
        if start_cursor is not None:
            pb.start_cursor = base64.urlsafe_b64decode(start_cursor)

        end_cursor = self._end_cursor
        if end_cursor is not None:
            pb.end_cursor = base64.urlsafe_b64decode(end_cursor)

        if self._limit is not None:
            pb.limit.value = self._limit

        pb.offset = self._offset

        transaction = self._client.current_transaction

        query_results = self._client.connection.run_query(
            query_pb=pb,
            project=self._query.project,
            namespace=self._query.namespace,
            transaction_id=transaction and transaction.id,
            )
        # NOTE: `query_results` contains an extra value that we don't use,
        #       namely `skipped_results`.
        #
        # NOTE: The value of `more_results` is not currently useful because
        #       the back-end always returns an enum
        #       value of MORE_RESULTS_AFTER_LIMIT even if there are no more
        #       results. See
        #       https://github.com/GoogleCloudPlatform/gcloud-python/issues/280
        #       for discussion.
        entity_pbs, cursor_as_bytes, more_results_enum = query_results[:3]

        if cursor_as_bytes == b'':
            self._start_cursor = None
        else:
            self._start_cursor = base64.urlsafe_b64encode(cursor_as_bytes)
        self._end_cursor = None

        if more_results_enum == self._NOT_FINISHED:
            self._more_results = True
        elif more_results_enum in self._FINISHED:
            self._more_results = False
        else:
            raise ValueError('Unexpected value returned for `more_results`.')

        self._page = [
            helpers.entity_from_protobuf(entity)
            for entity in entity_pbs]
        return self._page, self._more_results, self._start_cursor
Beispiel #9
0
    def next_page(self):
        """Fetch a single "page" of query results.

        Low-level API for fine control:  the more convenient API is
        to iterate on the current Iterator.

        :rtype: tuple, (entities, more_results, cursor)
        """
        pb = _pb_from_query(self._query)

        start_cursor = self._start_cursor
        if start_cursor is not None:
            pb.start_cursor = base64.urlsafe_b64decode(start_cursor)

        end_cursor = self._end_cursor
        if end_cursor is not None:
            pb.end_cursor = base64.urlsafe_b64decode(end_cursor)

        if self._limit is not None:
            pb.limit = self._limit

        pb.offset = self._offset

        transaction = self._client.current_transaction

        query_results = self._client.connection.run_query(
            query_pb=pb,
            project=self._query.project,
            namespace=self._query.namespace,
            transaction_id=transaction and transaction.id,
            )
        # NOTE: `query_results` contains an extra value that we don't use,
        #       namely `skipped_results`.
        #
        # NOTE: The value of `more_results` is not currently useful because
        #       the back-end always returns an enum
        #       value of MORE_RESULTS_AFTER_LIMIT even if there are no more
        #       results. See
        #       https://github.com/GoogleCloudPlatform/gcloud-python/issues/280
        #       for discussion.
        entity_pbs, cursor_as_bytes, more_results_enum = query_results[:3]

        if cursor_as_bytes == b'':
            self._start_cursor = None
        else:
            self._start_cursor = base64.urlsafe_b64encode(cursor_as_bytes)
        self._end_cursor = None

        if more_results_enum == self._NOT_FINISHED:
            self._more_results = True
        elif more_results_enum in self._FINISHED:
            self._more_results = False
        else:
            raise ValueError('Unexpected value returned for `more_results`.')

        self._page = [
            helpers.entity_from_protobuf(entity)
            for entity in entity_pbs]
        return self._page, self._more_results, self._start_cursor
Beispiel #10
0
    def get_entities(self, keys, missing=None, deferred=None):
        """Retrieves entities from the dataset, along with their attributes.

        :type keys: list of :class:`gcloud.datastore.key.Key`
        :param keys: List of keys to be retrieved.

        :type missing: an empty list or None.
        :param missing: If a list is passed, the key-only entities returned
                        by the backend as "missing" will be copied into it.
                        Use only as a keyword param.

        :type deferred: an empty list or None.
        :param deferred: If a list is passed, the keys returned
                        by the backend as "deferred" will be copied into it.
                        Use only as a keyword param.

        :rtype: list of :class:`gcloud.datastore.entity.Entity`
        :return: The requested entities.
        """
        entity_pbs = self.connection().lookup(
            dataset_id=self.id(),
            key_pbs=[k.to_protobuf() for k in keys],
            missing=missing,
            deferred=deferred,
        )

        if missing is not None:
            missing[:] = [
                helpers.entity_from_protobuf(missed_pb, dataset=self)
                for missed_pb in missing
            ]

        if deferred is not None:
            deferred[:] = [
                helpers.key_from_protobuf(deferred_pb)
                for deferred_pb in deferred
            ]

        entities = []
        for entity_pb in entity_pbs:
            entities.append(
                helpers.entity_from_protobuf(entity_pb, dataset=self))
        return entities
Beispiel #11
0
    def next_page(self):
        """Fetch a single "page" of query results.

        Low-level API for fine control:  the more convenient API is
        to iterate on the current Iterator.

        :rtype: tuple, (entities, more_results, cursor)
        :returns: The next page of results.
        """
        pb = _pb_from_query(self._query)

        start_cursor = self._start_cursor
        if start_cursor is not None:
            pb.start_cursor = base64.urlsafe_b64decode(start_cursor)

        end_cursor = self._end_cursor
        if end_cursor is not None:
            pb.end_cursor = base64.urlsafe_b64decode(end_cursor)

        if self._limit is not None:
            pb.limit.value = self._limit

        if self._offset is not None:
            pb.offset = self._offset

        transaction = self._client.current_transaction

        query_results = self._client.connection.run_query(
            query_pb=pb,
            project=self._query.project,
            namespace=self._query.namespace,
            transaction_id=transaction and transaction.id,
        )
        (entity_pbs, cursor_as_bytes, more_results_enum,
         self._skipped_results) = query_results

        if cursor_as_bytes == b'':
            self._start_cursor = None
        else:
            self._start_cursor = base64.urlsafe_b64encode(cursor_as_bytes)
        self._end_cursor = None

        if more_results_enum == self._NOT_FINISHED:
            self._more_results = True
        elif more_results_enum in self._FINISHED:
            self._more_results = False
        else:
            raise ValueError('Unexpected value returned for `more_results`.')

        self._page = [
            helpers.entity_from_protobuf(entity) for entity in entity_pbs
        ]
        return self._page, self._more_results, self._start_cursor
Beispiel #12
0
    def next_page(self):
        """Fetch a single "page" of query results.

        Low-level API for fine control:  the more convenient API is
        to iterate on the current Iterator.

        :rtype: tuple, (entities, more_results, cursor)
        :returns: The next page of results.
        """
        pb = _pb_from_query(self._query)

        start_cursor = self._start_cursor
        if start_cursor is not None:
            pb.start_cursor = base64.urlsafe_b64decode(start_cursor)

        end_cursor = self._end_cursor
        if end_cursor is not None:
            pb.end_cursor = base64.urlsafe_b64decode(end_cursor)

        if self._limit is not None:
            pb.limit.value = self._limit

        if self._offset is not None:
            pb.offset = self._offset

        transaction = self._client.current_transaction

        query_results = self._client.connection.run_query(
            query_pb=pb,
            project=self._query.project,
            namespace=self._query.namespace,
            transaction_id=transaction and transaction.id,
            )
        (entity_pbs, cursor_as_bytes,
         more_results_enum, self._skipped_results) = query_results

        if cursor_as_bytes == b'':
            self._start_cursor = None
        else:
            self._start_cursor = base64.urlsafe_b64encode(cursor_as_bytes)
        self._end_cursor = None

        if more_results_enum == self._NOT_FINISHED:
            self._more_results = True
        elif more_results_enum in self._FINISHED:
            self._more_results = False
        else:
            raise ValueError('Unexpected value returned for `more_results`.')

        self._page = [
            helpers.entity_from_protobuf(entity)
            for entity in entity_pbs]
        return self._page, self._more_results, self._start_cursor
Beispiel #13
0
    def get_entities(self, keys, missing=None, deferred=None):
        """Retrieves entities from the dataset, along with their attributes.

        :type keys: list of :class:`gcloud.datastore.key.Key`
        :param keys: List of keys to be retrieved.

        :type missing: an empty list or None.
        :param missing: If a list is passed, the key-only entities returned
                        by the backend as "missing" will be copied into it.
                        Use only as a keyword param.

        :type deferred: an empty list or None.
        :param deferred: If a list is passed, the keys returned
                        by the backend as "deferred" will be copied into it.
                        Use only as a keyword param.

        :rtype: list of :class:`gcloud.datastore.entity.Entity`
        :return: The requested entities.
        """
        entity_pbs = self.connection().lookup(
            dataset_id=self.id(),
            key_pbs=[k.to_protobuf() for k in keys],
            missing=missing, deferred=deferred,
        )

        if missing is not None:
            missing[:] = [
                helpers.entity_from_protobuf(missed_pb, dataset=self)
                for missed_pb in missing]

        if deferred is not None:
            deferred[:] = [
                helpers.key_from_protobuf(deferred_pb)
                for deferred_pb in deferred]

        entities = []
        for entity_pb in entity_pbs:
            entities.append(helpers.entity_from_protobuf(
                entity_pb, dataset=self))
        return entities
Beispiel #14
0
    def fetch(self, limit=None):
        """Executes the Query and returns all matching entities.

        This makes an API call to the Cloud Datastore, sends the Query as a
        protobuf, parses the responses to Entity protobufs, and then converts
        them to :class:`gcloud.datastore.entity.Entity` objects.

        For example::

          >>> from gcloud import datastore
          >>> dataset = datastore.get_dataset('dataset-id', email, key_path)
          >>> query = dataset.query('Person').filter('name =', 'Sally')
          >>> query.fetch()
          [<Entity object>, <Entity object>, ...]
          >>> query.fetch(1)
          [<Entity object>]
          >>> query.limit()
          None

        :type limit: integer
        :param limit: An optional limit to apply temporarily to this query.
                      That is, the Query itself won't be altered,
                      but the limit will be applied to the query
                      before it is executed.

        :rtype: list of :class:`gcloud.datastore.entity.Entity`'s
        :returns: The list of entities matching this query's criteria.
        """
        clone = self

        if limit:
            clone = self.limit(limit)

        query_results = self.dataset().connection().run_query(
            query_pb=clone.to_protobuf(),
            dataset_id=self.dataset().id(),
            namespace=self._namespace,
        )
        # NOTE: `query_results` contains two extra values that we don't use,
        #       namely `more_results` and `skipped_results`. The value of
        #       `more_results` is unusable because it always returns an enum
        #       value of MORE_RESULTS_AFTER_LIMIT even if there are no more
        #       results. See
        #       https://github.com/GoogleCloudPlatform/gcloud-python/issues/280
        #       for discussion.
        entity_pbs, end_cursor = query_results[:2]

        self._cursor = end_cursor
        return [
            helpers.entity_from_protobuf(entity, dataset=self.dataset())
            for entity in entity_pbs
        ]
Beispiel #15
0
    def test_inverts_to_protobuf(self):
        from gcloud.datastore._generated import entity_pb2
        from gcloud.datastore.helpers import _new_value_pb
        from gcloud.datastore.helpers import entity_from_protobuf

        original_pb = entity_pb2.Entity()
        # Add a key.
        original_pb.key.partition_id.dataset_id = project = 'PROJECT'
        elem1 = original_pb.key.path_element.add()
        elem1.kind = 'Family'
        elem1.id = 1234
        elem2 = original_pb.key.path_element.add()
        elem2.kind = 'King'
        elem2.name = 'Spades'

        # Add an integer property.
        val_pb1 = _new_value_pb(original_pb, 'foo')
        val_pb1.integer_value = 1337
        val_pb1.indexed = False
        # Add a string property.
        val_pb2 = _new_value_pb(original_pb, 'bar')
        val_pb2.string_value = u'hello'

        # Add a nested (entity) property.
        val_pb3 = _new_value_pb(original_pb, 'entity-baz')
        sub_pb = entity_pb2.Entity()
        sub_val_pb1 = _new_value_pb(sub_pb, 'x')
        sub_val_pb1.double_value = 3.14
        sub_val_pb2 = _new_value_pb(sub_pb, 'y')
        sub_val_pb2.double_value = 2.718281828
        val_pb3.meaning = 9
        val_pb3.entity_value.CopyFrom(sub_pb)

        # Add a list property.
        val_pb4 = _new_value_pb(original_pb, 'list-quux')
        list_val1 = val_pb4.list_value.add()
        list_val1.indexed = False
        list_val1.meaning = meaning = 22
        list_val1.blob_value = b'\xe2\x98\x83'
        list_val2 = val_pb4.list_value.add()
        list_val2.indexed = False
        list_val2.meaning = meaning
        list_val2.blob_value = b'\xe2\x98\x85'

        # Convert to the user-space Entity.
        entity = entity_from_protobuf(original_pb)
        # Convert the user-space Entity back to a protobuf.
        new_pb = self._callFUT(entity)

        # NOTE: entity_to_protobuf() strips the project so we "cheat".
        new_pb.key.partition_id.dataset_id = project
        self._compareEntityProto(original_pb, new_pb)
Beispiel #16
0
    def test_inverts_to_protobuf(self):
        from gcloud.datastore._generated import entity_pb2
        from gcloud.datastore.helpers import _new_value_pb
        from gcloud.datastore.helpers import entity_from_protobuf

        original_pb = entity_pb2.Entity()
        # Add a key.
        original_pb.key.partition_id.project_id = project = 'PROJECT'
        elem1 = original_pb.key.path.add()
        elem1.kind = 'Family'
        elem1.id = 1234
        elem2 = original_pb.key.path.add()
        elem2.kind = 'King'
        elem2.name = 'Spades'

        # Add an integer property.
        val_pb1 = _new_value_pb(original_pb, 'foo')
        val_pb1.integer_value = 1337
        val_pb1.exclude_from_indexes = True
        # Add a string property.
        val_pb2 = _new_value_pb(original_pb, 'bar')
        val_pb2.string_value = u'hello'

        # Add a nested (entity) property.
        val_pb3 = _new_value_pb(original_pb, 'entity-baz')
        sub_pb = entity_pb2.Entity()
        sub_val_pb1 = _new_value_pb(sub_pb, 'x')
        sub_val_pb1.double_value = 3.14
        sub_val_pb2 = _new_value_pb(sub_pb, 'y')
        sub_val_pb2.double_value = 2.718281828
        val_pb3.meaning = 9
        val_pb3.entity_value.CopyFrom(sub_pb)

        # Add a list property.
        val_pb4 = _new_value_pb(original_pb, 'list-quux')
        array_val1 = val_pb4.array_value.values.add()
        array_val1.exclude_from_indexes = False
        array_val1.meaning = meaning = 22
        array_val1.blob_value = b'\xe2\x98\x83'
        array_val2 = val_pb4.array_value.values.add()
        array_val2.exclude_from_indexes = False
        array_val2.meaning = meaning
        array_val2.blob_value = b'\xe2\x98\x85'

        # Convert to the user-space Entity.
        entity = entity_from_protobuf(original_pb)
        # Convert the user-space Entity back to a protobuf.
        new_pb = self._callFUT(entity)

        # NOTE: entity_to_protobuf() strips the project so we "cheat".
        new_pb.key.partition_id.project_id = project
        self._compareEntityProto(original_pb, new_pb)
Beispiel #17
0
    def fetch(self, limit=None):
        """Executes the Query and returns all matching entities.

        This makes an API call to the Cloud Datastore, sends the Query
        as a protobuf, parses the responses to Entity protobufs, and
        then converts them to :class:`gcloud.datastore.entity.Entity`
        objects.

        For example::

          >>> from gcloud import datastore
          >>> dataset = datastore.get_dataset('dataset-id', email, key_path)
          >>> query = dataset.query('Person').filter('name =', 'Sally')
          >>> query.fetch()
          [<Entity object>, <Entity object>, ...]
          >>> query.fetch(1)
          [<Entity object>]
          >>> query.limit()
          None

        :type limit: integer
        :param limit: An optional limit to apply temporarily to this query.
                      That is, the Query itself won't be altered,
                      but the limit will be applied to the query
                      before it is executed.

        :rtype: list of :class:`gcloud.datastore.entity.Entity`'s
        :returns: The list of entities matching this query's criteria.
        """
        clone = self

        if limit:
            clone = self.limit(limit)

        query_results = self.dataset().connection().run_query(
            query_pb=clone.to_protobuf(),
            dataset_id=self.dataset().id(),
            namespace=self._namespace,
            )
        # NOTE: `query_results` contains two extra values that we don't use,
        #       namely `more_results` and `skipped_results`. The value of
        #       `more_results` is unusable because it always returns an enum
        #       value of MORE_RESULTS_AFTER_LIMIT even if there are no more
        #       results. See
        #       https://github.com/GoogleCloudPlatform/gcloud-python/issues/280
        #       for discussion.
        entity_pbs, end_cursor = query_results[:2]

        self._cursor = end_cursor
        return [helpers.entity_from_protobuf(entity, dataset=self.dataset())
                for entity in entity_pbs]
Beispiel #18
0
    def get_entities(self, keys):
        """Retrieves entities from the dataset, along with their attributes.

        :type key: list of :class:`gcloud.datastore.key.Key`
        :param item_name: The name of the item to retrieve.

        :rtype: list of :class:`gcloud.datastore.entity.Entity`
        :return: The requested entities.
        """
        entity_pbs = self.connection().lookup(
            dataset_id=self.id(), key_pbs=[k.to_protobuf() for k in keys])

        entities = []
        for entity_pb in entity_pbs:
            entities.append(
                helpers.entity_from_protobuf(entity_pb, dataset=self))
        return entities
Beispiel #19
0
    def get_entities(self, keys):
        """Retrieves entities from the dataset, along with their attributes.

        :type key: list of :class:`gcloud.datastore.key.Key`
        :param item_name: The name of the item to retrieve.

        :rtype: list of :class:`gcloud.datastore.entity.Entity`
        :return: The requested entities.
        """
        entity_pbs = self.connection().lookup(
            dataset_id=self.id(),
            key_pbs=[k.to_protobuf() for k in keys]
        )

        entities = []
        for entity_pb in entity_pbs:
            entities.append(helpers.entity_from_protobuf(
                entity_pb, dataset=self))
        return entities
Beispiel #20
0
def get(keys, missing=None, deferred=None, connection=None, dataset_id=None):
    """Retrieves entities, along with their attributes.

    :type keys: list of :class:`gcloud.datastore.key.Key`
    :param keys: The keys to be retrieved from the datastore.

    :type missing: an empty list or None.
    :param missing: If a list is passed, the key-only entities returned
                    by the backend as "missing" will be copied into it.
                    Use only as a keyword param.

    :type deferred: an empty list or None.
    :param deferred: If a list is passed, the keys returned
                     by the backend as "deferred" will be copied into it.
                     Use only as a keyword param.

    :type connection: :class:`gcloud.datastore.connection.Connection`
    :param connection: Optional. The connection used to connect to datastore.
                       If not passed, inferred from the environment.

    :type dataset_id: :class:`gcloud.datastore.connection.Connection`
    :param dataset_id: Optional. The dataset ID used to connect to datastore.
                       If not passed, inferred from the environment.

    :rtype: list of :class:`gcloud.datastore.entity.Entity`
    :returns: The requested entities.
    :raises: EnvironmentError if ``connection`` or ``dataset_id`` not passed,
             and cannot be inferred from the environment.  ValueError if
             one or more of ``keys`` has a dataset ID which does not match
             the passed / inferred dataset ID.
    """
    if not keys:
        return []

    connection = _require_connection(connection)
    dataset_id = _require_dataset_id(dataset_id, keys[0])

    if list(set([key.dataset_id for key in keys])) != [dataset_id]:
        raise ValueError('Keys do not match dataset ID')

    transaction = Transaction.current()

    entity_pbs = _extended_lookup(
        connection,
        dataset_id=dataset_id,
        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]

    entities = []
    for entity_pb in entity_pbs:
        entities.append(helpers.entity_from_protobuf(entity_pb))

    return entities
Beispiel #21
0
 def _callFUT(self, val):
     from gcloud.datastore.helpers import entity_from_protobuf
     return entity_from_protobuf(val)
Beispiel #22
0
 def _callFUT(self, val):
     from gcloud.datastore.helpers import entity_from_protobuf
     return entity_from_protobuf(val)
Beispiel #23
0
    def fetch_page(self, limit=None):
        """Executes the Query and returns matching entities, and paging info.

        In addition to the fetched entities, it also returns a cursor to allow
        paging through a results set and a boolean `more_results` indicating
        if there are any more.

        This makes an API call to the Cloud Datastore, sends the Query
        as a protobuf, parses the responses to Entity protobufs, and
        then converts them to :class:`gcloud.datastore.entity.Entity`
        objects.

        For example::

          >>> from gcloud import datastore
          >>> dataset = datastore.get_dataset('dataset-id')
          >>> query = dataset.query('Person').filter('name', '=', 'Sally')
          >>> query.fetch_page()
          [<Entity object>, <Entity object>, ...], 'cursorbase64', True
          >>> query.fetch_page(1)
          [<Entity object>], 'cursorbase64', True
          >>> query.limit()
          None

        :type limit: integer
        :param limit: An optional limit to apply temporarily to this query.
                      That is, the Query itself won't be altered,
                      but the limit will be applied to the query
                      before it is executed.

        :rtype: tuple of mixed types
        :returns: The first entry is a :class:`gcloud.datastore.entity.Entity`
                  list matching this query's criteria. The second is a base64
                  encoded cursor for paging and the third is a boolean
                  indicating if there are more results.
        :raises: `ValueError` if more_results is not one of the enums
                 NOT_FINISHED, MORE_RESULTS_AFTER_LIMIT, NO_MORE_RESULTS.
        """
        clone = self

        if limit:
            clone = self.limit(limit)

        query_results = self.dataset().connection().run_query(
            query_pb=clone.to_protobuf(),
            dataset_id=self.dataset().id(),
            namespace=self._namespace,
            )
        # NOTE: `query_results` contains an extra value that we don't use,
        #       namely `skipped_results`.
        #
        # NOTE: The value of `more_results` is not currently useful because
        #       the back-end always returns an enum
        #       value of MORE_RESULTS_AFTER_LIMIT even if there are no more
        #       results. See
        #       https://github.com/GoogleCloudPlatform/gcloud-python/issues/280
        #       for discussion.
        entity_pbs, cursor_as_bytes, more_results_enum = query_results[:3]

        entities = [helpers.entity_from_protobuf(entity,
                                                 dataset=self.dataset())
                    for entity in entity_pbs]

        cursor = base64.b64encode(cursor_as_bytes)

        if more_results_enum == self._NOT_FINISHED:
            more_results = True
        elif more_results_enum in self._FINISHED:
            more_results = False
        else:
            raise ValueError('Unexpected value returned for `more_results`.')

        return entities, cursor, more_results
Beispiel #24
0
def get_multi(keys, missing=None, deferred=None,
              connection=None, dataset_id=None):
    """Retrieves entities, along with their attributes.

    :type keys: list of :class:`gcloud.datastore.key.Key`
    :param keys: The keys to be retrieved from the datastore.

    :type missing: an empty list or None.
    :param missing: If a list is passed, the key-only entities returned
                    by the backend as "missing" will be copied into it.
                    Use only as a keyword param.

    :type deferred: an empty list or None.
    :param deferred: If a list is passed, the keys returned
                     by the backend as "deferred" will be copied into it.
                     Use only as a keyword param.

    :type connection: :class:`gcloud.datastore.connection.Connection`
    :param connection: Optional. The connection used to connect to datastore.
                       If not passed, inferred from the environment.

    :type dataset_id: :class:`gcloud.datastore.connection.Connection`
    :param dataset_id: Optional. The dataset ID used to connect to datastore.
                       If not passed, inferred from the environment.

    :rtype: list of :class:`gcloud.datastore.entity.Entity`
    :returns: The requested entities.
    :raises: EnvironmentError if ``connection`` or ``dataset_id`` not passed,
             and cannot be inferred from the environment.  ValueError if
             one or more of ``keys`` has a dataset ID which does not match
             the passed / inferred dataset ID.
    """
    if not keys:
        return []

    connection = _require_connection(connection)
    dataset_id = _require_dataset_id(dataset_id, keys[0])

    if list(set([key.dataset_id for key in keys])) != [dataset_id]:
        raise ValueError('Keys do not match dataset ID')

    transaction = Transaction.current()

    entity_pbs = _extended_lookup(
        connection,
        dataset_id=dataset_id,
        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]

    entities = []
    for entity_pb in entity_pbs:
        entities.append(helpers.entity_from_protobuf(entity_pb))

    return entities