Redb use of structures

Hey guys:

I am looking at reddb

and with this code:

use redb::{Database, Error, ReadableTable, TableDefinition};

const TABLE: TableDefinition<&str, u64> = TableDefinition::new("my_data");

fn main() -> Result<(), Error> {
    let db = Database::create("my_db.redb")?;
    let write_txn = db.begin_write()?;
    {
        let mut table = write_txn.open_table(TABLE)?;
        table.insert("my_key", &123)?;
    }
    write_txn.commit()?;

    let read_txn = db.begin_read()?;
    let table = read_txn.open_table(TABLE)?;
    assert_eq!(table.get("my_key")?.unwrap().value(), 123);

    Ok(())
}

lets say I had a structure which is going to be used as a value, so I want to write to it and I want to find a particular value from one of the structure's fields, is this possible?

Yes that's possible, as long as your type implements Value. Here a very basic example:

use redb::{Database, Error, TableDefinition, TypeName, Value};

#[derive(Debug)]
struct Foo {
    foo: u64,
}

impl Value for Foo {
    type SelfType<'a> = Self;
    type AsBytes<'a> = [u8; std::mem::size_of::<Self>()] where Self: 'a;

    fn fixed_width() -> Option<usize> {
        Some(std::mem::size_of::<Self>())
    }

    fn from_bytes<'a>(data: &'a [u8]) -> Self
    where
        Self: 'a,
    {
        Self {
            foo: u64::from_le_bytes(data.try_into().unwrap()),
        }
    }

    fn as_bytes<'a, 'b: 'a>(value: &'a Self::SelfType<'b>) -> [u8; std::mem::size_of::<Self>()]
    where
        Self: 'a,
        Self: 'b,
    {
        value.foo.to_le_bytes()
    }

    fn type_name() -> TypeName {
        TypeName::new(stringify!(Foo))
    }
}

const TABLE: TableDefinition<&str, Foo> = TableDefinition::new("my_data");

fn main() -> Result<(), Error> {
    let db = Database::create("my_db.redb")?;
    let write_txn = db.begin_write()?;
    {
        let mut table = write_txn.open_table(TABLE)?;
        table.insert("my_key", &Foo { foo: 123 })?;
    }
    write_txn.commit()?;

    let read_txn = db.begin_read()?;
    let table = read_txn.open_table(TABLE)?;
    assert_eq!(table.get("my_key")?.unwrap().value().foo, 123);

    Ok(())
}
1 Like

I see thanks

Edit: It kinda looks complicated I have no idea what each line even does in the impl area isn't there an easier way to save and read from it?

Lets say I had this:

let x = Foo{foo: 123};

from this variable I want to save into the database, is that possible without using that entire impl code?

No idea if there is a way around implementing Value by hand/creating your own macro(s) to implement it for you. I couldn't find a derive macro that implements Value for you in the redb crate, but there might be some out there. The gist of the implementation is that you need to serialise and deserialise your type to and from bytes. I assume you could just implement serde's Serialize and Deserialize for your type and forward the Value implementation to a (de)serializer of your choice. Then a simple declarative macro would suffice to implement Value.

2 Likes

One thing I don't understand that if I had this variable:

let x = Foo{foo: 123};

then isn't it possible to write it like this:

table.insert("my_key", &x)?;

And no need for the impl code?

Like I said, because redb needs to serialise the data to some binary format it saves inside the database structure. This is not different from any other database out there, you need some sort of logic that translates the stored data to and from your types.

2 Likes

right I see, thanks then.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.