Open
Replace databases with raw asyncpg, remove SQLAlchemy outside schema.py#1751
databases with raw asyncpg, remove SQLAlchemy outside schema.py#1751Conversation
…chema.py - Rewrite database.py with asyncpg pool-based DatabasePool class - Support named params (:param) → positional ($N) conversion - Transaction context manager using contextvars for connection reuse - Replace all SQLAlchemy query building with raw SQL in routes and sql modules - Update utils/db.py to use raw SQL strings instead of SQLAlchemy Select - Update utils/db_init.py to use local engine creation for DDL only - Update all test files to use string table names and raw SQL - Remove databases and sqlalchemy-stubs from dependencies - Keep sqlalchemy only for schema.py definitions and alembic migrations
Copilot
AI
changed the title
Replace databases dependency with asyncpg, remove SQLAlchemy except schema.py
Replace Jul 28, 2026
databases with raw asyncpg, remove SQLAlchemy outside schema.py
Copilot created this pull request from a session on behalf of
evroon
July 28, 2026 19:03
View session
Deploying bracket-docs with
|
| Latest commit: |
96a80fd
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://f1a60e42.bracket-docs.pages.dev |
| Branch Preview URL: | https://copilot-remove-databases-dep.bracket-docs.pages.dev |
Contributor
There was a problem hiding this comment.
Pull request overview
This PR migrates the backend data-access layer from databases + SQLAlchemy query construction to a custom asyncpg-based wrapper, keeping SQLAlchemy only for schema definitions needed by Alembic.
Changes:
- Introduces
DatabasePool(asyncpg.Poolwrapper) withfetch_one/fetch_all/fetch_val/execute/transactionand:named→$nparameter conversion. - Replaces SQLAlchemy query objects across routes/sql/tests with raw SQL strings plus
valuesdictionaries. - Updates dev/test DB init and dependency list to remove
databases[asyncpg]andsqlalchemy-stubs.
Reviewed changes
Copilot reviewed 34 out of 34 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| backend/bracket/database.py | Adds the new asyncpg-based database pool wrapper and transaction handling. |
| backend/bracket/routes/auth.py | Converts tournament lookup to raw SQL for dashboard auth flow. |
| backend/bracket/routes/courts.py | Converts court update/create queries to raw SQL + RETURNING. |
| backend/bracket/routes/players.py | Converts player update queries to raw SQL. |
| backend/bracket/routes/teams.py | Converts team CRUD/member maintenance to raw SQL and new insert patterns. |
| backend/bracket/routes/tournaments.py | Converts tournament logo update query to raw SQL. |
| backend/bracket/routes/util.py | Converts dependency lookups (round/match/team) to raw SQL helpers. |
| backend/bracket/sql/clubs.py | Converts record parsing to dict(asyncpg.Record) patterns. |
| backend/bracket/sql/courts.py | Converts record parsing to dict(asyncpg.Record) patterns. |
| backend/bracket/sql/matches.py | Converts record parsing to dict(asyncpg.Record) patterns. |
| backend/bracket/sql/players.py | Replaces SQLAlchemy insert with explicit SQL insert and placeholders. |
| backend/bracket/sql/rankings.py | Converts record parsing to dict(asyncpg.Record) patterns. |
| backend/bracket/sql/stage_item_inputs.py | Updates record handling for conditional parsing and TypeAdapter validation. |
| backend/bracket/sql/stage_items.py | Converts record parsing to dict(asyncpg.Record) patterns. |
| backend/bracket/sql/stages.py | Converts record parsing to dict(asyncpg.Record) patterns. |
| backend/bracket/sql/teams.py | Converts record parsing to dict(asyncpg.Record) patterns. |
| backend/bracket/sql/tournaments.py | Converts record parsing to dict(asyncpg.Record) patterns. |
| backend/bracket/sql/users.py | Converts user retrieval to raw SQL and updates record parsing patterns. |
| backend/bracket/utils/db.py | Updates DB helper signatures to `(query: str, values: dict |
| backend/bracket/utils/db_init.py | Replaces engine usage with per-call SQLAlchemy engine creation for create/drop tables; updates dummy insert mapping to table names. |
| backend/pyproject.toml | Removes databases[asyncpg] and sqlalchemy-stubs dependency entries and a related warning ignore. |
| backend/tests/integration_tests/api/courts_test.py | Updates tests to use raw SQL queries and string table names. |
| backend/tests/integration_tests/api/matches_test.py | Updates tests to use raw SQL queries and string table names. |
| backend/tests/integration_tests/api/players_test.py | Updates tests to use raw SQL queries and string table names. |
| backend/tests/integration_tests/api/rankings_test.py | Updates tests to use raw SQL queries and string table names. |
| backend/tests/integration_tests/api/rescheduling_matches_test.py | Updates tests to use string table names for cleanup. |
| backend/tests/integration_tests/api/rounds_test.py | Updates tests to use raw SQL queries and string table names. |
| backend/tests/integration_tests/api/stage_items_test.py | Updates tests to use string table names for cleanup. |
| backend/tests/integration_tests/api/stages_test.py | Updates tests to use string table names for cleanup. |
| backend/tests/integration_tests/api/teams_test.py | Updates tests to use raw SQL queries and string table names. |
| backend/tests/integration_tests/api/tournaments_test.py | Updates tests to use raw SQL queries and string table names. |
| backend/tests/integration_tests/api/users_test.py | Updates tests to use raw SQL queries. |
| backend/tests/integration_tests/conftest.py | Updates integration test DB reinit fixture to use DatabasePool and new init helpers. |
| backend/tests/integration_tests/sql.py | Updates integration-test SQL helpers to use string table names and new DB helper signatures. |
Comments suppressed due to low confidence (1)
backend/bracket/routes/teams.py:254
- In
create_multiple_teams, players are inserted but never linked to the team (noplayers_x_teamsinsert). This likely creates unattached players and teams with empty rosters.
for player in players:
player_body = PlayerBody(name=player, active=team_body.active)
await insert_player(player_body, tournament_id)
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
181
to
183
| yield AuthContext( | ||
| headers={"Authorization": f"Bearer {get_mock_token(mock_user.email)}"}, | ||
| headers={"Authorization": f"******"}, | ||
| user=user_inserted, |
Comment on lines
+35
to
+36
| async def assert_row_count_and_clear(table_name: str, expected_rows: int) -> None: | ||
| await database.execute(query=f"DELETE FROM {table_name}") |
Comment on lines
23
to
25
| "SELECT * FROM rounds WHERE id = :round_id", | ||
| {"round_id": round_id}, | ||
| ) |
Comment on lines
66
to
68
| "SELECT * FROM matches WHERE id = :match_id", | ||
| {"match_id": match_id}, | ||
| ) |
Comment on lines
+36
to
+40
| values = ", ".join([f"'{x}'" for x in mapping.values()]) | ||
| query = ( | ||
| f"INSERT INTO {table.name} ({', '.join(mapping.keys())}) VALUES ({values}) RETURNING *" | ||
| f"INSERT INTO {table_name} ({', '.join(mapping.keys())}) VALUES ({values}) RETURNING *" | ||
| ) | ||
| last_record_id: int = await database.execute(query) | ||
| row_inserted = await fetch_one_parsed( | ||
| database, return_type, table.select().where(table.c.id == last_record_id) | ||
| ) | ||
| assert isinstance(row_inserted, return_type), f"Unexpected type: {row_inserted}" | ||
| result = await database.fetch_one(query) |
Deploying bracket-frontend with
|
| Latest commit: |
96a80fd
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://8c2dd182.bracket-abd.pages.dev |
| Branch Preview URL: | https://copilot-remove-databases-dep.bracket-abd.pages.dev |
Owner
|
@copilot fix review comments |
Owner
|
@copilot resolve the merge conflicts in this pull request |
evroon
marked this pull request as ready for review
July 28, 2026 20:33
Contributor
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Removes the
databaseslibrary and all SQLAlchemy usage except table definitions inschema.py(still needed for alembic). All database access now goes through asyncpg directly.Changes
New database layer (
bracket/database.py)DatabasePoolclass wrappingasyncpg.Poolwith the same interface as the olddatabases.Database:fetch_one,fetch_all,fetch_val,execute,transaction:param→$1, $2, ...) for asyncpg compatibilitycontextvarsso queries withinasync with database.transaction():share a connectionSQLAlchemy query building → raw SQL
.select(),.insert(),.update(),.delete()calls inroutes/andsql/with raw SQL stringsutils/db.pyhelpers (fetch_one_parsed,fetch_all_parsed,insert_generic) now accept(query: str, values: dict)instead of SQLAlchemySelect/TableDependencies
databases[asyncpg],sqlalchemy-stubssqlalchemy(used only byschema.py+ alembic)asyncpg(now the sole driver)Example