Skip to content

Commit

Permalink
feat(cat-gateway): Catalyst singed Documents indexing POST endpoint (
Browse files Browse the repository at this point in the history
…#1576)

* update query limits

* fix

* wip

* fix

* update test

* fix

* wip

* initial TryFrom<DocumentIndexQueryFilter> for DocsQueryFilter impl

* fix spelling

* fix

* wip

* wip

* fix

* add metadata field for query_filter

* wip

* wip

* wip

* fix

* fix

* add TODO comments

* fix typo

* update with the latest cat-signed-doc crate

* update hurl

* invalid redundant Errors doc section

---------

Co-authored-by: Steven Johnson <[email protected]>
  • Loading branch information
Mr-Leshiy and stevenj authored Jan 24, 2025
1 parent 6353090 commit 0c6d286
Show file tree
Hide file tree
Showing 18 changed files with 447 additions and 136 deletions.
2 changes: 1 addition & 1 deletion catalyst-gateway/bin/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ workspace = true
cardano-chain-follower = {version = "0.0.6", git = "https://github.com/input-output-hk/catalyst-libs.git", tag="v0.0.10" }
c509-certificate = { version = "0.0.3", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "v0.0.3" }
rbac-registration = { version = "0.0.2", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "v0.0.8" }
catalyst-signed-doc = { version = "0.0.1", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "r20250116-00" }
catalyst-signed-doc = { version = "0.0.1", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "r20250123-00" }


pallas = { version = "0.30.1", git = "https://github.com/input-output-hk/catalyst-pallas.git", rev = "9b5183c8b90b90fe2cc319d986e933e9518957b3" }
Expand Down
27 changes: 27 additions & 0 deletions catalyst-gateway/bin/src/db/event/common/eq_or_ranged_uuid.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//! `EqOrRangedUuid` query conditional stmt object.
/// Search either by a singe UUID, or a Range of UUIDs
#[derive(Clone, Debug, PartialEq)]
pub(crate) enum EqOrRangedUuid {
/// Search by the exact UUID
Eq(uuid::Uuid),
/// Search in this UUID's range
Range {
/// Minimum UUID to find (inclusive)
min: uuid::Uuid,
/// Maximum UUID to find (inclusive)
max: uuid::Uuid,
},
}

impl EqOrRangedUuid {
/// Return a sql conditional statement by the provided `table_field`
pub(crate) fn conditional_stmt(&self, table_field: &str) -> String {
match self {
Self::Eq(id) => format!("{table_field} = '{id}'"),
Self::Range { min, max } => {
format!("{table_field} >= '{min}' AND {table_field} <= '{max}'")
},
}
}
}
1 change: 1 addition & 0 deletions catalyst-gateway/bin/src/db/event/common/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//! Reusable common database objects
pub(crate) mod eq_or_ranged_uuid;
pub(crate) mod query_limits;
32 changes: 19 additions & 13 deletions catalyst-gateway/bin/src/db/event/common/query_limits.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
//! `QueryLimits` query argument object.
#![allow(dead_code)]

use std::fmt::Display;

use crate::service::common::types::generic::query::pagination::{Limit, Page};
Expand Down Expand Up @@ -33,27 +31,35 @@ impl Display for QueryLimits {

impl QueryLimits {
/// Create a `QueryLimits` object without the any limits.
#[allow(dead_code)]
pub(crate) const ALL: QueryLimits = Self(QueryLimitsInner::All);
/// Create a `QueryLimits` object with the limit equals to `1`.
#[allow(dead_code)]
pub(crate) const ONE: QueryLimits = Self(QueryLimitsInner::Limit(1));

/// Create a `QueryLimits` object from the service `Limit` and `Page` values.
///
/// # Errors
/// - Invalid `limit` value, must be more than `0`.
/// - Invalid arguments, `limit` must be provided when `page` is not None.
pub(crate) fn new(limit: Option<Limit>, page: Option<Page>) -> anyhow::Result<Self> {
pub(crate) fn new(limit: Option<Limit>, page: Option<Page>) -> Self {
match (limit, page) {
(Some(limit), Some(page)) => {
Ok(Self(QueryLimitsInner::LimitAndOffset(
Self(QueryLimitsInner::LimitAndOffset(limit.into(), page.into()))
},
(Some(limit), None) => {
Self(QueryLimitsInner::LimitAndOffset(
limit.into(),
Page::default().into(),
))
},
(None, Some(page)) => {
Self(QueryLimitsInner::LimitAndOffset(
Limit::default().into(),
page.into(),
)))
))
},
(Some(limit), None) => Ok(Self(QueryLimitsInner::Limit(limit.into()))),
(None, None) => Ok(Self(QueryLimitsInner::All)),
(None, Some(_)) => {
anyhow::bail!("Invalid arguments, `limit` must be provided when `page` is not None")
(None, None) => {
Self(QueryLimitsInner::LimitAndOffset(
Limit::default().into(),
Page::default().into(),
))
},
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@ impl FullSignedDoc {
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 {
Expand Down
99 changes: 79 additions & 20 deletions catalyst-gateway/bin/src/db/event/signed_docs/query_filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,90 @@
use std::fmt::Display;

use crate::db::event::common::eq_or_ranged_uuid::EqOrRangedUuid;

/// A `select_signed_docs` query filtering argument.
#[allow(dead_code)]
pub(crate) enum DocsQueryFilter {
/// All entries
All,
/// Select docs with the specific `type` field
DocType(uuid::Uuid),
/// Select docs with the specific `id` field
DocId(uuid::Uuid),
/// Select docs with the specific `id` and `ver` field
DocVer(uuid::Uuid, uuid::Uuid),
/// Select docs with the specific `authors` field
Author(String),
/// If all fields would be `None` the query will search for all entries from the db.
#[derive(Clone, Debug)]
pub(crate) struct DocsQueryFilter {
/// `type` field
doc_type: Option<uuid::Uuid>,
/// `id` field
id: Option<EqOrRangedUuid>,
/// `ver` field
ver: Option<EqOrRangedUuid>,
/// `metadata` field
metadata: Option<serde_json::Value>,
}

impl Display for DocsQueryFilter {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::All => write!(f, "TRUE"),
Self::DocType(doc_type) => write!(f, "signed_docs.type = '{doc_type}'"),
Self::DocId(id) => write!(f, "signed_docs.id = '{id}'"),
Self::DocVer(id, ver) => {
write!(f, "signed_docs.id = '{id}' AND signed_docs.ver = '{ver}'")
},
Self::Author(author) => write!(f, "signed_docs.authors @> '{{ \"{author}\" }}'"),
use std::fmt::Write;
let mut query = "TRUE".to_string();

if let Some(doc_type) = &self.doc_type {
write!(&mut query, " AND signed_docs.type = '{doc_type}'")?;
}

if let Some(id) = &self.id {
write!(&mut query, " AND {}", id.conditional_stmt("signed_docs.id"))?;
}
if let Some(ver) = &self.ver {
write!(
&mut query,
" AND {}",
ver.conditional_stmt("signed_docs.ver")
)?;
}
if let Some(metadata) = &self.metadata {
write!(&mut query, " AND signed_docs.metadata @> '{metadata}'",)?;
}

write!(f, "{query}")
}
}

impl DocsQueryFilter {
/// Creates an empty filter stmt, so the query will retrieve all entries from the db.
pub fn all() -> Self {
DocsQueryFilter {
doc_type: None,
id: None,
ver: None,
metadata: None,
}
}

/// Set the `type` field filter condition
pub fn with_type(self, doc_type: uuid::Uuid) -> Self {
DocsQueryFilter {
doc_type: Some(doc_type),
..self
}
}

/// Set the `id` field filter condition
pub fn with_id(self, id: EqOrRangedUuid) -> Self {
DocsQueryFilter {
id: Some(id),
..self
}
}

/// Set the `ver` field filter condition
pub fn with_ver(self, ver: EqOrRangedUuid) -> Self {
DocsQueryFilter {
ver: Some(ver),
..self
}
}

/// Set the `metadata` field filter condition
#[allow(dead_code)]
pub fn with_metadata(self, metadata: serde_json::Value) -> Self {
DocsQueryFilter {
metadata: Some(metadata),
..self
}
}
}
10 changes: 10 additions & 0 deletions catalyst-gateway/bin/src/db/event/signed_docs/signed_doc_body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,21 @@ impl SignedDocBody {
&self.ver
}

/// Returns the document type.
pub(crate) fn doc_type(&self) -> &uuid::Uuid {
&self.doc_type
}

/// Returns the document authors.
pub(crate) fn authors(&self) -> &Vec<String> {
&self.authors
}

/// Returns the document metadata.
pub(crate) fn metadata(&self) -> Option<&serde_json::Value> {
self.metadata.as_ref()
}

/// Returns all signed document fields for the event db queries
pub(crate) fn postgres_db_fields(&self) -> [&(dyn tokio_postgres::types::ToSql + Sync); 5] {
[
Expand Down
Loading

0 comments on commit 0c6d286

Please sign in to comment.