use serde_json::{Value, json};
use crate::types::{SearchModifier, SearchParameter};
pub fn build_clause(param: &SearchParameter, value: &str) -> Option<Value> {
let name = ¶m.name;
if param.modifier == Some(SearchModifier::Identifier) {
return build_identifier_clause(name, value);
}
let mut must_conditions = vec![json!({ "term": { "search_params.reference.name": name } })];
if value.contains('/') {
must_conditions.push(json!({ "term": { "search_params.reference.reference": value } }));
} else {
must_conditions.push(json!({
"bool": {
"should": [
{ "term": { "search_params.reference.resource_id": value } },
{ "term": { "search_params.reference.reference": value } }
],
"minimum_should_match": 1
}
}));
}
if let Some(SearchModifier::Type(type_name)) = ¶m.modifier {
must_conditions
.push(json!({ "term": { "search_params.reference.resource_type": type_name } }));
}
Some(json!({
"nested": {
"path": "search_params.reference",
"query": {
"bool": {
"must": must_conditions
}
}
}
}))
}
fn build_identifier_clause(name: &str, value: &str) -> Option<Value> {
let mut must_conditions = vec![json!({ "term": { "search_params.token.name": name } })];
if let Some((system, code)) = value.split_once('|') {
if !system.is_empty() {
must_conditions.push(json!({ "term": { "search_params.token.system": system } }));
}
must_conditions.push(json!({ "term": { "search_params.token.code": code } }));
} else {
must_conditions.push(json!({ "term": { "search_params.token.code": value } }));
}
Some(json!({
"nested": {
"path": "search_params.token",
"query": {
"bool": {
"must": must_conditions
}
}
}
}))
}
#[cfg(test)]
mod tests {
use super::*;
use crate::types::{SearchParamType, SearchValue};
fn make_param(name: &str, modifier: Option<SearchModifier>) -> SearchParameter {
SearchParameter {
name: name.to_string(),
param_type: SearchParamType::Reference,
modifier,
values: vec![SearchValue::eq("Patient/123")],
chain: vec![],
components: vec![],
}
}
#[test]
fn test_relative_reference() {
let param = make_param("subject", None);
let clause = build_clause(¶m, "Patient/123").unwrap();
let s = serde_json::to_string(&clause).unwrap();
assert!(s.contains("Patient/123"));
}
#[test]
fn test_id_only_reference() {
let param = make_param("subject", None);
let clause = build_clause(¶m, "123").unwrap();
let s = serde_json::to_string(&clause).unwrap();
assert!(s.contains("resource_id"));
}
}