diff options
Diffstat (limited to 'doc/source/user/usage.rst')
-rw-r--r-- | doc/source/user/usage.rst | 184 |
1 files changed, 184 insertions, 0 deletions
diff --git a/doc/source/user/usage.rst b/doc/source/user/usage.rst new file mode 100644 index 0000000..1b2d996 --- /dev/null +++ b/doc/source/user/usage.rst @@ -0,0 +1,184 @@ +======= + Usage +======= + +To use oslo.db in a project: + +Session Handling +================ + +Session handling is achieved using the :mod:`oslo_db.sqlalchemy.enginefacade` +system. This module presents a function decorator as well as a +context manager approach to delivering :class:`.Session` as well as +:class:`.Connection` objects to a function or block. + +Both calling styles require the use of a context object. This object may +be of any class, though when used with the decorator form, requires +special instrumentation. + +The context manager form is as follows: + +.. code:: python + + + from oslo_db.sqlalchemy import enginefacade + + + class MyContext(object): + "User-defined context class." + + + def some_reader_api_function(context): + with enginefacade.reader.using(context) as session: + return session.query(SomeClass).all() + + + def some_writer_api_function(context, x, y): + with enginefacade.writer.using(context) as session: + session.add(SomeClass(x, y)) + + + def run_some_database_calls(): + context = MyContext() + + results = some_reader_api_function(context) + some_writer_api_function(context, 5, 10) + + +The decorator form accesses attributes off the user-defined context +directly; the context must be decorated with the +:func:`oslo_db.sqlalchemy.enginefacade.transaction_context_provider` +decorator. Each function must receive the context argument: + +.. code:: python + + + from oslo_db.sqlalchemy import enginefacade + + @enginefacade.transaction_context_provider + class MyContext(object): + "User-defined context class." + + @enginefacade.reader + def some_reader_api_function(context): + return context.session.query(SomeClass).all() + + + @enginefacade.writer + def some_writer_api_function(context, x, y): + context.session.add(SomeClass(x, y)) + + + def run_some_database_calls(): + context = MyContext() + + results = some_reader_api_function(context) + some_writer_api_function(context, 5, 10) + + +``connection`` modifier can be used when a :class:`.Session` object is not +needed, e.g. when `SQLAlchemy Core <http://docs.sqlalchemy.org/en/latest/core/>`_ +is preferred: + +.. code:: python + + @enginefacade.reader.connection + def _refresh_from_db(context, cache): + sel = sa.select([table.c.id, table.c.name]) + res = context.connection.execute(sel).fetchall() + cache.id_cache = {r[1]: r[0] for r in res} + cache.str_cache = {r[0]: r[1] for r in res} + + +.. note:: The ``context.session`` and ``context.connection`` attributes + must be accessed within the scope of an appropriate writer/reader block + (either the decorator or contextmanager approach). An AttributeError is + raised otherwise. + + +The decorator form can also be used with class and instance methods which +implicitly receive the first positional argument: + +.. code:: python + + class DatabaseAccessLayer(object): + + @classmethod + @enginefacade.reader + def some_reader_api_function(cls, context): + return context.session.query(SomeClass).all() + + @enginefacade.writer + def some_writer_api_function(self, context, x, y): + context.session.add(SomeClass(x, y)) + +.. note:: Note that enginefacade decorators must be applied **before** + `classmethod`, otherwise you will get a ``TypeError`` at import time + (as enginefacade will try to use ``inspect.getargspec()`` on a descriptor, + not on a bound method, please refer to the `Data Model + <https://docs.python.org/3/reference/datamodel.html#data-model>`_ section + of the Python Language Reference for details). + + +The scope of transaction and connectivity for both approaches is managed +transparently. The configuration for the connection comes from the standard +:obj:`oslo_config.cfg.CONF` collection. Additional configurations can be +established for the enginefacade using the +:func:`oslo_db.sqlalchemy.enginefacade.configure` function, before any use of +the database begins: + +.. code:: python + + from oslo_db.sqlalchemy import enginefacade + + enginefacade.configure( + sqlite_fk=True, + max_retries=5, + mysql_sql_mode='ANSI' + ) + + +Base class for models usage +=========================== + +.. code:: python + + from oslo_db.sqlalchemy import models + + + class ProjectSomething(models.TimestampMixin, + models.ModelBase): + id = Column(Integer, primary_key=True) + ... + + +DB API backend support +====================== + +.. code:: python + + from oslo_config import cfg + from oslo_db import api as db_api + + + _BACKEND_MAPPING = {'sqlalchemy': 'project.db.sqlalchemy.api'} + + IMPL = db_api.DBAPI.from_config(cfg.CONF, backend_mapping=_BACKEND_MAPPING) + + def get_engine(): + return IMPL.get_engine() + + def get_session(): + return IMPL.get_session() + + # DB-API method + def do_something(somethind_id): + return IMPL.do_something(somethind_id) + +DB migration extensions +======================= + +Available extensions for `oslo_db.migration`. + +.. list-plugins:: oslo_db.sqlalchemy.migration + :detailed: |