@@ -230,7 +230,7 @@ async fn ensure_crud_dependencies() -> Result<()> {
230230 . any ( |line| line. trim_start ( ) . starts_with ( "sqlx " ) )
231231 {
232232 deps_to_add. push (
233- "sqlx = { version = \" 0.8 \" , default-features = false, features = [\" runtime-tokio\" , \" sqlite\" , \" derive\" ] }" ,
233+ "sqlx = { version = \" 0.9 \" , default-features = false, features = [\" runtime-tokio\" , \" sqlite\" , \" derive\" ] }" ,
234234 ) ;
235235 }
236236
@@ -269,7 +269,7 @@ const DB_RS_HEADER: &str = r#"//! Database bootstrap for generated CRUD resource
269269//! Default columns are the standard scaffold (`id`, `name`, `description`, timestamps).
270270
271271use sqlx::sqlite::SqlitePoolOptions;
272- use sqlx::SqlitePool;
272+ use sqlx::{AssertSqlSafe, SqlitePool} ;
273273
274274/// Default CRUD column layout for generated resources (customize per model as needed).
275275macro_rules! crud_columns {
@@ -311,7 +311,7 @@ async fn upsert_db_resource(table: &str, singular: &str) -> Result<()> {
311311 "{header}{module_block}\
312312 async fn ensure_table(pool: &SqlitePool, table: &str, columns: &str) -> Result<(), sqlx::Error> {{
313313 let schema = format!(\" CREATE TABLE IF NOT EXISTS {{}} ({{}})\" , table, columns.trim());
314- sqlx::query(& schema).execute(pool).await?;
314+ sqlx::query(AssertSqlSafe( schema.as_str()) ).execute(pool).await?;
315315 Ok(())
316316}}
317317
@@ -427,7 +427,7 @@ async fn generate_sqlx_handler(name: &str, type_name: &str, table: &str) -> Resu
427427use crate::db::{table_mod}::{{SINGULAR, TABLE}};
428428use crate::models::{{Create{type_name}, Update{type_name}, {type_name}}};
429429use rustapi_rs::prelude::*;
430- use sqlx::SqlitePool;
430+ use sqlx::{{AssertSqlSafe, SqlitePool}} ;
431431
432432fn now_ts() -> String {{
433433 chrono::Utc::now().to_rfc3339()
@@ -442,10 +442,10 @@ fn db_error(err: sqlx::Error) -> ApiError {{
442442#[rustapi_rs::tag("{type_name}")]
443443#[rustapi_rs::summary("List all {name}")]
444444pub async fn list(State(pool): State<SqlitePool>) -> Result<Json<Vec<{type_name}>>> {{
445- let rows = sqlx::query_as::<_, {type_name}>(& format!(
445+ let rows = sqlx::query_as::<_, {type_name}>(AssertSqlSafe( format!(
446446 "SELECT id, name, description, created_at, updated_at FROM {{}} ORDER BY id",
447447 TABLE
448- ))
448+ )))
449449 .fetch_all(&pool)
450450 .await
451451 .map_err(db_error)?;
@@ -457,10 +457,10 @@ pub async fn list(State(pool): State<SqlitePool>) -> Result<Json<Vec<{type_name}
457457#[rustapi_rs::tag("{type_name}")]
458458#[rustapi_rs::summary("Get {singular} by ID")]
459459pub async fn get(Path(id): Path<i64>, State(pool): State<SqlitePool>) -> Result<Json<{type_name}>> {{
460- let row = sqlx::query_as::<_, {type_name}>(& format!(
460+ let row = sqlx::query_as::<_, {type_name}>(AssertSqlSafe( format!(
461461 "SELECT id, name, description, created_at, updated_at FROM {{}} WHERE id = ?",
462462 TABLE
463- ))
463+ )))
464464 .bind(id)
465465 .fetch_optional(&pool)
466466 .await
@@ -478,10 +478,10 @@ pub async fn create(
478478 Json(body): Json<Create{type_name}>,
479479) -> Result<WithStatus<Json<{type_name}>, 201>> {{
480480 let now = now_ts();
481- let result = sqlx::query(& format!(
481+ let result = sqlx::query(AssertSqlSafe( format!(
482482 "INSERT INTO {{}} (name, description, created_at, updated_at) VALUES (?, ?, ?, ?)",
483483 TABLE
484- ))
484+ )))
485485 .bind(&body.name)
486486 .bind(&body.description)
487487 .bind(&now)
@@ -491,10 +491,10 @@ pub async fn create(
491491 .map_err(db_error)?;
492492
493493 let id = result.last_insert_rowid();
494- let row = sqlx::query_as::<_, {type_name}>(& format!(
494+ let row = sqlx::query_as::<_, {type_name}>(AssertSqlSafe( format!(
495495 "SELECT id, name, description, created_at, updated_at FROM {{}} WHERE id = ?",
496496 TABLE
497- ))
497+ )))
498498 .bind(id)
499499 .fetch_one(&pool)
500500 .await
@@ -511,10 +511,10 @@ pub async fn update(
511511 State(pool): State<SqlitePool>,
512512 Json(body): Json<Update{type_name}>,
513513) -> Result<Json<{type_name}>> {{
514- let existing = sqlx::query_as::<_, {type_name}>(& format!(
514+ let existing = sqlx::query_as::<_, {type_name}>(AssertSqlSafe( format!(
515515 "SELECT id, name, description, created_at, updated_at FROM {{}} WHERE id = ?",
516516 TABLE
517- ))
517+ )))
518518 .bind(id)
519519 .fetch_optional(&pool)
520520 .await
@@ -525,10 +525,10 @@ pub async fn update(
525525 let description = body.description.or(existing.description);
526526 let updated_at = now_ts();
527527
528- sqlx::query(& format!(
528+ sqlx::query(AssertSqlSafe( format!(
529529 "UPDATE {{}} SET name = ?, description = ?, updated_at = ? WHERE id = ?",
530530 TABLE
531- ))
531+ )))
532532 .bind(&name)
533533 .bind(&description)
534534 .bind(&updated_at)
@@ -537,10 +537,10 @@ pub async fn update(
537537 .await
538538 .map_err(db_error)?;
539539
540- let row = sqlx::query_as::<_, {type_name}>(& format!(
540+ let row = sqlx::query_as::<_, {type_name}>(AssertSqlSafe( format!(
541541 "SELECT id, name, description, created_at, updated_at FROM {{}} WHERE id = ?",
542542 TABLE
543- ))
543+ )))
544544 .bind(id)
545545 .fetch_one(&pool)
546546 .await
@@ -553,7 +553,7 @@ pub async fn update(
553553#[rustapi_rs::tag("{type_name}")]
554554#[rustapi_rs::summary("Delete {singular}")]
555555pub async fn delete(Path(id): Path<i64>, State(pool): State<SqlitePool>) -> Result<NoContent> {{
556- let result = sqlx::query(& format!("DELETE FROM {{}} WHERE id = ?", TABLE))
556+ let result = sqlx::query(AssertSqlSafe( format!("DELETE FROM {{}} WHERE id = ?", TABLE) ))
557557 .bind(id)
558558 .execute(&pool)
559559 .await
0 commit comments