No SQLModel

This commit is contained in:
ciomek committed 2026-09-04 23:41:35 +02:00
1 parent 5f0e8c11b4
commit 9964fbf044
16 files changed
+91 -84

No files matched your search

+2 -3
View File
@@ -4,9 +4,8 @@ from sqlalchemy import engine_from_config
from sqlalchemy import pool
from alembic import context
from sqlmodel import SQLModel
from loon.web.db import database_url
from loon.web.db import Base, database_url
import loon.web
@@ -23,7 +22,7 @@ if config.config_file_name is not None:
# for 'autogenerate' support
# from myapp import mymodel
# target_metadata = mymodel.Base.metadata
target_metadata = SQLModel.metadata
target_metadata = Base.metadata
config.set_main_option("sqlalchemy.url", database_url())
+6 -7
View File
@@ -10,7 +10,6 @@ from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
import sqlmodel
# revision identifiers, used by Alembic.
revision: str = '0f809a005dc6'
@@ -24,14 +23,14 @@ def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('logtype',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('code', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column('code', sa.String(), nullable=False),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('code')
)
op.create_table('minecraftuser',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('uuid', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column('username', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column('uuid', sa.String(), nullable=False),
sa.Column('username', sa.String(), nullable=False),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('uuid')
)
@@ -39,15 +38,15 @@ def upgrade() -> None:
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('log_type_id', sa.Integer(), nullable=False),
sa.Column('created_at', sa.DateTime(), nullable=False),
sa.Column('message', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column('message', sa.String(), nullable=False),
sa.ForeignKeyConstraint(['log_type_id'], ['logtype.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_table('user',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('minecraft_user_id', sa.Integer(), nullable=False),
sa.Column('internal_username', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column('password', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column('internal_username', sa.String(), nullable=False),
sa.Column('password', sa.String(), nullable=False),
sa.Column('admin', sa.Boolean(), nullable=False),
sa.ForeignKeyConstraint(['minecraft_user_id'], ['minecraftuser.id'], ),
sa.PrimaryKeyConstraint('id'),
@@ -1,7 +1,8 @@
import json
from sqlalchemy.exc import IntegrityError
from sqlmodel import Session, select
from sqlalchemy import select
from sqlalchemy.orm import Session
from loon.web.db import engine
from loon.web.logs.service import write_log, player_tag
@@ -25,16 +26,16 @@ async def change_password_handler(client, userdata, msg, data):
with Session(engine) as session:
statement = select(User).join(MinecraftUser).where(MinecraftUser.uuid == uuid)
user = session.exec(statement).first()
user = session.execute(statement).scalars().first()
if user is None:
client.publish(f"loon/auth/change_password/{uuid}/response",
json.dumps({"success": False, "error": "The user is not registered!"}))
return
user = session.exec(
user = session.execute(
select(User).join(MinecraftUser).where(MinecraftUser.uuid == uuid)
).first()
).scalars().first()
user.password = password
internal_username = user.internal_username
+5 -4
View File
@@ -1,7 +1,8 @@
import json
from sqlalchemy.exc import IntegrityError
from sqlmodel import Session, select
from sqlalchemy import select
from sqlalchemy.orm import Session
from loon.web.db import engine
from loon.web.logs.service import write_log, player_tag
@@ -25,7 +26,7 @@ async def register_request_handler(client, userdata, msg, data):
internal_username = data["internalUsername"]
with Session(engine) as session:
minecraft_user = session.exec(select(MinecraftUser).where(MinecraftUser.uuid == uuid)).first()
minecraft_user = session.execute(select(MinecraftUser).where(MinecraftUser.uuid == uuid)).scalars().first()
if minecraft_user is None:
client.publish(f"loon/auth/register/{uuid}/response",
@@ -33,7 +34,7 @@ async def register_request_handler(client, userdata, msg, data):
return
statement = select(User).where(User.minecraft_user_id == minecraft_user.id)
user = session.exec(statement).first()
user = session.execute(statement).scalars().first()
if user is not None:
client.publish(f"loon/auth/register/{uuid}/response",
@@ -41,7 +42,7 @@ async def register_request_handler(client, userdata, msg, data):
return
statement = select(User).where(User.internal_username == internal_username)
user = session.exec(statement).first()
user = session.execute(statement).scalars().first()
if user is not None:
client.publish(f"loon/auth/register/{uuid}/response",
+4 -3
View File
@@ -1,6 +1,7 @@
import json
from sqlmodel import Session, select
from sqlalchemy import select
from sqlalchemy.orm import Session
from loon.web.db import engine
from loon.web.users.models import MinecraftUser, User
@@ -19,9 +20,9 @@ async def show_username_handler(client, userdata, msg, data):
return
with Session(engine) as session:
user = session.exec(
user = session.execute(
select(User).join(MinecraftUser).where(MinecraftUser.uuid == uuid)
).first()
).scalars().first()
if user is None:
client.publish(f"loon/auth/show_username/{uuid}/response",
+4 -3
View File
@@ -1,4 +1,5 @@
from sqlmodel import Session, select
from sqlalchemy import select
from sqlalchemy.orm import Session
from loon.web.db import engine
from loon.web.users.models import User
@@ -6,9 +7,9 @@ from loon.web.users.models import User
def choose_admin(username: str) -> None:
with Session(engine) as session:
user = session.exec(
user = session.execute(
select(User).where(User.internal_username == username)
).first()
).scalars().first()
if user is None:
print(f"No user named {username!r}.")
+7 -7
View File
@@ -1,6 +1,6 @@
from fastapi import APIRouter, HTTPException
from sqlalchemy.orm import selectinload
from sqlmodel import Session, select
from sqlalchemy.orm import selectinload, Session
from sqlalchemy import select
from starlette.requests import Request
from loon.web.auth.middleware import admin
@@ -22,7 +22,7 @@ async def list_logs(request: Request):
.options(selectinload(LogEntry.log_type))
.order_by(LogEntry.created_at)
)
entries = session.exec(statement).all()
entries = session.execute(statement).scalars().all()
return [
LogEntryResponse(
id=entry.id,
@@ -39,7 +39,7 @@ async def list_logs(request: Request):
async def list_mc_users(request: Request):
with Session(engine) as session:
statement = select(MinecraftUser).order_by(MinecraftUser.username)
return session.exec(statement).all()
return session.execute(statement).scalars().all()
@router.get("/users", response_model=list[UserPublic])
@@ -51,7 +51,7 @@ async def list_users(request: Request):
.options(selectinload(User.minecraft_user))
.order_by(User.internal_username)
)
return session.exec(statement).all()
return session.execute(statement).scalars().all()
@router.get("/users/{internal_username}", response_model=UserPublic)
@@ -63,7 +63,7 @@ async def get_user(request: Request, internal_username: str):
.where(User.internal_username == internal_username)
.options(selectinload(User.minecraft_user))
)
user = session.exec(statement).first()
user = session.execute(statement).scalars().first()
if user is None:
raise HTTPException(status_code=404)
return user
@@ -79,7 +79,7 @@ async def get_user_by_uuid(request: Request, uuid: str):
.where(MinecraftUser.uuid == uuid)
.options(selectinload(User.minecraft_user))
)
user = session.exec(statement).first()
user = session.execute(statement).scalars().first()
if user is None:
raise HTTPException(status_code=404)
return user
+4 -4
View File
@@ -8,8 +8,8 @@ from starlette.authentication import (
)
from starlette.requests import HTTPConnection
from starlette.responses import JSONResponse, Response
from sqlalchemy.orm import selectinload
from sqlmodel import Session, select
from sqlalchemy.orm import selectinload, Session
from sqlalchemy import select
from loon.web.db import engine
from loon.web.users.models import User
@@ -63,9 +63,9 @@ class JWTAuthBackend(AuthenticationBackend):
raise AuthenticationError("Invalid or expired token")
with Session(engine) as session:
user = session.exec(
user = session.execute(
select(User).where(User.id == user_id).options(selectinload(User.minecraft_user))
).first()
).scalars().first()
if user is None:
raise AuthenticationError("User not found")
+3 -2
View File
@@ -1,5 +1,6 @@
from fastapi import APIRouter, HTTPException, Request, status
from sqlmodel import Session, select
from sqlalchemy import select
from sqlalchemy.orm import Session
from loon.web import limiter
from loon.web.auth.middleware import authenticated
@@ -17,7 +18,7 @@ router = APIRouter(prefix="/auth", tags=["auth"])
async def get_jwt(request: Request, body: JWTRequest) -> JWTResponse:
with Session(engine) as session:
statement = select(User).where(User.internal_username == body.username)
user = session.exec(statement).first()
user = session.execute(statement).scalars().first()
if user is None or user.id is None or not verify_password(body.password, user.password):
raise HTTPException(
+6 -1
View File
@@ -1,8 +1,13 @@
from sqlmodel import SQLModel, create_engine
from sqlalchemy import create_engine
from sqlalchemy.orm import DeclarativeBase
from config import settings
class Base(DeclarativeBase):
pass
def database_url(url: str | None = None) -> str:
url = url or settings.database.url
for src, dst in (
+18 -11
View File
@@ -1,17 +1,24 @@
from datetime import datetime, timezone
from sqlmodel import SQLModel, Field, Relationship
from sqlalchemy import ForeignKey
from sqlalchemy.orm import Mapped, mapped_column, relationship
from loon.web.db import Base
class LogType(SQLModel, table=True):
id: int = Field(default=None, primary_key=True)
code: str = Field(nullable=False, unique=True)
entries: list["LogEntry"] = Relationship(back_populates="log_type")
class LogType(Base):
__tablename__ = "logtype"
id: Mapped[int] = mapped_column(primary_key=True)
code: Mapped[str] = mapped_column(unique=True)
entries: Mapped[list["LogEntry"]] = relationship(back_populates="log_type")
class LogEntry(SQLModel, table=True):
id: int = Field(default=None, primary_key=True)
log_type_id: int = Field(foreign_key="logtype.id", nullable=False)
log_type: LogType = Relationship(back_populates="entries")
created_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
message: str = Field(nullable=False)
class LogEntry(Base):
__tablename__ = "logentry"
id: Mapped[int] = mapped_column(primary_key=True)
log_type_id: Mapped[int] = mapped_column(ForeignKey("logtype.id"))
log_type: Mapped[LogType] = relationship(back_populates="entries")
created_at: Mapped[datetime] = mapped_column(default=lambda: datetime.now(timezone.utc))
message: Mapped[str]
+3 -2
View File
@@ -1,6 +1,7 @@
import asyncio
from sqlmodel import Session, select
from sqlalchemy import select
from sqlalchemy.orm import Session
from loon.web.db import engine
from loon.web.logs.models import LogType, LogEntry
@@ -14,7 +15,7 @@ def player_tag(uuid: str, username: str) -> str:
def _write_log(log_type: LogTypeEnum, message: str) -> None:
with Session(engine) as session:
statement = select(LogType).where(LogType.code == log_type.value)
log_type_object = session.exec(statement).first()
log_type_object = session.execute(statement).scalars().first()
if not log_type_object:
log_type_object = LogType(code=log_type.value)
+20 -13
View File
@@ -1,22 +1,29 @@
from sqlmodel import SQLModel, Field, Relationship
from sqlalchemy import ForeignKey
from sqlalchemy.orm import Mapped, mapped_column, relationship
from loon.web.db import Base
class MinecraftUser(SQLModel, table=True):
id: int = Field(default=None, primary_key=True)
uuid: str = Field(unique=True)
username: str
user: "User" = Relationship(back_populates="minecraft_user")
class MinecraftUser(Base):
__tablename__ = "minecraftuser"
id: Mapped[int] = mapped_column(primary_key=True)
uuid: Mapped[str] = mapped_column(unique=True)
username: Mapped[str]
user: Mapped["User"] = relationship(back_populates="minecraft_user")
class User(SQLModel, table=True):
id: int = Field(default=None, primary_key=True)
class User(Base):
__tablename__ = "user"
minecraft_user_id: int = Field(foreign_key="minecraftuser.id", nullable=False, unique=True)
minecraft_user: MinecraftUser = Relationship(back_populates="user")
id: Mapped[int] = mapped_column(primary_key=True)
internal_username: str = Field(unique=True)
password: str
admin: bool = Field(default=False)
minecraft_user_id: Mapped[int] = mapped_column(ForeignKey("minecraftuser.id"), unique=True)
minecraft_user: Mapped[MinecraftUser] = relationship(back_populates="user")
internal_username: Mapped[str] = mapped_column(unique=True)
password: Mapped[str]
admin: Mapped[bool] = mapped_column(default=False)
@property
def uuid(self) -> str:
+4 -3
View File
@@ -1,6 +1,7 @@
import asyncio
from sqlmodel import Session, select
from sqlalchemy import select
from sqlalchemy.orm import Session
from loon.web.db import engine
from loon.web.users.models import MinecraftUser
@@ -10,9 +11,9 @@ def _sync_minecraft_users(players: list[dict]) -> list[MinecraftUser]:
players_by_uuid = {player["uuid"]: player["username"] for player in players}
with Session(engine) as session:
existing = session.exec(
existing = session.execute(
select(MinecraftUser).where(MinecraftUser.uuid.in_(players_by_uuid))
).all()
).scalars().all()
existing_by_uuid = {minecraft_user.uuid: minecraft_user for minecraft_user in existing}
new_users = []
-1
View File
@@ -55,7 +55,6 @@ dependencies = [
"shellingham==1.5.4",
"slowapi>=0.1.10",
"sqlalchemy==2.0.51",
"sqlmodel==0.0.39",
"starlette==1.3.1",
"typer==0.27.0",
"typing-extensions==4.16.0",
Generated
-16
View File
@@ -516,7 +516,6 @@ dependencies = [
{ name = "shellingham" },
{ name = "slowapi" },
{ name = "sqlalchemy" },
{ name = "sqlmodel" },
{ name = "starlette" },
{ name = "typer" },
{ name = "typing-extensions" },
@@ -580,7 +579,6 @@ requires-dist = [
{ name = "shellingham", specifier = "==1.5.4" },
{ name = "slowapi", specifier = ">=0.1.10" },
{ name = "sqlalchemy", specifier = "==2.0.51" },
{ name = "sqlmodel", specifier = "==0.0.39" },
{ name = "starlette", specifier = "==1.3.1" },
{ name = "typer", specifier = "==0.27.0" },
{ name = "typing-extensions", specifier = "==4.16.0" },
@@ -1022,20 +1020,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/e2/22/dbf013a12ec759e54a34a119e9e217435b3f71b2dd5c61a7ade0a25dae87/sqlalchemy-2.0.51-py3-none-any.whl", hash = "sha256:bb024d8b621d0be75f4f44ecc7c950450026e76d66dc8f791bb5331d7fed59d5", size = 1944334, upload-time = "2026-06-15T16:09:22.418Z" },
]
[[package]]
name = "sqlmodel"
version = "0.0.39"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "pydantic" },
{ name = "sqlalchemy" },
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/68/ee/22a0559283c3cf6048678e787ed5d4959dcd00dedd8ba4567eeae684eeb1/sqlmodel-0.0.39.tar.gz", hash = "sha256:23d8e50a8d8ee936032ed79c55023a5d618dd6bc3c510bbf4909d1a7a605a570", size = 91057, upload-time = "2026-06-25T13:01:38.475Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/cf/7d/b9813a582d4eb310be35e1fc7dfaae71207d7b62e9e53be314ebd251b53b/sqlmodel-0.0.39-py3-none-any.whl", hash = "sha256:90ebe92ce5cc11d7fff8dc7cb594790a102333c8fe7c14865254f6fc5c939795", size = 29680, upload-time = "2026-06-25T13:01:37.494Z" },
]
[[package]]
name = "starlette"
version = "1.3.1"