rust-indexed-db icon indicating copy to clipboard operation
rust-indexed-db copied to clipboard

Support for reading values as `JsValue`

Open richvdh opened this issue 1 month ago • 0 comments

Consider the following code:

fn decode_value(val: JsValue) -> Result<String, ()> {
    // do something complicated to process `val`.
    val.as_string().ok_or(())
}

async fn get_data() -> Result<Vec<String>, Error> {
    let db = Database::open("my_db").await?;
    let txn = db.transaction("my_store").build()?;
    let result_iter = txn.object_store("my_store")?.get_all().primitive()?.await?;
    result_iter.map(|result| Ok(decode_value(result?)?)).collect()
}

In this scenario, I want to get the raw JsValues from the database and handle the conversion/deserialization myself. The above works, but the map incantation is ugly with the double ?, and there are code paths there which are never used in practice.

The problem is that result_iteris GetAllPrimitiveIter<JsValue>: it passes each entry in the underlying array through JsValue::from_js. Of course, JsValue::from_js is a no-op so can never return Err in practice, but I still have to handle the Err case in my code, with result? or result.unwrap() or whatever.

I'd like to propose an alternative to primitive and serde for the various query sources, let's say js_value. This would return a request type which, unlike BasicRequest and GetAll{Primitive,Serde}Request, does not pass the returned values through a mapper, but instead just iterates over the returned JsValues.

I could then replace the last two lines of the above with:

    let result_iter = txn.object_store("my_store")?.get_all().js_value()?.await?;
    result_iter.map(decode).collect()

... which is somewhat neater.

richvdh avatar Oct 30 '25 17:10 richvdh