Skip to content

API reference

sqlalchemy_continuum.make_versioned(mapper=sa.orm.Mapper, session=sa.orm.session.Session, manager=versioning_manager, plugins=None, options=None, user_cls='User')

This is the public API function of SQLAlchemy-Continuum for making certain mappers and sessions versioned. By default this applies to all mappers and all sessions.

Parameters:

Name Type Description Default
mapper

SQLAlchemy mapper to apply the versioning to.

Mapper
session

SQLAlchemy session to apply the versioning to. By default this is sa.orm.session.Session meaning it applies to all Session subclasses.

Session
manager

SQLAlchemy-Continuum versioning manager.

versioning_manager
plugins

Plugins to pass for versioning manager.

None
options

A dictionary of VersioningManager options.

None
user_cls

User class which the Transaction class should have relationship to. This can either be a class or string name of a class for lazy evaluation.

'User'

Versioning Manager

sqlalchemy_continuum.manager.VersioningManager

VersioningManager delegates versioning configuration operations to builder classes and the actual versioning to UnitOfWork class. Manager contains configuration options that act as defaults for all versioned classes.

Parameters:

Name Type Description Default
unit_of_work_cls

The UnitOfWork class to use for initializing UnitOfWork objects for versioning

UnitOfWork
transaction_cls

Transaction class to use for versioning. If None, the default Transaction class generated by TransactionFactory will be used.

None
user_cls

User class which Transaction class should have relationship to. This can either be a class or string name of a class for lazy evaluation.

None
options

Versioning options

None
plugins

Versioning plugins that listen the events invoked by the manager.

None
builder

Builder object which handles the building of versioning tables and models.

None

after_flush(session, flush_context)

After flush listener for SQLAlchemy sessions. If this manager has versioning enabled this listener gets the UnitOfWork associated with session's connections and invokes the process_after_flush method of that object.

Parameters:

Name Type Description Default
session

SQLAlchemy session

required

append_association_operation(conn, table_name, params, op)

Append history association operation to pending_statements list.

apply_class_configuration_listeners(mapper)

Applies class configuration listeners for given mapper.

The listener work in two phases:

  1. Class instrumentation phase The first listeners listens to class instrumentation event and handles the collecting of versioned models and adds them to the pending_classes list.
  2. After class configuration phase The second listener listens to after class configuration event and handles the actual history model generation based on list that was collected during class instrumenation phase.

Parameters:

Name Type Description Default
mapper

SQLAlchemy mapper to apply the class configuration listeners to

required

before_flush(session, flush_context, instances)

Before flush listener for SQLAlchemy sessions. If this manager has versioning enabled this listener invokes the process before flush of associated UnitOfWork object.

Parameters:

Name Type Description Default
session

SQLAlchemy session

required

clear(session)

Simple SQLAlchemy listener that is being invoked after successful transaction commit or when transaction rollback occurs. The purpose of this listener is to reset this UnitOfWork back to its initialization state.

Parameters:

Name Type Description Default
session

SQLAlchemy session object

required

create_transaction_model()

Create Transaction class but only if it doesn't already exist in declarative model registry.

is_excluded_property(model, key)

Returns whether or not given property of given model is excluded from the associated history model.

Parameters:

Name Type Description Default
model

SQLAlchemy declarative model object.

required
key

Model property key

required

option(model, name)

Returns the option value for given model. If the option is not found from given model falls back to default values of this manager object. If the option is not found from this manager object either this method throws a KeyError.

Parameters:

Name Type Description Default
model

SQLAlchemy declarative object

required
name

name of the versioning option

required

remove_class_configuration_listeners(mapper)

Remove versioning class configuration listeners from specified mapper.

Parameters:

Name Type Description Default
mapper

mapper to remove class configuration listeners from

required

remove_operations_tracking(mapper)

Remove listeners from specified mapper that track SQL inserts, updates and deletes.

Parameters:

Name Type Description Default
mapper

