kvesteri / sqlalchemy-continuum

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

viewonly relationships cannot be accessed from the version #303

Open AbdealiLoKo opened 2 years ago

AbdealiLoKo commented 2 years ago

Error:

version <sqlalchemy_continuum.model_builder.BookVersion object at 0x7fa0e6c556d0>
authors [<sqlalchemy_continuum.model_builder.AuthorVersion object at 0x7fa0e6c00910>]
Traceback (most recent call last):
  File "run.py", line 64, in <module>
    print('primary_author', version.primary_author)
  File "/home/abdealijk/sqlalchemy-continuum/sqlalchemy_continuum/relationship_builder.py", line 227, in relationship
    query = self.query(obj)
  File "/home/abdealijk/sqlalchemy-continuum/sqlalchemy_continuum/relationship_builder.py", line 68, in query
    self.criteria(obj)
  File "/home/abdealijk/sqlalchemy-continuum/sqlalchemy_continuum/relationship_builder.py", line 92, in criteria
    return self.many_to_many_criteria(obj)
  File "/home/abdealijk/sqlalchemy-continuum/sqlalchemy_continuum/relationship_builder.py", line 144, in many_to_many_criteria
    self.association_subquery(obj),
  File "/home/abdealijk/sqlalchemy-continuum/sqlalchemy_continuum/relationship_builder.py", line 268, in association_subquery
    association_table_alias = self.association_version_table.alias()
AttributeError: 'RelationshipBuilder' object has no attribute 'association_version_table'

Code to reproduce:

from sqlalchemy import Column, Integer, String, create_engine, Table, ForeignKey, Boolean, and_
from sqlalchemy.event import listen
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, relationship, configure_mappers

from sqlalchemy_continuum import make_versioned

engine = create_engine('sqlite:////tmp/db.sqlite3')

factory = sessionmaker(bind=engine, autocommit=False)
make_versioned(user_cls=None)

Base = declarative_base()

book_author = Table(
    'book_author',
    Base.metadata,
    Column('book_id', Integer, ForeignKey('book.id'), primary_key=True, nullable=False),
    Column('author_id', Integer, ForeignKey('author.id'), primary_key=True, nullable=False),
)

class Author(Base):
    __tablename__ = 'author'
    __versioned__ = {}
    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String(255))
    isprimary = Column(Boolean())
    books = relationship('Book', secondary=book_author)

class Book(Base):
    __tablename__ = 'book'
    __versioned__ = {}
    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String(255))
    authors = relationship('Author', secondary=book_author)
    primary_author = relationship(
        'Author',
        secondary=book_author,
        secondaryjoin=and_(book_author.c.author_id == Author.id, Author.isprimary == True),
        viewonly=True,
        uselist=False,
    )

configure_mappers()
engine = create_engine('sqlite:///db.sqlite', echo=False)

# Create all tables
Base.metadata.create_all(bind=engine)

# Create a session
session = sessionmaker()
session.configure(bind=engine)
db = session()

lotr = Book(name='Lord of the rings')
tolkien = Author(name='JRR Tolkien', books=[lotr])
db.add(lotr)
db.add(tolkien)
db.commit()

version = lotr.versions[0]
print("version", version)
print('authors', version.authors)
print('primary_author', version.primary_author)