Rust
The crate compiles the bundled amalgamation itself (via build.rs and the cc
crate), so there are no system dependencies:
cargo add sqlite-predictcargo add rusqlite --features bundledRegister it as an auto-extension once at startup; every connection you open afterward has the functions:
fn main() -> rusqlite::Result<()> { // Registers sqlite-predict process-wide. Call once, before opening // connections. `register` is unsafe: it registers a C entry point globally. unsafe { sqlite_predict::register().expect("register sqlite-predict") };
let db = rusqlite::Connection::open_in_memory()?; let version: String = db.query_row("select predict_version()", [], |r| r.get(0))?; println!("{version}");
db.execute_batch( "create table readings(ts text, value real); insert into readings select printf('2024-01-01T%02d:00:00', n), 50 + n from (with recursive c(n) as (select 0 union all select n+1 from c where n < 23) select n from c);", )?;
// forecast() is an aggregate like sum(): plain SQL supplies the rows // (WHERE, joins, bound params compose, GROUP BY splits the series), // and each group returns one JSON document let doc: String = db.query_row( "select forecast(ts, value, 6) from readings", [], |r| r.get(0))?; println!("{doc}"); Ok(())}Because register() uses sqlite3_auto_extension, every connection any
rusqlite-based stack opens afterward has the functions, Diesel and sqlx
included, with no per-connection hook:
unsafe { sqlite_predict::register()?; } // once, before connecting
// then through any rusqlite-based stack:let doc: String = conn.query_row( "SELECT forecast(ts, value, 24) FROM readings WHERE city = ?1", ["SF"], |r| r.get(0))?;If a migration tool manages your schema, exclude sqlite-predict’s model
registry (_predict_* tables) from diffs so it doesn’t get dropped.
Next: Operations.