Continuum Schema
****************


Version tables
==============

By default SQLAlchemy-Continuum creates a version table for each
versioned entity table. The version tables are suffixed with
'_version'. So for example if you have two versioned tables 'article'
and 'category', SQLAlchemy-Continuum would create two version tables
'article_version' and 'category_version'.

By default the version tables contain these columns:

* id of the original entity (this can be more then one column in the
  case of composite primary keys)

* transaction_id - an integer that matches to the id number in the
  transaction_log table.

* end_transaction_id - an integer that matches the next version
  record's transaction_id. If this is the current version record then
  this field is null.

* operation_type - a small integer defining the type of the operation

* versioned fields from the original entity

If you are using PropertyModTracker Continuum also creates one boolean
field for each versioned field. By default these boolean fields are
suffixed with '_mod'.

The primary key of each version table is the combination of parent
table's primary key + the transaction_id. This means there can be at
most one version table entry for a given entity instance at given
transaction.


Transaction tables
==================

By default Continuum creates one transaction table called
*transaction*. Many continuum plugins also create additional tables
for efficient transaction storage. If you wish to query efficiently
transactions afterwards you should consider using some of these
plugins.

The transaction table only contains two fields by default: id and
issued_at.


Using vacuum
============

sqlalchemy_continuum.vacuum(session, model, yield_per=1000)

   When making structural changes to version tables (for example
   dropping columns) there are sometimes situations where some old
   version records become futile.

   Vacuum deletes all futile version rows which had no changes
   compared to previous version.

      from sqlalchemy_continuum import vacuum


      vacuum(session, User)  # vacuums user version

   Parameters:
      * **session** -- SQLAlchemy session object

      * **model** -- SQLAlchemy declarative model class

      * **yield_per** -- how many rows to process at a time


Schema tools
============

sqlalchemy_continuum.schema.update_end_tx_column(table, end_tx_column_name='end_transaction_id', tx_column_name='transaction_id', conn=None)

   Calculates end transaction columns and updates the version table
   with the calculated values. This function can be used for migrating
   between subquery versioning strategy and validity versioning
   strategy.

   Parameters:
      * **table** -- SQLAlchemy table object

      * **end_tx_column_name** -- Name of the end transaction column

      * **tx_column_name** -- Transaction column name

      * **conn** --

        Either SQLAlchemy Connection, Engine, Session or Alembic
        Operations object. Basically this should be an object that can
        execute the queries needed to update the end transaction
        column values.

        If no object is given then this function tries to use
        alembic.op for executing the queries.

sqlalchemy_continuum.schema.update_property_mod_flags(table, tracked_columns, mod_suffix='_mod', end_tx_column_name='end_transaction_id', tx_column_name='transaction_id', conn=None)

   Update property modification flags for given table and given
   columns. This function can be used for migrating an existing schema
   to use property mod flags (provided by PropertyModTracker plugin).

   Parameters:
      * **table** -- SQLAlchemy table object

      * **mod_suffix** -- Modification tracking columns suffix

      * **end_tx_column_name** -- Name of the end transaction column

      * **tx_column_name** -- Transaction column name

      * **conn** --

        Either SQLAlchemy Connection, Engine, Session or Alembic
        Operations object. Basically this should be an object that can
        execute the queries needed to update the property modification
        flags.

        If no object is given then this function tries to use
        alembic.op for executing the queries.
