summaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2014-12-07 17:48:32 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2014-12-07 17:48:32 -0500
commit1b260c7959c9b89e6a3993d5d96bc6b0918a8fb0 (patch)
tree59602c3151094de79d84c60391cf64e4a1b94084 /examples
parent68f1bcc9da191fc72a943f2353c8d80a39bdb76a (diff)
parentc8817e608788799837a91b1d2616227594698d2b (diff)
downloadsqlalchemy-1b260c7959c9b89e6a3993d5d96bc6b0918a8fb0.tar.gz
Merge branch 'master' into ticket_3100
Diffstat (limited to 'examples')
-rw-r--r--examples/generic_associations/discriminator_on_association.py1
-rw-r--r--examples/versioned_history/history_meta.py104
-rw-r--r--examples/versioned_history/test_versioning.py173
3 files changed, 204 insertions, 74 deletions
diff --git a/examples/generic_associations/discriminator_on_association.py b/examples/generic_associations/discriminator_on_association.py
index e03cfec00..7bb04cf85 100644
--- a/examples/generic_associations/discriminator_on_association.py
+++ b/examples/generic_associations/discriminator_on_association.py
@@ -84,6 +84,7 @@ class HasAddresses(object):
"%sAddressAssociation" % name,
(AddressAssociation, ),
dict(
+ __tablename__=None,
__mapper_args__={
"polymorphic_identity": discriminator
}
diff --git a/examples/versioned_history/history_meta.py b/examples/versioned_history/history_meta.py
index f9e979a6a..6d7b137eb 100644
--- a/examples/versioned_history/history_meta.py
+++ b/examples/versioned_history/history_meta.py
@@ -4,19 +4,22 @@ from sqlalchemy.ext.declarative import declared_attr
from sqlalchemy.orm import mapper, attributes, object_mapper
from sqlalchemy.orm.exc import UnmappedColumnError
from sqlalchemy import Table, Column, ForeignKeyConstraint, Integer, DateTime
-from sqlalchemy import event
+from sqlalchemy import event, util
import datetime
from sqlalchemy.orm.properties import RelationshipProperty
+
def col_references_table(col, table):
for fk in col.foreign_keys:
if fk.references(table):
return True
return False
+
def _is_versioning_col(col):
return "version_meta" in col.info
+
def _history_mapper(local_mapper):
cls = local_mapper.class_
@@ -33,52 +36,77 @@ def _history_mapper(local_mapper):
super_fks = []
def _col_copy(col):
+ orig = col
col = col.copy()
+ orig.info['history_copy'] = col
col.unique = False
col.default = col.server_default = None
return col
- if not super_mapper or local_mapper.local_table is not super_mapper.local_table:
+ properties = util.OrderedDict()
+ if not super_mapper or \
+ local_mapper.local_table is not super_mapper.local_table:
cols = []
+ version_meta = {"version_meta": True} # add column.info to identify
+ # columns specific to versioning
+
for column in local_mapper.local_table.c:
if _is_versioning_col(column):
continue
col = _col_copy(column)
- if super_mapper and col_references_table(column, super_mapper.local_table):
- super_fks.append((col.key, list(super_history_mapper.local_table.primary_key)[0]))
+ if super_mapper and \
+ col_references_table(column, super_mapper.local_table):
+ super_fks.append(
+ (
+ col.key,
+ list(super_history_mapper.local_table.primary_key)[0]
+ )
+ )
cols.append(col)
if column is local_mapper.polymorphic_on:
polymorphic_on = col
- if super_mapper:
- super_fks.append(('version', super_history_mapper.local_table.c.version))
+ orig_prop = local_mapper.get_property_by_column(column)
+ # carry over column re-mappings
+ if len(orig_prop.columns) > 1 or \
+ orig_prop.columns[0].key != orig_prop.key:
+ properties[orig_prop.key] = tuple(
+ col.info['history_copy'] for col in orig_prop.columns)
- version_meta = {"version_meta": True} # add column.info to identify
- # columns specific to versioning
+ if super_mapper:
+ super_fks.append(
+ (
+ 'version', super_history_mapper.local_table.c.version
+ )
+ )
# "version" stores the integer version id. This column is
# required.
- cols.append(Column('version', Integer, primary_key=True,
- autoincrement=False, info=version_meta))
+ cols.append(
+ Column(
+ 'version', Integer, primary_key=True,
+ autoincrement=False, info=version_meta))
# "changed" column stores the UTC timestamp of when the
# history row was created.
# This column is optional and can be omitted.
- cols.append(Column('changed', DateTime,
- default=datetime.datetime.utcnow,
- info=version_meta))
+ cols.append(Column(
+ 'changed', DateTime,
+ default=datetime.datetime.utcnow,
+ info=version_meta))
if super_fks:
cols.append(ForeignKeyConstraint(*zip(*super_fks)))
- table = Table(local_mapper.local_table.name + '_history',
- local_mapper.local_table.metadata,
- *cols,
- schema=local_mapper.local_table.schema
+ table = Table(
+ local_mapper.local_table.name + '_history',
+ local_mapper.local_table.metadata,
+ *cols,
+ schema=local_mapper.local_table.schema
)
else:
# single table inheritance. take any additional columns that may have
@@ -91,24 +119,33 @@ def _history_mapper(local_mapper):
if super_history_mapper:
bases = (super_history_mapper.class_,)
+
+ if table is not None:
+ properties['changed'] = (
+ (table.c.changed, ) +
+ tuple(super_history_mapper.attrs.changed.columns)
+ )
+
else:
bases = local_mapper.base_mapper.class_.__bases__
versioned_cls = type.__new__(type, "%sHistory" % cls.__name__, bases, {})
m = mapper(
- versioned_cls,
- table,
- inherits=super_history_mapper,
- polymorphic_on=polymorphic_on,
- polymorphic_identity=local_mapper.polymorphic_identity
- )
+ versioned_cls,
+ table,
+ inherits=super_history_mapper,
+ polymorphic_on=polymorphic_on,
+ polymorphic_identity=local_mapper.polymorphic_identity,
+ properties=properties
+ )
cls.__history_mapper__ = m
if not super_history_mapper:
local_mapper.local_table.append_column(
Column('version', Integer, default=1, nullable=False)
)
- local_mapper.add_property("version", local_mapper.local_table.c.version)
+ local_mapper.add_property(
+ "version", local_mapper.local_table.c.version)
class Versioned(object):
@@ -126,6 +163,7 @@ def versioned_objects(iter):
if hasattr(obj, '__history_mapper__'):
yield obj
+
def create_version(obj, session, deleted=False):
obj_mapper = object_mapper(obj)
history_mapper = obj.__history_mapper__
@@ -137,7 +175,10 @@ def create_version(obj, session, deleted=False):
obj_changed = False
- for om, hm in zip(obj_mapper.iterate_to_root(), history_mapper.iterate_to_root()):
+ for om, hm in zip(
+ obj_mapper.iterate_to_root(),
+ history_mapper.iterate_to_root()
+ ):
if hm.single:
continue
@@ -157,11 +198,12 @@ def create_version(obj, session, deleted=False):
# in the case of single table inheritance, there may be
# columns on the mapped table intended for the subclass only.
# the "unmapped" status of the subclass column on the
- # base class is a feature of the declarative module as of sqla 0.5.2.
+ # base class is a feature of the declarative module.
continue
- # expired object attributes and also deferred cols might not be in the
- # dict. force it to load no matter what by using getattr().
+ # expired object attributes and also deferred cols might not
+ # be in the dict. force it to load no matter what by
+ # using getattr().
if prop.key not in obj_state.dict:
getattr(obj, prop.key)
@@ -182,8 +224,9 @@ def create_version(obj, session, deleted=False):
# check those too
for prop in obj_mapper.iterate_properties:
if isinstance(prop, RelationshipProperty) and \
- attributes.get_history(obj, prop.key,
- passive=attributes.PASSIVE_NO_INITIALIZE).has_changes():
+ attributes.get_history(
+ obj, prop.key,
+ passive=attributes.PASSIVE_NO_INITIALIZE).has_changes():
for p in prop.local_columns:
if p.foreign_keys:
obj_changed = True
@@ -201,6 +244,7 @@ def create_version(obj, session, deleted=False):
session.add(hist)
obj.version += 1
+
def versioned_session(session):
@event.listens_for(session, 'before_flush')
def before_flush(session, flush_context, instances):
diff --git a/examples/versioned_history/test_versioning.py b/examples/versioned_history/test_versioning.py
index 874223d62..dde73a5ae 100644
--- a/examples/versioned_history/test_versioning.py
+++ b/examples/versioned_history/test_versioning.py
@@ -1,20 +1,28 @@
-"""Unit tests illustrating usage of the ``history_meta.py`` module functions."""
+"""Unit tests illustrating usage of the ``history_meta.py``
+module functions."""
from unittest import TestCase
from sqlalchemy.ext.declarative import declarative_base
from .history_meta import Versioned, versioned_session
-from sqlalchemy import create_engine, Column, Integer, String, ForeignKey, Boolean
-from sqlalchemy.orm import clear_mappers, Session, deferred, relationship
+from sqlalchemy import create_engine, Column, Integer, String, \
+ ForeignKey, Boolean, select
+from sqlalchemy.orm import clear_mappers, Session, deferred, relationship, \
+ column_property
from sqlalchemy.testing import AssertsCompiledSQL, eq_, assert_raises
from sqlalchemy.testing.entities import ComparableEntity
from sqlalchemy.orm import exc as orm_exc
+import warnings
+
+warnings.simplefilter("error")
engine = None
+
def setup_module():
global engine
engine = create_engine('sqlite://', echo=True)
+
class TestVersioning(TestCase, AssertsCompiledSQL):
__dialect__ = 'default'
@@ -52,14 +60,16 @@ class TestVersioning(TestCase, AssertsCompiledSQL):
SomeClassHistory = SomeClass.__history_mapper__.class_
eq_(
- sess.query(SomeClassHistory).filter(SomeClassHistory.version == 1).all(),
+ sess.query(SomeClassHistory).filter(
+ SomeClassHistory.version == 1).all(),
[SomeClassHistory(version=1, name='sc1')]
)
sc.name = 'sc1modified2'
eq_(
- sess.query(SomeClassHistory).order_by(SomeClassHistory.version).all(),
+ sess.query(SomeClassHistory).order_by(
+ SomeClassHistory.version).all(),
[
SomeClassHistory(version=1, name='sc1'),
SomeClassHistory(version=2, name='sc1modified')
@@ -76,7 +86,8 @@ class TestVersioning(TestCase, AssertsCompiledSQL):
sess.commit()
eq_(
- sess.query(SomeClassHistory).order_by(SomeClassHistory.version).all(),
+ sess.query(SomeClassHistory).order_by(
+ SomeClassHistory.version).all(),
[
SomeClassHistory(version=1, name='sc1'),
SomeClassHistory(version=2, name='sc1modified')
@@ -87,7 +98,8 @@ class TestVersioning(TestCase, AssertsCompiledSQL):
sess.commit()
eq_(
- sess.query(SomeClassHistory).order_by(SomeClassHistory.version).all(),
+ sess.query(SomeClassHistory).order_by(
+ SomeClassHistory.version).all(),
[
SomeClassHistory(version=1, name='sc1'),
SomeClassHistory(version=2, name='sc1modified'),
@@ -164,13 +176,13 @@ class TestVersioning(TestCase, AssertsCompiledSQL):
SomeClassHistory = SomeClass.__history_mapper__.class_
eq_(
- sess.query(SomeClassHistory.boole).order_by(SomeClassHistory.id).all(),
+ sess.query(SomeClassHistory.boole).order_by(
+ SomeClassHistory.id).all(),
[(True, ), (None, )]
)
eq_(sc.version, 3)
-
def test_deferred(self):
"""test versioning of unloaded, deferred columns."""
@@ -199,11 +211,11 @@ class TestVersioning(TestCase, AssertsCompiledSQL):
SomeClassHistory = SomeClass.__history_mapper__.class_
eq_(
- sess.query(SomeClassHistory).filter(SomeClassHistory.version == 1).all(),
+ sess.query(SomeClassHistory).filter(
+ SomeClassHistory.version == 1).all(),
[SomeClassHistory(version=1, name='sc1', data='somedata')]
)
-
def test_joined_inheritance(self):
class BaseClass(Versioned, self.Base, ComparableEntity):
__tablename__ = 'basetable'
@@ -212,12 +224,17 @@ class TestVersioning(TestCase, AssertsCompiledSQL):
name = Column(String(50))
type = Column(String(20))
- __mapper_args__ = {'polymorphic_on': type, 'polymorphic_identity': 'base'}
+ __mapper_args__ = {
+ 'polymorphic_on': type,
+ 'polymorphic_identity': 'base'}
class SubClassSeparatePk(BaseClass):
__tablename__ = 'subtable1'
- id = Column(Integer, primary_key=True)
+ id = column_property(
+ Column(Integer, primary_key=True),
+ BaseClass.id
+ )
base_id = Column(Integer, ForeignKey('basetable.id'))
subdata1 = Column(String(50))
@@ -226,7 +243,8 @@ class TestVersioning(TestCase, AssertsCompiledSQL):
class SubClassSamePk(BaseClass):
__tablename__ = 'subtable2'
- id = Column(Integer, ForeignKey('basetable.id'), primary_key=True)
+ id = Column(
+ Integer, ForeignKey('basetable.id'), primary_key=True)
subdata2 = Column(String(50))
__mapper_args__ = {'polymorphic_identity': 'same'}
@@ -246,38 +264,50 @@ class TestVersioning(TestCase, AssertsCompiledSQL):
sess.commit()
BaseClassHistory = BaseClass.__history_mapper__.class_
- SubClassSeparatePkHistory = SubClassSeparatePk.__history_mapper__.class_
+ SubClassSeparatePkHistory = \
+ SubClassSeparatePk.__history_mapper__.class_
SubClassSamePkHistory = SubClassSamePk.__history_mapper__.class_
eq_(
sess.query(BaseClassHistory).order_by(BaseClassHistory.id).all(),
[
- SubClassSeparatePkHistory(id=1, name='sep1', type='sep', version=1),
+ SubClassSeparatePkHistory(
+ id=1, name='sep1', type='sep', version=1),
BaseClassHistory(id=2, name='base1', type='base', version=1),
- SubClassSamePkHistory(id=3, name='same1', type='same', version=1)
+ SubClassSamePkHistory(
+ id=3, name='same1', type='same', version=1)
]
)
same1.subdata2 = 'same1subdatamod2'
eq_(
- sess.query(BaseClassHistory).order_by(BaseClassHistory.id, BaseClassHistory.version).all(),
+ sess.query(BaseClassHistory).order_by(
+ BaseClassHistory.id, BaseClassHistory.version).all(),
[
- SubClassSeparatePkHistory(id=1, name='sep1', type='sep', version=1),
+ SubClassSeparatePkHistory(
+ id=1, name='sep1', type='sep', version=1),
BaseClassHistory(id=2, name='base1', type='base', version=1),
- SubClassSamePkHistory(id=3, name='same1', type='same', version=1),
- SubClassSamePkHistory(id=3, name='same1', type='same', version=2)
+ SubClassSamePkHistory(
+ id=3, name='same1', type='same', version=1),
+ SubClassSamePkHistory(
+ id=3, name='same1', type='same', version=2)
]
)
base1.name = 'base1mod2'
eq_(
- sess.query(BaseClassHistory).order_by(BaseClassHistory.id, BaseClassHistory.version).all(),
+ sess.query(BaseClassHistory).order_by(
+ BaseClassHistory.id, BaseClassHistory.version).all(),
[
- SubClassSeparatePkHistory(id=1, name='sep1', type='sep', version=1),
+ SubClassSeparatePkHistory(
+ id=1, name='sep1', type='sep', version=1),
BaseClassHistory(id=2, name='base1', type='base', version=1),
- BaseClassHistory(id=2, name='base1mod', type='base', version=2),
- SubClassSamePkHistory(id=3, name='same1', type='same', version=1),
- SubClassSamePkHistory(id=3, name='same1', type='same', version=2)
+ BaseClassHistory(
+ id=2, name='base1mod', type='base', version=2),
+ SubClassSamePkHistory(
+ id=3, name='same1', type='same', version=1),
+ SubClassSamePkHistory(
+ id=3, name='same1', type='same', version=2)
]
)
@@ -289,13 +319,17 @@ class TestVersioning(TestCase, AssertsCompiledSQL):
name = Column(String(50))
type = Column(String(20))
- __mapper_args__ = {'polymorphic_on': type,
- 'polymorphic_identity': 'base'}
+ __mapper_args__ = {
+ 'polymorphic_on': type,
+ 'polymorphic_identity': 'base'}
class SubClass(BaseClass):
__tablename__ = 'subtable'
- id = Column(Integer, primary_key=True)
+ id = column_property(
+ Column(Integer, primary_key=True),
+ BaseClass.id
+ )
base_id = Column(Integer, ForeignKey('basetable.id'))
subdata1 = Column(String(50))
@@ -316,12 +350,18 @@ class TestVersioning(TestCase, AssertsCompiledSQL):
q = sess.query(SubSubHistory)
self.assert_compile(
q,
+
+
"SELECT "
"subsubtable_history.id AS subsubtable_history_id, "
"subtable_history.id AS subtable_history_id, "
"basetable_history.id AS basetable_history_id, "
+ "subsubtable_history.changed AS subsubtable_history_changed, "
+ "subtable_history.changed AS subtable_history_changed, "
+ "basetable_history.changed AS basetable_history_changed, "
+
"basetable_history.name AS basetable_history_name, "
"basetable_history.type AS basetable_history_type, "
@@ -330,9 +370,6 @@ class TestVersioning(TestCase, AssertsCompiledSQL):
"subtable_history.version AS subtable_history_version, "
"basetable_history.version AS basetable_history_version, "
- "subsubtable_history.changed AS subsubtable_history_changed, "
- "subtable_history.changed AS subtable_history_changed, "
- "basetable_history.changed AS basetable_history_changed, "
"subtable_history.base_id AS subtable_history_base_id, "
"subtable_history.subdata1 AS subtable_history_subdata1, "
@@ -342,7 +379,8 @@ class TestVersioning(TestCase, AssertsCompiledSQL):
"ON basetable_history.id = subtable_history.base_id "
"AND basetable_history.version = subtable_history.version "
"JOIN subsubtable_history ON subtable_history.id = "
- "subsubtable_history.id AND subtable_history.version = subsubtable_history.version"
+ "subsubtable_history.id AND subtable_history.version = "
+ "subsubtable_history.version"
)
ssc = SubSubClass(name='ss1', subdata1='sd1', subdata2='sd2')
@@ -360,10 +398,53 @@ class TestVersioning(TestCase, AssertsCompiledSQL):
[SubSubHistory(name='ss1', subdata1='sd1',
subdata2='sd2', type='subsub', version=1)]
)
- eq_(ssc, SubSubClass(name='ss1', subdata1='sd11',
- subdata2='sd22', version=2))
+ eq_(ssc, SubSubClass(
+ name='ss1', subdata1='sd11',
+ subdata2='sd22', version=2))
+
+ def test_joined_inheritance_changed(self):
+ class BaseClass(Versioned, self.Base, ComparableEntity):
+ __tablename__ = 'basetable'
+
+ id = Column(Integer, primary_key=True)
+ name = Column(String(50))
+ type = Column(String(20))
+
+ __mapper_args__ = {
+ 'polymorphic_on': type,
+ 'polymorphic_identity': 'base'
+ }
+
+ class SubClass(BaseClass):
+ __tablename__ = 'subtable'
+
+ id = Column(Integer, ForeignKey('basetable.id'), primary_key=True)
+
+ __mapper_args__ = {'polymorphic_identity': 'sep'}
+
+ self.create_tables()
+
+ BaseClassHistory = BaseClass.__history_mapper__.class_
+ SubClassHistory = SubClass.__history_mapper__.class_
+ sess = self.session
+ s1 = SubClass(name='s1')
+ sess.add(s1)
+ sess.commit()
+
+ s1.name = 's2'
+ sess.commit()
+ actual_changed_base = sess.scalar(
+ select([BaseClass.__history_mapper__.local_table.c.changed]))
+ actual_changed_sub = sess.scalar(
+ select([SubClass.__history_mapper__.local_table.c.changed]))
+ h1 = sess.query(BaseClassHistory).first()
+ eq_(h1.changed, actual_changed_base)
+ eq_(h1.changed, actual_changed_sub)
+ h1 = sess.query(SubClassHistory).first()
+ eq_(h1.changed, actual_changed_base)
+ eq_(h1.changed, actual_changed_sub)
def test_single_inheritance(self):
class BaseClass(Versioned, self.Base, ComparableEntity):
@@ -372,8 +453,9 @@ class TestVersioning(TestCase, AssertsCompiledSQL):
id = Column(Integer, primary_key=True)
name = Column(String(50))
type = Column(String(50))
- __mapper_args__ = {'polymorphic_on': type,
- 'polymorphic_identity': 'base'}
+ __mapper_args__ = {
+ 'polymorphic_on': type,
+ 'polymorphic_identity': 'base'}
class SubClass(BaseClass):
@@ -396,8 +478,8 @@ class TestVersioning(TestCase, AssertsCompiledSQL):
SubClassHistory = SubClass.__history_mapper__.class_
eq_(
- sess.query(BaseClassHistory).order_by(BaseClassHistory.id,
- BaseClassHistory.version).all(),
+ sess.query(BaseClassHistory).order_by(
+ BaseClassHistory.id, BaseClassHistory.version).all(),
[BaseClassHistory(id=1, name='b1', type='base', version=1)]
)
@@ -405,11 +487,12 @@ class TestVersioning(TestCase, AssertsCompiledSQL):
b1.name = 'b1modified2'
eq_(
- sess.query(BaseClassHistory).order_by(BaseClassHistory.id,
- BaseClassHistory.version).all(),
+ sess.query(BaseClassHistory).order_by(
+ BaseClassHistory.id, BaseClassHistory.version).all(),
[
BaseClassHistory(id=1, name='b1', type='base', version=1),
- BaseClassHistory(id=1, name='b1modified', type='base', version=2),
+ BaseClassHistory(
+ id=1, name='b1modified', type='base', version=2),
SubClassHistory(id=2, name='s1', type='sub', version=1)
]
)
@@ -475,14 +558,16 @@ class TestVersioning(TestCase, AssertsCompiledSQL):
assert sc.version == 2
eq_(
- sess.query(SomeClassHistory).filter(SomeClassHistory.version == 1).all(),
+ sess.query(SomeClassHistory).filter(
+ SomeClassHistory.version == 1).all(),
[SomeClassHistory(version=1, name='sc1', related_id=None)]
)
sc.related = None
eq_(
- sess.query(SomeClassHistory).order_by(SomeClassHistory.version).all(),
+ sess.query(SomeClassHistory).order_by(
+ SomeClassHistory.version).all(),
[
SomeClassHistory(version=1, name='sc1', related_id=None),
SomeClassHistory(version=2, name='sc1', related_id=sr1.id)