Skip to content

Commit 39260cb

Browse files
committed
modify SQL queries
1 parent a466291 commit 39260cb

File tree

9 files changed

+171
-112
lines changed

9 files changed

+171
-112
lines changed
Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,28 @@
11
//! Reusable common database objects
22
3-
pub(crate) mod eq_or_ranged_uuid;
43
pub(crate) mod query_limits;
4+
pub(crate) mod uuid_list;
5+
pub(crate) mod uuid_selector;
6+
7+
/// SQL conditional statement trait
8+
pub(crate) trait ConditionalStmt {
9+
/// Return a sql conditional statement by the provided `table_field`
10+
fn conditional_stmt(
11+
&self,
12+
f: &mut std::fmt::Formatter<'_>,
13+
table_field: &str,
14+
) -> std::fmt::Result;
15+
}
16+
17+
impl<T: ConditionalStmt> ConditionalStmt for Option<T> {
18+
fn conditional_stmt(
19+
&self,
20+
f: &mut std::fmt::Formatter<'_>,
21+
table_field: &str,
22+
) -> std::fmt::Result {
23+
if let Some(v) = self {
24+
v.conditional_stmt(f, table_field)?;
25+
}
26+
Ok(())
27+
}
28+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
//! `UuidList` query conditional stmt object.
2+
3+
use std::ops::Deref;
4+
5+
use itertools::Itertools;
6+
7+
use crate::db::event::common::ConditionalStmt;
8+
9+
/// Search by a list of UUIDs.
10+
#[derive(Clone, Debug, PartialEq, Default)]
11+
pub(crate) struct UuidList(Vec<uuid::Uuid>);
12+
13+
impl Deref for UuidList {
14+
type Target = Vec<uuid::Uuid>;
15+
16+
fn deref(&self) -> &Self::Target {
17+
&self.0
18+
}
19+
}
20+
21+
impl From<Vec<uuid::Uuid>> for UuidList {
22+
fn from(value: Vec<uuid::Uuid>) -> Self {
23+
Self(value)
24+
}
25+
}
26+
27+
impl ConditionalStmt for UuidList {
28+
fn conditional_stmt(
29+
&self,
30+
f: &mut std::fmt::Formatter<'_>,
31+
table_field: &str,
32+
) -> std::fmt::Result {
33+
write!(
34+
f,
35+
"{table_field} IN ({})",
36+
self.0.iter().map(|uuid| format!("'{uuid}'")).join(",")
37+
)
38+
}
39+
}
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
//! `EqOrRangedUuid` query conditional stmt object.
22
3+
use crate::db::event::common::{ConditionalStmt, uuid_list::UuidList};
4+
35
/// Search either by a singe UUID, a range of UUIDs or a list of UUIDs.
46
#[derive(Clone, Debug, PartialEq)]
57
pub(crate) enum UuidSelector {
@@ -13,27 +15,21 @@ pub(crate) enum UuidSelector {
1315
max: uuid::Uuid,
1416
},
1517
/// Search UUIDs in the given list.
16-
In(Vec<uuid::Uuid>),
18+
In(UuidList),
1719
}
1820

19-
impl UuidSelector {
20-
/// Return a sql conditional statement by the provided `table_field`
21-
pub(crate) fn conditional_stmt(
21+
impl ConditionalStmt for UuidSelector {
22+
fn conditional_stmt(
2223
&self,
24+
f: &mut std::fmt::Formatter<'_>,
2325
table_field: &str,
24-
) -> String {
26+
) -> std::fmt::Result {
2527
match self {
26-
Self::Eq(id) => format!("{table_field} = '{id}'"),
28+
Self::Eq(id) => write!(f, "{table_field} = '{id}'"),
2729
Self::Range { min, max } => {
28-
format!("{table_field} >= '{min}' AND {table_field} <= '{max}'")
29-
},
30-
Self::In(ids) => {
31-
itertools::intersperse(
32-
ids.iter().map(|id| format!("{table_field} = '{id}'")),
33-
" OR ".to_string(),
34-
)
35-
.collect()
30+
write!(f, "{table_field} >= '{min}' AND {table_field} <= '{max}'")
3631
},
32+
Self::In(ids) => ids.conditional_stmt(f, table_field),
3733
}
3834
}
3935
}
Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
//! Document Reference filtering object.
22
3-
use std::fmt::Write;
4-
5-
use crate::db::event::common::eq_or_ranged_uuid::UuidSelector;
3+
use crate::db::event::common::{ConditionalStmt, uuid_selector::UuidSelector};
64

75
/// Document Reference filtering struct.
86
#[derive(Clone, Debug)]
@@ -13,30 +11,26 @@ pub(crate) struct DocumentRef {
1311
pub(crate) ver: Option<UuidSelector>,
1412
}
1513

16-
impl DocumentRef {
17-
/// Return a sql conditional statement by the provided `table_field`
18-
pub(crate) fn conditional_stmt(
14+
impl ConditionalStmt for DocumentRef {
15+
fn conditional_stmt(
1916
&self,
17+
f: &mut std::fmt::Formatter<'_>,
2018
table_field: &str,
21-
) -> String {
22-
let mut stmt = "TRUE".to_string();
19+
) -> std::fmt::Result {
20+
write!(
21+
f,
22+
"EXISTS (SELECT 1 FROM JSONB_ARRAY_ELEMENTS({table_field}) AS doc_ref WHERE TRUE"
23+
)?;
24+
2325
if let Some(id) = &self.id {
24-
let _ = write!(
25-
stmt,
26-
" AND {}",
27-
id.conditional_stmt("(doc_ref->>'id')::uuid")
28-
);
26+
write!(f, " AND ")?;
27+
id.conditional_stmt(f, "(doc_ref->>'id')::uuid")?;
2928
}
3029
if let Some(ver) = &self.ver {
31-
let _ = write!(
32-
stmt,
33-
" AND {}",
34-
ver.conditional_stmt("(doc_ref->>'ver')::uuid")
35-
);
30+
write!(f, " AND ")?;
31+
ver.conditional_stmt(f, "(doc_ref->>'id')::uuid")?;
3632
}
3733

38-
format!(
39-
"EXISTS (SELECT 1 FROM JSONB_ARRAY_ELEMENTS({table_field}) AS doc_ref WHERE {stmt})"
40-
)
34+
write!(f, ")")
4135
}
4236
}

catalyst-gateway/bin/src/db/event/signed_docs/query_filter.rs

Lines changed: 70 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -3,78 +3,78 @@
33
use std::fmt::Display;
44

55
use super::DocumentRef;
6-
use crate::db::event::common::eq_or_ranged_uuid::UuidSelector;
6+
use crate::db::event::common::{ConditionalStmt, uuid_list::UuidList, uuid_selector::UuidSelector};
77

88
/// A `select_signed_docs` query filtering argument.
99
/// If all fields would be `None` the query will search for all entries from the db.
1010
#[derive(Clone, Debug, Default)]
1111
pub(crate) struct DocsQueryFilter {
1212
/// `type` field. Empty list if unspecified.
13-
doc_type: Vec<uuid::Uuid>,
13+
doc_type: UuidList,
1414
/// `id` field. `None` if unspecified.
1515
id: Option<UuidSelector>,
1616
/// `ver` field. `None` if unspecified.
1717
ver: Option<UuidSelector>,
18-
/// `metadata->'ref'` field. Empty list if unspecified.
19-
doc_ref: Vec<DocumentRef>,
20-
/// `metadata->'template'` field. Empty list if unspecified.
21-
template: Vec<DocumentRef>,
22-
/// `metadata->'reply'` field. Empty list if unspecified.
23-
reply: Vec<DocumentRef>,
24-
/// `metadata->'parameters'` field. Empty list if unspecified.
25-
parameters: Vec<DocumentRef>,
18+
/// `metadata->'ref'` field.
19+
doc_ref: Option<DocumentRef>,
20+
/// `metadata->'template'` field.
21+
template: Option<DocumentRef>,
22+
/// `metadata->'reply'` field.
23+
reply: Option<DocumentRef>,
24+
/// `metadata->'parameters'` field.
25+
parameters: Option<DocumentRef>,
2626
}
2727

2828
impl Display for DocsQueryFilter {
2929
fn fmt(
3030
&self,
3131
f: &mut std::fmt::Formatter<'_>,
3232
) -> std::fmt::Result {
33-
use std::fmt::Write;
34-
let mut query = "TRUE".to_string();
35-
36-
if !self.doc_type.is_empty() {
37-
write!(
38-
&mut query,
39-
" AND signed_docs.type IN ({})",
40-
self.doc_type
41-
.iter()
42-
.map(|uuid| format!("'{uuid}'"))
43-
.collect::<Vec<_>>()
44-
.join(",")
45-
)?;
46-
}
47-
48-
if let Some(id) = &self.id {
49-
write!(&mut query, " AND {}", id.conditional_stmt("signed_docs.id"))?;
50-
}
51-
if let Some(ver) = &self.ver {
52-
write!(
53-
&mut query,
54-
" AND {}",
55-
ver.conditional_stmt("signed_docs.ver")
56-
)?;
57-
}
58-
let doc_ref_queries = [
59-
("ref", &self.doc_ref),
60-
("template", &self.template),
61-
("reply", &self.reply),
62-
("parameters", &self.parameters),
33+
write!(f, "TRUE")?;
34+
35+
let stmts: [(_, Option<&dyn ConditionalStmt>); _] = [
36+
(
37+
"signed_docs.type",
38+
(!self.doc_type.is_empty()).then_some(&self.doc_type),
39+
),
40+
(
41+
"signed_docs.id",
42+
self.id.as_ref().map(|v| -> &dyn ConditionalStmt { v }),
43+
),
44+
(
45+
"signed_docs.ver",
46+
self.ver.as_ref().map(|v| -> &dyn ConditionalStmt { v }),
47+
),
48+
(
49+
"metadata->'ref'",
50+
self.doc_ref.as_ref().map(|v| -> &dyn ConditionalStmt { v }),
51+
),
52+
(
53+
"metadata->'template'",
54+
self.template
55+
.as_ref()
56+
.map(|v| -> &dyn ConditionalStmt { v }),
57+
),
58+
(
59+
"metadata->'reply'",
60+
self.reply.as_ref().map(|v| -> &dyn ConditionalStmt { v }),
61+
),
62+
(
63+
"metadata->'parameters'",
64+
self.parameters
65+
.as_ref()
66+
.map(|v| -> &dyn ConditionalStmt { v }),
67+
),
6368
];
6469

65-
for (field_name, doc_refs) in doc_ref_queries {
66-
if !doc_refs.is_empty() {
67-
let stmt = doc_refs
68-
.iter()
69-
.map(|doc_ref| doc_ref.conditional_stmt(&format!("metadata->'{field_name}'")))
70-
.collect::<Vec<_>>()
71-
.join(" OR ");
72-
73-
write!(&mut query, " AND ({stmt})")?;
70+
for (field_name, stmt) in stmts {
71+
if let Some(stmt) = stmt {
72+
write!(f, " AND ",)?;
73+
stmt.conditional_stmt(f, field_name)?;
7474
}
7575
}
7676

77-
write!(f, "{query}")
77+
Ok(())
7878
}
7979
}
8080

@@ -89,7 +89,10 @@ impl DocsQueryFilter {
8989
self,
9090
doc_type: Vec<uuid::Uuid>,
9191
) -> Self {
92-
DocsQueryFilter { doc_type, ..self }
92+
DocsQueryFilter {
93+
doc_type: doc_type.into(),
94+
..self
95+
}
9396
}
9497

9598
/// Set the `id` field filter condition
@@ -119,42 +122,42 @@ impl DocsQueryFilter {
119122
self,
120123
arg: DocumentRef,
121124
) -> Self {
122-
let mut doc_ref = self.doc_ref;
123-
doc_ref.push(arg);
124-
125-
DocsQueryFilter { doc_ref, ..self }
125+
DocsQueryFilter {
126+
doc_ref: Some(arg),
127+
..self
128+
}
126129
}
127130

128131
/// Set the `metadata->'template'` field filter condition
129132
pub fn with_template(
130133
self,
131134
arg: DocumentRef,
132135
) -> Self {
133-
let mut template = self.template;
134-
template.push(arg);
135-
136-
DocsQueryFilter { template, ..self }
136+
DocsQueryFilter {
137+
template: Some(arg),
138+
..self
139+
}
137140
}
138141

139142
/// Set the `metadata->'reply'` field filter condition
140143
pub fn with_reply(
141144
self,
142145
arg: DocumentRef,
143146
) -> Self {
144-
let mut reply = self.reply;
145-
reply.push(arg);
146-
147-
DocsQueryFilter { reply, ..self }
147+
DocsQueryFilter {
148+
reply: Some(arg),
149+
..self
150+
}
148151
}
149152

150153
/// Set the `metadata->'parameters'` field filter condition
151154
pub fn with_parameters(
152155
self,
153156
arg: DocumentRef,
154157
) -> Self {
155-
let mut parameters = self.parameters;
156-
parameters.push(arg);
157-
158-
DocsQueryFilter { parameters, ..self }
158+
DocsQueryFilter {
159+
parameters: Some(arg),
160+
..self
161+
}
159162
}
160163
}

catalyst-gateway/bin/src/db/event/signed_docs/tests/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use futures::TryStreamExt;
66

77
use super::*;
88
use crate::db::event::{
9-
common::{eq_or_ranged_uuid::UuidSelector, query_limits::QueryLimits},
9+
common::{query_limits::QueryLimits, uuid_selector::UuidSelector},
1010
establish_connection_pool,
1111
};
1212

catalyst-gateway/bin/src/service/api/documents/post_document_index_query/v2/request.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,12 +200,11 @@ impl TryFrom<DocumentIndexQueryFilterV2> for DocsQueryFilter {
200200
}
201201
if let Some(reply) = value.reply {
202202
db_filter = db_filter.with_reply(reply.try_into()?);
203-
204203
}
205204
if let Some(parameters) = value.parameters {
206205
db_filter = db_filter.with_parameters(parameters.try_into()?);
207206
}
208-
207+
209208
Ok(db_filter)
210209
}
211210
}

0 commit comments

Comments
 (0)