Asyncio Python Client for Google Cloud Datastore
================================================

|pypi| |pythons|

Installation
------------

.. code-block:: console

    $ pip install --upgrade gcloud-aio-datastore

Usage
-----

We're still working on documentation; for now, this should help get you
started:

.. code-block:: python

    from gcloud.aio.datastore import Datastore
    from gcloud.aio.datastore import Filter
    from gcloud.aio.datastore import GQLQuery
    from gcloud.aio.datastore import Key
    from gcloud.aio.datastore import PathElement
    from gcloud.aio.datastore import PropertyFilter
    from gcloud.aio.datastore import PropertyFilterOperator
    from gcloud.aio.datastore import Query
    from gcloud.aio.datastore import Value

    ds = Datastore('my-gcloud-project', '/path/to/creds.json')
    key1 = Key('my-gcloud-project', [PathElement('Kind', 'entityname')])
    key2 = Key('my-gcloud-project', [PathElement('Kind', 'entityname2')])

    # batched lookups
    entities = await ds.lookup([key1, key2])

    # convenience functions for any datastore mutations
    await ds.insert(key1, {'a_boolean': True, 'meaning_of_life': 41})
    await ds.update(key1, {'a_boolean': True, 'meaning_of_life': 42})
    await ds.upsert(key1, {'animal': 'aardvark'})
    await ds.delete(key1)

    # or build your own mutation sequences with full transaction support
    transaction = await ds.beginTransaction()
    try:
        mutations = [
            ds.make_mutation(Operation.INSERT, key1, properties={'animal': 'sloth'}),
            ds.make_mutation(Operation.UPSERT, key1, properties={'animal': 'aardvark'}),
            ds.make_mutation(Operation.INSERT, key2, properties={'animal': 'aardvark'}),
        ]
        await ds.commit(transaction, mutations=[mutation])
    except Exception:
        await ds.rollback(transaction)

    # support for partial keys
    partial_key = Key('my-gcloud-project', [PathElement('Kind')])
    # and ID allocation or reservation
    allocated_keys = await ds.allocateIds([partial_key])
    await ds.reserveIds(allocated_keys)

    # query support
    property_filter = PropertyFilter(prop='answer',
                                     operator=PropertyFilterOperator.EQUAL,
                                     value=Value(42))
    query = Query(kind='the_meaning_of_life',
                  query_filter=Filter(property_filter))
    results = await ds.runQuery(query, session=s)

    # alternatively, query support using GQL
    gql_query = GQLQuery('SELECT * FROM the_meaning_of_life WHERE answer = @answer',
                         named_bindings={'answer': 42})
    results = await ds.runQuery(gql_query, session=s)

Custom Subclasses
~~~~~~~~~~~~~~~~~

``gcloud-aio-datastore`` provides class interfaces mirroring all official
Google API types, ie. ``Key`` and ``PathElement``, ``Entity`` and
``EntityResult``, and ``QueryResultBatch``. These types will be returned from
arbitrary Datastore operations, for example ``Datastore.allocateIds(...)`` will
return a list of ``Key`` entities.

For advanced usage, all of these datatypes may be overloaded. A common use-case
may be to deserialize entities into more specific classes. For example, given a
custom entity class such as:

.. code-block:: python

    class MyEntityKind(gcloud.aio.datastore.Entity):
        def __init__(self, key, properties = None) -> None:
            self.key = key
            self.is_an_aardvark = (properties or {}).get('aardvark', False)

        def __repr__(self):
            return "I'm an aardvark!" if self.is_an_aardvark else "Sorry, nope"

We can then configure ``gcloud-aio-datastore`` to serialize/deserialize from
this custom entity class with:

.. code-block:: python

    class MyCustomDatastore(gcloud.aio.datastore.Datastore):
        entity_result_kind.entity_kind = MyEntityKind

The full list of classes which may be overridden in this way is:

.. code-block:: python

    class MyVeryCustomDatastore(gcloud.aio.datastore.Datastore):
        entity_result_kind = EntityResult
        entity_result_kind.entity_kind = Entity
        entity_result_kind.entity_kind.key_kind = Key
        key_kind = Key
        key_kind.path_element_kind = PathElement
        query_result_batch_kind = QueryResultBatch
        query_result_batch_kind.entity_result_kind = EntityResult

You can then drop-in the ``MyVeryCustomDatastore`` class anywhere where you
previously used ``Datastore``.

Contributing
------------

Please see our `contributing guide`_.

.. _contributing guide: https://github.com/talkiq/gcloud-aio/blob/master/.github/CONTRIBUTING.rst

.. |pypi| image:: https://img.shields.io/pypi/v/gcloud-aio-datastore.svg?style=flat-square
    :alt: Latest PyPI Version
    :target: https://pypi.org/project/gcloud-aio-datastore/

.. |pythons| image:: https://img.shields.io/pypi/pyversions/gcloud-aio-datastore.svg?style=flat-square
    :alt: Python Version Support
    :target: https://pypi.org/project/gcloud-aio-datastore/
