1use std::collections::BTreeMap;
6
7use async_graphql::*;
8use once_cell::sync::Lazy;
9use serde::{Deserialize, Serialize};
10use serde_json as json;
11
12#[derive(Enum, Copy, Clone, Serialize, Deserialize, Debug, Eq, PartialEq, Ord, PartialOrd)]
15#[serde(rename_all = "kebab-case")]
16#[graphql(name = "Feature")]
17pub(crate) enum FunctionalGroup {
18 Analytics,
21
22 Coins,
24
25 DynamicFields,
27
28 Subscriptions,
30
31 SystemState,
34}
35
36impl FunctionalGroup {
37 pub(crate) fn name(&self) -> String {
41 json::ser::to_string(self).expect("Serializing `FunctionalGroup` cannot fail.")
42 }
43
44 pub(crate) fn all() -> &'static [FunctionalGroup] {
46 use FunctionalGroup as G;
47 static ALL: &[FunctionalGroup] = &[
48 G::Analytics,
49 G::Coins,
50 G::DynamicFields,
51 G::Subscriptions,
52 G::SystemState,
53 ];
54 ALL
55 }
56}
57
58fn functional_groups() -> &'static BTreeMap<(&'static str, &'static str), FunctionalGroup> {
61 use FunctionalGroup as G;
67 static GROUPS: Lazy<BTreeMap<(&str, &str), FunctionalGroup>> = Lazy::new(|| {
68 BTreeMap::from_iter([
69 (("Address", "balance"), G::Coins),
70 (("Address", "balances"), G::Coins),
71 (("Address", "coins"), G::Coins),
72 (("Checkpoint", "addressMetrics"), G::Analytics),
73 (("Checkpoint", "networkTotalTransactions"), G::Analytics),
74 (("Epoch", "protocolConfigs"), G::SystemState),
75 (("Epoch", "referenceGasPrice"), G::SystemState),
76 (("Epoch", "validatorSet"), G::SystemState),
77 (("Object", "balance"), G::Coins),
78 (("Object", "balances"), G::Coins),
79 (("Object", "coins"), G::Coins),
80 (("Object", "dynamicField"), G::DynamicFields),
81 (("Object", "dynamicObjectField"), G::DynamicFields),
82 (("Object", "dynamicFields"), G::DynamicFields),
83 (("Owner", "balance"), G::Coins),
84 (("Owner", "balances"), G::Coins),
85 (("Owner", "coins"), G::Coins),
86 (("Owner", "dynamicField"), G::DynamicFields),
87 (("Owner", "dynamicObjectField"), G::DynamicFields),
88 (("Owner", "dynamicFields"), G::DynamicFields),
89 (("Query", "coinMetadata"), G::Coins),
90 (("Query", "moveCallMetrics"), G::Analytics),
91 (("Query", "networkMetrics"), G::Analytics),
92 (("Query", "protocolConfig"), G::SystemState),
93 (("Subscription", "events"), G::Subscriptions),
94 (("Subscription", "transactions"), G::Subscriptions),
95 (("SystemStateSummary", "safeMode"), G::SystemState),
96 (("SystemStateSummary", "storageFund"), G::SystemState),
97 (("SystemStateSummary", "systemParameters"), G::SystemState),
98 (("SystemStateSummary", "systemStateVersion"), G::SystemState),
99 ])
100 });
101
102 Lazy::force(&GROUPS)
103}
104
105pub(crate) fn functional_group(type_: &str, field: &str) -> Option<FunctionalGroup> {
108 functional_groups().get(&(type_, field)).copied()
109}
110
111#[cfg(test)]
112mod tests {
113 use std::collections::BTreeSet;
114
115 use async_graphql::{OutputType, registry::Registry};
116
117 use super::*;
118 use crate::types::query::Query;
119
120 #[test]
121 fn test_groups_match_schema() {
126 let mut registry = Registry::default();
127 Query::create_type_info(&mut registry);
128
129 let unimplemented = BTreeSet::from_iter([
130 ("Checkpoint", "addressMetrics"),
131 ("Epoch", "protocolConfig"),
132 ("Query", "moveCallMetrics"),
133 ("Query", "networkMetrics"),
134 ("Subscription", "events"),
135 ("Subscription", "transactions"),
136 ]);
137
138 for (type_, field) in &unimplemented {
139 let Some(meta_type) = registry.concrete_type_by_name(type_) else {
140 continue;
141 };
142
143 let Some(_) = meta_type.field_by_name(field) else {
144 continue;
145 };
146
147 panic!(
148 "Field '{type_}.{field}' is marked as unimplemented in this test, but it's in the \
149 schema. Fix this by removing it from the `unimplemented` set."
150 );
151 }
152
153 for (type_, field) in functional_groups().keys() {
154 if unimplemented.contains(&(type_, field)) {
155 continue;
156 }
157
158 let Some(meta_type) = registry.concrete_type_by_name(type_) else {
159 panic!("Type '{type_}' from functional group configs does not appear in schema.");
160 };
161
162 let Some(_) = meta_type.field_by_name(field) else {
163 panic!(
164 "Field '{type_}.{field}' from functional group configs does not appear in \
165 schema."
166 );
167 };
168 }
169 }
170}