kvesteri / sqlalchemy-continuum

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

Get versioning manager for association table #298

Open AbdealiLoKo opened 2 years ago

AbdealiLoKo commented 2 years ago

Currently - I am able to get the versioning manager used for a Model using: sqlalchemy_continuum.utils.get_versioning_manager()

But this does not work for Tables.

>>> get_versioning_manager(Book)
<sqlalchemy_continuum.manager.VersioningManager object at 0x7fd619a7d0d0>

>>> get_versioning_manager(book_author)
...
  File "/home/abdealijk/venv/lib/python3.7/site-packages/sqlalchemy_continuum/utils.py", line 30, in get_versioning_manager
    raise ClassNotVersioned(cls.__name__)
sqlalchemy_continuum.exc.ClassNotVersioned: Table

In most cases, I could use sqlalchemy_utils.functions import get_mapper to get the mapper of a table. But for association tables - I cannot do that as they do not have any Model associated with it

Example application to try this with:

from sqlalchemy import Column, ForeignKey, Integer, String, Table
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import configure_mappers, relationship
from sqlalchemy_continuum import get_versioning_manager, make_versioned

make_versioned(user_cls=None)
Base = declarative_base()

book_author = Table(
    "book_author",
    Base.metadata,
    Column("author_id", ForeignKey("author.id"), primary_key=True),
    Column("book_id", ForeignKey("book.id"), primary_key=True),
)

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

    books = relationship("Book", secondary=book_author, back_populates="authors")

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

    authors = relationship("Author", secondary=book_author, back_populates="books")

configure_mappers()
AbdealiLoKo commented 2 years ago

After digging a bit deeper - I realized: Book.__versioning_mapper__ can be used to access the manager. When I try to do the same for book_author.__versioning_manager__ - it says the property does not exist.

Looks like ModelBuilder.__call__() is adding the manager. But TableBuilder.__call__() is not adding the manager so there is no way to go from AssociationTable -> Manager as of now

chelodegli commented 1 year ago

I'm having this same issue, have been digging around for the last months but couldn't find anything about it.

Is there any workaround to get versioning manager for association tables? How could we replace "get_versioning_manager" for this case?

I'm querying into _version table but it's not a good solution because I can't filter by number of version.