Replace per-game update_standings() calls with pre-fetched dicts and
in-memory accumulation, then a single bulk_update at the end.
Reduces ~1,100+ queries for a full season to ~5 queries.
Closes#75
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Removes DATABASE_TYPE conditional entirely. PostgreSQL is now the only
supported backend. Moves PooledPostgresqlDatabase import to top-level
and raises RuntimeError at startup if POSTGRES_PASSWORD is unset,
preventing silent misconnection with misleading errors.
Closes#70
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Set timeout=5 so pool exhaustion surfaces as an error instead of hanging forever
- Set autoconnect=False to require explicit connection acquisition
- Add HTTP middleware in main.py to open/close connections per request
Closes#80
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Closes#78
Change CharField(max_length=20) to BigIntegerField to match the BIGINT
column created by the migration. Remove the str() workaround in
get_creator_by_discord_id() that was compensating for the type mismatch.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
After removing db.close() calls, 22 finally: blocks were left empty
(12 in custom_commands.py, 10 in help_commands.py), causing
IndentationError at import time. Removed the finally: clause entirely
since connection lifecycle is now handled by the middleware.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Match the discord bot's CI pattern — trigger on CalVer tag push
instead of branch push/PR. Removes auto-CalVer generation and
simplifies to a single build step.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
sp.on_first/on_second/on_third don't exist — the actual columns are
on_first_id/on_second_id/on_third_id. This caused failures when
updating season pitching stats after games.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
After handle_db_errors no longer catches HTTPException, GET /plays/999999999
correctly returns 404 instead of 500. Update the assertion and docstring
to reflect the fixed behavior.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The decorator was catching all exceptions including intentional
HTTPException (401, 404, etc.) and re-wrapping them as 500 "Database
error". This masked auth failures and other deliberate HTTP errors.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The MAX_LIMIT/DEFAULT_LIMIT caps added in 16f3f8d are too restrictive
for the /players endpoint — bot and website consumers need full player
lists without pagination. Reverts limit param to Optional[int] with no
ceiling while keeping caps on all other endpoints.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Capture total_count before .limit() so the response count reflects
all matching rows, not just the capped page size. Resolves#100.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add MAX_LIMIT=500 cap across all list endpoints, empty string
stripping middleware, and limit/offset to /transactions. Resolves#98.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds schema_versions table and migrations.py runner to prevent
double-application and missed migrations across dev/prod environments.
- migrations/2026-03-27_add_schema_versions_table.sql: creates tracking table
- migrations.py: applies pending .sql files in sorted order, records each in schema_versions
- .gitignore: untrack migrations.py (was incorrectly ignored as legacy root file)
First run on an existing DB will apply all migrations (safe — all use IF NOT EXISTS).
Closes#81
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>