openmls_sqlite_storage 0.2.0

A storage provider for OpenMLS based on SQlite based on the rusqlite crate.
Documentation
use std::marker::PhantomData;

use openmls_traits::storage::{Entity, Key};
use rusqlite::{params, OptionalExtension};

use crate::{
    codec::Codec,
    storage_provider::StorableGroupIdRef,
    wrappers::{EntitySliceWrapper, EntityVecWrapper, KeyRefWrapper},
    STORAGE_PROVIDER_VERSION,
};

pub(crate) struct StorableEpochKeyPairs<EpochKeyPairs: Entity<STORAGE_PROVIDER_VERSION>>(
    pub Vec<EpochKeyPairs>,
);

impl<EpochKeyPairs: Entity<STORAGE_PROVIDER_VERSION>> StorableEpochKeyPairs<EpochKeyPairs> {
    fn from_row<C: Codec>(row: &rusqlite::Row) -> Result<Self, rusqlite::Error> {
        let EntityVecWrapper::<C, _>(key_pairs, ..) = row.get(0)?;
        Ok(Self(key_pairs))
    }

    pub(super) fn load<
        C: Codec,
        GroupId: Key<STORAGE_PROVIDER_VERSION>,
        EpochKey: Key<STORAGE_PROVIDER_VERSION>,
    >(
        connection: &rusqlite::Connection,
        group_id: &GroupId,
        epoch_id: &EpochKey,
        leaf_index: u32,
    ) -> Result<Vec<EpochKeyPairs>, rusqlite::Error> {
        let mut stmt = connection.prepare(
            "SELECT key_pairs
            FROM openmls_epoch_keys_pairs
            WHERE group_id = ?1
                AND epoch_id = ?2
                AND leaf_index = ?3
                AND provider_version = ?4",
        )?;
        let result = stmt
            .query_row(
                params![
                    KeyRefWrapper::<C, _>(group_id, PhantomData),
                    KeyRefWrapper::<C, _>(epoch_id, PhantomData),
                    leaf_index,
                    STORAGE_PROVIDER_VERSION
                ],
                |row| Self::from_row::<C>(row).map(|x| x.0),
            )
            .optional()?
            .unwrap_or_default();
        Ok(result)
    }
}

pub(super) struct StorableEpochKeyPairsRef<'a, EpochKeyPairs: Entity<STORAGE_PROVIDER_VERSION>>(
    pub &'a [EpochKeyPairs],
);

impl<EpochKeyPairs: Entity<STORAGE_PROVIDER_VERSION>> StorableEpochKeyPairsRef<'_, EpochKeyPairs> {
    pub(super) fn store<
        C: Codec,
        GroupId: Key<STORAGE_PROVIDER_VERSION>,
        EpochKey: Key<STORAGE_PROVIDER_VERSION>,
    >(
        &self,
        connection: &rusqlite::Connection,
        group_id: &GroupId,
        epoch_id: &EpochKey,
        leaf_index: u32,
    ) -> Result<(), rusqlite::Error> {
        connection.execute(
            "INSERT OR REPLACE INTO openmls_epoch_keys_pairs (group_id, epoch_id, leaf_index, key_pairs, provider_version)
                VALUES (?1, ?2, ?3, ?4, ?5)",
            params![
                KeyRefWrapper::<C, _>(group_id, PhantomData),
                KeyRefWrapper::<C, _>(epoch_id, PhantomData),
                leaf_index,
                EntitySliceWrapper::<'_, C, _>(self.0, PhantomData),
                STORAGE_PROVIDER_VERSION
            ],
        )?;
        Ok(())
    }
}

impl<GroupId: Key<STORAGE_PROVIDER_VERSION>> StorableGroupIdRef<'_, GroupId> {
    pub(super) fn delete_epoch_key_pair<C: Codec, EpochKey: Key<STORAGE_PROVIDER_VERSION>>(
        &self,
        connection: &rusqlite::Connection,
        epoch_key: &EpochKey,
        leaf_index: u32,
    ) -> Result<(), rusqlite::Error> {
        connection.execute(
            "DELETE FROM openmls_epoch_keys_pairs
            WHERE group_id = ?1
                AND epoch_id = ?2
                AND leaf_index = ?3
                AND provider_version = ?4",
            params![
                KeyRefWrapper::<C, _>(self.0, PhantomData),
                KeyRefWrapper::<C, _>(epoch_key, PhantomData),
                leaf_index,
                STORAGE_PROVIDER_VERSION
            ],
        )?;
        Ok(())
    }
}