From 7563250809398ee0bc36344d1158b35eff2c973f Mon Sep 17 00:00:00 2001 From: Jon Seager Date: Mon, 8 Jun 2026 10:56:18 +0000 Subject: [PATCH] fix: support sqlx 0.9 --- .mise.toml | 2 +- Dockerfile | 11 +++++++++-- src/infrastructure/backup.rs | 5 +++-- src/infrastructure/repositories/coffee/bags.rs | 4 ++-- src/infrastructure/repositories/coffee/brews.rs | 4 ++-- src/infrastructure/repositories/coffee/cups.rs | 4 ++-- src/infrastructure/repositories/pagination.rs | 10 +++++----- tests/e2e/checkin_tests.rs | 5 ++++- 8 files changed, 28 insertions(+), 17 deletions(-) diff --git a/.mise.toml b/.mise.toml index 3d88536..79a683e 100644 --- a/.mise.toml +++ b/.mise.toml @@ -1,5 +1,5 @@ [tools] -rust = { version = "1.93", components = "rustfmt,clippy,rust-analyzer,rust-src" } +rust = { version = "1.94", components = "rustfmt,clippy,rust-analyzer,rust-src" } node = "latest" uv = "latest" prek = "latest" diff --git a/Dockerfile b/Dockerfile index 4393a27..94b7971 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,16 +4,23 @@ # Uses chisel to create a minimal Ubuntu rootfs for the runtime image. # --------------------------------------------------------------------------- -# Builder — Ubuntu with Rust toolchain pre-installed +# Builder — Ubuntu with Rust toolchain installed # --------------------------------------------------------------------------- -FROM ubuntu/rust:1.93-26.04_edge AS builder +FROM ubuntu:26.04 AS builder +ENV RUSTUP_HOME=/usr/local/rustup \ + CARGO_HOME=/usr/local/cargo \ + PATH=/usr/local/cargo/bin:${PATH} RUN apt-get update && apt-get install -y --no-install-recommends \ + ca-certificates \ + build-essential \ pkg-config \ libssl-dev \ mold \ binutils \ curl \ && rm -rf /var/lib/apt/lists/* +RUN curl -sSf https://sh.rustup.rs \ + | sh -s -- -y --profile minimal --default-toolchain 1.94.1 # Install tailwindcss standalone (needed by build.rs) RUN mkdir -p /usr/local/bin \ diff --git a/src/infrastructure/backup.rs b/src/infrastructure/backup.rs index 4d4a85d..91464c4 100644 --- a/src/infrastructure/backup.rs +++ b/src/infrastructure/backup.rs @@ -4,6 +4,7 @@ use anyhow::{Context, bail}; use chrono::{DateTime, NaiveDate, Utc}; use serde::{Deserialize, Serialize}; use serde_json::{from_str, to_string}; +use sqlx::AssertSqlSafe; use crate::domain::bags::Bag; use crate::domain::brews::{Brew, QuickNote}; @@ -175,7 +176,7 @@ impl BackupService { for table in tables { let query = format!("DELETE FROM {table}"); - sqlx::query(&query) + sqlx::query(AssertSqlSafe(query)) .execute(&mut *tx) .await .with_context(|| format!("failed to delete from {table}"))?; @@ -316,7 +317,7 @@ impl BackupService { for table in tables { let query = format!("SELECT COUNT(*) as count FROM {table}"); - let row: (i64,) = sqlx::query_as(&query) + let row: (i64,) = sqlx::query_as(AssertSqlSafe(query)) .fetch_one(&self.pool) .await .with_context(|| format!("failed to check table {table}"))?; diff --git a/src/infrastructure/repositories/coffee/bags.rs b/src/infrastructure/repositories/coffee/bags.rs index 7c75edf..7ef101a 100644 --- a/src/infrastructure/repositories/coffee/bags.rs +++ b/src/infrastructure/repositories/coffee/bags.rs @@ -1,6 +1,6 @@ use async_trait::async_trait; use chrono::{DateTime, NaiveDate, Utc}; -use sqlx::{QueryBuilder, query_as}; +use sqlx::{AssertSqlSafe, QueryBuilder, query_as}; use crate::domain::RepositoryError; use crate::domain::bags::{Bag, BagFilter, BagSortKey, BagWithRoast, NewBag, UpdateBag}; @@ -119,7 +119,7 @@ impl BagRepository for SqlBagRepository { async fn get_with_roast(&self, id: BagId) -> Result { let query = format!("{BASE_SELECT} WHERE b.id = ?"); - let record = query_as::<_, BagWithRoastRecord>(&query) + let record = query_as::<_, BagWithRoastRecord>(AssertSqlSafe(query)) .bind(id.into_inner()) .fetch_optional(&self.pool) .await diff --git a/src/infrastructure/repositories/coffee/brews.rs b/src/infrastructure/repositories/coffee/brews.rs index 260a860..f9cbffe 100644 --- a/src/infrastructure/repositories/coffee/brews.rs +++ b/src/infrastructure/repositories/coffee/brews.rs @@ -1,6 +1,6 @@ use async_trait::async_trait; use chrono::{DateTime, Utc}; -use sqlx::{QueryBuilder, query_as}; +use sqlx::{AssertSqlSafe, QueryBuilder, query_as}; use crate::domain::RepositoryError; use crate::domain::brews::{ @@ -189,7 +189,7 @@ impl BrewRepository for SqlBrewRepository { async fn get_with_details(&self, id: BrewId) -> Result { let query = format!("{BASE_SELECT} WHERE br.id = ?"); - let record = query_as::<_, BrewWithDetailsRecord>(&query) + let record = query_as::<_, BrewWithDetailsRecord>(AssertSqlSafe(query)) .bind(id.into_inner()) .fetch_optional(&self.pool) .await diff --git a/src/infrastructure/repositories/coffee/cups.rs b/src/infrastructure/repositories/coffee/cups.rs index e21f247..27b668b 100644 --- a/src/infrastructure/repositories/coffee/cups.rs +++ b/src/infrastructure/repositories/coffee/cups.rs @@ -1,6 +1,6 @@ use async_trait::async_trait; use chrono::{DateTime, Utc}; -use sqlx::{QueryBuilder, query, query_as}; +use sqlx::{AssertSqlSafe, QueryBuilder, query, query_as}; use crate::domain::RepositoryError; use crate::domain::cups::{Cup, CupFilter, CupSortKey, CupWithDetails, NewCup, UpdateCup}; @@ -113,7 +113,7 @@ impl CupRepository for SqlCupRepository { async fn get_with_details(&self, id: CupId) -> Result { let query = format!("{BASE_SELECT} WHERE c.id = ?"); - let record = query_as::<_, CupWithDetailsRecord>(&query) + let record = query_as::<_, CupWithDetailsRecord>(AssertSqlSafe(query)) .bind(id.into_inner()) .fetch_optional(&self.pool) .await diff --git a/src/infrastructure/repositories/pagination.rs b/src/infrastructure/repositories/pagination.rs index a2a9b61..dc5adc0 100644 --- a/src/infrastructure/repositories/pagination.rs +++ b/src/infrastructure/repositories/pagination.rs @@ -1,4 +1,4 @@ -use sqlx::{FromRow, QueryBuilder, query_scalar}; +use sqlx::{AssertSqlSafe, FromRow, QueryBuilder, query_scalar}; use crate::domain::RepositoryError; use crate::domain::listing::{ListRequest, Page, PageSize, SortKey}; @@ -102,7 +102,7 @@ where qb.push(" OFFSET "); qb.push_bind(offset); } - qb.build_query_as() + qb.build_query_as::() .fetch_all(pool) .await .map_err(|err| RepositoryError::unexpected(err.to_string())) @@ -117,13 +117,13 @@ async fn fetch_count( let mut qb = QueryBuilder::new(count_query); append_search_condition(&mut qb, count_query, sf); let row: (i64,) = qb - .build_query_as() + .build_query_as::<(i64,)>() .fetch_one(pool) .await .map_err(|err| RepositoryError::unexpected(err.to_string()))?; Ok(row.0) } else { - query_scalar(count_query) + query_scalar(AssertSqlSafe(count_query)) .fetch_one(pool) .await .map_err(|err| RepositoryError::unexpected(err.to_string())) @@ -131,7 +131,7 @@ async fn fetch_count( } fn append_search_condition( - qb: &mut QueryBuilder<'_, DatabaseDriver>, + qb: &mut QueryBuilder, base_sql: &str, search: &SearchFilter, ) { diff --git a/tests/e2e/checkin_tests.rs b/tests/e2e/checkin_tests.rs index 17f4638..0855bba 100644 --- a/tests/e2e/checkin_tests.rs +++ b/tests/e2e/checkin_tests.rs @@ -233,7 +233,10 @@ async fn checkin_with_new_cafe_and_scanned_roast() { .unwrap(); prompt_input.send_keys(Key::Enter).await.unwrap(); - // Wait for scan to complete — step 3 becomes visible with the submit button + // Wait for scan to complete and populate the review before submitting. + wait_for_text(&session.driver, "body", "Kiandu AA") + .await + .unwrap(); let submit_btn = wait_for_visible(&session.driver, "button[type='submit']") .await .unwrap();