mobiusml / aana_sdk

Aana SDK is a powerful framework for building AI enabled multimodal applications.
https://www.mobiuslabs.com/
Apache License 2.0
12 stars 1 forks source link

[BUG] UndefinedTable Error during Alembic Migration with PostgeSQL #110

Closed movchan74 closed 4 weeks ago

movchan74 commented 1 month ago

Bug Description

When attempting to run Alembic migrations to set up a PostgreSQL database, a ProgrammingError occurs indicating that the video table does not exist. This error is encountered during the creation of the media table, which includes a foreign key reference to the video table.

Steps to Reproduce

  1. Configure SDK to use the PostgreSQL database.
  2. Run the Alembic migration (start any example).

Expected Behavior

The Alembic migration should execute successfully, creating the necessary tables (media, video, captions) along with their respective foreign key constraints without any errors.

Actual Behavior

The migration fails with a ProgrammingError, specifically indicating that the video table does not exist. This error occurs because the media table attempts to create a foreign key constraint referencing the video table before the video table has been created.

Environment

I've noticed the issue while working on task queue: 0cb7697b09e8dce3f979a74b9ac47fba6b56af00 But it is not specific to the task queue changes and I assume it affects the main branch as well.

Error Traceback

UndefinedTable: relation "video" does not exist

[SQL: 
CREATE TABLE media (
    id VARCHAR NOT NULL, 
    media_type VARCHAR, 
    video_id INTEGER, 
    create_ts TIMESTAMP WITH TIME ZONE DEFAULT (CURRENT_TIMESTAMP), 
    update_ts TIMESTAMP WITH TIME ZONE, 
    CONSTRAINT pk_media PRIMARY KEY (id), 
    CONSTRAINT fk_media_video_id_video FOREIGN KEY(video_id) REFERENCES video (id)
)
]

(Background on this error at: https://sqlalche.me/e/20/f405)

Additional Notes

movchan74 commented 1 month ago

Here is the proposed change to simplify media and video relationship.

Things to consider:

I've tested it and it seems to be working just fine. Cascade deletion works and it works with postgres.

Here is the code of proposed changes:

Before:

class MediaEntity(BaseEntity, TimeStampEntity):
    """Table for media items."""

    __tablename__ = "media"
    id = Column(MediaIdSqlType, primary_key=True)
    media_type = Column(String, comment="The type of media")
    video_id = Column(
        Integer,
        ForeignKey("video.id", ondelete="CASCADE"),
        nullable=True,
        comment="If media_type is `video`, the id of the video this entry represents.",
    )

    video = relationship(
        "VideoEntity",
        backref=backref("media", passive_deletes=True, uselist=False),
        cascade="all, delete",
        uselist=False,
        post_update=True,
        foreign_keys=[video_id],
    )

After:

class MediaEntity(BaseEntity, TimeStampEntity):
    """Table for media items."""

    __tablename__ = "media"
    id = Column(String, primary_key=True, default=lambda: str(uuid4()), comment="Unique identifier for the media")
    media_type = Column(String, comment="The type of media")

    video = relationship(
        "VideoEntity",
        backref=backref("media", passive_deletes=True),
        cascade="all, delete",
        uselist=True,
    )

Before:

class VideoEntity(BaseEntity, TimeStampEntity):
    """ORM class for video file (video, etc)."""

    __tablename__ = "video"

    id = Column(Integer, primary_key=True)
    media_id = Column(
        MediaIdSqlType,
        ForeignKey("media.id"),
        nullable=False,
        comment="Foreign key to media table",
    )
    duration = Column(Float, comment="Media duration in seconds")
    <...>

After:

class VideoEntity(BaseEntity, TimeStampEntity):
    """ORM class for video file (video, etc)."""

    __tablename__ = "video"

    id = Column(String, ForeignKey("media.id"), primary_key=True)
    duration = Column(Float, comment="Media duration in seconds")
    <...>

@ashwinnair14 @evanderiel @HRashidi What do you think?

HRashidi commented 1 month ago

It's ok to remove the video_id from the media. But why we need to set the id of the VideoEntity as a Foreign key to the media_id. Can we just work with the media_id and use the video from it? (removing the video_id) video = relationship( 'Video', back_populates="video", lazy="dynamic", cascade="all, delete", )

HRashidi commented 1 month ago

Can we just remove the video_id from the media_id (but keep the relationship there)? Also we can use the media_id inside the video table as it is and add an index for it for being fast (instead of using media_id as it's primary id)

movchan74 commented 1 month ago

Can we just remove the video_id from the media_id (but keep the relationship there)? Also we can use the media_id inside the video table as it is and add an index for it for being fast (instead of using media_id as it's primary id)

Can you write the code for MediaEntity and VideoEntity to illustrate your point? I don't get it.

evanderiel commented 1 month ago

Having the primary key also be a foreign key is unusual but I guess it's fine.

HRashidi commented 1 month ago
class MediaEntity(BaseEntity, TimeStampEntity):
    """Table for media items."""

    __tablename__ = "media"
    id = Column(MediaIdSqlType, primary_key=True)
    media_type = Column(String, comment="The type of media")

    video = relationship(
        'VideoEntity',
        back_populates="video",
        lazy="dynamic",
        cascade="all, delete",
    )
class VideoEntity(BaseEntity, TimeStampEntity):
    """ORM class for video file (video, etc)."""

    __tablename__ = "video"

    id = Column(Integer, primary_key=True)
    media_id = Column(
        MediaIdSqlType,
        ForeignKey("media.id"),
        nullable=False,
        comment="Foreign key to media table",
        index=True
    )
    media = relationship('MediaEntity')
    ...
movchan74 commented 1 month ago

@HRashidi Thanks for the code! I understand what you mean now.

Here are a few reasons why I believe my proposed changes might be more beneficial:

movchan74 commented 4 weeks ago

Done: https://github.com/mobiusml/aana_sdk/pull/115