warg-server 0.10.0

A server library for Warg component registries.
Documentation
use super::schema::{checkpoints, contents, logs, records};
use chrono::{DateTime, Utc};
use diesel::{
    deserialize::{self, FromSql},
    pg::{Pg, PgValue},
    prelude::*,
    serialize::{self, IsNull, ToSql},
    sql_types, AsExpression, FromSqlRow, Insertable,
};
use diesel_json::Json;
use serde::Serialize;
use std::{fmt::Display, io::Write, str::FromStr};
use warg_crypto::{
    hash::AnyHash,
    signing::{KeyID, Signature},
};
use warg_protocol::registry::{LogId, RecordId};

#[derive(Debug, Copy, Clone, Eq, PartialEq, diesel_derive_enum::DbEnum)]
#[ExistingTypePath = "crate::datastore::postgres::schema::sql_types::RecordStatus"]
pub enum RecordStatus {
    Pending,
    Rejected,
    Validated,
}

#[derive(FromSqlRow, AsExpression, Debug)]
#[diesel(sql_type = sql_types::Text)]
pub struct Text<T>(pub T);

impl<T: From<String>> FromSql<sql_types::Text, Pg> for Text<T> {
    fn from_sql(bytes: PgValue) -> deserialize::Result<Self> {
        Ok(Self(T::from(String::from_sql(bytes)?)))
    }
}

#[derive(FromSqlRow, AsExpression, Debug)]
#[diesel(sql_type = sql_types::Text)]
pub struct ParsedText<T>(pub T);

impl<T: FromStr> FromSql<sql_types::Text, Pg> for ParsedText<T>
where
    <T as std::str::FromStr>::Err: std::error::Error + Send + Sync + 'static,
{
    fn from_sql(bytes: PgValue) -> deserialize::Result<Self> {
        Ok(Self(T::from_str(&String::from_sql(bytes)?)?))
    }
}

#[derive(FromSqlRow, AsExpression, Debug)]
#[diesel(sql_type = sql_types::Text)]
pub struct TextRef<'a, T>(pub &'a T);

impl<'a, T: std::fmt::Debug + Display> ToSql<sql_types::Text, Pg> for TextRef<'a, T> {
    fn to_sql<'b>(&'b self, out: &'b mut serialize::Output<Pg>) -> serialize::Result {
        write!(out, "{}", self.0)?;
        Ok(IsNull::No)
    }
}

#[derive(Insertable)]
#[diesel(table_name = logs)]
pub struct NewLog<'a, V>
where
    V: Serialize,
{
    pub log_id: TextRef<'a, LogId>,
    pub name: Option<&'a str>,
    pub validator: &'a Json<V>,
}

#[derive(Insertable)]
#[diesel(table_name = records)]
pub struct NewRecord<'a> {
    pub log_id: i32,
    pub record_id: TextRef<'a, RecordId>,
    pub content: &'a [u8],
}

#[derive(Insertable)]
#[diesel(table_name = checkpoints)]
pub struct NewCheckpoint<'a> {
    pub checkpoint_id: TextRef<'a, AnyHash>,
    pub log_root: TextRef<'a, AnyHash>,
    pub log_length: i64,
    pub map_root: TextRef<'a, AnyHash>,
    pub key_id: TextRef<'a, KeyID>,
    pub signature: TextRef<'a, Signature>,
    pub timestamp: i64,
}

#[derive(Queryable)]
#[diesel(table_name = checkpoints)]
#[allow(dead_code)]
pub struct CheckpointData {
    pub id: i32,
    pub checkpoint_id: ParsedText<AnyHash>,
    pub log_root: ParsedText<AnyHash>,
    pub log_length: i64,
    pub map_root: ParsedText<AnyHash>,
    pub key_id: Text<KeyID>,
    pub signature: ParsedText<Signature>,
    pub created_at: DateTime<Utc>,
    pub updated_at: DateTime<Utc>,
    pub timestamp: i64,
}

/// Selects only the record content and status
#[derive(Queryable, Selectable)]
#[diesel(table_name = records)]
pub struct RecordContent {
    pub status: RecordStatus,
    pub registry_log_index: Option<i64>,
    pub reason: Option<String>,
    pub content: Vec<u8>,
}

#[derive(Insertable)]
#[diesel(table_name = contents)]
pub struct NewContent<'a> {
    pub record_id: i32,
    pub digest: TextRef<'a, AnyHash>,
    pub missing: bool,
}