@@ -9,6 +9,7 @@ use async_trait::async_trait;
99use cqrs_es:: Aggregate ;
1010use cqrs_es:: persist:: { PersistenceError , ViewContext , ViewRepository } ;
1111use sqlite_es:: SqliteViewRepository ;
12+ use sqlx:: AssertSqlSafe ;
1213use sqlx:: SqlitePool ;
1314use sqlx:: sqlite:: Sqlite ;
1415use std:: fmt:: Debug ;
@@ -162,7 +163,8 @@ impl<Entity: EventSourced<Materialized = Table>> Projection<Entity> {
162163 ORDER BY view_id ASC"
163164 ) ;
164165
165- let rows: Vec < ( String , String ) > = sqlx:: query_as ( & query) . fetch_all ( pool) . await ?;
166+ let rows: Vec < ( String , String ) > =
167+ sqlx:: query_as ( AssertSqlSafe ( query) ) . fetch_all ( pool) . await ?;
166168
167169 Ok ( Self :: parse_rows ( rows) )
168170 }
@@ -202,8 +204,10 @@ impl<Entity: EventSourced<Materialized = Table>> Projection<Entity> {
202204 ORDER BY view_id ASC"
203205 ) ;
204206
205- let rows: Vec < ( String , String ) > =
206- sqlx:: query_as ( & query) . bind ( value) . fetch_all ( pool) . await ?;
207+ let rows: Vec < ( String , String ) > = sqlx:: query_as ( AssertSqlSafe ( query) )
208+ . bind ( value)
209+ . fetch_all ( pool)
210+ . await ?;
207211
208212 Ok ( Self :: parse_rows ( rows) )
209213 }
@@ -224,8 +228,9 @@ impl<Entity: EventSourced<Materialized = Table>> Projection<Entity> {
224228 // Drive from events table (LEFT JOIN) so we also detect aggregates
225229 // with persisted events but no view row (crash before initial view write).
226230 // view_version is NULL when the view row is missing.
227- let stale_aggregates: Vec < ( String , Option < i64 > , i64 ) > = sqlx:: query_as ( & format ! (
228- "SELECT e.aggregate_id, v.version, e.max_seq \
231+ let stale_aggregates: Vec < ( String , Option < i64 > , i64 ) > =
232+ sqlx:: query_as ( AssertSqlSafe ( format ! (
233+ "SELECT e.aggregate_id, v.version, e.max_seq \
229234 FROM ( \
230235 SELECT aggregate_id, MAX(sequence) as max_seq \
231236 FROM events \
@@ -234,10 +239,10 @@ impl<Entity: EventSourced<Materialized = Table>> Projection<Entity> {
234239 ) e \
235240 LEFT JOIN {table} v ON v.view_id = e.aggregate_id \
236241 WHERE v.version IS NULL OR e.max_seq > v.version"
237- ) )
238- . bind ( & aggregate_type)
239- . fetch_all ( pool)
240- . await ?;
242+ ) ) )
243+ . bind ( & aggregate_type)
244+ . fetch_all ( pool)
245+ . await ?;
241246
242247 if stale_aggregates. is_empty ( ) {
243248 debug ! ( target: "cqrs" , %aggregate_type, "All views up to date, nothing to replay" ) ;
@@ -275,10 +280,12 @@ impl<Entity: EventSourced<Materialized = Table>> Projection<Entity> {
275280
276281 info ! ( target: "cqrs" , %view_id, %table, "Rebuilding view from event history" ) ;
277282
278- sqlx:: query ( & format ! ( "DELETE FROM {table} WHERE view_id = ?1" ) )
279- . bind ( & view_id)
280- . execute ( pool)
281- . await ?;
283+ sqlx:: query ( AssertSqlSafe ( format ! (
284+ "DELETE FROM {table} WHERE view_id = ?1"
285+ ) ) )
286+ . bind ( & view_id)
287+ . execute ( pool)
288+ . await ?;
282289
283290 self . catch_up ( ) . await
284291 }
@@ -293,7 +300,7 @@ impl<Entity: EventSourced<Materialized = Table>> Projection<Entity> {
293300
294301 info ! ( target: "cqrs" , %table, "Rebuilding all views from event history" ) ;
295302
296- sqlx:: query ( & format ! ( "DELETE FROM {table}" ) )
303+ sqlx:: query ( AssertSqlSafe ( format ! ( "DELETE FROM {table}" ) ) )
297304 . execute ( pool)
298305 . await ?;
299306
@@ -375,11 +382,11 @@ impl<Entity: EventSourced<Materialized = Table>> Projection<Entity> {
375382 // Write directly with version = max_seq, bypassing the view repo's
376383 // optimistic lock (which expects version + 1 increments). This is
377384 // safe because catch_up runs once at startup before the main loop.
378- sqlx:: query ( & format ! (
385+ sqlx:: query ( AssertSqlSafe ( format ! (
379386 "INSERT INTO {table} (view_id, version, payload) \
380387 VALUES (?1, ?2, ?3) \
381388 ON CONFLICT(view_id) DO UPDATE SET version = ?2, payload = ?3"
382- ) )
389+ ) ) )
383390 . bind ( view_id)
384391 . bind ( max_seq)
385392 . bind ( & payload)
@@ -557,10 +564,11 @@ async fn validate_column<Entity: EventSourced>(
557564) -> Result < ( ) , ProjectionError < Entity > > {
558565 let column_name = column. 0 ;
559566
560- let columns: Vec < ( String , ) > =
561- sqlx:: query_as ( & format ! ( "SELECT name FROM pragma_table_xinfo('{table}')" ) )
562- . fetch_all ( pool)
563- . await ?;
567+ let columns: Vec < ( String , ) > = sqlx:: query_as ( AssertSqlSafe ( format ! (
568+ "SELECT name FROM pragma_table_xinfo('{table}')"
569+ ) ) )
570+ . fetch_all ( pool)
571+ . await ?;
564572
565573 if !columns. iter ( ) . any ( |( name, ) | name == column_name) {
566574 warn ! (
@@ -575,15 +583,15 @@ async fn validate_column<Entity: EventSourced>(
575583 } ) ;
576584 }
577585
578- let row_count: ( i64 , ) = sqlx:: query_as ( & format ! ( "SELECT COUNT(*) FROM {table}" ) )
586+ let row_count: ( i64 , ) = sqlx:: query_as ( AssertSqlSafe ( format ! ( "SELECT COUNT(*) FROM {table}" ) ) )
579587 . fetch_one ( pool)
580588 . await ?;
581589
582590 if row_count. 0 > 0 {
583- let non_null_count: ( i64 , ) = sqlx:: query_as ( & format ! (
591+ let non_null_count: ( i64 , ) = sqlx:: query_as ( AssertSqlSafe ( format ! (
584592 "SELECT COUNT(*) FROM {table}
585593 WHERE {column_name} IS NOT NULL"
586- ) )
594+ ) ) )
587595 . fetch_one ( pool)
588596 . await ?;
589597
0 commit comments