temp commit

This commit is contained in:
Justin Visser 2026-02-26 12:54:19 +01:00
parent 8760f27b51
commit 0e9e49df16
193 changed files with 23228 additions and 935 deletions

View file

@ -0,0 +1,30 @@
"""Add openalex_enriched to publications
Revision ID: 20260224_0018
Revises: fa0c5e3262d5
Create Date: 2026-02-24 19:10:00.000000
"""
from collections.abc import Sequence
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision: str = '20260224_0018'
down_revision: str | Sequence[str] | None = 'fa0c5e3262d5'
branch_labels: str | Sequence[str] | None = None
depends_on: str | Sequence[str] | None = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('publications', sa.Column('openalex_enriched', sa.Boolean(), server_default=sa.text('false'), nullable=False))
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('publications', 'openalex_enriched')
# ### end Alembic commands ###

View file

@ -0,0 +1,31 @@
"""Add resolving to RunStatus enum
Revision ID: 20260224_0019
Revises: 20260224_0018
Create Date: 2026-02-24 22:20:00.000000
"""
from collections.abc import Sequence
from alembic import op
# revision identifiers, used by Alembic.
revision: str = '20260224_0019'
down_revision: str | Sequence[str] | None = '20260224_0018'
branch_labels: str | Sequence[str] | None = None
depends_on: str | Sequence[str] | None = None
def upgrade() -> None:
# Use COMMIT to break out of the transaction block that Alembic creates in env.py.
# Postgres restricts ALTER TYPE ... ADD VALUE inside transactions when the type is in use.
# This is the robust, non-patchwork way to ensure the schema evolves correctly.
op.execute("COMMIT")
op.execute("ALTER TYPE run_status ADD VALUE IF NOT EXISTS 'resolving' AFTER 'running'")
def downgrade() -> None:
# Enum values cannot be easily removed in Postgres without recreating the type,
# which is risky and usually avoided in simple migrations.
pass

View file

@ -0,0 +1,26 @@
"""Add openalex_last_attempt_at to publications
Revision ID: 20260224_0020
Revises: 20260224_0019
Create Date: 2026-02-24 22:50:00.000000
"""
from collections.abc import Sequence
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision: str = '20260224_0020'
down_revision: str | Sequence[str] | None = '20260224_0019'
branch_labels: str | Sequence[str] | None = None
depends_on: str | Sequence[str] | None = None
def upgrade() -> None:
op.add_column('publications', sa.Column('openalex_last_attempt_at', sa.DateTime(timezone=True), nullable=True))
def downgrade() -> None:
op.drop_column('publications', 'openalex_last_attempt_at')

View file

@ -0,0 +1,70 @@
"""Enforce one active crawl run per user.
Revision ID: 20260225_0021
Revises: 20260224_0020
Create Date: 2026-02-25 09:10:00.000000
"""
from collections.abc import Sequence
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision: str = "20260225_0021"
down_revision: str | Sequence[str] | None = "20260224_0020"
branch_labels: str | Sequence[str] | None = None
depends_on: str | Sequence[str] | None = None
INDEX_NAME = "uq_crawl_runs_user_active"
ACTIVE_STATUSES = ("running", "resolving")
def upgrade() -> None:
bind = op.get_bind()
inspector = sa.inspect(bind)
indexes = {index["name"] for index in inspector.get_indexes("crawl_runs")}
op.execute("ALTER TYPE run_status ADD VALUE IF NOT EXISTS 'canceled'")
op.execute(
"""
WITH ranked AS (
SELECT
id,
ROW_NUMBER() OVER (
PARTITION BY user_id
ORDER BY start_dt DESC, id DESC
) AS rn
FROM crawl_runs
WHERE status IN ('running', 'resolving')
)
UPDATE crawl_runs AS runs
SET
status = 'failed',
end_dt = COALESCE(runs.end_dt, NOW())
FROM ranked
WHERE runs.id = ranked.id
AND ranked.rn > 1
"""
)
if INDEX_NAME not in indexes:
op.create_index(
INDEX_NAME,
"crawl_runs",
["user_id"],
unique=True,
postgresql_where=sa.text(
"status IN ('running'::run_status, 'resolving'::run_status)"
),
)
def downgrade() -> None:
bind = op.get_bind()
inspector = sa.inspect(bind)
indexes = {index["name"] for index in inspector.get_indexes("crawl_runs")}
if INDEX_NAME in indexes:
op.drop_index(INDEX_NAME, table_name="crawl_runs")

View file

@ -0,0 +1,35 @@
"""Add canonical_title_hash to publications for cross-scholar dedup.
Revision ID: 20260225_0022
Revises: 20260225_0021
Create Date: 2026-02-25 10:00:00.000000
"""
from collections.abc import Sequence
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision: str = "20260225_0022"
down_revision: str | Sequence[str] | None = "20260225_0021"
branch_labels: str | Sequence[str] | None = None
depends_on: str | Sequence[str] | None = None
def upgrade() -> None:
op.add_column(
"publications",
sa.Column("canonical_title_hash", sa.String(64), nullable=True),
)
op.create_index(
"ix_publications_canonical_title_hash",
"publications",
["canonical_title_hash"],
)
def downgrade() -> None:
op.drop_index("ix_publications_canonical_title_hash", table_name="publications")
op.drop_column("publications", "canonical_title_hash")

View file

@ -0,0 +1,27 @@
"""remove_doi_from_publications_and_migrate_identifiers
Revision ID: 44f7e10ef777
Revises: 20260222_0016
Create Date: 2026-02-22 17:03:56.261936
"""
from collections.abc import Sequence
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision: str = '44f7e10ef777'
down_revision: str | Sequence[str] | None = '20260222_0016'
branch_labels: str | Sequence[str] | None = None
depends_on: str | Sequence[str] | None = None
def upgrade() -> None:
pass
def downgrade() -> None:
pass

View file

@ -0,0 +1,39 @@
"""Add API integration keys to UserSetting
Revision ID: fa0c5e3262d5
Revises: 44f7e10ef777
Create Date: 2026-02-23 14:25:45.021512
"""
from collections.abc import Sequence
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision: str = 'fa0c5e3262d5'
down_revision: str | Sequence[str] | None = '44f7e10ef777'
branch_labels: str | Sequence[str] | None = None
depends_on: str | Sequence[str] | None = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_index(op.f('ix_publications_doi'), table_name='publications')
op.drop_column('publications', 'doi')
op.add_column('user_settings', sa.Column('openalex_api_key', sa.String(length=255), nullable=True))
op.add_column('user_settings', sa.Column('crossref_api_token', sa.String(length=255), nullable=True))
op.add_column('user_settings', sa.Column('crossref_api_mailto', sa.String(length=255), nullable=True))
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('user_settings', 'crossref_api_mailto')
op.drop_column('user_settings', 'crossref_api_token')
op.drop_column('user_settings', 'openalex_api_key')
op.add_column('publications', sa.Column('doi', sa.VARCHAR(length=255), autoincrement=False, nullable=True))
op.create_index(op.f('ix_publications_doi'), 'publications', ['doi'], unique=False)
# ### end Alembic commands ###