Table and data are not saved in Limbo database file

⚓ rust    📅 2025-05-22    👤 surdeus    👁️ 4      

surdeus

Warning

This post was published 38 days ago. The information described in this article may have changed.

Hello, I have backend like this :

use ntex::{web, web::types::State};
use serde_json::{Map, Value as JsonValue};
use limbo::{Builder, Connection, value::Value, Error as LimboError};
use std::{future::Future, env::set_var};
use bb8::{ManageConnection, Pool};
use log::error;

struct LimboConnectionManager {
    db: limbo::Database,
}

impl LimboConnectionManager {
    async fn new(path: &str) -> Self {
        let db = Builder::new_local(path).build().await.unwrap();
        Self { db }
    }
}

impl ManageConnection for LimboConnectionManager {
    type Connection = Connection;
    type Error = LimboError;

    fn connect(&self) -> impl Future<Output = Result<Self::Connection, Self::Error>> + Send {
        let db = self.db.clone();
        async move { db.connect() }
    }


    fn is_valid(&self, conn: &mut Self::Connection) -> impl Future<Output = Result<(), Self::Error>> + Send {
        async move {
            conn.execute("SELECT 1", ()).await.map(|_| ())
        }
    }

    fn has_broken(&self, _conn: &mut Self::Connection) -> bool {
        false
    }
}

async fn row_to_json(row: &limbo::Row, columns: &[&str]) -> serde_json::Value {
    let mut map = Map::new();

    for (i, &col_name) in columns.iter().enumerate() {
        match row.get_value(i) {
            Ok(Value::Text(t)) => {
                map.insert(col_name.to_string(), JsonValue::String(t));
            }
            Ok(Value::Integer(i)) => {
                map.insert(col_name.to_string(), JsonValue::Number(i.into()));
            }
            Ok(Value::Null) => {
                map.insert(col_name.to_string(), JsonValue::Null);
            }
            Ok(val) => {
                map.insert(col_name.to_string(), JsonValue::String(format!("{:?}", val)));
            }
            Err(_) => continue,
        }
    }

    JsonValue::Object(map)
}

async fn test(pool: State<Pool<LimboConnectionManager>>) -> impl web::Responder {
    let conn = match pool.get().await {
        Ok(c) => c,
        Err(e) => {
            error!("Failed to get DB connection: {}", e);
            return web::HttpResponse::InternalServerError().finish();
        }
    };

    if let Err(e) = conn.execute("create table if not exists tes(nama text);", ()).await {
        error!("Failed to create table: {}", e);
        return web::HttpResponse::InternalServerError().finish();
    }

    if let Err(e) = conn.execute("insert into tes(nama) values('fuji');", ()).await {
        error!("Failed to insert data: {}", e);
        return web::HttpResponse::InternalServerError().finish();
    }

    let mut hasil = match conn.query("SELECT * FROM tes;", ()).await {
        Ok(q) => q,
        Err(e) => {
            error!("Query failed: {}", e);
            return web::HttpResponse::InternalServerError().finish();
        }
    };

    let mut rows_json = Vec::new();
    while let Some(row_result) = hasil.next().await.transpose() {
        match row_result {
            Ok(row) => {
                let json = row_to_json(&row, &["nama"]).await;
                rows_json.push(json);
            }
            Err(e) => {
                error!("Error reading row: {}", e);
                return web::HttpResponse::InternalServerError().finish();
            }
        }
    }

    match serde_json::to_string(&rows_json) {
        Ok(json_str) => web::HttpResponse::Ok()
            .content_type("application/json")
            .body(json_str),
        Err(e) => {
            error!("JSON serialization error: {}", e);
            web::HttpResponse::InternalServerError().finish()
        }
    }
}

#[ntex::main]
async fn main() -> std::io::Result<()> {
    unsafe {
        set_var("RUST_LOG", "info");
        set_var("RUST_BACKTRACE", "1");
    }
    env_logger::init();

    let manager = LimboConnectionManager::new("database.db").await;

    let pool = Pool::builder()
        .max_size(50)
        .build(manager)
        .await
        .unwrap();

    web::HttpServer::new(move || {
        let logger = web::middleware::Logger::default();

        web::App::new()
            .wrap(logger)
            .state(pool.clone())
            .route("/", web::get().to(test))
    })
    .bind(("127.0.0.1", 8080))?
    .run()
    .await
}

I place table creation and data insertion queries before select * to test it. It works

{"nama":"fuji"}

When I revisit the endpoint, it successfully add and fetch new data

[{"nama":"fuji"},{"nama":"fuji"}]

But if I stop the app, comment the table creattion and data insertion queries, and rerun the app. it doesn't work saying there is no table tes

[2025-05-22T06:38:35Z ERROR svr] Query failed: SQL execution failure: `Parse error: Table tes not found`

The table and data are not saved to database.db file because when I stop and rerun the app, they are lost. It seems that it is saved in memory only, but I didn't use ":memory:" when opening the database, but I use "database.db"

Does anyone know how to solve this?

1 post - 1 participant

Read full topic

🏷️ rust_feed