DEVELOPER
Rust API
Embed Teide in your Rust application using the Context, Session, Table, Graph, and Column types.
Quick Start
use teide::sql::{Session, ExecResult};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut session = Session::new()?;
session.execute("CREATE TABLE t AS SELECT * FROM read_csv('data.csv')")?;
match session.execute("SELECT name, SUM(val) AS total FROM t GROUP BY name ORDER BY total DESC")? {
ExecResult::Query(r) => {
println!("{} rows, {} columns", r.table.nrows(), r.columns.len());
}
ExecResult::Ddl(msg) => println!("{msg}"),
}
Ok(())
}
Context
The engine runtime. Manages heap, symbol table, and thread pool.
use teide::Context;
let ctx = Context::new()?;
let table = ctx.read_csv("data.csv")?;
let table = ctx.read_csv_opts("data.tsv", '\t', true, None)?;
let table = ctx.read_splayed("/path/to/table")?;
let table = ctx.read_parted("/path/to/db", "trades")?;
Important: Only one Context should exist at a time. Context is !Send + !Sync (C engine uses thread-local heaps).
Table
A columnar table with ref-counted storage.
let table = ctx.read_csv("data.csv")?;
// Metadata
println!("{} rows, {} cols", table.nrows(), table.ncols());
println!("Column 0: {}", table.col_name_str(0));
println!("Type: {}", table.col_type(0));
// Read values
let val: i64 = table.get_i64(0, 0).unwrap();
let val: f64 = table.get_f64(1, 0).unwrap();
let val: String = table.get_str(0, 0).unwrap();
// Manipulate
let renamed = table.with_column_names(&["a".into(), "b".into()])?;
let subset = table.pick_columns(&["name", "score"])?;
table.write_csv("output.csv")?;
Graph
A lazy operation DAG bound to a table. Operations build a computation graph that is optimized and executed on demand.
let ctx = Context::new()?;
let table = ctx.read_csv("data.csv")?;
let mut g = ctx.graph(&table)?;
// Build computation graph
let tbl = g.const_table(&table)?;
let v1 = g.scan("v1")?;
let threshold = g.const_i64(3)?;
let pred = g.gt(v1, threshold)?;
let filtered = g.filter(tbl, pred)?;
let result = g.execute(filtered)?;
Aggregation:
let id1 = g.scan("id1")?;
let v1 = g.scan("v1")?;
let grouped = g.group_by(
&[id1],
&[teide::AggOp::Sum],
&[v1],
)?;
let result = g.execute(grouped)?;
Available operations:
- Arithmetic: add, sub, mul, div, modulo
- Comparison: eq, ne, lt, le, gt, ge
- Logic: and, or, not
- String: upper, lower, strlen, trim, substr, replace, concat
- Math: abs, sqrt, log, exp, ceil, floor, neg
- Aggregation: sum, avg, min_op, max_op, count, first, last
- Structural: filter, sort, join, group_by, distinct, project, head, tail
- Window: window_op with RowNumber, Rank, DenseRank, Ntile, Lag, Lead, etc.
Session (SQL API)
A stateful SQL session that maintains a table registry.
use teide::sql::{Session, ExecResult};
let mut session = Session::new()?;
// DDL
session.execute("CREATE TABLE t (id INTEGER, name VARCHAR)")?;
session.execute("INSERT INTO t VALUES (1, 'alice'), (2, 'bob')")?;
// Query
match session.execute("SELECT * FROM t ORDER BY id")? {
ExecResult::Query(result) => {
for col in &result.columns {
print!("{col}\t");
}
println!();
println!("{} rows", result.table.nrows());
}
ExecResult::Ddl(msg) => println!("{msg}"),
}
// Inspect tables
for name in session.table_names() {
if let Some((rows, cols)) = session.table_info(name) {
println!("{name}: {rows} rows, {cols} cols");
}
}
Error Handling
use teide::Error;
match result {
Err(Error::Oom) => eprintln!("Out of memory"),
Err(Error::Type) => eprintln!("Type mismatch"),
Err(Error::Schema) => eprintln!("Schema error"),
Err(e) => eprintln!("Error: {e:?}"),
Ok(val) => { /* success */ }
}
Error variants: Oom, Type, Range, Length, Rank, Domain, Nyi, Io, Schema, Corrupt, Cancel, InvalidInput, NullPointer, EngineNotInitialized, RuntimeUnavailable.