helios_persistence/backends/sqlite/search/parameter_handlers/
reference.rs1use crate::types::{SearchModifier, SearchValue};
4
5use super::super::query_builder::{SqlFragment, SqlParam};
6
7pub struct ReferenceHandler;
9
10impl ReferenceHandler {
11 pub fn build_sql(
22 value: &SearchValue,
23 modifier: Option<&SearchModifier>,
24 param_offset: usize,
25 ) -> SqlFragment {
26 let param_num = param_offset + 1;
27 let ref_value = &value.value;
28
29 if matches!(modifier, Some(SearchModifier::Identifier)) {
31 return Self::build_identifier_condition(ref_value, param_num);
32 }
33
34 if let Some(SearchModifier::Type(type_name)) = modifier {
36 let expected_prefix = format!("{}/", type_name);
38
39 if ref_value.contains('/') {
40 SqlFragment::with_params(
42 format!("value_reference = ?{}", param_num),
43 vec![SqlParam::string(ref_value)],
44 )
45 } else {
46 SqlFragment::with_params(
48 format!("value_reference = ?{}", param_num),
49 vec![SqlParam::string(format!(
50 "{}{}",
51 expected_prefix, ref_value
52 ))],
53 )
54 }
55 } else {
56 Self::build_reference_condition(ref_value, param_num)
58 }
59 }
60
61 fn build_reference_condition(ref_value: &str, param_num: usize) -> SqlFragment {
63 if ref_value.contains('/') {
64 SqlFragment::with_params(
66 format!("value_reference = ?{}", param_num),
67 vec![SqlParam::string(ref_value)],
68 )
69 } else {
70 SqlFragment::with_params(
74 format!(
75 "(value_reference = ?{} OR value_reference LIKE '%/' || ?{})",
76 param_num,
77 param_num + 1
78 ),
79 vec![SqlParam::string(ref_value), SqlParam::string(ref_value)],
80 )
81 }
82 }
83
84 fn build_identifier_condition(identifier_value: &str, param_num: usize) -> SqlFragment {
89 if let Some(pipe_pos) = identifier_value.find('|') {
91 let system = &identifier_value[..pipe_pos];
92 let value = &identifier_value[pipe_pos + 1..];
93
94 if system.is_empty() {
95 SqlFragment::with_params(
97 format!(
98 "EXISTS (SELECT 1 FROM search_index si2 WHERE si2.resource_id = SUBSTR(value_reference, INSTR(value_reference, '/') + 1) AND si2.param_name = 'identifier' AND (si2.value_token_system IS NULL OR si2.value_token_system = '') AND si2.value_token_code = ?{})",
99 param_num
100 ),
101 vec![SqlParam::string(value)],
102 )
103 } else if value.is_empty() {
104 SqlFragment::with_params(
106 format!(
107 "EXISTS (SELECT 1 FROM search_index si2 WHERE si2.resource_id = SUBSTR(value_reference, INSTR(value_reference, '/') + 1) AND si2.param_name = 'identifier' AND si2.value_token_system = ?{})",
108 param_num
109 ),
110 vec![SqlParam::string(system)],
111 )
112 } else {
113 SqlFragment::with_params(
115 format!(
116 "EXISTS (SELECT 1 FROM search_index si2 WHERE si2.resource_id = SUBSTR(value_reference, INSTR(value_reference, '/') + 1) AND si2.param_name = 'identifier' AND si2.value_token_system = ?{} AND si2.value_token_code = ?{})",
117 param_num,
118 param_num + 1
119 ),
120 vec![SqlParam::string(system), SqlParam::string(value)],
121 )
122 }
123 } else {
124 SqlFragment::with_params(
126 format!(
127 "EXISTS (SELECT 1 FROM search_index si2 WHERE si2.resource_id = SUBSTR(value_reference, INSTR(value_reference, '/') + 1) AND si2.param_name = 'identifier' AND si2.value_token_code = ?{})",
128 param_num
129 ),
130 vec![SqlParam::string(identifier_value)],
131 )
132 }
133 }
134}
135
136#[cfg(test)]
137mod tests {
138 use super::*;
139 use crate::types::SearchPrefix;
140
141 #[test]
142 fn test_reference_with_type() {
143 let value = SearchValue::new(SearchPrefix::Eq, "Patient/123");
144 let frag = ReferenceHandler::build_sql(&value, None, 0);
145
146 assert!(frag.sql.contains("value_reference = ?1"));
147 assert_eq!(frag.params.len(), 1);
148 }
149
150 #[test]
151 fn test_reference_id_only() {
152 let value = SearchValue::new(SearchPrefix::Eq, "123");
153 let frag = ReferenceHandler::build_sql(&value, None, 0);
154
155 assert!(frag.sql.contains("OR"));
157 assert!(frag.sql.contains("LIKE"));
158 }
159
160 #[test]
161 fn test_reference_type_modifier() {
162 let value = SearchValue::new(SearchPrefix::Eq, "123");
163 let frag = ReferenceHandler::build_sql(
164 &value,
165 Some(&SearchModifier::Type("Patient".to_string())),
166 0,
167 );
168
169 assert!(frag.sql.contains("value_reference = ?1"));
170 }
172
173 #[test]
174 fn test_reference_identifier_modifier() {
175 let value = SearchValue::new(SearchPrefix::Eq, "http://example.org|12345");
176 let frag = ReferenceHandler::build_sql(&value, Some(&SearchModifier::Identifier), 0);
177
178 assert!(frag.sql.contains("EXISTS"));
179 assert!(frag.sql.contains("identifier"));
180 }
181}