Add a unique constraint for the repo url and source graph repo id

This commit is contained in:
Vladyslav Fedoriuk 2023-08-15 14:30:44 +02:00
parent cca18fbd33
commit 102de55b12
8 changed files with 68 additions and 25 deletions

View File

@ -19,7 +19,7 @@ from collections.abc import AsyncGenerator
from pathlib import PurePath
from typing import Final
from sqlalchemy import BigInteger, ForeignKey, String, Text
from sqlalchemy import BigInteger, ForeignKey, MetaData, String, Text, UniqueConstraint
from sqlalchemy.ext.asyncio import (
AsyncAttrs,
AsyncEngine,
@ -27,7 +27,12 @@ from sqlalchemy.ext.asyncio import (
async_sessionmaker,
create_async_engine,
)
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship
from sqlalchemy.orm import (
Mapped,
declarative_base,
mapped_column,
relationship,
)
DB_PATH: Final[PurePath] = PurePath(__file__).parent.parent / "db.sqlite3"
@ -39,6 +44,16 @@ async_session_maker: Final[async_sessionmaker[AsyncSession]] = async_sessionmake
engine, expire_on_commit=False, autoflush=False, autocommit=False
)
metadata = MetaData(
naming_convention={
"ix": "ix_%(table_name)s_%(column_0_N_name)s ",
"uq": "uq_%(table_name)s_%(column_0_N_name)s ",
"ck": "ck_%(table_name)s_%(constraint_name)s ",
"fk": "fk_%(table_name)s_%(column_0_N_name)s_%(referred_table_name)s",
"pk": "pk_%(table_name)s",
}
)
async def get_async_session() -> AsyncGenerator[AsyncSession, None]:
"""Get an async session."""
@ -46,10 +61,7 @@ async def get_async_session() -> AsyncGenerator[AsyncSession, None]:
yield session
class Base(AsyncAttrs, DeclarativeBase):
"""Declarative base for database models."""
pass
Base = declarative_base(metadata=metadata, cls=AsyncAttrs)
class Repo(Base):
@ -66,6 +78,7 @@ class Repo(Base):
dependencies: Mapped[list["Dependency"]] = relationship(
"Dependency", secondary="repo_dependency", back_populates="repos"
)
__table_args__ = (UniqueConstraint("url", "source_graph_repo_id"),)
class Dependency(Base):

View File

