Skip to content

Commit

Permalink
Merge pull request #246 from killthekitten/fix-245-create-column-aliases
Browse files Browse the repository at this point in the history
Fix #245: create column aliases in the version table
  • Loading branch information
kvesteri committed May 24, 2020
2 parents 54af8b2 + f2ee5b6 commit b5c732f
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 6 deletions.
42 changes: 36 additions & 6 deletions sqlalchemy_continuum/builder.py
Expand Up @@ -144,14 +144,16 @@ def build_transaction_class(self):
def configure_versioned_classes(self):
"""
Configures all versioned classes that were collected during
instrumentation process. The configuration has 4 steps:
instrumentation process. The configuration has 6 steps:
1. Build tables for version models.
2. Build the actual version model declarative classes.
3. Build relationships between these models.
4. Empty pending_classes list so that consecutive mapper configuration
does not create multiple version classes
5. Assign all versioned attributes to use active history.
5. Build aliases for columns.
6. Assign all versioned attributes to use active history.
"""
if not self.manager.options['versioning']:
return
Expand All @@ -168,11 +170,39 @@ def configure_versioned_classes(self):

# Create copy of all pending versioned classes so that we can inspect
# them later when creating relationships.
pending_copy = copy(self.manager.pending_classes)
pending_classes_copies = copy(self.manager.pending_classes)
self.manager.pending_classes = []
self.build_relationships(pending_copy)
self.build_relationships(pending_classes_copies)
self.enable_active_history(pending_classes_copies)
self.create_column_aliases(pending_classes_copies)

for cls in pending_copy:
# set the "active_history" flag
def enable_active_history(self, version_classes):
"""
Assign all versioned attributes to use active history.
"""
for cls in version_classes:
for prop in sa.inspect(cls).iterate_properties:
getattr(cls, prop.key).impl.active_history = True

def create_column_aliases(self, version_classes):
"""
Create aliases for the columns from the original model.
This, for example, imitates the behavior of @declared_attr columns.
"""
for cls in version_classes:
model_mapper = sa.inspect(cls)
version_class = self.manager.version_class_map.get(cls)
if not version_class:
continue

version_class_mapper = sa.inspect(version_class)

for key, column in model_mapper.columns.items():
if key != column.key:
version_class_column = version_class.__table__.c.get(column.key)

if version_class_column is None:
continue

version_class_mapper.add_property(key, sa.orm.column_property(version_class_column))
1 change: 1 addition & 0 deletions sqlalchemy_continuum/model_builder.py
Expand Up @@ -272,6 +272,7 @@ def mapper_args(cls):
name = '%sVersion' % (self.model.__name__,)
return type(name, self.base_classes(), args)


def __call__(self, table, tx_class):
"""
Build history model and relationships to parent model, transaction
Expand Down
8 changes: 8 additions & 0 deletions tests/inheritance/test_single_table_inheritance.py
@@ -1,4 +1,5 @@
import sqlalchemy as sa
from sqlalchemy.ext.declarative import declared_attr
from sqlalchemy_continuum import versioning_manager, version_class
from tests import TestCase, create_test_cases

Expand All @@ -25,6 +26,10 @@ class Article(TextItem):
__mapper_args__ = {'polymorphic_identity': u'article'}
name = sa.Column(sa.Unicode(255))

@sa.ext.declarative.declared_attr
def status(cls):
return sa.Column("_status", sa.Unicode(255))

class BlogPost(TextItem):
__mapper_args__ = {'polymorphic_identity': u'blog_post'}
title = sa.Column(sa.Unicode(255))
Expand Down Expand Up @@ -79,5 +84,8 @@ def test_transaction_changed_entities(self):
assert transaction.entity_names == [u'Article']
assert transaction.changed_entities

def test_declared_attr_inheritance(self):
assert self.ArticleVersion.status


create_test_cases(SingleTableInheritanceTestCase)

0 comments on commit b5c732f

Please sign in to comment.