use chain_builder::{
ChainBuilder, Client, HavingClauses, JoinMethods, QueryCommon, Select, WhereClauses,
};
use serde_json::Value;
use sqlx::Execute;
#[test]
fn test_sqlite_basic_select() {
let mut builder = ChainBuilder::new(Client::Sqlite);
builder
.select(Select::Columns(vec!["*".into()]))
.table("users")
.query(|qb| {
qb.where_eq("status", Value::String("active".to_string()));
});
let (sql, binds) = builder.to_sql();
println!("SQLite SELECT SQL: {}", sql);
println!("Binds: {:?}", binds);
assert!(sql.contains("SELECT * FROM \"users\""));
assert!(sql.contains("WHERE \"status\" = ?"));
assert_eq!(binds.len(), 1);
}
#[test]
fn test_sqlite_empty_in_conditions() {
let mut builder = ChainBuilder::new(Client::Sqlite);
builder
.select(Select::Columns(vec!["*".into()]))
.table("users")
.query(|qb| {
qb.where_in("id", vec![]);
});
let sql = builder.to_sql();
assert!(sql.0.contains("1 = 0"));
}
#[test]
fn test_sqlite_having_empty_in() {
let mut builder = ChainBuilder::new(Client::Sqlite);
builder
.select(Select::Columns(vec!["id".into()]))
.table("users")
.query(|qb| {
qb.group_by(vec!["id".into()]);
qb.having_in("status", vec![]);
});
let sql = builder.to_sql();
assert!(sql.0.contains("1 = 0"));
}
#[test]
fn test_sqlite_where_exists_with_binds() {
let mut builder = ChainBuilder::new(Client::Sqlite);
builder
.select(Select::Columns(vec!["*".into()]))
.table("users")
.query(|qb| {
qb.where_exists(|sub| {
sub.select(Select::Columns(vec!["1".into()]))
.table("orders")
.query(|q| {
q.where_eq("orders.user_id", Value::Number(1.into()));
});
});
});
let (sql, binds) = builder.to_sql();
assert!(sql.contains("EXISTS"));
assert_eq!(binds.len(), 1);
}
#[test]
fn test_sqlite_chain_builder() {
let mut builder = ChainBuilder::new(Client::Sqlite);
builder
.db("mydb") .select(Select::Columns(vec!["*".into()]))
.table("users")
.query(|qb| {
qb.where_eq("name", Value::String("John".to_string()));
qb.where_eq("city", Value::String("New York".to_string()));
qb.where_in(
"department",
vec![
Value::String("IT".to_string()),
Value::String("HR".to_string()),
],
);
qb.where_subquery(|sub| {
sub.where_eq("status", Value::String("active".to_string()));
let or_sub = sub.or();
or_sub.where_eq("status", Value::String("pending".to_string()));
or_sub.where_between(
"registered_at",
[
Value::String("2024-01-01".to_string()),
Value::String("2024-01-31".to_string()),
],
);
});
qb.where_raw(
"(latitude BETWEEN ? AND ?) AND (longitude BETWEEN ? AND ?)",
Some(vec![
Value::Number(serde_json::Number::from_f64(40.0).unwrap()),
Value::Number(serde_json::Number::from_f64(41.0).unwrap()),
Value::Number(serde_json::Number::from_f64(70.0).unwrap()),
Value::Number(serde_json::Number::from_f64(71.0).unwrap()),
]),
);
});
builder.add_raw("LIMIT ?", Some(vec![10.into()]));
let sql = builder.to_sql();
assert_eq!(
sql.0,
"SELECT * FROM \"mydb\".\"users\" WHERE \"name\" = ? AND \"city\" = ? AND \"department\" IN (?,?) AND (\"status\" = ? OR (\"status\" = ? AND \"registered_at\" BETWEEN ? AND ?)) AND (latitude BETWEEN ? AND ?) AND (longitude BETWEEN ? AND ?) LIMIT ?"
);
assert_eq!(
sql.1,
vec![
Value::String("John".to_string()),
Value::String("New York".to_string()),
Value::String("IT".to_string()),
Value::String("HR".to_string()),
Value::String("active".to_string()),
Value::String("pending".to_string()),
Value::String("2024-01-01".to_string()),
Value::String("2024-01-31".to_string()),
Value::Number(serde_json::Number::from_f64(40.0).unwrap()),
Value::Number(serde_json::Number::from_f64(41.0).unwrap()),
Value::Number(serde_json::Number::from_f64(70.0).unwrap()),
Value::Number(serde_json::Number::from_f64(71.0).unwrap()),
Value::Number(10.into()),
]
);
}
#[test]
fn test_sqlite_join() {
let mut builder = ChainBuilder::new(Client::Sqlite);
builder
.db("mydb") .select(Select::Columns(vec!["*".into()]))
.table("users")
.query(|qb| {
qb.join("details", |join| {
join.on("details.id", "=", "users.d_id");
join.on("details.id_w", "=", "users.d_id_w");
join.or().on("details.id_s", "=", "users.d_id_s").on(
"details.id_w",
"=",
"users.d_id_w",
);
});
qb.where_eq("name", Value::String("John".to_string()));
});
builder.select(Select::Raw(
"(SELECT COUNT(*) FROM `mydb`.`users` WHERE users.id = ?) AS count".into(),
Some(vec![Value::Number(1.into())]),
));
let sql = builder.to_sql();
let to_sqlx = builder.to_sqlx_query();
let true_sql = "SELECT *, (SELECT COUNT(*) FROM `mydb`.`users` WHERE users.id = ?) AS count FROM \"mydb\".\"users\" JOIN \"mydb\".\"details\" ON \"details\".\"id\" = \"users\".\"d_id\" AND \"details\".\"id_w\" = \"users\".\"d_id_w\" OR (\"details\".\"id_s\" = \"users\".\"d_id_s\" AND \"details\".\"id_w\" = \"users\".\"d_id_w\") WHERE \"name\" = ?";
assert_eq!(sql.0, true_sql);
assert_eq!(
sql.1,
vec![Value::Number(1.into()), Value::String("John".to_string()),]
);
assert_eq!(to_sqlx.sql(), true_sql);
}
#[test]
fn test_sqlite_tow_join() {
let mut builder = ChainBuilder::new(Client::Sqlite);
builder
.db("mydb") .select(Select::Columns(vec!["*".into()]))
.table("users")
.query(|qb| {
qb.join("details", |join| {
join.on("details.id", "=", "users.d_id");
});
qb.join("profiles", |join| {
join.on("profiles.id", "=", "users.p_id");
});
qb.where_eq("name", Value::String("John".to_string()));
});
let sql = builder.to_sql();
let to_sqlx = builder.to_sqlx_query();
let true_sql = "SELECT * FROM \"mydb\".\"users\" JOIN \"mydb\".\"details\" ON \"details\".\"id\" = \"users\".\"d_id\" JOIN \"mydb\".\"profiles\" ON \"profiles\".\"id\" = \"users\".\"p_id\" WHERE \"name\" = ?";
assert_eq!(sql.0, true_sql);
assert_eq!(sql.1, vec![Value::String("John".to_string())]);
assert_eq!(to_sqlx.sql(), true_sql);
}
#[test]
fn test_sqlite_join_raw() {
let mut builder = ChainBuilder::new(Client::Sqlite);
builder
.db("mydb") .select(Select::Columns(vec!["*".into()]))
.table("users")
.query(|qb| {
qb.raw_join(
"JOIN details ON details.id = users.d_id AND details.status = ?",
Some(vec![Value::String("active".to_string())]),
);
qb.where_eq("name", Value::String("John".to_string()));
});
let sql = builder.to_sql();
let to_sqlx = builder.to_sqlx_query();
let true_sql = "SELECT * FROM \"mydb\".\"users\" JOIN details ON details.id = users.d_id AND details.status = ? WHERE \"name\" = ?";
assert_eq!(sql.0, true_sql);
assert_eq!(
sql.1,
vec![
Value::String("active".to_string()),
Value::String("John".to_string()),
]
);
assert_eq!(to_sqlx.sql(), true_sql);
}
#[test]
fn test_sqlite_insert() {
let mut builder = ChainBuilder::new(Client::Sqlite);
builder.table("users").insert(serde_json::json!({
"name": "John Doe",
"email": "john@example.com",
"age": 30
}));
let (sql, binds) = builder.to_sql();
println!("SQLite INSERT SQL: {}", sql);
println!("Binds: {:?}", binds);
assert!(sql.contains("INSERT INTO \"users\""));
assert!(sql.contains("VALUES (?, ?, ?)"));
assert_eq!(binds.len(), 3);
}
#[test]
fn test_sqlite_insert_many() {
let mut builder = ChainBuilder::new(Client::Sqlite);
builder.table("users").insert_many(vec![
serde_json::json!({
"name": "John Doe",
"email": "john@example.com",
"age": 30
}),
serde_json::json!({
"name": "Jane Smith",
"email": "jane@example.com",
"age": 25
}),
]);
let (sql, binds) = builder.to_sql();
println!("SQLite INSERT MANY SQL: {}", sql);
println!("Binds: {:?}", binds);
assert!(sql.contains("INSERT INTO \"users\""));
assert!(sql.contains("VALUES (?, ?, ?), (?, ?, ?)"));
assert_eq!(binds.len(), 6);
}
#[test]
fn test_sqlite_update() {
let mut builder = ChainBuilder::new(Client::Sqlite);
builder
.table("users")
.update(serde_json::json!({
"status": "inactive",
"updated_at": "2024-01-15"
}))
.query(|qb| {
qb.where_eq("id", Value::Number(1.into()));
});
let (sql, binds) = builder.to_sql();
println!("SQLite UPDATE SQL: {}", sql);
println!("Binds: {:?}", binds);
assert!(sql.contains("UPDATE \"users\" SET"));
assert!(sql.contains("\"status\" = ?"));
assert!(sql.contains("\"updated_at\" = ?"));
assert!(sql.contains("WHERE \"id\" = ?"));
assert_eq!(binds.len(), 3);
}
#[test]
fn test_sqlite_delete() {
let mut builder = ChainBuilder::new(Client::Sqlite);
builder.table("users").delete().query(|qb| {
qb.where_eq("status", Value::String("deleted".to_string()));
});
let (sql, binds) = builder.to_sql();
println!("SQLite DELETE SQL: {}", sql);
println!("Binds: {:?}", binds);
assert!(sql.contains("DELETE FROM \"users\""));
assert!(sql.contains("WHERE \"status\" = ?"));
assert_eq!(binds.len(), 1);
}
#[test]
fn test_sqlite_with() {
let mut slct = ChainBuilder::new(Client::Sqlite);
slct.db("mydb") .table("address")
.select(Select::Columns(vec!["*".into()]))
.query(|qb| {
qb.where_eq("city", Value::String("New York".to_string()));
});
let mut active_users = ChainBuilder::new(Client::Sqlite);
active_users
.db("mydb") .table("users")
.select(Select::Columns(vec!["*".into()]))
.select(Select::Builder("address".to_string(), slct))
.query(|qb| {
qb.where_eq("status", Value::String("active".to_string()));
});
let mut builder = ChainBuilder::new(Client::Sqlite);
builder
.with("active_users", active_users)
.select(Select::Columns(vec!["*".into()]))
.table("active_users")
.query(|qb| {
qb.where_eq("name", Value::String("John".to_string()));
});
let sql = builder.to_sql();
let to_sqlx = builder.to_sqlx_query();
let true_sql = "WITH \"active_users\" AS (SELECT *, (SELECT * FROM \"mydb\".\"address\" WHERE \"city\" = ?) AS \"address\" FROM \"mydb\".\"users\")SELECT * FROM \"active_users\" WHERE \"name\" = ?";
assert_eq!(sql.0, true_sql);
assert_eq!(
sql.1,
vec![
Value::String("New York".to_string()),
Value::String("John".to_string())
]
);
assert_eq!(to_sqlx.sql(), true_sql);
}
#[test]
fn test_sqlite_with_recursive() {
let mut slct = ChainBuilder::new(Client::Sqlite);
slct.db("mydb") .table("address")
.select(Select::Columns(vec!["*".into()]))
.query(|qb| {
qb.where_eq("city", Value::String("New York".to_string()));
});
let mut active_users = ChainBuilder::new(Client::Sqlite);
active_users
.db("mydb") .table("users")
.select(Select::Columns(vec!["*".into()]))
.select(Select::Builder("address".to_string(), slct))
.query(|qb| {
qb.where_eq("status", Value::String("active".to_string()));
});
let mut builder = ChainBuilder::new(Client::Sqlite);
builder
.with_recursive("active_users", active_users)
.select(Select::Columns(vec!["*".into()]))
.table("active_users")
.query(|qb| {
qb.where_eq("name", Value::String("John".to_string()));
});
let sql = builder.to_sql();
let to_sqlx = builder.to_sqlx_query();
let true_sql = "WITH RECURSIVE \"active_users\" AS (SELECT *, (SELECT * FROM \"mydb\".\"address\" WHERE \"city\" = ?) AS \"address\" FROM \"mydb\".\"users\")SELECT * FROM \"active_users\" WHERE \"name\" = ?";
assert_eq!(sql.0, true_sql);
assert_eq!(
sql.1,
vec![
Value::String("New York".to_string()),
Value::String("John".to_string())
]
);
assert_eq!(to_sqlx.sql(), true_sql);
}
#[test]
fn test_sqlite_union() {
let mut pending_users = ChainBuilder::new(Client::Sqlite);
pending_users
.db("mydb") .table("users")
.select(Select::Columns(vec!["*".into()]))
.query(|qb| {
qb.where_eq("status", Value::String("pending".to_string()));
});
let mut builder = ChainBuilder::new(Client::Sqlite);
builder
.union(pending_users)
.db("mydb") .select(Select::Columns(vec!["*".into()]))
.table("users")
.query(|qb| {
qb.where_eq("name", Value::String("John".to_string()));
});
let sql = builder.to_sql();
let to_sqlx = builder.to_sqlx_query();
let true_sql = "SELECT * FROM \"mydb\".\"users\" WHERE \"name\" = ? UNION SELECT * FROM \"mydb\".\"users\"";
assert_eq!(sql.0, true_sql);
assert_eq!(sql.1, vec![Value::String("John".to_string()),]);
assert_eq!(to_sqlx.sql(), true_sql);
}
#[test]
fn test_sqlite_union_all() {
let mut pending_users = ChainBuilder::new(Client::Sqlite);
pending_users
.db("mydb") .table("users")
.select(Select::Columns(vec!["*".into()]))
.query(|qb| {
qb.where_eq("status", Value::String("pending".to_string()));
});
let mut builder = ChainBuilder::new(Client::Sqlite);
builder
.union_all(pending_users)
.db("mydb") .select(Select::Columns(vec!["*".into()]))
.table("users")
.query(|qb| {
qb.where_eq("name", Value::String("John".to_string()));
});
let sql = builder.to_sql();
let to_sqlx = builder.to_sqlx_query();
let true_sql = "SELECT * FROM \"mydb\".\"users\" WHERE \"name\" = ? UNION ALL SELECT * FROM \"mydb\".\"users\"";
assert_eq!(sql.0, true_sql);
assert_eq!(sql.1, vec![Value::String("John".to_string()),]);
assert_eq!(to_sqlx.sql(), true_sql);
}
#[test]
fn test_sqlite_limit_offset() {
let mut builder = ChainBuilder::new(Client::Sqlite);
builder
.db("mydb") .select(Select::Columns(vec!["*".into()]))
.table("users")
.query(|qb| {
qb.limit(10);
qb.offset(20);
});
let sql = builder.to_sql();
let to_sqlx = builder.to_sqlx_query();
let true_sql = "SELECT * FROM \"mydb\".\"users\" LIMIT 20, 10";
assert_eq!(sql.0, true_sql);
assert_eq!(sql.1, Vec::<Value>::new());
assert_eq!(to_sqlx.sql(), true_sql);
}
#[test]
fn test_sqlite_group_by() {
let mut builder = ChainBuilder::new(Client::Sqlite);
builder
.db("mydb") .select(Select::Columns(vec!["*".into()]))
.table("users")
.query(|qb| {
qb.group_by(vec!["department".to_string(), "status".to_string()]);
});
let sql = builder.to_sql();
let to_sqlx = builder.to_sqlx_query();
let true_sql = "SELECT * FROM \"mydb\".\"users\" GROUP BY \"department\", \"status\"";
assert_eq!(sql.0, true_sql);
assert_eq!(sql.1, Vec::<Value>::new());
assert_eq!(to_sqlx.sql(), true_sql);
}
#[test]
fn test_sqlite_group_by_raw() {
let mut builder = ChainBuilder::new(Client::Sqlite);
builder
.db("mydb") .select(Select::Columns(vec!["*".into()]))
.table("users")
.query(|qb| {
qb.group_by_raw("department, status", None);
});
let sql = builder.to_sql();
let to_sqlx = builder.to_sqlx_query();
let true_sql = "SELECT * FROM \"mydb\".\"users\" GROUP BY department, status";
assert_eq!(sql.0, true_sql);
assert_eq!(sql.1, Vec::<Value>::new());
assert_eq!(to_sqlx.sql(), true_sql);
}
#[test]
fn test_sqlite_order_by() {
let mut builder = ChainBuilder::new(Client::Sqlite);
builder
.db("mydb") .select(Select::Columns(vec!["*".into()]))
.table("users")
.query(|qb| {
qb.order_by("name", "ASC");
qb.order_by("age", "DESC");
});
let sql = builder.to_sql();
let to_sqlx = builder.to_sqlx_query();
let true_sql = "SELECT * FROM \"mydb\".\"users\" ORDER BY \"name\" ASC, \"age\" DESC";
assert_eq!(sql.0, true_sql);
assert_eq!(sql.1, Vec::<Value>::new());
assert_eq!(to_sqlx.sql(), true_sql);
}
#[test]
fn test_sqlite_order_by_raw() {
let mut builder = ChainBuilder::new(Client::Sqlite);
builder
.db("mydb") .select(Select::Columns(vec!["*".into()]))
.table("users")
.query(|qb| {
qb.order_by_raw("name ASC, age DESC", None);
});
let sql = builder.to_sql();
let to_sqlx = builder.to_sqlx_query();
let true_sql = "SELECT * FROM \"mydb\".\"users\" ORDER BY name ASC, age DESC";
assert_eq!(sql.0, true_sql);
assert_eq!(sql.1, Vec::<Value>::new());
assert_eq!(to_sqlx.sql(), true_sql);
}
#[test]
fn test_sqlite_table_raw() {
let mut builder = ChainBuilder::new(Client::Sqlite);
builder
.db("mydb") .select(Select::Columns(vec!["*".into()]))
.table_raw(
"(SELECT * FROM users WHERE status = ?) as active_users",
Some(vec![Value::String("active".to_string())]),
)
.query(|qb| {
qb.where_eq("name", Value::String("John".to_string()));
});
let sql = builder.to_sql();
let to_sqlx = builder.to_sqlx_query();
let true_sql =
"SELECT * FROM (SELECT * FROM users WHERE status = ?) as active_users WHERE \"name\" = ?";
assert_eq!(sql.0, true_sql);
assert_eq!(
sql.1,
vec![
Value::String("active".to_string()),
Value::String("John".to_string()),
]
);
assert_eq!(to_sqlx.sql(), true_sql);
}
#[test]
fn test_sqlite_joins() {
let mut builder = ChainBuilder::new(Client::Sqlite);
builder
.select(Select::Columns(vec![
"users.name".into(),
"profiles.bio".into(),
]))
.table("users")
.query(|qb| {
qb.left_join("profiles", |join| {
join.on("users.id", "=", "profiles.user_id");
});
qb.where_eq("users.status", Value::String("active".to_string()));
});
let (sql, binds) = builder.to_sql();
println!("SQLite JOIN SQL: {}", sql);
println!("Binds: {:?}", binds);
assert!(sql.contains("SELECT \"users\".\"name\", \"profiles\".\"bio\" FROM \"users\""));
assert!(sql.contains("LEFT JOIN \"profiles\" ON \"users\".\"id\" = \"profiles\".\"user_id\""));
assert!(sql.contains("WHERE \"users\".\"status\" = ?"));
}
#[test]
fn test_sqlite_aggregate_functions() {
let mut builder = ChainBuilder::new(Client::Sqlite);
builder.table("orders").query(|qb| {
qb.group_by(vec!["user_id".to_string()]);
qb.having("COUNT(*)", ">", Value::Number(5.into()));
});
builder
.select_count("id")
.select_sum("amount")
.select_avg("amount");
let (sql, binds) = builder.to_sql();
println!("SQLite Aggregate SQL: {}", sql);
println!("Binds: {:?}", binds);
assert!(sql.contains("SELECT COUNT(\"id\"), SUM(\"amount\"), AVG(\"amount\") FROM \"orders\""));
assert!(sql.contains("GROUP BY \"user_id\""));
assert!(sql.contains("HAVING COUNT(*) > ?"));
}
#[test]
fn test_sqlite_limit_offset_old() {
let mut builder = ChainBuilder::new(Client::Sqlite);
builder
.select(Select::Columns(vec!["*".into()]))
.table("users")
.query(|qb| {
qb.limit(10);
qb.offset(20);
});
let (sql, binds) = builder.to_sql();
println!("SQLite LIMIT/OFFSET SQL: {}", sql);
println!("Binds: {:?}", binds);
assert!(sql.contains("LIMIT 20, 10"));
}
#[test]
fn test_sqlite_with_cte() {
let mut active_users = ChainBuilder::new(Client::Sqlite);
active_users
.table("users")
.select(Select::Columns(vec!["*".into()]))
.query(|qb| {
qb.where_eq("status", Value::String("active".to_string()));
});
let mut builder = ChainBuilder::new(Client::Sqlite);
builder
.with("active_users", active_users)
.select(Select::Columns(vec!["*".into()]))
.table("active_users")
.query(|qb| {
qb.where_gt("age", Value::Number(25.into()));
});
let (sql, binds) = builder.to_sql();
println!("SQLite CTE SQL: {}", sql);
println!("Binds: {:?}", binds);
assert!(sql.contains("WITH \"active_users\" AS ("));
assert!(sql.contains("SELECT * FROM \"active_users\""));
}
#[test]
fn test_sqlite_union_old() {
let mut pending_users = ChainBuilder::new(Client::Sqlite);
pending_users
.table("users")
.select(Select::Columns(vec!["*".into()]))
.query(|qb| {
qb.where_eq("status", Value::String("pending".to_string()));
});
let mut builder = ChainBuilder::new(Client::Sqlite);
builder
.union(pending_users)
.table("users")
.select(Select::Columns(vec!["*".into()]))
.query(|qb| {
qb.where_eq("status", Value::String("active".to_string()));
});
let (sql, binds) = builder.to_sql();
println!("SQLite UNION SQL: {}", sql);
println!("Binds: {:?}", binds);
assert!(sql.contains("UNION"));
assert!(sql.contains("SELECT * FROM \"users\""));
}