kvesteri / sqlalchemy-continuum

Versioning extension for SQLAlchemy.
BSD 3-Clause "New" or "Revised" License
575 stars 127 forks source link

Error when using polymorphic_on with CASE statement #297

Open AbdealiLoKo opened 2 years ago

AbdealiLoKo commented 2 years ago

The polymorphic_on can be a CASE WHEN statement. Ref: https://docs.sqlalchemy.org/en/14/orm/mapping_api.html#sqlalchemy.orm.mapper.params.polymorphic_on

But it looks like sqlalchemy-continuum fails when I try to add __versioned__ to a model with it.

  File "/home/abdealijk/venv/lib/python3.7/site-packages/sqlalchemy_continuum/builder.py", line 22, in check_reentry
    handler(*args, **kwargs)
  File "/home/abdealijk/venv/lib/python3.7/site-packages/sqlalchemy_continuum/builder.py", line 190, in configure_versioned_classes
    self.enable_active_history(pending_classes_copies)
  File "/home/abdealijk/venv/lib/python3.7/site-packages/sqlalchemy_continuum/builder.py", line 201, in enable_active_history
    getattr(cls, prop.key).impl.active_history = True
AttributeError: type object 'Writer' has no attribute '_sa_polymorphic_on'

Reproducible example:

from sqlalchemy import Column, Integer, String, case
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import configure_mappers
from sqlalchemy_continuum import make_versioned

make_versioned(user_cls=None)
Base = declarative_base()

class Writer(Base):
    __tablename__ = 'writer'
    __versioned__ = {}

    id = Column(Integer, primary_key=True)
    name = Column(String(255))
    type = Column(String(255))

    __mapper_args__ = {
        'polymorphic_on': (
            case(
                [(type.in_(['poet', 'lyricist']), 'bard')],
                else_=type,
            )
        ),
        'polymorphic_identity': 'writer',
    }

class Author(Base):
    __tablename__ = "author"
    __versioned__ = {}
    id = Column(Integer, primary_key=True)
    name = Column(String(255))

    __mapper_args__ = {
        'polymorphic_identity': 'author',
    }

configure_mappers()
AbdealiLoKo commented 2 years ago

A alternate syntax here is:

class Writer(Base):
    ...
    poly_col = column_property(
        case(
            [(type.in_(['poet', 'lyricist']), 'bard')],
            else_=type,
        )
    )

    __mapper_args__ = {
        'polymorphic_on': poly_col,
        'polymorphic_identity': 'writer',
    }

But this seems to be failing with the error that the column property is not found in the version table