static sqlx queries

This commit is contained in:
Brandon Thomas committed 2026-04-13 22:31:22 -04:00
1 parent 75ba968ace
commit d3dab49af6
8 files changed
+36 -45

No files matched your search

+2 -1
View File
@@ -6,7 +6,8 @@
- No minimum supported Rust version; use latest stable features freely
- `#[macro_use] extern crate serde_derive;` is used in binary crates; library crates use `use serde_derive::{Serialize, Deserialize};`
- Never use `println!` or `eprintln!` outside of tests; use `log` crate macros (`info!`, `warn!`, `error!`, `debug!`, `trace!`) instead
- Use `anyhow::Result` / `AnyhowResult` for fallible functions in application code
- Use `anyhow::Result` / `AnyhowResult` for fallible functions in application code; new database queries should use `Result<T, sqlx::Error>` instead
- SQLx queries: prefer `sqlx::query!` and `sqlx::query_as!` compile-time checked macros over runtime `sqlx::query()` / `sqlx::query_as()`. The macros catch SQL typos, column mismatches, and type errors at build time. Use runtime queries only when the table isn't in the offline cache yet.
- Enum Display/Debug: use `impl_enum_display_and_debug_using_to_str!` macro, not `derive_more::Display` (CLion doesn't understand it)
- Fields that are optional use the `maybe_` prefix: `maybe_creator_user_token`, `maybe_prompt_token`
- When implementing `fmt::Display` for error types, use the pattern: `write!(f, "{:?}", self)`
+1 -1
View File
@@ -58,7 +58,7 @@ artcraft/
- Rust with no minimum supported version
- Actix-web for HTTP services
- SQLx for MySQL and SQLite
- SQLx for MySQL and SQLite; prefer `sqlx::query!` / `sqlx::query_as!` compile-time checked macros over runtime `sqlx::query()` whenever possible
- A mix of wreq and reqwest for Rust HTTP clients
- Never use `println!` or `eprintln!` outside of tests; use `log` crate macros instead
- When two crates export the same type name, alias imports with a suffix: `use foo::Bar as BarFoo;`
@@ -29,7 +29,7 @@ pub async fn insert_staff_audit_log<'a, 'c, E>(
{
let token = StaffAuditLogToken::generate();
sqlx::query(
sqlx::query!(
r#"
INSERT INTO staff_audit_logs
SET
@@ -40,13 +40,13 @@ SET
staff_user_token = ?,
staff_ip_address = ?
"#,
token.as_str(),
args.audit_action.to_str(),
args.maybe_entity_type.map(|ty| ty.to_str()),
args.maybe_entity_token,
args.staff_user_token.as_str(),
args.actor_ip_address,
)
.bind(token.as_str())
.bind(args.audit_action.to_str())
.bind(args.maybe_entity_type.map(|ty| ty.to_str()))
.bind(args.maybe_entity_token)
.bind(args.staff_user_token.as_str())
.bind(args.actor_ip_address)
.execute(args.mysql_executor)
.await?;
@@ -26,7 +26,7 @@ pub async fn insert_user_impersonation_request<'a, 'c, E>(
{
let token = UserImpersonationRequestToken::generate();
sqlx::query(
sqlx::query!(
r#"
INSERT INTO user_impersonation_requests
SET
@@ -37,13 +37,13 @@ SET
ip_address_creation = ?,
expires_at = ?
"#,
token.as_str(),
args.impersonated_user_token.as_str(),
args.impersonator_user_token.as_str(),
args.public_impersonation_token,
args.ip_address_creation,
args.expires_at,
)
.bind(token.as_str())
.bind(args.impersonated_user_token.as_str())
.bind(args.impersonator_user_token.as_str())
.bind(args.public_impersonation_token)
.bind(args.ip_address_creation)
.bind(args.expires_at)
.execute(args.mysql_executor)
.await?;
@@ -1,5 +1,5 @@
use chrono::{DateTime, Utc};
use sqlx::{FromRow, MySqlPool, Row};
use sqlx::MySqlPool;
use tokens::tokens::users::UserToken;
@@ -17,35 +17,24 @@ pub async fn lookup_user_impersonation_request(
public_impersonation_token: &str,
mysql_pool: &MySqlPool,
) -> Result<Option<UserImpersonationRequestRecord>, sqlx::Error> {
let maybe_row = sqlx::query(
let maybe_record = sqlx::query_as!(
UserImpersonationRequestRecord,
r#"
SELECT
token,
impersonated_user_token,
impersonator_user_token,
impersonated_user_token as `impersonated_user_token: UserToken`,
impersonator_user_token as `impersonator_user_token: UserToken`,
public_impersonation_token,
is_redeemed,
is_redeemed as `is_redeemed: bool`,
expires_at
FROM user_impersonation_requests
WHERE public_impersonation_token = ?
LIMIT 1
"#,
public_impersonation_token,
)
.bind(public_impersonation_token)
.fetch_optional(mysql_pool)
.await?;
let row = match maybe_row {
Some(row) => row,
None => return Ok(None),
};
Ok(Some(UserImpersonationRequestRecord {
token: row.get("token"),
impersonated_user_token: UserToken::new_from_str(row.get("impersonated_user_token")),
impersonator_user_token: UserToken::new_from_str(row.get("impersonator_user_token")),
public_impersonation_token: row.get("public_impersonation_token"),
is_redeemed: row.get("is_redeemed"),
expires_at: row.get("expires_at"),
}))
Ok(maybe_record)
}
@@ -17,7 +17,7 @@ pub async fn mark_impersonation_token_as_redeemed<'a, 'c, E>(
) -> Result<(), sqlx::Error>
where E: 'a + Executor<'c, Database = MySql>
{
sqlx::query(
sqlx::query!(
r#"
UPDATE user_impersonation_requests
SET
@@ -25,9 +25,9 @@ SET
ip_address_redemption = ?
WHERE public_impersonation_token = ?
"#,
args.ip_address_redemption,
args.public_impersonation_token,
)
.bind(args.ip_address_redemption)
.bind(args.public_impersonation_token)
.execute(args.mysql_executor)
.await?;
@@ -29,7 +29,7 @@ pub async fn create_impersonated_user_session<'a, 'c, E>(
{
let session_token = UserSessionToken::generate();
sqlx::query(
sqlx::query!(
r#"
INSERT INTO user_sessions (
token,
@@ -40,12 +40,12 @@ INSERT INTO user_sessions (
)
VALUES (?, ?, ?, ?, ?)
"#,
session_token.as_str(),
args.user_token.as_str(),
args.impersonator_user_token.as_str(),
args.ip_address,
args.expires_at,
)
.bind(session_token.as_str())
.bind(args.user_token.as_str())
.bind(args.impersonator_user_token.as_str())
.bind(args.ip_address)
.bind(args.expires_at)
.execute(args.mysql_executor)
.await?;
@@ -32,6 +32,7 @@ use utoipa::ToSchema;
use artcraft_api_defs::users::login::{LoginErrorType, LoginRequest, LoginSuccessResponse};
use password::errors::password_confirm_error::PasswordConfirmError;
use tokens::tokens::users::UserToken;
use crate::http_server::session::lookup::user_session_feature_flags::UserSessionFeatureFlags;
use crate::util::enroll_in_studio::enroll_in_studio;
@@ -224,7 +225,7 @@ pub async fn login_handler(
/// Returns the impersonated user's session token on success, or an error if the
/// impersonation token is invalid, expired, already redeemed, or doesn't match.
async fn try_impersonation_login(
target_user_token: &tokens::tokens::users::UserToken,
target_user_token: &UserToken,
password: &str,
ip_address: &str,
mysql_pool: &MySqlPool,