mirror of
https://github.com/Kludex/awesome-fastapi-projects.git
synced 2025-05-13 20:57:04 +00:00
Add a unique constraint for the repo url and source graph repo id
This commit is contained in:
parent
cca18fbd33
commit
102de55b12
@ -19,7 +19,7 @@ from collections.abc import AsyncGenerator
|
|||||||
from pathlib import PurePath
|
from pathlib import PurePath
|
||||||
from typing import Final
|
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 (
|
from sqlalchemy.ext.asyncio import (
|
||||||
AsyncAttrs,
|
AsyncAttrs,
|
||||||
AsyncEngine,
|
AsyncEngine,
|
||||||
@ -27,7 +27,12 @@ from sqlalchemy.ext.asyncio import (
|
|||||||
async_sessionmaker,
|
async_sessionmaker,
|
||||||
create_async_engine,
|
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"
|
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
|
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]:
|
async def get_async_session() -> AsyncGenerator[AsyncSession, None]:
|
||||||
"""Get an async session."""
|
"""Get an async session."""
|
||||||
@ -46,10 +61,7 @@ async def get_async_session() -> AsyncGenerator[AsyncSession, None]:
|
|||||||
yield session
|
yield session
|
||||||
|
|
||||||
|
|
||||||
class Base(AsyncAttrs, DeclarativeBase):
|
Base = declarative_base(metadata=metadata, cls=AsyncAttrs)
|
||||||
"""Declarative base for database models."""
|
|
||||||
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class Repo(Base):
|
class Repo(Base):
|
||||||
@ -66,6 +78,7 @@ class Repo(Base):
|
|||||||
dependencies: Mapped[list["Dependency"]] = relationship(
|
dependencies: Mapped[list["Dependency"]] = relationship(
|
||||||
"Dependency", secondary="repo_dependency", back_populates="repos"
|
"Dependency", secondary="repo_dependency", back_populates="repos"
|
||||||
)
|
)
|
||||||
|
__table_args__ = (UniqueConstraint("url", "source_graph_repo_id"),)
|
||||||
|
|
||||||
|
|
||||||
class Dependency(Base):
|
class Dependency(Base):
|
||||||
|
@ -21,7 +21,7 @@ async def create_or_update_repos_from_source_graph_repos_data(
|
|||||||
"""
|
"""
|
||||||
insert_statement = sqlalchemy.dialects.sqlite.insert(database.Repo)
|
insert_statement = sqlalchemy.dialects.sqlite.insert(database.Repo)
|
||||||
update_statement = insert_statement.on_conflict_do_update(
|
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_={
|
set_={
|
||||||
"url": insert_statement.excluded.url,
|
"url": insert_statement.excluded.url,
|
||||||
"description": insert_statement.excluded.description,
|
"description": insert_statement.excluded.description,
|
||||||
|
BIN
db.sqlite3
BIN
db.sqlite3
Binary file not shown.
@ -1,15 +1,15 @@
|
|||||||
"""Create Repo, Dependency and RepoDependency tables
|
"""Set up the database
|
||||||
|
|
||||||
Revision ID: 0232d84a5aea
|
Revision ID: 90eb9d1f9267
|
||||||
Revises:
|
Revises:
|
||||||
Create Date: 2023-08-02 22:14:12.910175
|
Create Date: 2023-08-15 14:13:30.562069
|
||||||
|
|
||||||
"""
|
"""
|
||||||
import sqlalchemy as sa
|
import sqlalchemy as sa
|
||||||
from alembic import op
|
from alembic import op
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
# revision identifiers, used by Alembic.
|
||||||
revision = "0232d84a5aea"
|
revision = "90eb9d1f9267"
|
||||||
down_revision = None
|
down_revision = None
|
||||||
branch_labels = None
|
branch_labels = None
|
||||||
depends_on = None
|
depends_on = None
|
||||||
@ -21,8 +21,8 @@ def upgrade() -> None:
|
|||||||
"dependency",
|
"dependency",
|
||||||
sa.Column("id", sa.Integer(), nullable=False),
|
sa.Column("id", sa.Integer(), nullable=False),
|
||||||
sa.Column("name", sa.String(length=255), nullable=False),
|
sa.Column("name", sa.String(length=255), nullable=False),
|
||||||
sa.PrimaryKeyConstraint("id"),
|
sa.PrimaryKeyConstraint("id", name=op.f("pk_dependency")),
|
||||||
sa.UniqueConstraint("name"),
|
sa.UniqueConstraint("name", name=op.f("uq_dependency_name ")),
|
||||||
)
|
)
|
||||||
op.create_table(
|
op.create_table(
|
||||||
"repo",
|
"repo",
|
||||||
@ -31,19 +31,36 @@ def upgrade() -> None:
|
|||||||
sa.Column("description", sa.Text(), nullable=False),
|
sa.Column("description", sa.Text(), nullable=False),
|
||||||
sa.Column("stars", sa.BigInteger(), nullable=False),
|
sa.Column("stars", sa.BigInteger(), nullable=False),
|
||||||
sa.Column("source_graph_repo_id", sa.BigInteger(), nullable=True),
|
sa.Column("source_graph_repo_id", sa.BigInteger(), nullable=True),
|
||||||
sa.PrimaryKeyConstraint("id"),
|
sa.PrimaryKeyConstraint("id", name=op.f("pk_repo")),
|
||||||
sa.UniqueConstraint("source_graph_repo_id"),
|
sa.UniqueConstraint(
|
||||||
sa.UniqueConstraint("url"),
|
"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(
|
op.create_table(
|
||||||
"repo_dependency",
|
"repo_dependency",
|
||||||
sa.Column("repo_id", sa.Integer(), nullable=False),
|
sa.Column("repo_id", sa.Integer(), nullable=False),
|
||||||
sa.Column("dependency_id", sa.Integer(), nullable=False),
|
sa.Column("dependency_id", sa.Integer(), nullable=False),
|
||||||
sa.ForeignKeyConstraint(
|
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 ###
|
# ### end Alembic commands ###
|
||||||
|
|
@ -16,7 +16,7 @@ dependencies = [
|
|||||||
"alembic",
|
"alembic",
|
||||||
"fastapi[all]",
|
"fastapi[all]",
|
||||||
"httpx-sse",
|
"httpx-sse",
|
||||||
"sqlalchemy[asyncio]",
|
"sqlalchemy[asyncio,mypy]",
|
||||||
"stamina",
|
"stamina",
|
||||||
"third-party-imports",
|
"third-party-imports",
|
||||||
"typer[all]",
|
"typer[all]",
|
||||||
@ -114,7 +114,8 @@ convention = "numpy"
|
|||||||
|
|
||||||
[tool.mypy]
|
[tool.mypy]
|
||||||
plugins = [
|
plugins = [
|
||||||
"pydantic.mypy"
|
"pydantic.mypy",
|
||||||
|
"sqlalchemy.ext.mypy.plugin",
|
||||||
]
|
]
|
||||||
strict = true
|
strict = true
|
||||||
exclude = [
|
exclude = [
|
||||||
|
@ -66,6 +66,10 @@ markupsafe==2.1.3
|
|||||||
# mako
|
# mako
|
||||||
mdurl==0.1.2
|
mdurl==0.1.2
|
||||||
# via markdown-it-py
|
# via markdown-it-py
|
||||||
|
mypy==1.4.1
|
||||||
|
# via sqlalchemy
|
||||||
|
mypy-extensions==1.0.0
|
||||||
|
# via mypy
|
||||||
orjson==3.9.2
|
orjson==3.9.2
|
||||||
# via fastapi
|
# via fastapi
|
||||||
pydantic==2.1.1
|
pydantic==2.1.1
|
||||||
@ -100,7 +104,7 @@ sniffio==1.3.0
|
|||||||
# anyio
|
# anyio
|
||||||
# httpcore
|
# httpcore
|
||||||
# httpx
|
# httpx
|
||||||
sqlalchemy[asyncio]==2.0.19
|
sqlalchemy[asyncio,mypy]==2.0.19
|
||||||
# via
|
# via
|
||||||
# alembic
|
# alembic
|
||||||
# awesome-fastapi-projects (pyproject.toml)
|
# awesome-fastapi-projects (pyproject.toml)
|
||||||
@ -118,6 +122,7 @@ typing-extensions==4.7.1
|
|||||||
# via
|
# via
|
||||||
# alembic
|
# alembic
|
||||||
# fastapi
|
# fastapi
|
||||||
|
# mypy
|
||||||
# pydantic
|
# pydantic
|
||||||
# pydantic-core
|
# pydantic-core
|
||||||
# sqlalchemy
|
# sqlalchemy
|
||||||
|
@ -95,7 +95,9 @@ matplotlib-inline==0.1.6
|
|||||||
mdurl==0.1.2
|
mdurl==0.1.2
|
||||||
# via markdown-it-py
|
# via markdown-it-py
|
||||||
mypy==1.4.1
|
mypy==1.4.1
|
||||||
# via awesome-fastapi-projects (pyproject.toml)
|
# via
|
||||||
|
# awesome-fastapi-projects (pyproject.toml)
|
||||||
|
# sqlalchemy
|
||||||
mypy-extensions==1.0.0
|
mypy-extensions==1.0.0
|
||||||
# via
|
# via
|
||||||
# black
|
# black
|
||||||
@ -176,7 +178,7 @@ sniffio==1.3.0
|
|||||||
# anyio
|
# anyio
|
||||||
# httpcore
|
# httpcore
|
||||||
# httpx
|
# httpx
|
||||||
sqlalchemy[asyncio]==2.0.19
|
sqlalchemy[asyncio,mypy]==2.0.19
|
||||||
# via
|
# via
|
||||||
# alembic
|
# alembic
|
||||||
# awesome-fastapi-projects (pyproject.toml)
|
# awesome-fastapi-projects (pyproject.toml)
|
||||||
|
@ -75,6 +75,10 @@ markupsafe==2.1.3
|
|||||||
# mako
|
# mako
|
||||||
mdurl==0.1.2
|
mdurl==0.1.2
|
||||||
# via markdown-it-py
|
# via markdown-it-py
|
||||||
|
mypy==1.4.1
|
||||||
|
# via sqlalchemy
|
||||||
|
mypy-extensions==1.0.0
|
||||||
|
# via mypy
|
||||||
orjson==3.9.2
|
orjson==3.9.2
|
||||||
# via fastapi
|
# via fastapi
|
||||||
packaging==23.1
|
packaging==23.1
|
||||||
@ -133,7 +137,7 @@ sniffio==1.3.0
|
|||||||
# anyio
|
# anyio
|
||||||
# httpcore
|
# httpcore
|
||||||
# httpx
|
# httpx
|
||||||
sqlalchemy[asyncio]==2.0.19
|
sqlalchemy[asyncio,mypy]==2.0.19
|
||||||
# via
|
# via
|
||||||
# alembic
|
# alembic
|
||||||
# awesome-fastapi-projects (pyproject.toml)
|
# awesome-fastapi-projects (pyproject.toml)
|
||||||
@ -151,6 +155,7 @@ typing-extensions==4.7.1
|
|||||||
# via
|
# via
|
||||||
# alembic
|
# alembic
|
||||||
# fastapi
|
# fastapi
|
||||||
|
# mypy
|
||||||
# polyfactory
|
# polyfactory
|
||||||
# pydantic
|
# pydantic
|
||||||
# pydantic-core
|
# pydantic-core
|
||||||
|
Loading…
x
Reference in New Issue
Block a user