Skip to main content

sift_query_sqlx/renderer/
window.rs

1use 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}