cat_gateway/db/event/signed_docs/full_signed_doc.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
//! `FullSignedDoc` struct implementation.
use super::SignedDocBody;
use crate::{
db::event::{EventDB, NotFoundError},
jinja::{get_template, JinjaTemplateSource},
};
/// Insert sql query
const INSERT_SIGNED_DOCS: &str = include_str!("./sql/insert_signed_documents.sql");
/// Select sql query jinja template
pub(crate) const SELECT_SIGNED_DOCS_TEMPLATE: JinjaTemplateSource = JinjaTemplateSource {
name: "select_signed_documents.jinja.template",
source: include_str!("./sql/select_signed_documents.sql.jinja"),
};
/// Full signed doc event db struct
#[derive(Debug, Clone, PartialEq)]
pub(crate) struct FullSignedDoc {
/// Signed doc body
body: SignedDocBody,
/// `signed_doc` table `payload` field
payload: Option<serde_json::Value>,
/// `signed_doc` table `raw` field
raw: Vec<u8>,
}
impl FullSignedDoc {
/// Creates a `FullSignedDoc` instance.
#[allow(dead_code)]
pub(crate) fn new(
body: SignedDocBody, payload: Option<serde_json::Value>, raw: Vec<u8>,
) -> Self {
Self { body, payload, raw }
}
/// Returns the document id.
pub(crate) fn id(&self) -> &uuid::Uuid {
self.body.id()
}
/// Returns the document version.
pub(crate) fn ver(&self) -> &uuid::Uuid {
self.body.ver()
}
/// Returns the document author.
#[allow(dead_code)]
pub(crate) fn authors(&self) -> &Vec<String> {
self.body.authors()
}
/// Returns the document metadata.
#[allow(dead_code)]
pub(crate) fn metadata(&self) -> Option<&serde_json::Value> {
self.body.metadata()
}
/// Returns the `SignedDocBody`.
#[allow(dead_code)]
pub(crate) fn body(&self) -> &SignedDocBody {
&self.body
}
/// Returns the document raw bytes.
#[allow(dead_code)]
pub(crate) fn raw(&self) -> &Vec<u8> {
&self.raw
}
/// Uploads a `FullSignedDoc` to the event db.
/// Returns `true` if document was added into the db, `false` if it was already added
/// previously.
///
/// Make an insert query into the `event-db` by adding data into the `signed_docs`
/// table.
///
/// * IF the record primary key (id,ver) does not exist, then add the new record.
/// Return success.
/// * IF the record does exist, but all values are the same as stored, return Success.
/// * Otherwise return an error. (Can not over-write an existing record with new
/// data).
///
/// # Arguments:
/// - `id` is a UUID v7
/// - `ver` is a UUID v7
/// - `doc_type` is a UUID v4
#[allow(dead_code)]
pub(crate) async fn store(&self) -> anyhow::Result<bool> {
match Self::retrieve(self.id(), Some(self.ver())).await {
Ok(res_doc) => {
anyhow::ensure!(
&res_doc == self,
"Document with the same `id` and `ver` already exists"
);
Ok(false)
},
Err(err) if err.is::<NotFoundError>() => {
EventDB::modify(INSERT_SIGNED_DOCS, &self.postgres_db_fields()).await?;
Ok(true)
},
Err(err) => Err(err),
}
}
/// Loads a `FullSignedDoc` from the event db.
///
/// Make a select query into the `event-db` by getting data from the `signed_docs`
/// table.
///
/// * This returns a single document. All data from the document is returned,
/// including the `payload` and `raw` fields.
/// * `ver` should be able to be optional, in which case get the latest ver of the
/// given `id`.
///
/// # Arguments:
/// - `id` is a UUID v7
/// - `ver` is a UUID v7
#[allow(dead_code)]
pub(crate) async fn retrieve(
id: &uuid::Uuid, ver: Option<&uuid::Uuid>,
) -> anyhow::Result<Self> {
let query_template = get_template(&SELECT_SIGNED_DOCS_TEMPLATE)?;
let query = query_template.render(serde_json::json!({
"id": id,
"ver": ver,
}))?;
let row = EventDB::query_one(&query, &[]).await?;
Self::from_row(id, ver, &row)
}
/// Returns all signed document fields for the event db queries
fn postgres_db_fields(&self) -> [&(dyn tokio_postgres::types::ToSql + Sync); 7] {
let body_fields = self.body.postgres_db_fields();
[
body_fields[0],
body_fields[1],
body_fields[2],
body_fields[3],
body_fields[4],
&self.payload,
&self.raw,
]
}
/// Creates a `FullSignedDoc` from postgresql row object.
fn from_row(
id: &uuid::Uuid, ver: Option<&uuid::Uuid>, row: &tokio_postgres::Row,
) -> anyhow::Result<Self> {
let ver = if let Some(ver) = ver {
*ver
} else {
row.try_get("ver")?
};
Ok(FullSignedDoc {
body: SignedDocBody::new(
*id,
ver,
row.try_get("type")?,
row.try_get("authors")?,
row.try_get("metadata")?,
),
payload: row.try_get("payload")?,
raw: row.try_get("raw")?,
})
}
}