Extract SQL into a dedicated data access layer

Extract SQL into a dedicated data access layer

#14 in tonybierman/dx-blog — merged 2026-05-30

Summary

SQL queries were inline across ~14 server-function modules with no separation between data access and HTTP/RPC concerns. This introduces a clean src/db/ layer.

  • New src/db/ — one module per domain: posts, comments, reactions, taxonomy, analytics, settings, subscribers, authors, media, feeds.
  • Each db function takes &SqlitePool and returns Result<T, sqlx::Error>.
  • Server functions become thin wrappers: extract the pool, call the db function, map errors with sfe().

What stays in the server layer

Business logic was deliberately not moved: auth checks (require_perm, can_edit_post), visitor_hash, comment cooldown/burst gating, live-hub publishing, and the create_with_unique_slug retry policy (it owns a terminal ServerFnError with no sqlx::Error home). Shared SQL constants (POST_CARD_COLUMNS/JOINS, COMMENT_VIEW_*) and unique_slug moved into db. feeds.rs keeps its StatusCode error contract rather than sfe().

Verification

  • cargo check --no-default-features --features server,sqlite
  • cargo check --no-default-features --features web --target wasm32-unknown-unknown
  • cargo test --no-default-features --features server,sqlite — 16 passed ✅
  • cargo fmt --check

No behavior change; pure structural refactor.

🤖 Generated with Claude Code

Last updated 2026-05-30