@ -21,7 +21,7 @@ async def create_or_update_repos_from_source_graph_repos_data(
"""
insert_statement = sqlalchemy.dialects.sqlite.insert(database.Repo)
update_statement = insert_statement.on_conflict_do_update(
index_elements=[database.Repo.url],
index_elements=[database.Repo.url, database.Repo.source_graph_repo_id],
set_={
"url": insert_statement.excluded.url,
"description": insert_statement.excluded.description,

Binary file not shown.

View File

@ -1,15 +1,15 @@
"""Create Repo, Dependency and RepoDependency tables
"""Set up the database
Revision ID: 0232d84a5aea
Revision ID: 90eb9d1f9267
Revises:
Create Date: 2023-08-02 22:14:12.910175
Create Date: 2023-08-15 14:13:30.562069
"""
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision = "0232d84a5aea"
revision = "90eb9d1f9267"
down_revision = None
branch_labels = None
depends_on = None
@ -21,8 +21,8 @@ def upgrade() -> None:
"dependency",
sa.Column("id", sa.Integer(), nullable=False),
sa.Column("name", sa.String(length=255), nullable=False),
sa.PrimaryKeyConstraint("id"),
sa.UniqueConstraint("name"),
sa.PrimaryKeyConstraint("id", name=op.f("pk_dependency")),
sa.UniqueConstraint("name", name=op.f("uq_dependency_name ")),
)
op.create_table(
"repo",
@ -31,19 +31,36 @@ def upgrade() -> None:
sa.Column("description", sa.Text(), nullable=False),
sa.Column("stars", sa.BigInteger(), nullable=False),
sa.Column("source_graph_repo_id", sa.BigInteger(), nullable=True),
sa.PrimaryKeyConstraint("id"),
sa.UniqueConstraint("source_graph_repo_id"),
sa.UniqueConstraint("url"),
sa.PrimaryKeyConstraint("id", name=op.f("pk_repo")),
sa.UniqueConstraint(
"source_graph_repo_id", name=op.f("uq_repo_source_graph_repo_id ")
),
sa.UniqueConstraint(
"url",
"source_graph_repo_id",
name=op.f("uq_repo_url_source_graph_repo_id "),
),
sa.UniqueConstraint("url", name=op.f("uq_repo_url ")),
)
op.create_table(
"repo_dependency",
sa.Column("repo_id", sa.Integer(), nullable=False),
sa.Column("dependency_id", sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(
["dependency_id"], ["dependency.id"], ondelete="CASCADE"
["dependency_id"],
["dependency.id"],
name=op.f("fk_repo_dependency_dependency_id_dependency"),
ondelete="CASCADE",
),
sa.ForeignKeyConstraint(
["repo_id"],
["repo.id"],
name=op.f("fk_repo_dependency_repo_id_repo"),
ondelete="CASCADE",
),
sa.PrimaryKeyConstraint(
"repo_id", "dependency_id", name=op.f("pk_repo_dependency")
),
sa.ForeignKeyConstraint(["repo_id"], ["repo.id"], ondelete="CASCADE"),
sa.PrimaryKeyConstraint("repo_id", "dependency_id"),
)
# ### end Alembic commands ###

View File

@ -16,7 +16,7 @@ dependencies = [
"alembic",
"fastapi[all]",
"httpx-sse",
"sqlalchemy[asyncio]",
"sqlalchemy[asyncio,mypy]",
"stamina",
"third-party-imports",
"typer[all]",
@ -114,7 +114,8 @@ convention = "numpy"
[tool.mypy]
plugins = [
"pydantic.mypy"
"pydantic.mypy",
"sqlalchemy.ext.mypy.plugin",
]
strict = true
exclude = [

View File

@ -66,6 +66,10 @@ markupsafe==2.1.3
# mako
mdurl==0.1.2
# via markdown-it-py
mypy==1.4.1
# via sqlalchemy
mypy-extensions==1.0.0
# via mypy
orjson==3.9.2
# via fastapi
pydantic==2.1.1
@ -100,7 +104,7 @@ sniffio==1.3.0
# anyio
# httpcore
# httpx
sqlalchemy[asyncio]==2.0.19
sqlalchemy[asyncio,mypy]==2.0.19
# via
# alembic
# awesome-fastapi-projects (pyproject.toml)
@ -118,6 +122,7 @@ typing-extensions==4.7.1
# via
# alembic
# fastapi
# mypy
# pydantic
# pydantic-core
# sqlalchemy

View File

@ -95,7 +95,9 @@ matplotlib-inline==0.1.6
mdurl==0.1.2
# via markdown-it-py
mypy==1.4.1
# via awesome-fastapi-projects (pyproject.toml)
# via
# awesome-fastapi-projects (pyproject.toml)
# sqlalchemy
mypy-extensions==1.0.0
# via
# black
@ -176,7 +178,7 @@ sniffio==1.3.0
# anyio
# httpcore
# httpx
sqlalchemy[asyncio]==2.0.19
sqlalchemy[asyncio,mypy]==2.0.19
# via
# alembic
# awesome-fastapi-projects (pyproject.toml)

View File

@ -75,6 +75,10 @@ markupsafe==2.1.3
# mako
mdurl==0.1.2
# via markdown-it-py
mypy==1.4.1
# via sqlalchemy
mypy-extensions==1.0.0
# via mypy
orjson==3.9.2
# via fastapi
packaging==23.1
@ -133,7 +137,7 @@ sniffio==1.3.0
# anyio
# httpcore
# httpx
sqlalchemy[asyncio]==2.0.19
sqlalchemy[asyncio,mypy]==2.0.19
# via
# alembic
# awesome-fastapi-projects (pyproject.toml)
@ -151,6 +155,7 @@ typing-extensions==4.7.1
# via
# alembic
# fastapi
# mypy
# polyfactory
# pydantic
# pydantic-core