mapper to remove the SQL operations tracking listeners from

required

remove_session_tracking(session)

Remove listeners that track the operations (flushing, committing and rolling back) of given session. This method should be used in conjunction with remove_operations_tracking.

Parameters:

Name Type Description Default
session

SQLAlchemy session to remove the operations tracking from

required

reset()

Resets this manager's internal state.

This method should be used in test cases that create models on the fly. Otherwise history_class_map and some other variables would be polluted by no more used model classes.

track_cloned_connections(c, opt)

Track cloned connections from association tables.

track_deletes(uow, target)

Track object deletion operations. Whenever object is deleted it is added to this UnitOfWork's internal operations dictionary.

track_inserts(uow, target)

Track object insert operations. Whenever object is inserted it is added to this UnitOfWork's internal operations dictionary.

track_operations(mapper)

Attach listeners for specified mapper that track SQL inserts, updates and deletes.

Parameters:

Name Type Description Default
mapper

mapper to track the SQL operations from

required

track_session(session)

Attach listeners that track the operations (flushing, committing and rolling back) of given session. This method should be used in conjunction with track_operations.

Parameters:

Name Type Description Default
session

SQLAlchemy session to track the operations from

required

track_updates(uow, target)

Track object update operations. Whenever object is updated it is added to this UnitOfWork's internal operations dictionary.

unit_of_work(session)

Return the associated SQLAlchemy-Continuum UnitOfWork object for given SQLAlchemy session object.

If no UnitOfWork object exists for given object then this method tries to create one.

Parameters:

Name Type Description Default
session

SQLAlchemy session object

required

Builders

sqlalchemy_continuum.table_builder.TableBuilder

TableBuilder handles the building of version tables based on parent table's structure and versioning configuration options.

table_name property

Returns the version table name for current parent table.

__call__(extends=None)

Builds version table.

sqlalchemy_continuum.model_builder.ModelBuilder

VersionedModelBuilder handles the building of Version models based on parent table attributes and versioning configuration.

__call__(table, tx_class)

Build history model and relationships to parent model, transaction log model.

__init__(versioning_manager, model)

Parameters:

Name Type Description Default
versioning_manager

VersioningManager object

required
model

SQLAlchemy declarative model object that acts as a parent for the built version model

required

base_classes()

Returns all base classes for history model.

build_model(table)

Build history model class.

build_parent_relationship()

Builds a relationship between currently built version class and parent class (the model whose history the currently build version class represents).

build_transaction_relationship(tx_class)

Builds a relationship between currently built version class and Transaction class.

Parameters:

Name Type Description Default
tx_class

Transaction class

required

inheritance_args(cls, version_table, table)

Return mapper inheritance args for currently built history model.

sqlalchemy_continuum.relationship_builder.RelationshipBuilder

__call__()

Builds reflected relationship between version classes based on given parent object's RelationshipProperty.

association_subquery(obj)

Returns an EXISTS clause that checks if an association exists for given SQLAlchemy declarative object. This query is used by many_to_many_criteria method.

Example query:

EXISTS (
    SELECT 1
    FROM article_tag_version
    WHERE article_id = 3
    AND tag_id = tags_version.id
    AND operation_type != 2
    AND EXISTS (
        SELECT 1
        FROM article_tag_version as article_tag_version2
        WHERE article_tag_version2.tag_id = article_tag_version.tag_id
        AND article_tag_version2.tx_id <=5
        AND article_tag_version2.article_id = 3
        GROUP BY article_tag_version2.tag_id
        HAVING
            MAX(article_tag_version2.tx_id) =
            article_tag_version.tx_id
    )
)

Parameters:

Name Type Description Default
obj

SQLAlchemy declarative object

required

build_association_version_tables()

Builds many-to-many association version table for given property. Association version tables are used for tracking change history of many-to-many associations.

many_to_many_criteria(obj)

Returns the many-to-many query.

