Skip to content

Commit 2815750

Browse files
authored
Merge pull request #7941 from eth3lbert/count-subq
Improve crates endpoint performance
2 parents f4ef9a7 + 81c6424 commit 2815750

File tree

3 files changed

+326
-160
lines changed

3 files changed

+326
-160
lines changed

src/controllers/helpers/pagination.rs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,18 @@ pub(crate) trait Paginate: Sized {
146146
options,
147147
}
148148
}
149+
150+
fn pages_pagination_with_count_query<C>(
151+
self,
152+
options: PaginationOptions,
153+
count_query: C,
154+
) -> PaginatedQueryWithCountSubq<Self, C> {
155+
PaginatedQueryWithCountSubq {
156+
query: self,
157+
count_query,
158+
options,
159+
}
160+
}
149161
}
150162

151163
impl<T> Paginate for T {}
@@ -303,6 +315,61 @@ pub(crate) fn decode_seek<D: for<'a> Deserialize<'a>>(seek: &str) -> anyhow::Res
303315
Ok(decoded)
304316
}
305317

318+
#[derive(Debug)]
319+
pub(crate) struct PaginatedQueryWithCountSubq<T, C> {
320+
query: T,
321+
count_query: C,
322+
options: PaginationOptions,
323+
}
324+
325+
impl<T, C> QueryId for PaginatedQueryWithCountSubq<T, C> {
326+
const HAS_STATIC_QUERY_ID: bool = false;
327+
type QueryId = ();
328+
}
329+
330+
impl<
331+
T: Query,
332+
C: Query + QueryDsl + diesel::query_dsl::methods::SelectDsl<diesel::dsl::CountStar>,
333+
> Query for PaginatedQueryWithCountSubq<T, C>
334+
{
335+
type SqlType = (T::SqlType, BigInt);
336+
}
337+
338+
impl<T, C, DB> RunQueryDsl<DB> for PaginatedQueryWithCountSubq<T, C> {}
339+
340+
impl<T, C> QueryFragment<Pg> for PaginatedQueryWithCountSubq<T, C>
341+
where
342+
T: QueryFragment<Pg>,
343+
C: QueryFragment<Pg>,
344+
{
345+
fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, Pg>) -> QueryResult<()> {
346+
out.push_sql("SELECT *, (");
347+
self.count_query.walk_ast(out.reborrow())?;
348+
out.push_sql(") FROM (");
349+
self.query.walk_ast(out.reborrow())?;
350+
out.push_sql(") t LIMIT ");
351+
out.push_bind_param::<BigInt, _>(&self.options.per_page)?;
352+
if let Some(offset) = self.options.offset() {
353+
out.push_sql(format!(" OFFSET {offset}").as_str());
354+
}
355+
Ok(())
356+
}
357+
}
358+
359+
impl<T, C> PaginatedQueryWithCountSubq<T, C> {
360+
pub(crate) fn load<'a, U>(self, conn: &mut PgConnection) -> QueryResult<Paginated<U>>
361+
where
362+
Self: LoadQuery<'a, PgConnection, WithCount<U>>,
363+
{
364+
let options = self.options.clone();
365+
let records_and_total = self.internal_load(conn)?.collect::<QueryResult<_>>()?;
366+
Ok(Paginated {
367+
records_and_total,
368+
options,
369+
})
370+
}
371+
}
372+
306373
#[cfg(test)]
307374
mod tests {
308375
use super::*;

0 commit comments

Comments
 (0)