feat: migrate from MySQL to Postgres with pgschema#114
feat: migrate from MySQL to Postgres with pgschema#114tlongwell-block merged 13 commits intomainfrom
Conversation
Replace MySQL 8.0 with Postgres 17 across the entire stack: - Add declarative schema/schema.sql for pgschema (merged from 21 migrations) - Delete migrations/ directory (sqlx migrations no longer used) - Update all sprout-db queries: positional $N params, ON CONFLICT, string_agg, array_position, encode(), pg_catalog partitions - Update sprout-audit: pg_advisory_lock replaces GET_LOCK - Update docker-compose, .env.example, justfile, CI, and scripts - Cargo.toml: sqlx mysql feature → postgres Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Ai-assisted: true
The relay no longer runs migrations itself — pgschema must be invoked explicitly after Postgres is healthy and before the relay starts. Co-authored-by: Claude Code <noreply@anthropic.com> Ai-assisted: true
…postgres * origin/main: fix(mcp): send threaded replies via WebSocket to prevent self-mention echo (#115)
|
Fixed the two runtime bugs that were failing CI:
Also added 17 files, net -105 lines. All quality gates green. |
…s, partitions The MySQL→Postgres migration (688846e) introduced two runtime type-mapping bugs that broke the relay on first DB query, failing CI's Desktop E2E Integration job. Bug 1 — UUID columns decoded as Vec<u8>: sqlx maps Vec<u8> to BYTEA, not Postgres native UUID. Every query touching a UUID column (channels.id, workflows.id, channel_members. channel_id, etc.) crashed with ColumnDecode at runtime. Fixed by reading/writing UUID columns as uuid::Uuid directly and removing the now-unnecessary uuid_from_bytes helper. Bug 2 — Postgres custom enums decoded as String: sqlx's String type is only compatible with TEXT/VARCHAR, not custom enum OIDs (channel_type, channel_visibility, member_role, workflow_ status, run_status, approval_status, channel_add_policy). Fixed by adding ::text casts to all enum columns in SELECT statements. Also: - Add events_p_past and delivery_log_p_past partitions (MINVALUE) so historical timestamps don't fail with 'no partition found' - Clean up all remaining MySQL references in code, comments, and docs - Update TESTING.md for Postgres (pgschema, psql, container names) - Remove dead uuid_from_bytes helper and all orphaned imports 18 files changed. All quality gates green: cargo check (0 warnings), clippy -D warnings, fmt, 142 unit tests pass.
9f00160 to
ffd2b89
Compare
Postgres requires ORDER BY expressions to appear in the SELECT list when using SELECT DISTINCT. The LEFT JOIN on channel_members with a specific pubkey bind can't produce duplicates (PK is channel_id+pubkey), so DISTINCT was unnecessary.
Postgres won't auto-cast text bind parameters to custom enum types (only string literals get auto-cast). Add explicit casts: - $N::channel_type, $N::channel_visibility in channel INSERT - $N::member_role in channel_members INSERT - $N::workflow_status, $N::run_status, $N::approval_status in workflow UPDATEs - $N::channel_add_policy in user UPDATE Found via live relay testing — channel creation was returning 500.
|
Three additional fixes from live testing:
Live-tested with three ACP-harnessed agents (Alice, Bob, Charlie) against a fresh Postgres instance. Channel creation, membership, DMs, mentions, threads, fan-out — all working. 110 events, 6 channels, 4 users in the DB. |
MySQL: 'Duplicate entry' / error 1062 Postgres: 'duplicate key value' / error 23505 Found via e2e_rest_api test_nip05_duplicate_handle_conflict.
Postgres won't auto-cast text bind parameters to jsonb (only string literals get auto-cast). The workflow definition is passed as &str and bound to a JSONB column — add ::jsonb casts on INSERT and UPDATE. Found via e2e_workflows integration tests.
|
Full e2e integration test results against a live Postgres relay:
The 1 workflow failure ( Latest fix: workflow |
…el to steps - The API returns 'error_message' not 'error' for workflow run failures - send_message steps need an explicit 'channel' when trigger has no channel context (webhook)
|
All 99 e2e integration tests passing on Postgres:
Also fixed the 8 pre-existing test failures (stale tool names from PR #115, wrong error field name in workflow approval test). Those were test bugs, not relay bugs. |
|
🎉 |
Up to you if you want to take this one, but I thought I'd throw it out there.
Replace MySQL 8.0 with Postgres 17 across the entire stack:
string_agg, array_position, encode(), pg_catalog partitions
Co-Authored-By: Claude Opus 4.6 (1M context) noreply@anthropic.com
Ai-assisted: true