Skip to content

Commit 4d61fef

Browse files
committed
sentry - db - channel - Get total count of the channels inside list_channels
- sentry - routes - list_channels - Fix bug with total pages
1 parent 7b6b26f commit 4d61fef

File tree

2 files changed

+52
-29
lines changed

2 files changed

+52
-29
lines changed

sentry/src/db/channel.rs

Lines changed: 42 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
use crate::db::DbPool;
22
use bb8::RunError;
3-
use bb8_postgres::tokio_postgres::types::{accepts, FromSql, ToSql, Type};
3+
use bb8_postgres::tokio_postgres::{
4+
types::{accepts, FromSql, Json, ToSql, Type},
5+
Row,
6+
};
47
use chrono::{DateTime, Utc};
58
use primitives::{Channel, ChannelId, ValidatorId};
9+
use serde::Deserialize;
610
use std::error::Error;
711
use std::str::FromStr;
812

9-
struct TotalPages(pub u64);
10-
impl<'a> FromSql<'a> for TotalPages {
13+
struct TotalCount(pub u64);
14+
impl<'a> FromSql<'a> for TotalCount {
1115
fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<Self, Box<dyn Error + Sync + Send>> {
1216
let str_slice = <&str as FromSql>::from_sql(ty, raw)?;
1317

@@ -83,26 +87,45 @@ pub async fn insert_channel(
8387
.await
8488
}
8589

90+
#[derive(Debug, Deserialize)]
91+
pub struct ListChannels {
92+
pub total_count: u64,
93+
pub channels: Vec<Channel>,
94+
}
95+
96+
impl From<&Row> for ListChannels {
97+
fn from(row: &Row) -> Self {
98+
let total_count = row.get::<_, TotalCount>(0).0;
99+
let channels = row.get::<_, Json<Vec<Channel>>>(1).0;
100+
101+
Self {
102+
channels,
103+
total_count,
104+
}
105+
}
106+
}
107+
86108
pub async fn list_channels(
87109
pool: &DbPool,
88110
skip: u64,
89111
limit: u32,
90112
creator: &Option<String>,
91113
validator: &Option<ValidatorId>,
92114
valid_until_ge: &DateTime<Utc>,
93-
) -> Result<Vec<Channel>, RunError<bb8_postgres::tokio_postgres::Error>> {
115+
) -> Result<ListChannels, RunError<bb8_postgres::tokio_postgres::Error>> {
94116
let validator = validator.as_ref().map(|validator_id| {
95117
serde_json::Value::from_str(&format!(r#"[{{"id": "{}"}}]"#, validator_id))
96118
.expect("Not a valid json")
97119
});
98120
let (where_clauses, params) =
99121
channel_list_query_params(creator, validator.as_ref(), valid_until_ge);
122+
let total_count_params = (where_clauses.clone(), params.clone());
100123

101-
pool
124+
let channels = pool
102125
.run(move |connection| {
103126
async move {
104127
// To understand why we use Order by, see Postgres Documentation: https://www.postgresql.org/docs/8.1/queries-limit.html
105-
let statement = format!("SELECT id, creator, deposit_asset, deposit_amount, valid_until, spec FROM channels WHERE {} ORDER BY id DESC LIMIT {} OFFSET {}", where_clauses.join(" AND "), limit, skip);
128+
let statement = format!("SELECT id, creator, deposit_asset, deposit_amount, valid_until, spec FROM channels WHERE {} ORDER BY spec->>'created' DESC LIMIT {} OFFSET {}", where_clauses.join(" AND "), limit, skip);
106129
match connection.prepare(&statement).await {
107130
Ok(stmt) => {
108131
match connection.query(&stmt, params.as_slice()).await {
@@ -118,22 +141,22 @@ pub async fn list_channels(
118141
}
119142
}
120143
})
121-
.await
144+
.await?;
145+
146+
Ok(ListChannels {
147+
total_count: list_channels_total_count(
148+
&pool,
149+
(&total_count_params.0, total_count_params.1),
150+
)
151+
.await?,
152+
channels,
153+
})
122154
}
123155

124-
pub async fn list_channels_total_pages(
156+
async fn list_channels_total_count<'a>(
125157
pool: &DbPool,
126-
creator: &Option<String>,
127-
validator: &Option<ValidatorId>,
128-
valid_until_ge: &DateTime<Utc>,
158+
(where_clauses, params): (&'a [String], Vec<&'a (dyn ToSql + Sync)>),
129159
) -> Result<u64, RunError<bb8_postgres::tokio_postgres::Error>> {
130-
let validator = validator.as_ref().map(|validator_id| {
131-
serde_json::Value::from_str(&format!(r#"[{{"id": "{}"}}]"#, validator_id))
132-
.expect("Not a valid json")
133-
});
134-
let (where_clauses, params) =
135-
channel_list_query_params(creator, validator.as_ref(), valid_until_ge);
136-
137160
pool.run(move |connection| {
138161
async move {
139162
let statement = format!(
@@ -142,7 +165,7 @@ pub async fn list_channels_total_pages(
142165
);
143166
match connection.prepare(&statement).await {
144167
Ok(stmt) => match connection.query_one(&stmt, params.as_slice()).await {
145-
Ok(row) => Ok((row.get::<_, TotalPages>(0).0, connection)),
168+
Ok(row) => Ok((row.get::<_, TotalCount>(0).0, connection)),
146169
Err(e) => Err((e, connection)),
147170
},
148171
Err(e) => Err((e, connection)),

sentry/src/routes/channel.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use self::channel_list::ChannelListQuery;
2-
use crate::db::{get_channel_by_id, insert_channel, list_channels, list_channels_total_pages};
2+
use crate::db::{get_channel_by_id, insert_channel, list_channels};
33
use crate::routes::channel::channel_list::ChannelListResponse;
44
use crate::success_response;
55
use crate::Application;
@@ -73,7 +73,7 @@ pub async fn channel_list<A: Adapter>(
7373
.checked_mul(app.config.channels_find_limit.into())
7474
.ok_or_else(|| ResponseError::BadRequest("Page and/or limit is too large".into()))?;
7575

76-
let channels = list_channels(
76+
let list_channels = list_channels(
7777
&app.pool,
7878
skip,
7979
app.config.channels_find_limit,
@@ -82,16 +82,16 @@ pub async fn channel_list<A: Adapter>(
8282
&query.valid_until_ge,
8383
)
8484
.await?;
85-
let total_pages = list_channels_total_pages(
86-
&app.pool,
87-
&query.creator,
88-
&query.validator,
89-
&query.valid_until_ge,
90-
)
91-
.await?;
85+
86+
// fast ceil for total_pages
87+
let total_pages = if list_channels.total_count == 0 {
88+
1
89+
} else {
90+
1 + ((list_channels.total_count - 1) / app.config.channels_find_limit as u64)
91+
};
9292

9393
let list_response = ChannelListResponse {
94-
channels,
94+
channels: list_channels.channels,
9595
total_pages,
9696
};
9797

0 commit comments

Comments
 (0)