native db is just a key value store with more boilerplate but handy generics

main
Bel LaPointe 2025-03-02 12:47:31 -07:00
parent 20a3bc7864
commit 4c2ab4a592
4 changed files with 94 additions and 14 deletions

3
gd/node_2d.tscn Normal file
View File

@ -0,0 +1,3 @@
[gd_scene format=3 uid="uid://dg85xsdqg6wj0"]
[node name="Node2D" type="Node2D"]

2
src/rust/Cargo.lock generated
View File

@ -305,6 +305,8 @@ version = "0.1.0"
dependencies = [
"futures",
"native_db",
"native_model",
"serde",
]
[[package]]

View File

@ -6,3 +6,5 @@ edition = "2024"
[dependencies]
futures = "0.3.31"
native_db = "0.8.1"
native_model = "0.4.20"
serde = "1.0.218"

View File

@ -1,28 +1,101 @@
mod main {
use {
};
use {super::data};
pub fn run() {
let mut db = DB::new(false);
db.init().expect("db init failed");
let db = data::DB::new().expect("could not make db");
}
struct DB {
db: bool,
}
impl DB {
fn new(db: bool) -> DB {
DB{db: db}
mod data {
mod models {
use {
native_db::{
native_db,
ToKey,
},
native_model::{
native_model,
Model,
},
serde::{Deserialize, Serialize},
};
pub mod v1 {
use super::*;
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
#[native_model(id = 1, version = 1)]
#[native_db]
pub struct Person {
#[primary_key]
pub name: String,
}
}
}
fn init(self: &mut DB) -> Result<(), String> {
//self.exec("DROP TABLE IF EXISTS t")?;
//self.exec("DROP TABLE IF EXISTS t2")?;
//self.exec("CREATE TABLE t (id INTEGER PRIMARY KEY, k TEXT, v TEXT)")?;
//self.exec("CREATE TABLE t2 (id INTEGER PRIMARY KEY, t_id INTEGER, FOREIGN KEY (t_id) REFERENCES t (id))")?;
use native_db::*;
pub type Person = models::v1::Person;
static MODELS: std::sync::LazyLock<Models> = std::sync::LazyLock::new(|| {
let mut models = Models::new();
models.define::<Person>().expect("failed to define person");
models
});
pub struct DB<'a> {
db: Database<'a>,
}
impl<'a> DB<'a> {
pub fn new() -> Result<DB<'a>, String> {
let db = match Builder::new().create_in_memory(&MODELS) {
Ok(db) => Ok(db),
Err(msg) => Err(msg.to_string()),
}?;
Ok(DB{
db: db,
})
}
pub fn insert<T: ToInput>(self: &DB<'a>, v: T) -> Result<(), String> {
let t = match self.db.rw_transaction() {
Ok(t) => t,
Err(msg) => return Err(msg.to_string()),
};
if let Err(msg) = t.insert(v) {
return Err(msg.to_string());
}
if let Err(msg) = t.commit() {
return Err(msg.to_string());
}
Ok(())
}
pub fn get<T: ToInput, S: ToKey>(self: &DB<'a>, primary: S) -> Result<Option<T>, String> {
let t = match self.db.r_transaction() {
Ok(t) => t,
Err(msg) => return Err(msg.to_string()),
};
match t.get().primary(primary) {
Ok(v) => Ok(v),
Err(msg) => Err(msg.to_string()),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn mvp() {
let db = DB::new().expect("could not make db");
let person = Person{name: "me".to_string()};
db.insert(person.clone()).expect("could not insert person");
assert_eq!(person, db.get("me".to_string()).expect("could not get").expect("got none"));
}
}
}