serde_json_path/parser/selector/function/
registry.rs

1use std::{collections::HashMap, sync::LazyLock};
2
3use serde_json::Value;
4use serde_json_path_core::spec::functions::{Function, LogicalType, NodesType, ValueType};
5
6/// The main registry of functions for use in JSONPath queries
7///
8/// These come directly from the JSONPath specification, which includes a registry of standardized
9/// functions.
10///
11/// # Note
12///
13/// There is a function in `serde_json_path_core/src/spec/functions.rs` that gives
14/// the return type for each function registered here. When adding new functions to
15/// the register, i.e., when new functions are standardized, the function there needs
16/// to be updated too.
17pub(crate) static REGISTRY: LazyLock<HashMap<&'static str, &'static Function>> =
18    LazyLock::new(|| {
19        let mut m = HashMap::new();
20        m.insert("length", &LENGTH_FUNC);
21        m.insert("count", &COUNT_FUNC);
22        #[cfg(feature = "regex")]
23        {
24            m.insert("match", &MATCH_FUNC);
25            m.insert("search", &SEARCH_FUNC);
26        }
27        m.insert("value", &VALUE_FUNC);
28        m
29    });
30
31fn value_length(value: &Value) -> Option<usize> {
32    match value {
33        Value::String(s) => Some(s.chars().count()),
34        Value::Array(a) => Some(a.len()),
35        Value::Object(o) => Some(o.len()),
36        _ => None,
37    }
38}
39
40#[serde_json_path_macros::register(target = LENGTH_FUNC)]
41fn length(value: ValueType) -> ValueType {
42    match value {
43        ValueType::Value(v) => value_length(&v),
44        ValueType::Node(v) => value_length(v),
45        ValueType::Nothing => None,
46    }
47    .map_or(ValueType::Nothing, |l| ValueType::Value(l.into()))
48}
49
50#[serde_json_path_macros::register(target = COUNT_FUNC)]
51fn count(nodes: NodesType) -> ValueType {
52    nodes.len().into()
53}
54
55#[cfg(feature = "regex")]
56#[serde_json_path_macros::register(name = "match", target = MATCH_FUNC)]
57fn match_func(value: ValueType, rgx: ValueType) -> LogicalType {
58    match (value.as_value(), rgx.as_value()) {
59        (Some(Value::String(s)), Some(Value::String(r))) => {
60            regex::Regex::new(format!("(?R)^({r})$").as_str())
61                .map(|r| r.is_match(s))
62                .map(Into::into)
63                .unwrap_or_default()
64        }
65        _ => LogicalType::False,
66    }
67}
68
69#[cfg(feature = "regex")]
70#[serde_json_path_macros::register(target = SEARCH_FUNC)]
71fn search(value: ValueType, rgx: ValueType) -> LogicalType {
72    match (value.as_value(), rgx.as_value()) {
73        (Some(Value::String(s)), Some(Value::String(r))) => {
74            regex::Regex::new(format!("(?R)({r})").as_str())
75                .map(|r| r.is_match(s))
76                .map(Into::into)
77                .unwrap_or_default()
78        }
79        _ => LogicalType::False,
80    }
81}
82
83#[serde_json_path_macros::register(target = VALUE_FUNC)]
84fn value(nodes: NodesType) -> ValueType {
85    if nodes.len() > 1 {
86        ValueType::Nothing
87    } else {
88        match nodes.first() {
89            Some(v) => ValueType::Node(v),
90            None => ValueType::Nothing,
91        }
92    }
93}