kvesteri / sqlalchemy-continuum

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

Querying deleted relationship (when record and rel deleted in same transaction) #309

Open AbdealiLoKo opened 2 years ago

AbdealiLoKo commented 2 years ago

I have a case where I am trying to document some information about what was deleted in my application. In the book-author example, I want to document:

Book deleted: Lord of the Rings
Author of the book that was deleted: JRR Tolkien

Now, I can do this very simply if I delete just a book in my transaction. But if I delete the book and author in the same transaction, I am unable to figure out how to get the author's information using the properties that sqla-continuum is providing

It throws an error that the author is None - I guess because it is considering the author to be deleted at this point.

It looks like if I need to query this - I would need to redo a huge amount of the logic in RelationshipBuilder which seems like a tough task.

Full example:

from sqlalchemy import Column, ForeignKey, Integer, String, create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import configure_mappers, relationship, sessionmaker
from sqlalchemy_continuum import make_versioned, version_class

make_versioned(user_cls=None)

Base = declarative_base()

class Author(Base):
    __tablename__ = 'author'
    id = Column(Integer, primary_key=True)
    name = Column(String(255))

class Book(Base):
    __tablename__ = 'book'
    __versioned__ = {}
    id = Column(Integer, primary_key=True)
    name = Column(String(255))
    author_id = Column(Integer, ForeignKey('author.id'))

    author = relationship(Author)

configure_mappers()

# Create all tables
engine = create_engine('sqlite:////tmp/db.sqlite3', echo=True)
Base.metadata.drop_all(bind=engine)
Base.metadata.create_all(bind=engine)

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

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

lotr_id = lotr.id

db.delete(lotr)
db.delete(tolkien)
db.commit()

lotr_version = db.query(version_class(Book)).all()[-1]
print("Deleted book:", lotr_version.name)
print("Deleted book's author:", lotr_version.author.name)