diff --git a/athena/athena/models/big_integer_with_autoincrement.py b/athena/athena/models/big_integer_with_autoincrement.py new file mode 100644 index 000000000..e9b9ce168 --- /dev/null +++ b/athena/athena/models/big_integer_with_autoincrement.py @@ -0,0 +1,16 @@ +""" +SQLAlchemy + SQLite does not support the autoincrement feature for BigInteger columns. +This file provides a class as a workaround for this problem: +It uses a normal Integer column in SQLite and a BigInteger column otherwise. +SQLite Integer columns can autoincrement, but they are limited to 2^63-1. +See https://stackoverflow.com/a/23175518/4306257 for more information. +""" + +from sqlalchemy import BigInteger +from sqlalchemy.dialects import postgresql, mysql, sqlite + +# Solution from https://stackoverflow.com/a/23175518/4306257 +BigIntegerWithAutoincrement = BigInteger() +BigIntegerWithAutoincrement = BigIntegerWithAutoincrement.with_variant(postgresql.BIGINT(), 'postgresql') +BigIntegerWithAutoincrement = BigIntegerWithAutoincrement.with_variant(mysql.BIGINT(), 'mysql') +BigIntegerWithAutoincrement = BigIntegerWithAutoincrement.with_variant(sqlite.INTEGER(), 'sqlite') \ No newline at end of file diff --git a/athena/athena/models/db_exercise.py b/athena/athena/models/db_exercise.py index 888daaf6d..9a2ea929a 100644 --- a/athena/athena/models/db_exercise.py +++ b/athena/athena/models/db_exercise.py @@ -1,11 +1,12 @@ -from sqlalchemy import Column, BigInteger, String, Float, JSON, Enum as SqlEnum +from sqlalchemy import Column, String, Float, JSON, Enum as SqlEnum from athena.schemas import ExerciseType from .model import Model +from .big_integer_with_autoincrement import BigIntegerWithAutoincrement class DBExercise(Model): - id = Column(BigInteger, primary_key=True, index=True, nullable=False) + id = Column(BigIntegerWithAutoincrement, primary_key=True, index=True, nullable=False) title = Column(String, index=True, nullable=False) type = Column(SqlEnum(ExerciseType), index=True, nullable=False) max_points = Column(Float, index=True, nullable=False) diff --git a/athena/athena/models/db_feedback.py b/athena/athena/models/db_feedback.py index 94bb9a33d..95a07836f 100644 --- a/athena/athena/models/db_feedback.py +++ b/athena/athena/models/db_feedback.py @@ -1,12 +1,13 @@ from sqlalchemy import Column, BigInteger, Boolean, String, Float, JSON, UniqueConstraint from .model import Model +from .big_integer_with_autoincrement import BigIntegerWithAutoincrement class DBFeedback(Model): __table_args__ = (UniqueConstraint('lms_id'),) - id = Column(BigInteger, primary_key=True, index=True, autoincrement=True) + id = Column(BigIntegerWithAutoincrement, primary_key=True, index=True, autoincrement=True) lms_id = Column(BigInteger) title = Column(String) description = Column(String) diff --git a/athena/athena/models/db_programming_feedback.py b/athena/athena/models/db_programming_feedback.py index b096f9ece..94e855f2d 100644 --- a/athena/athena/models/db_programming_feedback.py +++ b/athena/athena/models/db_programming_feedback.py @@ -1,11 +1,12 @@ from typing import cast, Optional from athena.schemas.programming_submission import ProgrammingSubmission -from sqlalchemy import Column, Integer, BigInteger, String, ForeignKey +from sqlalchemy import Column, Integer, String, ForeignKey from sqlalchemy.orm import relationship from athena.database import Base, get_db from .db_programming_submission import DBProgrammingSubmission from .db_feedback import DBFeedback +from .big_integer_with_autoincrement import BigIntegerWithAutoincrement class DBProgrammingFeedback(DBFeedback, Base): @@ -15,8 +16,8 @@ class DBProgrammingFeedback(DBFeedback, Base): line_start: Optional[int] = Column(Integer) # type: ignore line_end: Optional[int] = Column(Integer) # type: ignore - exercise_id = Column(BigInteger, ForeignKey("programming_exercises.id", ondelete="CASCADE"), index=True) - submission_id = Column(BigInteger, ForeignKey("programming_submissions.id", ondelete="CASCADE"), index=True) + exercise_id = Column(BigIntegerWithAutoincrement, ForeignKey("programming_exercises.id", ondelete="CASCADE"), index=True) + submission_id = Column(BigIntegerWithAutoincrement, ForeignKey("programming_submissions.id", ondelete="CASCADE"), index=True) exercise = relationship("DBProgrammingExercise", back_populates="feedbacks") submission = relationship("DBProgrammingSubmission", back_populates="feedbacks") diff --git a/athena/athena/models/db_programming_submission.py b/athena/athena/models/db_programming_submission.py index 607ef8e0c..9dedc1809 100644 --- a/athena/athena/models/db_programming_submission.py +++ b/athena/athena/models/db_programming_submission.py @@ -1,15 +1,16 @@ -from sqlalchemy import ForeignKey, BigInteger, Column, String +from sqlalchemy import ForeignKey, Column, String from sqlalchemy.orm import relationship from athena.database import Base from .db_submission import DBSubmission +from .big_integer_with_autoincrement import BigIntegerWithAutoincrement class DBProgrammingSubmission(DBSubmission, Base): __tablename__ = "programming_submissions" repository_url: str = Column(String, nullable=False) # type: ignore - exercise_id = Column(BigInteger, ForeignKey("programming_exercises.id", ondelete="CASCADE"), index=True) + exercise_id = Column(BigIntegerWithAutoincrement, ForeignKey("programming_exercises.id", ondelete="CASCADE"), index=True) exercise = relationship("DBProgrammingExercise", back_populates="submissions") feedbacks = relationship("DBProgrammingFeedback", back_populates="submission") diff --git a/athena/athena/models/db_submission.py b/athena/athena/models/db_submission.py index b9d55dd2c..c2e490345 100644 --- a/athena/athena/models/db_submission.py +++ b/athena/athena/models/db_submission.py @@ -1,7 +1,9 @@ -from sqlalchemy import Column, BigInteger, JSON +from sqlalchemy import Column, JSON + from .model import Model +from .big_integer_with_autoincrement import BigIntegerWithAutoincrement class DBSubmission(Model): - id = Column(BigInteger, primary_key=True, index=True, nullable=False) + id = Column(BigIntegerWithAutoincrement, primary_key=True, index=True, autoincrement=True,) meta = Column(JSON, nullable=False) diff --git a/athena/athena/models/db_text_feedback.py b/athena/athena/models/db_text_feedback.py index ca31ec4ed..309f4fd28 100644 --- a/athena/athena/models/db_text_feedback.py +++ b/athena/athena/models/db_text_feedback.py @@ -1,10 +1,11 @@ from typing import Optional -from sqlalchemy import Column, Integer, BigInteger, ForeignKey +from sqlalchemy import Column, Integer, ForeignKey from sqlalchemy.orm import relationship from athena.database import Base from .db_feedback import DBFeedback +from .big_integer_with_autoincrement import BigIntegerWithAutoincrement class DBTextFeedback(DBFeedback, Base): @@ -13,8 +14,8 @@ class DBTextFeedback(DBFeedback, Base): index_start: Optional[int] = Column(Integer) # type: ignore index_end: Optional[int] = Column(Integer) # type: ignore - exercise_id = Column(BigInteger, ForeignKey("text_exercises.id", ondelete="CASCADE"), index=True) - submission_id = Column(BigInteger, ForeignKey("text_submissions.id", ondelete="CASCADE"), index=True) + exercise_id = Column(BigIntegerWithAutoincrement, ForeignKey("text_exercises.id", ondelete="CASCADE"), index=True) + submission_id = Column(BigIntegerWithAutoincrement, ForeignKey("text_submissions.id", ondelete="CASCADE"), index=True) exercise = relationship("DBTextExercise", back_populates="feedbacks") submission = relationship("DBTextSubmission", back_populates="feedbacks") diff --git a/athena/athena/models/db_text_submission.py b/athena/athena/models/db_text_submission.py index b4bf90fea..742f6bbfe 100644 --- a/athena/athena/models/db_text_submission.py +++ b/athena/athena/models/db_text_submission.py @@ -1,8 +1,9 @@ -from sqlalchemy import ForeignKey, BigInteger, Column, String +from sqlalchemy import ForeignKey, Column, String from sqlalchemy.orm import relationship from athena.database import Base from .db_submission import DBSubmission +from .big_integer_with_autoincrement import BigIntegerWithAutoincrement class DBTextSubmission(DBSubmission, Base): @@ -10,7 +11,7 @@ class DBTextSubmission(DBSubmission, Base): text: str = Column(String, nullable=False) # type: ignore language: str = Column(String, nullable=True) # type: ignore - exercise_id = Column(BigInteger, ForeignKey("text_exercises.id", ondelete="CASCADE"), index=True) + exercise_id = Column(BigIntegerWithAutoincrement, ForeignKey("text_exercises.id", ondelete="CASCADE"), index=True) exercise = relationship("DBTextExercise", back_populates="submissions") feedbacks = relationship("DBTextFeedback", back_populates="submission")