Looks up remote items through associations and for each item returns returns the last version with a transaction less than or equal to the transaction of obj. This must hold true for both the association and the remote relation items.

Example

Select all tags of article with id 3 and transaction 5

SELECT tags_version.*
FROM tags_version
WHERE EXISTS (
    SELECT 1
    FROM article_tag_version
    WHERE article_id = 3
    AND tag_id = tags_version.id
    AND operation_type != 2
    AND EXISTS (
        SELECT 1
        FROM article_tag_version as article_tag_version2
        WHERE article_tag_version2.tag_id = article_tag_version.tag_id
        AND article_tag_version2.tx_id <= 5
        GROUP BY article_tag_version2.tag_id
        HAVING
            MAX(article_tag_version2.tx_id) =
            article_tag_version.tx_id
    )
)
AND EXISTS (
    SELECT 1
    FROM tags_version as tags_version_2
    WHERE tags_version_2.id = tags_version.id
    AND tags_version_2.tx_id <= 5
    GROUP BY tags_version_2.id
    HAVING MAX(tags_version_2.tx_id) = tags_version.tx_id
)
AND operation_type != 2

many_to_one_criteria(obj)

Returns the many-to-one query.

Returns the item on the 'one' side with the highest transaction id as long as it is less or equal to the transaction id of the obj.

Example

Look up the Article of a Tag with article_id = 4 and transaction_id = 5

SELECT *
FROM articles_version
WHERE id = 4
AND transaction_id = (
    SELECT max(transaction_id)
    FROM articles_version
    WHERE transaction_id <= 5
    AND id = 4
)
AND operation_type != 2

one_to_many_criteria(obj)

Returns the one-to-many query.

For each item on the 'many' side, returns its latest version as long as the transaction of that version is less than equal of the transaction of obj.

Example

Using the Article-Tags relationship, where we look for tags of article_version with id = 3 and transaction = 5 the sql produced is

SELECT tags_version.*
FROM tags_version
WHERE tags_version.article_id = 3
AND tags_version.operation_type != 2
AND EXISTS (
    SELECT 1
    FROM tags_version as tags_version_last
    WHERE tags_version_last.transaction_id <= 5
    AND tags_version_last.id = tags_version.id
    GROUP BY tags_version_last.id
    HAVING
        MAX(tags_version_last.transaction_id) =
        tags_version.transaction_id
)

process_query(query)

Process given SQLAlchemy Query object depending on the associated RelationshipProperty object.

Parameters:

Name Type Description Default
query

SQLAlchemy Query object

required

reflected_relationship()

Builds a reflected one-to-many, one-to-one and many-to-one relationship between two version classes.

UnitOfWork

sqlalchemy_continuum.unit_of_work.UnitOfWork

has_changes property

Return whether or not this unit of work has changes.

assign_attributes(parent_obj, version_obj)

Assign attributes values from parent object to version object.

Parameters:

Name Type Description Default
parent_obj

Parent object to get the attribute values from

required
version_obj

Version object to assign the attribute values to

required

create_association_versions(session)

Creates association table version records for given session.

Parameters:

Name Type Description Default
session

SQLAlchemy session object

required

create_transaction(session)

Create transaction object for given SQLAlchemy session.

Parameters:

Name Type Description Default
session

SQLAlchemy session object

required

create_version_objects(session)

Create version objects for given session based on operations collected by insert, update and deleted trackers.

Parameters:

Name Type Description Default
session

SQLAlchemy session object

required

get_or_create_version_object(target)

Return version object for given parent object. If no version object exists for given parent object, create one.

Parameters:

Name Type Description Default
target

Parent object to create the version object for

required

is_modified(session)

Return whether or not given session has been modified. Session has been modified if any versioned property of any version object in given session has been modified or if any of the plugins returns that session has been modified.

Parameters:

Name Type Description Default
session

SQLAlchemy session object

required

make_versions(session)

Create transaction, transaction changes records, version objects.

Parameters:

Name Type Description Default
session

SQLAlchemy session object

