1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
// Rust guideline compliant
//! Cross-crate registry of plugin-registered aggregate function names.
//!
//! The Cypher AST's [`crate::ast::Expr::is_aggregate`] uses a hardcoded
//! list of built-in aggregate names (`count`, `sum`, `min`, …) to
//! decide whether a `FunctionCall` routes through the planner's
//! aggregate translation. Plugin-registered aggregates (M9
//! `uni.plugin.declareAggregate` and any other
//! `uni_plugin::traits::aggregate::AggregatePluginFn` source) are
//! not in that list, so a Cypher query like `RETURN myAgg(n.value)`
//! would otherwise fall through to scalar UDF resolution and fail.
//!
//! Rather than thread a `PluginRegistry` reference through every AST
//! query, plugin registrars publish each aggregate's lowercased qname
//! into this process-wide set at registration time. The AST consults
//! it inside `is_aggregate`; the planner's own copy of the hardcoded
//! list (in `uni-query/src/query/planner.rs::is_aggregate_function_name`)
//! does the same.
//!
//! # Lifecycle
//!
//! Entries are added but never removed today (M9 declared aggregates
//! cannot be dropped while in-flight queries reference them). When
//! `dropDeclared` infrastructure matures past M11, a counterpart
//! `unregister_plugin_aggregate` will follow.
use HashSet;
use ;
/// Register a fully-qualified aggregate name (`"namespace.local"`)
/// so the Cypher planner routes calls to it through the aggregate
/// translation path instead of scalar UDF resolution.
///
/// The name is stored lowercase. Calls are idempotent.
/// Return `true` if `name` (case-insensitive) was previously registered
/// via [`register_plugin_aggregate`].