mirror of
https://github.com/bigchaindb/bigchaindb.git
synced 2024-10-13 13:34:05 +00:00
Abstract db layer cherrypick docs (#932)
* Add README.md to tests/ to describe test structure and pytest customizations * Add package-level docstrings to backends * Add README.md explaining the backend architecture * Small improvements to docstrings in backend modules * Restructure the backend automodule docs * Add more docstrings to backend connections * Add init to base backend Connection class to document expected interface * Reword the backend/README.md docs
This commit is contained in:
parent
4c3d5f0e2b
commit
8a68e24e69
45
bigchaindb/backend/README.md
Normal file
45
bigchaindb/backend/README.md
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
# Backend Interfaces
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
- [`changefeed.py`](./changefeed.py): Changefeed-related interfaces
|
||||||
|
- [`connection.py`](./connection.py): Database connection-related interfaces
|
||||||
|
- [`query.py`](./query.py): Database query-related interfaces, dispatched through single-dispatch
|
||||||
|
- [`schema.py`](./schema.py): Database setup and schema-related interfaces, dispatched through
|
||||||
|
single-dispatch
|
||||||
|
|
||||||
|
Built-in implementations (e.g. [RethinkDB's](./rethinkdb)) are provided in sub-directories and
|
||||||
|
have their connection type's location exposed as `BACKENDS` in [`connection.py`](./connection.py).
|
||||||
|
|
||||||
|
## Single-Dispatched Interfaces
|
||||||
|
|
||||||
|
The architecture of this module is based heavily upon Python's newly-introduced [single-dispatch
|
||||||
|
generic functions](https://www.python.org/dev/peps/pep-0443/). Single-dispatch is convenient,
|
||||||
|
because it allows Python, rather than something we design ourselves, to manage the dispatching of
|
||||||
|
generic functions based on certain conditions being met (e.g. the database backend to use).
|
||||||
|
|
||||||
|
To see what this looks like in BigchainDB, first note that our backend interfaces have been
|
||||||
|
configured to dispatch based on a backend's **connection type**.
|
||||||
|
|
||||||
|
Call `bigchaindb.backend.connect()` to create an instance of a `Connection`:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from bigchaindb.backend import connect
|
||||||
|
connection = connect() # By default, uses the current configuration for backend, host, port, etc.
|
||||||
|
```
|
||||||
|
|
||||||
|
Then, we can call a backend function by directly calling its interface:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from bigchaindb.backend import query
|
||||||
|
query.write_transaction(connection, ...)
|
||||||
|
```
|
||||||
|
|
||||||
|
Notice that we don't need to care about which backend implementation to use or how to access it.
|
||||||
|
Code can simply call the base interface function with a `Connection` instance, and single-dispatch
|
||||||
|
will handle routing the call to the actual implementation.
|
||||||
|
|
||||||
|
BigchainDB will load and register the configured backend's implementation automatically (see
|
||||||
|
`bigchaindb.backend.connect()`), so you should always just be able to call an interface function if
|
||||||
|
you have a `Connection` instance. A few helper utilities (see [`backend/utils.py`](./utils.py)) are
|
||||||
|
also provided to make registering new backend implementations easier.
|
@ -1,4 +1,10 @@
|
|||||||
"""Backend interfaces ..."""
|
"""Generic backend database interfaces expected by BigchainDB.
|
||||||
|
|
||||||
|
The interfaces in this module allow BigchainDB to be agnostic about its
|
||||||
|
database backend. One can configure BigchainDB to use different databases as
|
||||||
|
its data store by setting the ``database.backend`` property in the
|
||||||
|
configuration or the ``BIGCHAINDB_DATABASE_BACKEND`` environment variable.
|
||||||
|
"""
|
||||||
|
|
||||||
# Include the backend interfaces
|
# Include the backend interfaces
|
||||||
from bigchaindb.backend import changefeed, schema, query # noqa
|
from bigchaindb.backend import changefeed, schema, query # noqa
|
||||||
|
@ -1 +1 @@
|
|||||||
"""Changefeed interfaces for backend databases."""
|
"""Changefeed interfaces for backends."""
|
||||||
|
@ -9,7 +9,10 @@ BACKENDS = {
|
|||||||
|
|
||||||
|
|
||||||
def connect(backend=None, host=None, port=None, name=None):
|
def connect(backend=None, host=None, port=None, name=None):
|
||||||
"""Create a connection to the database backend.
|
"""Create a new connection to the database backend.
|
||||||
|
|
||||||
|
All arguments default to the current configuration's values if not
|
||||||
|
given.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
backend (str): the name of the backend to use.
|
backend (str): the name of the backend to use.
|
||||||
@ -18,7 +21,12 @@ def connect(backend=None, host=None, port=None, name=None):
|
|||||||
name (str): the name of the database to use.
|
name (str): the name of the database to use.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
An instance of :class:`~bigchaindb.backend.connection.Connection`.
|
An instance of :class:`~bigchaindb.backend.connection.Connection`
|
||||||
|
based on the given (or defaulted) :attr:`backend`.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
:exc:`~ConfigurationError`: If the given (or defaulted) :attr:`backend`
|
||||||
|
is not supported or could not be loaded.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
backend = backend or bigchaindb.config['database']['backend']
|
backend = backend or bigchaindb.config['database']['backend']
|
||||||
@ -39,6 +47,28 @@ def connect(backend=None, host=None, port=None, name=None):
|
|||||||
|
|
||||||
|
|
||||||
class Connection:
|
class Connection:
|
||||||
|
"""Connection class interface.
|
||||||
|
|
||||||
|
All backend implementations should provide a connection class that
|
||||||
|
from and implements this class.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, host=None, port=None, dbname=None, *args, **kwargs):
|
||||||
|
"""Create a new :class:`~.Connection` instance.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
host (str): the host to connect to.
|
||||||
|
port (int): the port to connect to.
|
||||||
|
dbname (str): the name of the database to use.
|
||||||
|
**kwargs: arbitrary keyword arguments provided by the
|
||||||
|
configuration's ``database`` settings
|
||||||
|
"""
|
||||||
|
|
||||||
def run(self, query):
|
def run(self, query):
|
||||||
|
"""Run a query.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
query: the query to run
|
||||||
|
"""
|
||||||
|
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
"""Query interfaces for backend databases."""
|
"""Query interfaces for backends."""
|
||||||
|
|
||||||
from functools import singledispatch
|
from functools import singledispatch
|
||||||
|
|
||||||
|
@ -1,4 +1,22 @@
|
|||||||
"""RethinkDB backend components ..."""
|
"""RethinkDB backend implementation.
|
||||||
|
|
||||||
|
Contains a RethinkDB-specific implementation of the
|
||||||
|
:mod:`~bigchaindb.backend.changefeed`, :mod:`~bigchaindb.backend.query`, and
|
||||||
|
:mod:`~bigchaindb.backend.schema` interfaces.
|
||||||
|
|
||||||
|
You can specify BigchainDB to use RethinkDB as its database backend by either
|
||||||
|
setting ``database.backend`` to ``'rethinkdb'`` in your configuration file, or
|
||||||
|
setting the ``BIGCHAINDB_DATABASE_BACKEND`` environment variable to
|
||||||
|
``'rethinkdb'``.
|
||||||
|
|
||||||
|
If configured to use RethinkDB, BigchainDB will automatically return instances
|
||||||
|
of :class:`~bigchaindb.backend.rethinkdb.RethinkDBConnection` for
|
||||||
|
:func:`~bigchaindb.backend.connection.connect` and dispatch calls of the
|
||||||
|
generic backend interfaces to the implementations in this module.
|
||||||
|
"""
|
||||||
|
|
||||||
# Register the single dispatched modules on import.
|
# Register the single dispatched modules on import.
|
||||||
from bigchaindb.backend.rethinkdb import changefeed, schema, query # noqa
|
from bigchaindb.backend.rethinkdb import changefeed, schema, query # noqa
|
||||||
|
|
||||||
|
# RethinkDBConnection should always be accessed via
|
||||||
|
# ``bigchaindb.backend.connect()``.
|
||||||
|
@ -18,12 +18,12 @@ class RethinkDBConnection(Connection):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, host, port, dbname, max_tries=3):
|
def __init__(self, host, port, dbname, max_tries=3):
|
||||||
"""Create a new Connection instance.
|
"""Create a new :class:`~.RethinkDBConnection` instance.
|
||||||
|
|
||||||
|
See :meth:`.Connection.__init__` for
|
||||||
|
:attr:`host`, :attr:`port`, and :attr:`dbname`.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
host (str): the host to connect to.
|
|
||||||
port (int): the port to connect to.
|
|
||||||
dbname (str): the name of the database to use.
|
|
||||||
max_tries (int, optional): how many tries before giving up.
|
max_tries (int, optional): how many tries before giving up.
|
||||||
Defaults to 3.
|
Defaults to 3.
|
||||||
"""
|
"""
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
"""Query implementation for RethinkDB"""
|
|
||||||
|
|
||||||
from time import time
|
from time import time
|
||||||
|
|
||||||
import rethinkdb as r
|
import rethinkdb as r
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
"""Utils to initialize and drop the database."""
|
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
import rethinkdb as r
|
import rethinkdb as r
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
"""Schema-providing interfaces for backend databases"""
|
"""Database creation and schema-providing interfaces for backends."""
|
||||||
|
|
||||||
from functools import singledispatch
|
from functools import singledispatch
|
||||||
|
|
||||||
|
@ -1,41 +1,41 @@
|
|||||||
###############################################
|
###########################
|
||||||
:mod:`bigchaindb.backend` -- Backend Interfaces
|
Database Backend Interfaces
|
||||||
###############################################
|
###########################
|
||||||
|
|
||||||
.. automodule:: bigchaindb.backend
|
.. automodule:: bigchaindb.backend
|
||||||
:special-members: __init__
|
:special-members: __init__
|
||||||
|
|
||||||
|
|
||||||
Generic Backend
|
Generic Interfaces
|
||||||
===============
|
==================
|
||||||
|
|
||||||
:mod:`bigchaindb.backend.connection` -- Connection
|
:mod:`bigchaindb.backend.connection`
|
||||||
--------------------------------------------------
|
------------------------------------
|
||||||
|
|
||||||
.. automodule:: bigchaindb.backend.connection
|
.. automodule:: bigchaindb.backend.connection
|
||||||
|
:special-members: __init__
|
||||||
|
|
||||||
:mod:`bigchaindb.backend.schema` -- Schema
|
:mod:`bigchaindb.backend.changefeed`
|
||||||
------------------------------------------
|
------------------------------------
|
||||||
.. automodule:: bigchaindb.backend.schema
|
.. automodule:: bigchaindb.backend.changefeed
|
||||||
|
|
||||||
:mod:`bigchaindb.backend.query` -- Query
|
:mod:`bigchaindb.backend.query`
|
||||||
----------------------------------------
|
-------------------------------
|
||||||
.. automodule:: bigchaindb.backend.query
|
.. automodule:: bigchaindb.backend.query
|
||||||
|
|
||||||
:mod:`bigchaindb.backend.changefeed` -- Changefeed
|
:mod:`bigchaindb.backend.schema`
|
||||||
--------------------------------------------------
|
--------------------------------
|
||||||
.. automodule:: bigchaindb.backend.changefeed
|
.. automodule:: bigchaindb.backend.schema
|
||||||
|
|
||||||
:mod:`bigchaindb.backend.utils`
|
:mod:`bigchaindb.backend.utils`
|
||||||
-------------------------------
|
-------------------------------
|
||||||
.. automodule:: bigchaindb.backend.utils
|
.. automodule:: bigchaindb.backend.utils
|
||||||
|
|
||||||
|
|
||||||
:mod:`bigchaindb.backend.rethinkdb` -- RethinkDB Backend
|
RethinkDB Backend
|
||||||
========================================================
|
=================
|
||||||
|
|
||||||
.. automodule:: bigchaindb.backend.rethinkdb
|
.. automodule:: bigchaindb.backend.rethinkdb
|
||||||
:special-members: __init__
|
|
||||||
|
|
||||||
:mod:`bigchaindb.backend.rethinkdb.connection`
|
:mod:`bigchaindb.backend.rethinkdb.connection`
|
||||||
----------------------------------------------
|
----------------------------------------------
|
||||||
|
18
tests/README.md
Normal file
18
tests/README.md
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Tests
|
||||||
|
|
||||||
|
## Test Structure
|
||||||
|
|
||||||
|
Generally all tests are meant to be unit tests, with the exception of those in the [`integration/` folder](./integration/).
|
||||||
|
|
||||||
|
A few notes:
|
||||||
|
|
||||||
|
- [`common/`](./common/) contains self-contained tests only testing
|
||||||
|
[`bigchaindb/common/`](../bigchaindb/common/)
|
||||||
|
- [`db/`](./db/) contains tests requiring the database backend (e.g. RethinkDB)
|
||||||
|
|
||||||
|
## Pytest Customizations
|
||||||
|
|
||||||
|
Customizations we've added to `pytest`:
|
||||||
|
|
||||||
|
- `--database-backend`: Defines the backend to use for the tests. Must be one of the backends
|
||||||
|
available in the [server configuration](https://docs.bigchaindb.com/projects/server/en/latest/server-reference/configuration.html)
|
@ -25,7 +25,7 @@ def mock_changefeed_data():
|
|||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def mock_changefeed_bigchain(mock_changefeed_data):
|
def mock_changefeed_bigchain(mock_changefeed_data):
|
||||||
connection = Connection()
|
connection = Connection(host=None, port=None, dbname=None)
|
||||||
connection.run = Mock(return_value=mock_changefeed_data)
|
connection.run = Mock(return_value=mock_changefeed_data)
|
||||||
return Bigchain(connection=connection)
|
return Bigchain(connection=connection)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user