uni_query_functions/
function_props.rs1use std::collections::HashMap;
8use std::sync::LazyLock;
9
10#[derive(Debug, Clone, Copy)]
15pub struct FunctionPropertySpec {
16 pub entity_args: &'static [usize],
19
20 pub property_name_args: &'static [(usize, usize)],
25
26 pub needs_full_entity: bool,
28}
29
30static FUNCTION_SPECS: LazyLock<HashMap<&'static str, FunctionPropertySpec>> =
33 LazyLock::new(|| {
34 let full_entity = FunctionPropertySpec {
36 entity_args: &[0],
37 property_name_args: &[],
38 needs_full_entity: true,
39 };
40 let entity_arg_only = FunctionPropertySpec {
41 entity_args: &[0],
42 property_name_args: &[],
43 needs_full_entity: false,
44 };
45 let no_entity = FunctionPropertySpec {
46 entity_args: &[],
47 property_name_args: &[],
48 needs_full_entity: false,
49 };
50
51 HashMap::from([
52 (
54 "UNI.TEMPORAL.VALIDAT",
55 FunctionPropertySpec {
56 entity_args: &[0],
57 property_name_args: &[(1, 0), (2, 0)],
58 needs_full_entity: false,
59 },
60 ),
61 ("KEYS", full_entity),
63 ("PROPERTIES", full_entity),
64 ("LABELS", full_entity),
65 ("NODES", full_entity),
66 ("RELATIONSHIPS", full_entity),
67 ("ID", entity_arg_only),
74 ("ELEMENTID", entity_arg_only),
75 ("TYPE", entity_arg_only),
76 ("COUNT", entity_arg_only),
78 ("COALESCE", no_entity),
80 ("SUM", no_entity),
81 ("AVG", no_entity),
82 ("MIN", no_entity),
83 ("MAX", no_entity),
84 ("COLLECT", no_entity),
85 ("PERCENTILEDISC", no_entity),
86 ("PERCENTILECONT", no_entity),
87 ])
88 });
89
90pub fn get_function_spec(name: &str) -> Option<&'static FunctionPropertySpec> {
92 let name_upper = name.to_uppercase();
93 FUNCTION_SPECS.get(name_upper.as_str())
94}
95
96#[cfg(test)]
97mod tests {
98 use super::*;
99
100 #[test]
101 fn test_validat_spec() {
102 let spec = get_function_spec("uni.temporal.validAt").unwrap();
103 assert_eq!(spec.entity_args, &[0]);
104 assert_eq!(spec.property_name_args, &[(1, 0), (2, 0)]);
105 assert!(!spec.needs_full_entity);
106 }
107
108 #[test]
109 fn test_keys_spec() {
110 let spec = get_function_spec("keys").unwrap();
111 assert_eq!(spec.entity_args, &[0]);
112 assert!(spec.needs_full_entity);
113 }
114
115 #[test]
116 fn test_properties_spec() {
117 let spec = get_function_spec("PROPERTIES").unwrap();
118 assert_eq!(spec.entity_args, &[0]);
119 assert!(spec.needs_full_entity);
120 }
121
122 #[test]
123 fn test_unknown_function_returns_none() {
124 assert!(get_function_spec("unknownFunction").is_none());
125 }
126
127 #[test]
128 fn test_count_spec_exists() {
129 let spec = get_function_spec("COUNT").unwrap();
130 assert!(!spec.needs_full_entity);
131 assert_eq!(spec.entity_args, &[0]);
132 }
133
134 #[test]
135 fn test_all_aggregates_registered() {
136 for func in ["COUNT", "SUM", "AVG", "MIN", "MAX", "COLLECT"] {
137 let spec = get_function_spec(func);
138 assert!(
139 spec.is_some(),
140 "Aggregate function {} should be registered",
141 func
142 );
143 assert!(
144 !spec.unwrap().needs_full_entity,
145 "Aggregate function {} should not need full entity",
146 func
147 );
148 }
149 }
150
151 #[test]
152 fn test_aggregate_case_insensitive() {
153 assert!(get_function_spec("count").is_some());
155 assert!(get_function_spec("Count").is_some());
156 assert!(get_function_spec("COUNT").is_some());
157 }
158}