sift_query_sqlx/renderer/
window.rs1use std::fmt::Write;
2
3use sift_query_core::{PagingMode, QueryPlan, QueryTarget, ScalarValue, SearchEntity};
4
5use super::{RenderState, render_filters, render_order, render_projection};
6use crate::{PgRenderer, RenderError, RenderedPgQuery};
7
8impl PgRenderer {
9 #[must_use]
10 pub fn supports_window_count<E: SearchEntity>(&self, plan: &QueryPlan<E>) -> bool {
11 !plan.distinct
12 && !plan.meta.is_grouped()
13 && !matches!(plan.paging.mode, PagingMode::Cursor(_))
14 && matches!(
15 plan.target,
16 QueryTarget::TypedPage | QueryTarget::MapPage | QueryTarget::StaticPage
17 )
18 && plan.paging.size > 0
19 }
20
21 pub fn render_window_list<E: SearchEntity>(
22 &self,
23 plan: &QueryPlan<E>,
24 ) -> Result<RenderedPgQuery, RenderError> {
25 if !self.supports_window_count(plan) {
26 return Err(RenderError::WrongTarget);
27 }
28 let mut state = RenderState::default();
29 let mut sql = format!(
30 "SELECT {}, count(*) OVER() AS \"sq_total_count\" FROM {}",
31 render_projection(plan, true)?,
32 plan.meta.from
33 );
34 render_filters(plan, &mut state, &mut sql, false)?;
35 render_order(plan, &mut state, &mut sql)?;
36 let limit = state.bind(ScalarValue::I64(i64::from(plan.paging.size)));
37 let offset = state.bind(ScalarValue::I64(
38 i64::try_from(plan.paging.offset)
39 .map_err(|_| RenderError::InvalidCondition("offset overflow".to_owned()))?,
40 ));
41 write!(sql, " LIMIT {limit} OFFSET {offset}").expect("writing to String cannot fail");
42 Ok(state.finish(sql, plan.shape_fingerprint_seed()))
43 }
44}