Skip to main content

max / makenotwork

server: adopt sqlx-offline; convert db::idempotency to compile-checked SQL (ultra-fuzz Run #1 --deep Phase 4) Mirror mt-db's playbook: enable the sqlx `macros` feature and commit the server's .sqlx offline query cache (un-ignored like multithreaded/.sqlx), so the server's compile-time-checked queries build without a live DB on every host and the Sando gate. This also fixes a latent gap — the pre-existing db::email_signups query! macros had no committed cache, so the crate couldn't build offline at all. Convert db::idempotency (3 queries) from runtime sqlx::query() strings to query!/query_as! macros validated against the real schema at build time. First money-path module; the rest follow. Gate: SQLX_OFFLINE=true build + lib clippy clean; idempotency workflow tests (6) green offline. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-06-22 22:47 UTC
Commit: 897378b8f6f882b7c6edd6bf0b9eee5bcc1b26f4
Parent: 7971fa8
9 files changed, +155 insertions, -16 deletions
M .gitignore +3 -2
@@ -58,6 +58,7 @@ sando/daemon/work/
58 58 sando/daemon/releases/
59 59 sando/daemon/cargo-target/
60 60
61 - # mt-db uses sqlx compile-time macros; its offline query cache must be committed
62 - # so build hosts (and the Sando gate) compile without a live DB.
61 + # mt-db and the server use sqlx compile-time macros; their offline query cache
62 + # must be committed so build hosts (and the Sando gate) compile without a live DB.
63 63 !multithreaded/.sqlx/
64 + !server/.sqlx/
@@ -0,0 +1,12 @@
1 + {
2 + "db_name": "PostgreSQL",
3 + "query": "DELETE FROM idempotency_keys WHERE created_at < NOW() - INTERVAL '24 hours'",
4 + "describe": {
5 + "columns": [],
6 + "parameters": {
7 + "Left": []
8 + },
9 + "nullable": []
10 + },
11 + "hash": "45a5c6823b2107d40dae97ba132bc3e1f683e5af43f0b7186489b4ec1012e2e6"
12 + }
@@ -0,0 +1,31 @@
1 + {
2 + "db_name": "PostgreSQL",
3 + "query": "SELECT status_code, response_body FROM idempotency_keys WHERE key = $1 AND user_id = $2 AND method = $3 AND path = $4",
4 + "describe": {
5 + "columns": [
6 + {
7 + "ordinal": 0,
8 + "name": "status_code",
9 + "type_info": "Int2"
10 + },
11 + {
12 + "ordinal": 1,
13 + "name": "response_body",
14 + "type_info": "Text"
15 + }
16 + ],
17 + "parameters": {
18 + "Left": [
19 + "Text",
20 + "Uuid",
21 + "Text",
22 + "Text"
23 + ]
24 + },
25 + "nullable": [
26 + false,
27 + false
28 + ]
29 + },
30 + "hash": "5bb0f0d537f75635202a3acc37101cdb2327aedde7d0a110357b856687e36685"
31 + }
@@ -0,0 +1,19 @@
1 + {
2 + "db_name": "PostgreSQL",
3 + "query": "INSERT INTO idempotency_keys (key, user_id, method, path, status_code, response_body)\n VALUES ($1, $2, $3, $4, $5, $6)\n ON CONFLICT (key, user_id, method, path) DO NOTHING",
4 + "describe": {
5 + "columns": [],
6 + "parameters": {
7 + "Left": [
8 + "Text",
9 + "Uuid",
10 + "Text",
11 + "Text",
12 + "Int2",
13 + "Text"
14 + ]
15 + },
16 + "nullable": []
17 + },
18 + "hash": "615ef0e996461da6943ed45802bc1a98c0b7b8ccc1f7cfe50566e44f620928eb"
19 + }
@@ -0,0 +1,23 @@
1 + {
2 + "db_name": "PostgreSQL",
3 + "query": "\n INSERT INTO email_signups (email, source)\n VALUES ($1, $2)\n ON CONFLICT (email) DO UPDATE SET email = EXCLUDED.email\n RETURNING id\n ",
4 + "describe": {
5 + "columns": [
6 + {
7 + "ordinal": 0,
8 + "name": "id",
9 + "type_info": "Uuid"
10 + }
11 + ],
12 + "parameters": {
13 + "Left": [
14 + "Text",
15 + "Varchar"
16 + ]
17 + },
18 + "nullable": [
19 + false
20 + ]
21 + },
22 + "hash": "a515b612f62ccae3f613e6b3e6f4954a347f41cea6737150ca9736c5efed2594"
23 + }
@@ -0,0 +1,20 @@
1 + {
2 + "db_name": "PostgreSQL",
3 + "query": "SELECT COUNT(*) FROM email_signups",
4 + "describe": {
5 + "columns": [
6 + {
7 + "ordinal": 0,
8 + "name": "count",
9 + "type_info": "Int8"
10 + }
11 + ],
12 + "parameters": {
13 + "Left": []
14 + },
15 + "nullable": [
16 + null
17 + ]
18 + },
19 + "hash": "c0afc028ccde9b67ce6a8275cf0faad7672269a5d316464b82b2782bb137fc25"
20 + }
@@ -0,0 +1,32 @@
1 + {
2 + "db_name": "PostgreSQL",
3 + "query": "\n SELECT email, source,\n created_at as \"created_at: chrono::DateTime<chrono::Utc>\"\n FROM email_signups\n ORDER BY created_at DESC\n LIMIT 500\n ",
4 + "describe": {
5 + "columns": [
6 + {
7 + "ordinal": 0,
8 + "name": "email",
9 + "type_info": "Text"
10 + },
11 + {
12 + "ordinal": 1,
13 + "name": "source",
14 + "type_info": "Varchar"
15 + },
16 + {
17 + "ordinal": 2,
18 + "name": "created_at: chrono::DateTime<chrono::Utc>",
19 + "type_info": "Timestamptz"
20 + }
21 + ],
22 + "parameters": {
23 + "Left": []
24 + },
25 + "nullable": [
26 + false,
27 + false,
28 + false
29 + ]
30 + },
31 + "hash": "c21e33476fadb61eb586bb1b8399caa95b5e4850bc358711003edcc46abd12e9"
32 + }
@@ -35,7 +35,7 @@ askama = "0.13.1"
35 35 dotenvy = "0.15.7"
36 36
37 37 # Database
38 - sqlx = { version = "0.8.6", features = ["runtime-tokio", "postgres", "uuid", "chrono", "migrate"] }
38 + sqlx = { version = "0.8.6", features = ["runtime-tokio", "postgres", "uuid", "chrono", "migrate", "macros"] }
39 39 uuid = { version = "1.22.0", features = ["v4", "serde"] }
40 40 chrono = { version = "0.4.44", features = ["serde"] }
41 41
@@ -21,13 +21,14 @@ pub async fn get_cached_response(
21 21 method: &str,
22 22 path: &str,
23 23 ) -> Result<Option<CachedResponse>> {
24 - let row = sqlx::query_as::<_, CachedResponse>(
24 + let row = sqlx::query_as!(
25 + CachedResponse,
25 26 "SELECT status_code, response_body FROM idempotency_keys WHERE key = $1 AND user_id = $2 AND method = $3 AND path = $4",
27 + key,
28 + user_id as UserId,
29 + method,
30 + path,
26 31 )
27 - .bind(key)
28 - .bind(user_id)
29 - .bind(method)
30 - .bind(path)
31 32 .fetch_optional(pool)
32 33 .await?;
33 34
@@ -46,17 +47,17 @@ pub async fn store_response(
46 47 status_code: u16,
47 48 response_body: &str,
48 49 ) -> Result<()> {
49 - sqlx::query(
50 + sqlx::query!(
50 51 r#"INSERT INTO idempotency_keys (key, user_id, method, path, status_code, response_body)
51 52 VALUES ($1, $2, $3, $4, $5, $6)
52 53 ON CONFLICT (key, user_id, method, path) DO NOTHING"#,
54 + key,
55 + user_id as UserId,
56 + method,
57 + path,
58 + status_code as i16,
59 + response_body,
53 60 )
54 - .bind(key)
55 - .bind(user_id)
56 - .bind(method)
57 - .bind(path)
58 - .bind(status_code as i16)
59 - .bind(response_body)
60 61 .execute(pool)
61 62 .await?;
62 63
@@ -66,7 +67,7 @@ pub async fn store_response(
66 67 /// Delete expired idempotency keys (older than 24 hours).
67 68 #[tracing::instrument(skip_all)]
68 69 pub async fn cleanup_expired(pool: &PgPool) -> Result<u64> {
69 - let result = sqlx::query(
70 + let result = sqlx::query!(
70 71 "DELETE FROM idempotency_keys WHERE created_at < NOW() - INTERVAL '24 hours'",
71 72 )
72 73 .execute(pool)