#![cfg(any(feature = "rusqlite", feature = "turso", feature = "libsql"))]
#[cfg(feature = "uuid")]
use crate::common::schema::sqlite::{ComplexSchema, InsertComplex, Role, UpdateComplex};
use crate::common::schema::sqlite::{InsertSimple, SelectSimple, SimpleSchema, UpdateSimple};
use drizzle::core::expr::*;
use drizzle::sqlite::prelude::*;
#[cfg(all(feature = "serde", feature = "uuid"))]
#[drizzle::test]
fn test_insert_with_placeholders(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
let user_name = simple.name.placeholder("user_name");
let insert_data = InsertSimple::new(user_name);
let insert_result = db.insert(simple).values([insert_data]);
let sql_string = insert_result.to_sql().sql();
assert!(
sql_string.contains(":user_name"),
"SQL should contain the :user_name placeholder"
);
let sql = insert_result.to_sql();
let params: Vec<_> = sql.params().collect();
assert!(
params.is_empty(),
"Should have no bound parameters since we used a placeholder"
);
}
#[drizzle::test]
fn test_insert_with_placeholders_execute_and_retrieve(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
let user_name = simple.name.placeholder("user_name");
let insert_data = InsertSimple::new(user_name);
let prepared_insert = db.insert(simple).values([insert_data]).prepare();
let row_count = prepared_insert.execute(db.conn(), [user_name.bind("Alice")]);
assert_eq!(row_count, 1, "Should have inserted one row");
let results: Vec<SelectSimple> = db
.select((simple.id, simple.name))
.from(simple)
.r#where(eq(simple.name, "Alice"))
.all();
assert_eq!(results.len(), 1, "Should have found one result");
assert_eq!(
results[0].name, "Alice",
"Name should match the bound placeholder value"
);
}
#[drizzle::test]
fn test_parameter_integration_with_query_builder(db: &mut TestDb<SimpleSchema>) {
#[derive(SQLiteFromRow, Default)]
struct SimpleResult(String);
let SimpleSchema { simple } = schema;
let test_data = vec![
InsertSimple::new("alice"),
InsertSimple::new("bob"),
InsertSimple::new("charlie"),
];
db.insert(simple).values(test_data).execute();
let results: Vec<SimpleResult> = db
.select(simple.name)
.from(simple)
.r#where(eq(simple.name, "alice"))
.all();
assert_eq!(results.len(), 1);
assert_eq!(results[0].0, "alice");
let alice_results: Vec<SimpleResult> = db
.select(simple.name)
.from(simple)
.r#where(eq(simple.name, "alice"))
.all();
let bob_results: Vec<SimpleResult> = db
.select(simple.name)
.from(simple)
.r#where(eq(simple.name, "bob"))
.all();
assert_eq!(alice_results.len(), 1);
assert_eq!(bob_results.len(), 1);
assert_eq!(alice_results[0].0, "alice");
assert_eq!(bob_results[0].0, "bob");
}
#[drizzle::test]
fn test_update_with_placeholders_sql(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
let new_name = simple.name.placeholder("new_name");
let old_name = simple.name.placeholder("old_name");
let update = UpdateSimple::default().with_name(new_name);
let stmt = db
.update(simple)
.set(update)
.r#where(eq(simple.name, old_name));
let sql = stmt.to_sql();
let sql_string = sql.sql();
assert!(
sql_string.starts_with("UPDATE"),
"Should be an UPDATE statement, got: {}",
sql_string
);
assert!(
sql_string.contains("\"simple\""),
"Should reference the simple table, got: {}",
sql_string
);
assert!(
sql_string.contains(":new_name"),
"SET clause should contain :new_name placeholder, got: {}",
sql_string
);
assert!(
sql_string.contains(":old_name"),
"WHERE clause should contain :old_name placeholder, got: {}",
sql_string
);
let params: Vec<_> = sql.params().collect();
assert!(
params.is_empty(),
"Should have no bound parameters since all values are placeholders, got {} params",
params.len()
);
}
#[drizzle::test]
fn test_update_with_placeholders_execute(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
db.insert(simple)
.values([InsertSimple::new("original_name")])
.execute();
let new_name = simple.name.placeholder("new_name");
let old_name = simple.name.placeholder("old_name");
let update = UpdateSimple::default().with_name(new_name);
let prepared = db
.update(simple)
.set(update)
.r#where(eq(simple.name, old_name))
.prepare();
let update_count = prepared.execute(
db.conn(),
[
new_name.bind("updated_name"),
old_name.bind("original_name"),
],
);
assert_eq!(1, update_count, "Should have updated one row");
let results: Vec<SelectSimple> = db
.select((simple.id, simple.name))
.from(simple)
.r#where(eq(simple.name, "updated_name"))
.all();
assert_eq!(results.len(), 1, "Should find the updated row");
assert_eq!(results[0].name, "updated_name");
let old_results: Vec<SelectSimple> = db
.select((simple.id, simple.name))
.from(simple)
.r#where(eq(simple.name, "original_name"))
.all();
assert_eq!(old_results.len(), 0, "Original name should no longer exist");
}
#[cfg(feature = "uuid")]
#[drizzle::test]
fn test_update_with_mixed_values_and_placeholders(db: &mut TestDb<ComplexSchema>) {
#[allow(dead_code)]
#[derive(SQLiteFromRow, Debug)]
struct ComplexResult {
name: String,
email: Option<String>,
age: Option<i32>,
score: Option<f64>,
}
let ComplexSchema { complex } = schema;
let insert_data = InsertComplex::new("alice", true, Role::User)
.with_id(uuid::Uuid::new_v4())
.with_email("alice@old.com".to_string())
.with_age(25)
.with_score(90.5);
db.insert(complex).values([insert_data]).execute();
let new_age = complex.age.placeholder("new_age");
let update = UpdateComplex::default()
.with_email("alice@new.com".to_string())
.with_age(new_age);
let prepared = db
.update(complex)
.set(update)
.r#where(eq(complex.name, "alice"))
.prepare();
let update_count = prepared.execute(db.conn(), [new_age.bind(30)]);
assert_eq!(1, update_count, "Should have updated one row");
let results: Vec<ComplexResult> = db
.select((complex.name, complex.email, complex.age, complex.score))
.from(complex)
.r#where(eq(complex.name, "alice"))
.all();
assert_eq!(results.len(), 1);
assert_eq!(
results[0].email,
Some("alice@new.com".to_string()),
"Concrete value should be updated"
);
assert_eq!(
results[0].age,
Some(30),
"Placeholder-bound value should be updated"
);
assert_eq!(
results[0].score,
Some(90.5),
"Untouched field should remain unchanged"
);
}
#[cfg(feature = "uuid")]
#[drizzle::test]
fn test_update_skip_excludes_unset_fields(db: &mut TestDb<ComplexSchema>) {
let ComplexSchema { complex } = schema;
let update = UpdateComplex::default().with_email("only-this@test.com".to_string());
let stmt = db
.update(complex)
.set(update)
.r#where(eq(complex.name, "someone"));
let sql_string = stmt.to_sql().sql();
assert!(
sql_string.contains("\"email\""),
"SQL should include email in SET, got: {}",
sql_string
);
assert!(
!sql_string.contains("\"age\""),
"SQL should NOT include age (it was Skip), got: {}",
sql_string
);
assert!(
!sql_string.contains("\"score\""),
"SQL should NOT include score (it was Skip), got: {}",
sql_string
);
assert!(
!sql_string.contains("\"active\""),
"SQL should NOT include active (it was Skip), got: {}",
sql_string
);
assert!(
!sql_string.contains("\"description\""),
"SQL should NOT include description (it was Skip), got: {}",
sql_string
);
}