use ferrule_sql::{
ColumnInfo, ConnectOptions, Connection, DatabaseUrl, Row, TypeHint, Value, WriteMode,
WriteOptions, write_rows,
};
use secrecy::SecretString;
use std::error::Error;
fn main() -> Result<(), Box<dyn Error>> {
let path =
std::env::temp_dir().join(format!("ferrule-embed-example-{}.db", std::process::id()));
let _ = std::fs::remove_file(&path);
let url = DatabaseUrl::parse(&format!("sqlite://{}", path.display()))?;
let opts = ConnectOptions {
insecure: false,
password: Some(SecretString::from("unused-for-sqlite")),
};
let mut conn = ferrule_sql::connect(&url, &opts, None)?;
conn.execute("CREATE TABLE widget (id INTEGER PRIMARY KEY, name TEXT)")?;
conn.execute(
"INSERT INTO widget (id, name) VALUES \
(1, 'alpha'), (2, 'beta'), (3, 'gamma'), (4, 'delta'), (5, 'epsilon')",
)?;
println!("streaming read (batched, bounded memory):");
let mut streamed = 0u64;
{
let mut cursor = conn.query_cursor("SELECT id, name FROM widget ORDER BY id")?;
loop {
let batch = cursor.next_batch(2)?; if batch.is_empty() {
break; }
for row in &batch {
println!(" row: {} = {}", render(&row[0]), render(&row[1]));
streamed += 1;
}
}
}
println!(" streamed {streamed} rows total\n");
conn.execute("CREATE TABLE sink (id INTEGER PRIMARY KEY, label TEXT)")?;
let columns = [
ColumnInfo {
name: "id".into(),
type_hint: TypeHint::Int64,
nullable: false,
},
ColumnInfo {
name: "label".into(),
type_hint: TypeHint::String,
nullable: true,
},
];
let rows: Vec<Row> = (1..=2500)
.map(|i| vec![Value::Int64(i), Value::String(format!("item-{i}"))])
.collect();
let write_opts = WriteOptions {
mode: WriteMode::Insert,
batch_size: 500, ..Default::default()
};
let report = write_rows(
&mut *conn,
ferrule_sql::Backend::Sqlite,
"sink",
&columns,
rows,
&write_opts,
)?;
println!("batched write report:");
println!(" rows attempted : {}", report.rows_attempted);
println!(" rows written : {}", report.rows_written);
println!(" batches : {}", report.batches_committed);
println!(" complete : {}", report.is_complete());
let count = conn.query("SELECT COUNT(*) FROM sink")?;
if let Some(Value::Int64(n)) = count.rows.first().and_then(|r| r.first()) {
println!(" verified count : {n}");
}
let _ = std::fs::remove_file(&path);
Ok(())
}
fn render(v: &Value) -> String {
match v {
Value::Null => "NULL".to_string(),
Value::Int64(n) => n.to_string(),
Value::String(s) => s.clone(),
other => format!("{other}"),
}
}