Skip to main content

qualia_core_db/sparql_library/
range_select_apply.rs

1//! Shared Project / Filter / Limit application for range SPARQL pages.
2
3use super::sparql_ast::{BindingRow, ExpressionId, SparqlQueryContext, VariableId, MAX_VARIABLES};
4use super::sparql_filter::{EvalResult, ExpressionEvaluator};
5
6#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
7pub struct SelectWrapperState {
8    pub skipped: u64,
9    pub emitted: u64,
10}
11
12#[derive(Clone, Copy, Debug, Eq, PartialEq)]
13pub struct SelectApplyPage {
14    pub returned: usize,
15    pub limit_reached: bool,
16}
17
18pub fn apply_select_wrappers(
19    ctx: &SparqlQueryContext,
20    filters: &[ExpressionId],
21    filter_count: u8,
22    projection: [VariableId; MAX_VARIABLES],
23    projection_count: u8,
24    limit: u64,
25    offset: u64,
26    state: &mut SelectWrapperState,
27    input: &[BindingRow],
28    out: &mut [BindingRow],
29) -> Result<SelectApplyPage, String> {
30    let mut returned = 0usize;
31    for row in input {
32        let mut accepted = true;
33        for filter in filters.iter().take(filter_count as usize) {
34            if !matches!(
35                ExpressionEvaluator::evaluate(*filter, ctx, row),
36                Ok(EvalResult::Boolean(true))
37            ) {
38                accepted = false;
39                break;
40            }
41        }
42        if !accepted {
43            continue;
44        }
45        if state.skipped < offset {
46            state.skipped += 1;
47            continue;
48        }
49        if state.emitted >= limit {
50            return Ok(SelectApplyPage {
51                returned,
52                limit_reached: true,
53            });
54        }
55        let mut projected = *row;
56        if projection_count != 0 {
57            let mut next = BindingRow::default();
58            for variable in projection.iter().take(projection_count as usize) {
59                if let Some(value) = projected.get(*variable) {
60                    next.set(*variable, value);
61                }
62            }
63            projected = next;
64        }
65        if returned == out.len() {
66            return Ok(SelectApplyPage {
67                returned,
68                limit_reached: false,
69            });
70        }
71        out[returned] = projected;
72        returned += 1;
73        state.emitted += 1;
74    }
75    Ok(SelectApplyPage {
76        returned,
77        limit_reached: state.emitted >= limit,
78    })
79}