"""Cards remember when they were last answered "Known" and "to review" were React state: they vanished on reload, so a deck of two hundred was two hundred cards every time and the only spacing was whichever cards a learner remembered to skip. This is the log the scheduler reads. A log rather than a row per card, because what the scheduler needs is the latest verdict and its age — and keeping the history means a card missed three times running can later be treated differently from one missed once, without a migration to add the column that would have recorded it. Revision ID: m3d4e5f6a7b8 Revises: l2c3d4e5f6a7 """ import sqlalchemy as sa from alembic import op revision = "m3d4e5f6a7b8" down_revision = "l2c3d4e5f6a7" branch_labels = None depends_on = None def upgrade() -> None: if "flashcard_reviews" in sa.inspect(op.get_bind()).get_table_names(): return op.create_table( "flashcard_reviews", sa.Column("id", sa.Integer(), primary_key=True), sa.Column("user_id", sa.Integer(), sa.ForeignKey("users.id", ondelete="CASCADE"), nullable=False), sa.Column("flashcard_id", sa.Integer(), sa.ForeignKey("flashcards.id", ondelete="CASCADE"), nullable=False), sa.Column("outcome", sa.String(length=10), nullable=False), sa.Column("created_at", sa.DateTime(), nullable=True), ) op.create_index("ix_flashcard_reviews_user_id", "flashcard_reviews", ["user_id"]) op.create_index("ix_flashcard_reviews_flashcard_id", "flashcard_reviews", ["flashcard_id"]) # The scheduler asks "this learner's latest verdict per card", which is this # index read backwards. op.create_index("ix_flashcard_reviews_recent", "flashcard_reviews", ["user_id", "flashcard_id", "created_at"]) def downgrade() -> None: op.drop_table("flashcard_reviews")