cuprate_database

Macro define_tables

Source
macro_rules! define_tables {
    (
        $(
            // Documentation and any `derive`'s.
            $(#[$attr:meta])*

            // The table name + doubles as the table struct name.
            $index:literal => $table:ident,

            // Key type => Value type.
            $key:ty => $value:ty
        ),* $(,)?
    ) => { ... };
}
Expand description

Define all table types.

§Purpose

This macro allows you to define all database tables in one place.

A by-product of this macro is that it defines some convenient traits specific to your tables (see Output).

§Inputs

This macro expects a list of tables, and their key/value types.

This syntax is as follows:

cuprate_database::define_tables! {
    /// Any extra attributes you'd like to add to
    /// this table type, e.g. docs or derives.

    0 => TableName,
//  ▲    ▲
//  │    └─ Table struct name. The macro generates this for you.
//  │
// Incrementing index. This must start at 0
// and increment by 1 per table added.

    u8 => u64,
//  ▲    ▲
//  │    └─ Table value type.
//  │
// Table key type.

   // Another table.
   1 => TableName2,
   i8 => i64,
}

An example:

use cuprate_database::{
    ConcreteEnv, Table,
    config::ConfigBuilder,
    Env, EnvInner,
    DatabaseRo, DatabaseRw, TxRo, TxRw,
};

// This generates `pub struct Table{1,2,3}`
// where all those implement `Table` with
// the defined name and key/value types.
//
// It also generate traits specific to our tables.
cuprate_database::define_tables! {
    0 => Table1,
    u32 => i32,

    /// This one has extra docs.
    1 => Table2,
    u64 => (),

    2 => Table3,
    i32 => i32,
}

// Open the database.
let env = ConcreteEnv::open(config)?;
let env_inner = env.env_inner();

// Open the table we just defined.
{
    let tx_rw = env_inner.tx_rw()?;
    env_inner.create_db::<Table1>(&tx_rw)?;
    let mut table = env_inner.open_db_rw::<Table1>(&tx_rw)?;

    // Write data to the table.
    table.put(&0, &1)?;

    drop(table);
    TxRw::commit(tx_rw)?;
}

// Read the data, assert it is correct.
{
    let tx_ro = env_inner.tx_ro()?;
    let table = env_inner.open_db_ro::<Table1>(&tx_ro)?;
    assert_eq!(table.first()?, (0, 1));
}

// Create all tables at once using the
// `OpenTables` trait generated with the
// macro above.
{
    let tx_rw = env_inner.tx_rw()?;
    env_inner.create_tables(&tx_rw)?;
    TxRw::commit(tx_rw)?;
}

// Open all tables at once.
{
    let tx_ro = env_inner.tx_ro()?;
    let all_tables = env_inner.open_tables(&tx_ro)?;
}

§Output

This macro:

  1. Implements Table on all your table types
  2. Creates a pub trait Tables trait (in scope)
  3. Creates a pub trait TablesIter trait (in scope)
  4. Creates a pub trait TablesMut trait (in scope)
  5. Blanket implements a (tuples, containing, all, open, database, tables, ...) for the above traits
  6. Creates a pub trait OpenTables trait (in scope)

All table types are zero-sized structs that implement the Table trait.

Table structs are automatically CamelCase, and their static string names are automatically snake_case.

For why the table traits + blanket implementation on the tuple exists, see: https://github.com/Cuprate/cuprate/pull/102#pullrequestreview-1978348871.

The OpenTables trait lets you open all tables you’ve defined, at once.

§Example

For examples of usage & output, see cuprate_blockchain::tables.