required

process_after_flush(session)

After flush processor for given session.

Creates version objects for all modified versioned parent objects that were affected during the flush phase.

Parameters:

Name Type Description Default
session

SQLAlchemy session object

required

process_before_flush(session)

Before flush processor for given session.

This method creates a version session which is later on used for the creation of version objects. It also creates Transaction object for the current transaction and invokes before_flush template method on all plugins.

If the given session had no relevant modifications regarding versioned objects this method does nothing.

Parameters:

Name Type Description Default
session

SQLAlchemy session object

required

process_operation(operation)

Process given operation object. The operation processing has x stages:

  1. Get or create a version object for given parent object
  2. Assign the operation type for this object
  3. Invoke listeners
  4. Update version validity in case validity strategy is used
  5. Mark operation as processed

Parameters:

Name Type Description Default
operation

Operation object

required

reset(session=None)

Reset the internal state of this UnitOfWork object. Normally this is called after transaction has been committed or rolled back.

update_version_validity(parent, version_obj)

Updates previous version object end_transaction_id based on given parent object and newly created version object.

This method is only used when using 'validity' versioning strategy.

Parameters:

Name Type Description Default
parent

SQLAlchemy declarative parent object

required
version_obj

SQLAlchemy declarative version object

See also: version_validity_subquery

required

version_validity_subquery(parent, version_obj, alias=None)

Return the subquery needed by update_version_validity.

This method is only used when using 'validity' versioning strategy.

Parameters:

Name Type Description Default
parent

SQLAlchemy declarative parent object

required
version_obj

SQLAlchemy declarative version object

See also: update_version_validity

required

History class

sqlalchemy_continuum.version.VersionClassBase

changeset property

Return a dictionary of changed fields in this version with keys as field names and values as lists with first value as the old field value and second list value as the new value.

index property

Return the index of this version in the version history.

next property

Returns the next version relative to this version in the version history. If current version is the last version this method returns None.

If versions have been pre-fetched using all_versions() with link_versions(), this will use the cached value instead of making a database query.

previous property

Returns the previous version relative to this version in the version history. If current version is the first version this method returns None.

If versions have been pre-fetched using all_versions() with link_versions(), this will use the cached value instead of making a database query.

all_versions(session, primary_key_values, limit=None, offset=0, desc=True, link=True) classmethod

Efficiently fetch all versions for an entity in a single query.

This avoids N+1 queries when iterating through version history by fetching all versions at once. When link=True, the returned versions will have their .previous and .next properties pre-populated from the cache.

Example:

# Get all versions of Article #5, newest first
versions = ArticleVersion.all_versions(
    session,
    {'id': 5},
    limit=10  # Only get the 10 most recent versions
)

# Iterate without N+1 queries
for version in versions:
    print(version.changeset)
    print(version.previous)  # Uses cached value, no query

Parameters:

Name Type Description Default
session

SQLAlchemy session

required
primary_key_values dict

Dict mapping primary key column names to values

required
limit int | None

Maximum number of versions to return (None for all)

None
offset int

Number of versions to skip

0
desc bool

If True, return newest versions first (default)

True
link bool

If True, pre-populate previous/next caches (default)

True

Returns:

Type Description
list[VersionClassBase]

List of version objects

version_at(session, primary_key_values, transaction_id) classmethod

Efficiently retrieve the version that was active at a specific transaction.

This is more efficient than iterating through versions manually, especially when using the validity strategy which can use range conditions.

Example:

# Get the version of Article #5 that was active at transaction #100
version = ArticleVersion.version_at(
    session,
    {'id': 5},
    transaction_id=100
)

Parameters:

Name Type Description Default
session

SQLAlchemy session

required
primary_key_values dict

Dict mapping primary key column names to values

required
transaction_id int

The transaction ID to query at

required

Returns:

Type Description
VersionClassBase | None

The version object active at that transaction, or None

Changelog

See the changelog for a full list of changes in each release.