#![allow(clippy::unwrap_used, clippy::expect_used)]
use mssql_client::{
Client, Column, Config, Error, FromRow, Row, SqlValue, ToParams, Tvp, TvpValue,
};
#[derive(Debug, FromRow)]
#[allow(dead_code)]
struct User {
id: i32,
name: String,
#[mssql(rename = "email_address")]
email: String,
phone: Option<String>,
}
#[derive(Debug, ToParams)]
struct NewUser {
name: String,
#[mssql(rename = "email_address")]
email: String,
active: bool,
}
#[derive(Debug, Tvp)]
#[mssql(type_name = "dbo.UserIdList")]
struct UserIdParam {
#[mssql(rename = "UserId")]
user_id: i32,
}
#[tokio::main]
async fn main() -> Result<(), Error> {
tracing_subscriber::fmt::init();
println!("=== FromRow Example ===\n");
demonstrate_from_row();
println!("\n=== ToParams Example ===\n");
demonstrate_to_params();
println!("\n=== TVP Example ===\n");
demonstrate_tvp();
Ok(())
}
fn demonstrate_from_row() {
let columns = vec![
Column::new("id", 0, "INT"),
Column::new("name", 1, "NVARCHAR"),
Column::new("email_address", 2, "NVARCHAR"),
Column::new("phone", 3, "NVARCHAR"),
];
let values = vec![
SqlValue::Int(42),
SqlValue::String("Alice".into()),
SqlValue::String("alice@example.com".into()),
SqlValue::String("+1-555-1234".into()),
];
let row = Row::from_values(columns, values);
let user = User::from_row(&row).expect("from_row should succeed");
println!("Mapped user: {user:?}");
let columns_null = vec![
Column::new("id", 0, "INT"),
Column::new("name", 1, "NVARCHAR"),
Column::new("email_address", 2, "NVARCHAR"),
Column::new("phone", 3, "NVARCHAR"),
];
let values_null = vec![
SqlValue::Int(99),
SqlValue::String("Bob".into()),
SqlValue::String("bob@example.com".into()),
SqlValue::Null,
];
let row_null = Row::from_values(columns_null, values_null);
let user_null = User::from_row(&row_null).expect("from_row with NULL should succeed");
println!("User with NULL phone: {user_null:?}");
}
fn demonstrate_to_params() {
let new_user = NewUser {
name: "Bob".into(),
email: "bob@example.com".into(),
active: true,
};
println!("NewUser struct: {new_user:?}");
match new_user.to_params() {
Ok(params) => {
println!("\nGenerated parameters:");
for param in ¶ms {
println!(" @{} = {:?}", param.name, param.value);
}
}
Err(e) => println!("Error: {e}"),
}
println!("\nUsage:");
println!(" client.execute_named(");
println!(
" \"INSERT INTO users (name, email_address, active) VALUES (@name, @email_address, @active)\","
);
println!(" &new_user.to_params()?");
println!(" ).await?;");
}
fn demonstrate_tvp() {
let user_ids = vec![
UserIdParam { user_id: 1 },
UserIdParam { user_id: 2 },
UserIdParam { user_id: 3 },
];
println!("UserIdParam list:");
for param in &user_ids {
println!(" user_id: {}", param.user_id);
}
println!("\nTVP type name: {}", UserIdParam::type_name());
println!("TVP columns:");
for col in UserIdParam::columns() {
println!(
" {} ({}) at ordinal {}",
col.name, col.sql_type, col.ordinal
);
}
match TvpValue::new(&user_ids) {
Ok(tvp) => println!("\nTvpValue created with {} rows", tvp.len()),
Err(e) => println!("\nTvpValue error: {e}"),
}
println!("\nUsage:");
println!(" // SQL Server type: CREATE TYPE dbo.UserIdList AS TABLE (UserId INT NOT NULL);");
println!(" let tvp = TvpValue::new(&user_ids)?;");
println!(" client.execute(\"EXEC GetUserDetails @UserIds\", &[&tvp]).await?;");
}
#[allow(dead_code)]
async fn database_example() -> Result<(), Error> {
let conn_str = "Server=localhost;Database=master;User Id=sa;Password=Password123!;TrustServerCertificate=true";
let config = Config::from_connection_string(conn_str)?;
let mut client = Client::connect(config).await?;
let rows = client
.query(
"SELECT 1 as id, 'Alice' as name, 'alice@example.com' as email_address, NULL as phone",
&[],
)
.await?;
for result in rows {
let row = result?;
let user = User::from_row(&row)?;
println!("User: {user:?}");
}
let new_user = NewUser {
name: "Charlie".into(),
email: "charlie@example.com".into(),
active: true,
};
let params = new_user
.to_params()
.map_err(|e| Error::Config(e.to_string()))?;
client
.execute_named(
"INSERT INTO users (name, email_address, active) VALUES (@name, @email_address, @active)",
¶ms,
)
.await?;
client.close().await?;
Ok(())
}