-
-
Notifications
You must be signed in to change notification settings - Fork 43
refactor!: Migrate database from prisma to sqlmodel #982
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
refactor!: Migrate database from prisma to sqlmodel #982
Conversation
Co-authored-by: admin <[email protected]>
Reviewer's GuideThis PR migrates the database layer from Prisma to a SQLModel/SQLAlchemy stack with Alembic support, introducing new SQLModel-based models, refactoring the database client and base controller into async SQLAlchemy patterns, and updating key controllers to leverage the new generic CRUD infrastructure while preserving backward-compatible APIs. Entity relationship diagram for new SQLModel tableserDiagram
GUILD ||--o{ CASE : has
GUILD ||--o{ SNIPPET : has
GUILD ||--o{ NOTE : has
GUILD ||--o{ REMINDER : has
GUILD ||--|{ GUILDCONFIG : has
GUILD ||--o{ AFKMODEL : has
GUILD ||--|{ STARBOARD : has
GUILD ||--o{ STARBOARDMESSAGE : has
GUILD ||--o{ LEVELS : has
CASE }o--|| GUILD : belongs_to
SNIPPET }o--|| GUILD : belongs_to
NOTE }o--|| GUILD : belongs_to
REMINDER }o--|| GUILD : belongs_to
GUILDCONFIG }|--|| GUILD : belongs_to
AFKMODEL }o--|| GUILD : belongs_to
STARBOARD }|--|| GUILD : belongs_to
STARBOARDMESSAGE }o--|| GUILD : belongs_to
LEVELS }o--|| GUILD : belongs_to
GUILD {
int guild_id PK
datetime guild_joined_at
int case_count
}
CASE {
int case_id PK
bool case_status
string case_type
string case_reason
int case_moderator_id
int case_user_id
int[] case_user_roles
int case_number
datetime case_created_at
datetime case_expires_at
bool case_tempban_expired
int guild_id FK
}
SNIPPET {
int snippet_id PK
string snippet_name
string snippet_content
int snippet_user_id
datetime snippet_created_at
int guild_id FK
int uses
bool locked
string alias
}
NOTE {
int note_id PK
string note_content
datetime note_created_at
int note_moderator_id
int note_user_id
int note_number
int guild_id FK
}
REMINDER {
int reminder_id PK
string reminder_content
datetime reminder_created_at
datetime reminder_expires_at
int reminder_channel_id
int reminder_user_id
bool reminder_sent
int guild_id FK
}
GUILDCONFIG {
int guild_id PK, FK
string prefix
int mod_log_id
int audit_log_id
int join_log_id
int private_log_id
int report_log_id
int dev_log_id
int jail_channel_id
int general_channel_id
int starboard_channel_id
int perm_level_0_role_id
int perm_level_1_role_id
int perm_level_2_role_id
int perm_level_3_role_id
int perm_level_4_role_id
int perm_level_5_role_id
int perm_level_6_role_id
int perm_level_7_role_id
int base_staff_role_id
int base_member_role_id
int jail_role_id
int quarantine_role_id
}
AFKMODEL {
int member_id PK
string nickname
string reason
datetime since
datetime until
int guild_id FK
bool enforced
bool perm_afk
}
STARBOARD {
int guild_id PK, FK
int starboard_channel_id
string starboard_emoji
int starboard_threshold
}
STARBOARDMESSAGE {
int message_id PK
string message_content
datetime message_created_at
datetime message_expires_at
int message_channel_id
int message_user_id
int message_guild_id FK
int star_count
int starboard_message_id
}
LEVELS {
int member_id PK
int guild_id PK, FK
float xp
int level
bool blacklisted
datetime last_message
}
Class diagram for new SQLModel-based data modelsclassDiagram
class Guild {
+int guild_id
+datetime guild_joined_at
+int case_count
+List~Case~ cases
+List~Snippet~ snippets
+List~Note~ notes
+List~Reminder~ reminders
+GuildConfig guild_config
+List~AFKModel~ afk_records
+Starboard starboard
+List~StarboardMessage~ starboard_messages
+List~Levels~ levels
}
class Case {
+int case_id
+bool case_status
+CaseType case_type
+str case_reason
+int case_moderator_id
+int case_user_id
+List~int~ case_user_roles
+int case_number
+datetime case_created_at
+datetime case_expires_at
+bool case_tempban_expired
+int guild_id
+Guild guild
}
class AFKModel {
+int member_id
+str nickname
+str reason
+datetime since
+datetime until
+int guild_id
+bool enforced
+bool perm_afk
+Guild guild
}
class GuildConfig {
+int guild_id
+str prefix
+int mod_log_id
+int audit_log_id
+int join_log_id
+int private_log_id
+int report_log_id
+int dev_log_id
+int jail_channel_id
+int general_channel_id
+int starboard_channel_id
+int perm_level_0_role_id
+int perm_level_1_role_id
+int perm_level_2_role_id
+int perm_level_3_role_id
+int perm_level_4_role_id
+int perm_level_5_role_id
+int perm_level_6_role_id
+int perm_level_7_role_id
+int base_staff_role_id
+int base_member_role_id
+int jail_role_id
+int quarantine_role_id
+Guild guild
}
class Levels {
+int member_id
+int guild_id
+float xp
+int level
+bool blacklisted
+datetime last_message
+Guild guild
}
class Note {
+int note_id
+str note_content
+datetime note_created_at
+int note_moderator_id
+int note_user_id
+int note_number
+int guild_id
+Guild guild
}
class Reminder {
+int reminder_id
+str reminder_content
+datetime reminder_created_at
+datetime reminder_expires_at
+int reminder_channel_id
+int reminder_user_id
+bool reminder_sent
+int guild_id
+Guild guild
}
class Snippet {
+int snippet_id
+str snippet_name
+str snippet_content
+int snippet_user_id
+datetime snippet_created_at
+int guild_id
+int uses
+bool locked
+str alias
+Guild guild
}
class Starboard {
+int guild_id
+int starboard_channel_id
+str starboard_emoji
+int starboard_threshold
+Guild guild
}
class StarboardMessage {
+int message_id
+str message_content
+datetime message_created_at
+datetime message_expires_at
+int message_channel_id
+int message_user_id
+int message_guild_id
+int star_count
+int starboard_message_id
+Guild guild
}
Guild "1" --o "*" Case : cases
Guild "1" --o "*" Snippet : snippets
Guild "1" --o "*" Note : notes
Guild "1" --o "*" Reminder : reminders
Guild "1" --o "1" GuildConfig : guild_config
Guild "1" --o "*" AFKModel : afk_records
Guild "1" --o "1" Starboard : starboard
Guild "1" --o "*" StarboardMessage : starboard_messages
Guild "1" --o "*" Levels : levels
Case "*" --o "1" Guild : guild
AFKModel "*" --o "1" Guild : guild
GuildConfig "1" --o "1" Guild : guild
Levels "*" --o "1" Guild : guild
Note "*" --o "1" Guild : guild
Reminder "*" --o "1" Guild : guild
Snippet "*" --o "1" Guild : guild
Starboard "1" --o "1" Guild : guild
StarboardMessage "*" --o "1" Guild : guild
class CaseType {
<<enum>>
BAN
UNBAN
HACKBAN
TEMPBAN
KICK
SNIPPETBAN
TIMEOUT
UNTIMEOUT
WARN
JAIL
UNJAIL
SNIPPETUNBAN
UNTEMPBAN
POLLBAN
POLLUNBAN
}
Class diagram for refactored BaseController and DatabaseClientclassDiagram
class BaseController~ModelT~ {
-Type model
-str model_name
-Type table
+find_one(where, include, ...)
+find_unique(where, include, ...)
+find_many(where, order, take, skip, ...)
+count(where)
+create(data)
+update(where, data)
+delete(where)
+upsert(where, create, update)
+safe_get_attr(obj, attr, default)
+connect_or_create_relation(id_field, model_id, ...)
}
class DatabaseClient {
-AsyncEngine _engine
-async_sessionmaker _session_factory
+is_connected
+connect(database_url, echo)
+disconnect()
+session()
+transaction()
}
BaseController~ModelT~ <|-- AfkController
BaseController~ModelT~ <|-- CaseController
BaseController~ModelT~ <|-- GuildController
note for BaseController~ModelT~ "Now generic over SQLModel types"
note for DatabaseClient "Now wraps SQLAlchemy async engine/session"
AfkController : +get_afk_member(member_id, guild_id)
CaseController : +get_next_case_number(guild_id)
CaseController : +insert_case(...)
GuildController : +get_guild_by_id(guild_id)
GuildController : +get_or_create_guild(guild_id)
GuildController : +insert_guild_by_id(guild_id)
DatabaseClient : +db (singleton instance)
class AfkController
class CaseController
class GuildController
File-Level Changes
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
Dependency ReviewThe following issues were found:
License Issuespoetry.lock
OpenSSF ScorecardScorecard details
Scanned Files
|
Deploying tux with
|
Latest commit: |
03a0cb6
|
Status: | ✅ Deploy successful! |
Preview URL: | https://49692e84.tux-afh.pages.dev |
Branch Preview URL: | https://cursor-migrate-database-from.tux-afh.pages.dev |
Co-authored-by: admin <[email protected]>
…ollers Co-authored-by: admin <[email protected]>
Co-authored-by: admin <[email protected]>
Co-authored-by: admin <[email protected]>
Co-authored-by: admin <[email protected]>
Co-authored-by: admin <[email protected]>
Co-authored-by: admin <[email protected]>
… setup-python action
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #982 +/- ##
=======================================
Coverage ? 10.78%
=======================================
Files ? 124
Lines ? 10530
Branches ? 1281
=======================================
Hits ? 1136
Misses ? 9289
Partials ? 105
*This pull request uses carry forward flags. Click here to find out more.
☔ View full report in Codecov by Sentry. |
…rams, update_many)
Co-authored-by: admin <[email protected]>
Co-authored-by: admin <[email protected]>
…restore db.is_connected callable
Co-authored-by: admin <[email protected]>
Co-authored-by: admin <[email protected]>
Co-authored-by: admin <[email protected]>
Move `from __future__ import annotations` to the top of files to ensure future compatibility. Reorganize imports in `cases.py` and `snippet.py` for better readability and maintainability. Remove redundant inline imports in `snippet.py` to streamline the code. style: replace en dashes with hyphens for consistency Replace en dashes with hyphens in comments and docstrings to maintain consistency across the codebase. This change improves readability and ensures uniformity in documentation style. These changes enhance code readability, maintainability, and ensure future compatibility by organizing imports and standardizing comment styles.
refactor(core.py): update log message for clarity on database usage refactor(client.py): improve comments and add type ignores for SQLAlchemy methods refactor(base.py): enhance comments for clarity and maintain API consistency refactor(case.py, guild_config.py): update comments and remove Prisma-specific notes refactor(snippet.py): add type ignores for SQLAlchemy methods refactor(models.py): simplify imports and update comments for consistency The addition of Pydantic is necessary for data validation and parsing, which enhances the robustness of the application. The refactoring across various files aims to improve code readability and maintainability by updating comments, removing outdated references to Prisma, and ensuring type consistency with SQLAlchemy methods. These changes help in maintaining a clean codebase and facilitate easier future updates.
Description
This PR initiates the migration of the project's database layer from Prisma to SQLModel, integrating Alembic for future database migrations. The primary motivation is to transition to a more Pythonic and mature database solution.
Key changes include:
prisma
and addition ofsqlmodel
,sqlalchemy
(v2-series), andalembic
topyproject.toml
.tux/database/models.py
containing all data models (e.g.,Guild
,Case
,AFKModel
) rewritten using SQLModel conventions, including theCaseType
enum.tux/database/client.py
has been re-implemented to utilize an async SQLAlchemy engine and session factory, providing a similar public API for minimal disruption to higher-level code.tux/database/controllers/base.py
has been rewritten to provide a SQLModel-powered asynchronous CRUD (Create, Read, Update, Delete) layer, maintaining compatibility with the previous Prisma-based controller's API.AfkController
,CaseController
, andGuildController
have been updated to use the new SQLModel-based models and the refactoredBaseController
.CaseController
'sget_next_case_number
now uses SQLModel logic for atomic increments.This PR lays the foundational groundwork for fully deprecating Prisma from the codebase.
Guidelines
How Has This Been Tested? (if applicable)
The changes have been verified to compile successfully. Initial manual checks confirm the new database client and base controller are functional, and the partially migrated controllers (
AfkController
,CaseController
,GuildController
) integrate correctly. Full test suite integration and validation will follow once all remaining controllers are migrated.Screenshots (if applicable)
N/A
Additional Information
This PR represents the first major phase of the database migration. Remaining work includes:
note.py
,reminder.py
,snippet.py
,guild_config.py
,levels.py
,starboard.py
).tux/cli/database.py
.README.md
to reflect the new SQLModel and Alembic stack.Open in Web • Open in Cursor • Open Docs
Summary by Sourcery
Migrate the database layer from Prisma to SQLModel/SQLAlchemy, replacing the Prisma client with an async SQLModel-powered repository pattern and integrating Alembic for future migrations.
New Features:
Enhancements:
Build: