Skip to main content

sift_query_core/query/
sql.rs

1use super::predicate::CustomOperator;
2use crate::{ConfigError, ValueType};
3
4/// A server-owned SQL extension declaration. The SQL template remains in the
5/// binary and only bound values can come from a request.
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub struct ServerSqlExtension {
8    pub operator: CustomOperator,
9    pub input_type: ValueType,
10    pub fields: &'static [&'static str],
11}
12
13/// Bounded registry used by an HTTP/service boundary. Registration is a
14/// startup operation; lookup accepts only a name that was registered by the
15/// server and never parses SQL supplied by a caller.
16#[derive(Debug, Clone)]
17pub struct ServerSqlRegistry {
18    extensions: Vec<ServerSqlExtension>,
19    max_extensions: usize,
20}
21
22impl Default for ServerSqlRegistry {
23    fn default() -> Self {
24        Self {
25            extensions: Vec::new(),
26            max_extensions: 64,
27        }
28    }
29}
30
31impl ServerSqlRegistry {
32    pub fn with_limit(max_extensions: usize) -> Result<Self, ConfigError> {
33        if max_extensions == 0 || max_extensions > 256 {
34            return Err(ConfigError::Invalid(
35                "server SQL registry limit must be between 1 and 256".to_owned(),
36            ));
37        }
38        Ok(Self {
39            extensions: Vec::new(),
40            max_extensions,
41        })
42    }
43
44    pub fn register(&mut self, extension: ServerSqlExtension) -> Result<(), ConfigError> {
45        extension.validate()?;
46        if self.extensions.len() >= self.max_extensions {
47            return Err(ConfigError::Invalid(
48                "server SQL extension registry limit exceeded".to_owned(),
49            ));
50        }
51        if self
52            .extensions
53            .iter()
54            .any(|item| item.operator.name() == extension.operator.name())
55        {
56            return Err(ConfigError::Invalid(
57                "duplicate server SQL extension name".to_owned(),
58            ));
59        }
60        self.extensions.push(extension);
61        Ok(())
62    }
63
64    #[must_use]
65    pub fn get(&self, name: &str) -> Option<ServerSqlExtension> {
66        self.extensions
67            .iter()
68            .find(|item| item.operator.name() == name)
69            .copied()
70    }
71
72    pub fn iter(&self) -> impl Iterator<Item = &ServerSqlExtension> {
73        self.extensions.iter()
74    }
75}
76
77impl ServerSqlExtension {
78    pub fn new(
79        operator: CustomOperator,
80        input_type: ValueType,
81        fields: &'static [&'static str],
82    ) -> Result<Self, ConfigError> {
83        let extension = Self {
84            operator,
85            input_type,
86            fields,
87        };
88        extension.validate()?;
89        Ok(extension)
90    }
91
92    fn validate(&self) -> Result<(), ConfigError> {
93        if self.fields.is_empty() || self.fields.len() > 256 {
94            return Err(ConfigError::Invalid(
95                "server SQL extension requires 1..=256 fields".to_owned(),
96            ));
97        }
98        if self
99            .operator
100            .types()
101            .is_some_and(|(_, input)| input != self.input_type)
102        {
103            return Err(ConfigError::Invalid(
104                "server SQL extension input type differs from operator".to_owned(),
105            ));
106        }
107        if self.fields.windows(2).any(|pair| pair[0] >= pair[1]) {
108            return Err(ConfigError::Invalid(
109                "server SQL extension fields must be sorted and unique".to_owned(),
110            ));
111        }
112        if self
113            .fields
114            .iter()
115            .any(|field| !crate::policy::names::is_name(field))
116        {
117            return Err(ConfigError::Invalid(
118                "server SQL extension fields must be valid public names".to_owned(),
119            ));
120        }
121        Ok(())
122    }
123}