Crates.io | mssqlrust |
lib.rs | mssqlrust |
version | 1.0.2 |
created_at | 2025-08-29 16:10:44.162955+00 |
updated_at | 2025-08-29 21:09:07.621158+00 |
description | Lightweight Rust library for Microsoft SQL Server using dataset and datatable |
homepage | |
repository | https://github.com/Luigimonsoft/mssqlrust |
max_upload_size | |
id | 1816089 |
size | 111,671 |
mssqlrust is a lightweight Rust library for Microsoft SQL Server built on top of Tiberius. It executes queries, stored procedures and views and returns results in a typed hierarchy DataSet → DataTable → DataRow → DataValue
with column metadata, nullable handling and streaming support.
Add the dependency to your Cargo.toml
:
[dependencies]
mssqlrust = "1.0.2"
The crate wraps the SQL Server connection using Tiberius and exposes an async execute
function that receives a MssqlConfig
and a Command
. The returned data is built into the hierarchy DataSet → DataTable → DataRow → DataValue
for typed access to results.
flowchart LR
A[Create MssqlConfig] --> B[Build Command]
B --> C[execute]
C --> D[SQL Server]
D --> E[DataSet]
E --> F[DataTable]
F --> G[DataRow]
sequenceDiagram
actor Client
participant mssqlrust
participant SQLServer
Client->>mssqlrust: execute(config, cmd)
mssqlrust->>SQLServer: run query
SQLServer-->>mssqlrust: result rows
mssqlrust-->>Client: DataSet
Run a simple text query and read the first row/column. Results are accessed via DataSet → DataTable → DataRow
, and you can compare values directly with native Rust types.
use mssqlrust::{execute, Command};
use mssqlrust::infrastructure::mssql::MssqlConfig;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let config = MssqlConfig::new(
"localhost", 1433, "sa", "YourStrong!Passw0rd", "master", true,
);
let cmd = Command::query("SELECT 1 AS value");
let ds = execute(config, cmd).await?;
let row = &ds.tables["table0"][0];
assert_eq!(row["value"], 1);
println!("value: {:?}", row["value"]);
Ok(())
}
use mssqlrust::{execute, Command, Parameter};
use mssqlrust::infrastructure::mssql::MssqlConfig;
use chrono::NaiveDate;
use rust_decimal::Decimal;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let config = MssqlConfig::new(
"localhost", 1433, "sa", "YourStrong!Passw0rd", "master", true,
);
let cmd = Command::query("SELECT @id AS id, @flag AS flag, @amount AS amount, @when AS when_date")
.with_param(Parameter::new("id", 7))
.with_param(Parameter::new("flag", false))
.with_param(Parameter::new("amount", Decimal::new(1999, 2)))
.with_param(Parameter::new("when", NaiveDate::from_ymd_opt(2024, 6, 1).unwrap()));
let ds = execute(config, cmd).await?;
let row = &ds.tables["table0"][0];
println!("id: {:?}, flag: {:?}, amount: {:?}, when: {:?}", row["id"], row["flag"], row["amount"], row["when_date"]);
Ok(())
}
Execute commands that don't return result sets (INSERT/UPDATE/DELETE/DDL) and get how many rows were affected.
use mssqlrust::{execute_non_query, Command, Parameter};
use mssqlrust::infrastructure::mssql::MssqlConfig;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let config = MssqlConfig::new(
"localhost", 1433, "sa", "YourStrong!Passw0rd", "master", true,
);
// Text command
let cmd = Command::query("UPDATE Users SET Active = 0 WHERE LastLogin < @cutoff")
.with_param(Parameter::new("cutoff", "2024-01-01"));
let affected = execute_non_query(config.clone(), cmd).await?;
println!("Updated rows: {}", affected);
// Stored procedure
let sp = Command::stored_procedure("sp_archive_users")
.with_param(Parameter::new("days", 30));
let archived = execute_non_query(config, sp).await?;
println!("Archived rows: {}", archived);
Ok(())
}
You can execute stored procedures and pass named parameters (with or without the @
prefix). Parameters accept native Rust types and are converted internally.
use mssqlrust::{execute, Command, Parameter};
use mssqlrust::infrastructure::mssql::MssqlConfig;
use chrono::NaiveDate;
use rust_decimal::Decimal;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let config = MssqlConfig::new(
"localhost", 1433, "sa", "YourStrong!Passw0rd", "master", true,
);
// EXEC sp_upsert_order @id = @P1, @status = @P2, @amount = @P3, @when = @P4
let cmd = Command::stored_procedure("sp_upsert_order")
.with_param(Parameter::new("id", 1001))
.with_param(Parameter::new("status", "PAID"))
.with_param(Parameter::new("amount", Decimal::new(1299, 2)))
.with_param(Parameter::new("@when", NaiveDate::from_ymd_opt(2024, 6, 1).unwrap()));
let ds = execute(config, cmd).await?;
// If the procedure returns rows, access them normally
if let Some(table) = ds.tables.get("table0") {
if !table.rows.is_empty() {
let row = &table.rows[0];
println!("order_id: {} status: {}", row["id"].clone(), row["status"].clone());
}
}
Ok(())
}
Return the first column of the first row from either a text query or a stored procedure.
use mssqlrust::{execute_scalar, Command, Parameter};
use mssqlrust::infrastructure::mssql::MssqlConfig;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let config = MssqlConfig::new(
"localhost", 1433, "sa", "YourStrong!Passw0rd", "master", true,
);
// Query scalar
let v = execute_scalar(config.clone(), Command::query("SELECT 42")).await?;
assert_eq!(v.unwrap(), 42);
// Stored procedure scalar
// CREATE PROCEDURE dbo.sp_add1 @x INT AS BEGIN SELECT @x + 1; END
let v = execute_scalar(
config,
Command::stored_procedure("dbo.sp_add1").with_param(Parameter::new("x", 5)),
)
.await?;
assert_eq!(v.unwrap(), 6);
Ok(())
}
classDiagram
class DataSet {
tables: HashMap<String, DataTable>
}
class DataTable {
name: String
columns: Vec<DataColumn>
rows: Vec<DataRow>
}
class DataColumn {
name: String
sql_type: String
size: Option<u32>
nullable: bool
}
class DataRow {
cells: HashMap<String, DataCell>
}
class DataCell {
value: DataValue
}
DataSet --> DataTable
DataTable --> DataColumn
DataTable --> DataRow
DataRow --> DataCell
DataCell --> DataValue
The tests
directory contains additional examples that show parameterized queries, stored procedures and mapping of various SQL types.
This project is distributed under the terms of the MIT license.