use flowdb::jsondb::{JsonDB, SortDir, StoreSchema, TransactionMode};
use flowdb::{Config, ObjectStore};
use serde::{Deserialize, Serialize};
use serde_json::json;
#[derive(Debug, Serialize, Deserialize, ObjectStore)]
#[store(name = "users", key_path = "id")]
struct User {
id: String,
#[index(name = "by_email", unique)]
email: String,
#[index(name = "by_age")]
age: u32,
city: String,
}
#[allow(dead_code)]
#[derive(Debug, Serialize, Deserialize, ObjectStore)]
#[store(key_path = "id")]
struct Log {
#[index(name = "by_level")]
level: String,
msg: String,
}
fn main() {
let dir = tempfile::TempDir::with_prefix("flowdb_jsondb_").unwrap();
let db = JsonDB::open(Config {
data_dir: dir.path().to_path_buf(),
..Config::default()
})
.unwrap();
db.apply_schema::<User>().unwrap();
db.apply_store(
&StoreSchema::new("logs", "id")
.with_index("by_level", &["level"], false),
)
.unwrap();
println!("Schemas applied: users (derived), logs (builder)");
let docs = vec![
json!({"id": "u1", "email": "alice@ex.com", "age": 30, "city": "NYC"}),
json!({"id": "u2", "email": "bob@ex.com", "age": 25, "city": "NYC"}),
json!({"id": "u3", "email": "carol@ex.com", "age": 35, "city": "SF"}),
json!({"id": "u4", "email": "dave@ex.com", "age": 28, "city": "SF"}),
];
for doc in &docs {
db.put("users", doc.clone()).unwrap();
}
println!("Inserted {} users", docs.len());
let user = db.get("users", &json!("u1")).unwrap();
println!("get u1 → {:#}", user.unwrap());
let results = db
.query("users")
.where_eq("city", json!("NYC"))
.order_by("age", SortDir::Asc)
.collect()
.unwrap();
println!("NYC users (asc age):");
for doc in &results {
println!(" {} (age {})", doc["email"], doc["age"]);
}
db.create_index("users", "by_city_age", &["city", "age"], false, false)
.unwrap();
let results = db
.query("users")
.where_eq("city", json!("SF"))
.where_range("age", json!(20), json!(30))
.collect()
.unwrap();
println!("SF users age [20,30): {} found", results.len());
let by_email = db.get_by_index("users", "by_email", &json!("alice@ex.com")).unwrap();
println!("by_email alice → {:?}", by_email.first().map(|d| &d["id"]));
let results = db
.range_by_index("users", "by_email", &json!("a"), &json!("z"))
.unwrap();
println!("users by email [a..z): {}", results.len());
let new_user = User {
id: "u5".into(),
email: "eve@ex.com".into(),
age: 32,
city: "LA".into(),
};
db.put_doc("users", &new_user).unwrap();
let back: Option<User> = db.get_doc("users", "u5").unwrap();
println!("serde round-trip → {:?}", back.unwrap());
{
let mut tx = db
.transaction(&["users"], TransactionMode::ReadWrite)
.unwrap();
let doc = tx.get("users", &json!("u1")).unwrap().unwrap();
let mut updated = doc.as_object().unwrap().clone();
updated.insert("email".into(), json!("alice_new@ex.com"));
tx.put("users", json!(updated)).unwrap();
tx.commit().unwrap();
println!("transaction committed");
}
let user = db.get("users", &json!("u1")).unwrap();
println!("u1 email after tx → {}", user.unwrap()["email"]);
println!("stores: {:?}", db.store_names());
let store = db.get_store("users").unwrap();
println!("users key_path={}", store.key_path);
for idx in &store.indexes {
println!(" index {} fields={:?} unique={}", idx.name, idx.key_paths, idx.unique);
}
db.apply_schema::<User>().unwrap();
println!("apply_schema (idempotent) OK");
db.shutdown().unwrap();
println!("Done (data in {})", dir.path().display());
}