1use std::collections::HashMap;
7
8use once_cell::sync::Lazy;
9
10pub type FieldMapping = HashMap<&'static str, &'static str>;
12
13pub type MethodFieldMappings = HashMap<&'static str, FieldMapping>;
15
16pub static CEL_FIELD_MAPPINGS: Lazy<MethodFieldMappings> = Lazy::new(|| {
18 let mut mappings = HashMap::new();
19
20 mappings.insert(
22 "subscribe_wallet_balance",
23 HashMap::from([
24 ("walletAddress", "a"),
25 ("tokenAddress", "ta"),
26 ("tokenPriceInUsd", "tpiu"),
27 ("balance", "b"),
28 ("timestamp", "t"),
29 ]),
30 );
31
32 mappings.insert(
34 "subscribe_token_candles",
35 HashMap::from([
36 ("open", "o"),
37 ("close", "c"),
38 ("high", "h"),
39 ("low", "l"),
40 ("volume", "v"),
41 ("resolution", "r"),
42 ("time", "t"),
43 ("number", "n"),
44 ]),
45 );
46
47 mappings.insert(
49 "subscribe_token_stats",
50 HashMap::from([
51 ("address", "a"),
52 ("timestamp", "t"),
53 ("buys1m", "b1m"),
54 ("sells1m", "s1m"),
55 ("buyers1m", "be1m"),
56 ("sellers1m", "se1m"),
57 ("buyVolumeInUsd1m", "bviu1m"),
58 ("sellVolumeInUsd1m", "sviu1m"),
59 ("price1m", "p1m"),
60 ("openInUsd1m", "oiu1m"),
61 ("closeInUsd1m", "ciu1m"),
62 ("buys5m", "b5m"),
63 ("sells5m", "s5m"),
64 ("buyers5m", "be5m"),
65 ("sellers5m", "se5m"),
66 ("buyVolumeInUsd5m", "bviu5m"),
67 ("sellVolumeInUsd5m", "sviu5m"),
68 ("price5m", "p5m"),
69 ("openInUsd5m", "oiu5m"),
70 ("closeInUsd5m", "ciu5m"),
71 ("buys15m", "b15m"),
72 ("sells15m", "s15m"),
73 ("buyers15m", "be15m"),
74 ("sellers15m", "se15m"),
75 ("buyVolumeInUsd15m", "bviu15m"),
76 ("sellVolumeInUsd15m", "sviu15m"),
77 ("price15m", "p15m"),
78 ("openInUsd15m", "oiu15m"),
79 ("closeInUsd15m", "ciu15m"),
80 ("buys30m", "b30m"),
81 ("sells30m", "s30m"),
82 ("buyers30m", "be30m"),
83 ("sellers30m", "se30m"),
84 ("buyVolumeInUsd30m", "bviu30m"),
85 ("sellVolumeInUsd30m", "sviu30m"),
86 ("price30m", "p30m"),
87 ("openInUsd30m", "oiu30m"),
88 ("closeInUsd30m", "ciu30m"),
89 ("buys1h", "b1h"),
90 ("sells1h", "s1h"),
91 ("buyers1h", "be1h"),
92 ("sellers1h", "se1h"),
93 ("buyVolumeInUsd1h", "bviu1h"),
94 ("sellVolumeInUsd1h", "sviu1h"),
95 ("price1h", "p1h"),
96 ("openInUsd1h", "oiu1h"),
97 ("closeInUsd1h", "ciu1h"),
98 ("buys4h", "b4h"),
99 ("sells4h", "s4h"),
100 ("buyers4h", "be4h"),
101 ("sellers4h", "se4h"),
102 ("buyVolumeInUsd4h", "bviu4h"),
103 ("sellVolumeInUsd4h", "sviu4h"),
104 ("price4h", "p4h"),
105 ("openInUsd4h", "oiu4h"),
106 ("closeInUsd4h", "ciu4h"),
107 ("buys24h", "b24h"),
108 ("sells24h", "s24h"),
109 ("buyers24h", "be24h"),
110 ("sellers24h", "se24h"),
111 ("buyVolumeInUsd24h", "bviu24h"),
112 ("sellVolumeInUsd24h", "sviu24h"),
113 ("price24h", "p24h"),
114 ("price", "p"),
115 ("openInUsd24h", "oiu24h"),
116 ("closeInUsd24h", "ciu24h"),
117 ]),
118 );
119
120 mappings.insert(
122 "subscribe_token_holders",
123 HashMap::from([
124 ("tokenAddress", "a"),
125 ("holders", "h"),
126 ("top100Amount", "t100a"),
127 ("top10Amount", "t10a"),
128 ("top100Holders", "t100h"),
129 ("top10Holders", "t10h"),
130 ("top100Ratio", "t100r"),
131 ("top10Ratio", "t10r"),
132 ("timestamp", "ts"),
133 ]),
134 );
135
136 mappings.insert(
138 "subscribe_new_token",
139 HashMap::from([
140 ("tokenAddress", "a"),
141 ("name", "n"),
142 ("symbol", "s"),
143 ("createdAtMs", "cts"),
144 ]),
145 );
146
147 mappings.insert(
149 "subscribe_token_supply",
150 HashMap::from([("tokenAddress", "a"), ("supply", "s"), ("timestamp", "ts")]),
151 );
152
153 mappings.insert(
155 "subscribe_dex_pool_balance",
156 HashMap::from([
157 ("poolAddress", "a"),
158 ("tokenAAddress", "taa"),
159 ("tokenALiquidityInUsd", "taliu"),
160 ("tokenBAddress", "tba"),
161 ("tokenBLiquidityInUsd", "tbliu"),
162 ]),
163 );
164
165 mappings.insert(
167 "subscribe_token_liquidity",
168 HashMap::from([
169 ("tokenAddress", "a"),
170 ("metricType", "t"),
171 ("value", "v"),
172 ("timestamp", "ts"),
173 ]),
174 );
175
176 mappings.insert(
178 "subscribe_new_tokens_metadata",
179 HashMap::from([
180 ("tokenAddress", "a"),
181 ("name", "n"),
182 ("symbol", "s"),
183 ("imageUrl", "iu"),
184 ("description", "de"),
185 ("socialMedia", "sm"),
186 ("createdAtMs", "cts"),
187 ]),
188 );
189
190 mappings.insert(
192 "subscribe_token_trades",
193 HashMap::from([
194 ("tokenAddress", "a"),
195 ("timestamp", "t"),
196 ("kind", "k"),
197 ("buyAmount", "ba"),
198 ("buyAmountInUsd", "baiu"),
199 ("buyTokenAddress", "btma"),
200 ("buyTokenName", "btn"),
201 ("buyTokenSymbol", "bts"),
202 ("buyWalletAddress", "bwa"),
203 ("sellAmount", "sa"),
204 ("sellAmountInUsd", "saiu"),
205 ("sellTokenAddress", "stma"),
206 ("sellTokenName", "stn"),
207 ("sellTokenSymbol", "sts"),
208 ("sellWalletAddress", "swa"),
209 ("txHash", "h"),
210 ]),
211 );
212
213 mappings.insert(
215 "subscribe_wallet_pnl",
216 HashMap::from([
217 ("walletAddress", "a"),
218 ("tokenAddress", "ta"),
219 ("tokenPriceInUsd", "tpiu"),
220 ("timestamp", "t"),
221 ("opentime", "ot"),
222 ("lasttime", "lt"),
223 ("closetime", "ct"),
224 ("buyAmount", "ba"),
225 ("buyAmountInUsd", "baiu"),
226 ("buyCount", "bs"),
227 ("buyCount30d", "bs30d"),
228 ("buyCount7d", "bs7d"),
229 ("sellAmount", "sa"),
230 ("sellAmountInUsd", "saiu"),
231 ("sellCount", "ss"),
232 ("sellCount30d", "ss30d"),
233 ("sellCount7d", "ss7d"),
234 ("heldDurationTimestamp", "hdts"),
235 ("averageBuyPriceInUsd", "abpiu"),
236 ("averageSellPriceInUsd", "aspiu"),
237 ("unrealizedProfitInUsd", "upiu"),
238 ("unrealizedProfitRatio", "upr"),
239 ("realizedProfitInUsd", "rpiu"),
240 ("realizedProfitRatio", "rpr"),
241 ("totalRealizedProfitInUsd", "trpiu"),
242 ("totalRealizedProfitRatio", "trr"),
243 ]),
244 );
245
246 mappings.insert(
248 "subscribe_wallet_trade",
249 HashMap::from([
250 ("tokenAddress", "a"),
251 ("timestamp", "t"),
252 ("kind", "k"),
253 ("buyAmount", "ba"),
254 ("buyAmountInUsd", "baiu"),
255 ("buyTokenAddress", "btma"),
256 ("buyTokenName", "btn"),
257 ("buyTokenSymbol", "bts"),
258 ("buyWalletAddress", "bwa"),
259 ("sellAmount", "sa"),
260 ("sellAmountInUsd", "saiu"),
261 ("sellTokenAddress", "stma"),
262 ("sellTokenName", "stn"),
263 ("sellTokenSymbol", "sts"),
264 ("sellWalletAddress", "swa"),
265 ("txHash", "h"),
266 ]),
267 );
268
269 mappings.insert(
271 "subscribe_token_max_liquidity",
272 HashMap::from([
273 ("tokenAddress", "a"),
274 ("poolAddress", "p"),
275 ("liquidityInUsd", "liu"),
276 ("liquidityInNative", "lin"),
277 ("timestamp", "ts"),
278 ]),
279 );
280
281 mappings.insert(
283 "subscribe_token_total_liquidity",
284 HashMap::from([
285 ("tokenAddress", "a"),
286 ("liquidityInUsd", "liu"),
287 ("liquidityInNative", "lin"),
288 ("poolCount", "pc"),
289 ("timestamp", "ts"),
290 ]),
291 );
292
293 mappings
294});
295
296pub fn get_field_mappings(method_name: &str) -> Option<&FieldMapping> {
298 CEL_FIELD_MAPPINGS.get(method_name)
299}
300
301pub fn replace_filter_fields(filter: &str, method_name: &str) -> String {
304 if filter.is_empty() {
305 return filter.to_string();
306 }
307
308 let field_mappings = match get_field_mappings(method_name) {
309 Some(m) => m,
310 None => return filter.to_string(),
311 };
312
313 let mut result = filter.to_string();
314
315 for (long_field, short_field) in field_mappings {
317 let pattern1 = format!(r"\b{}\b", regex::escape(long_field));
320 if let Ok(re) = regex::Regex::new(&pattern1) {
321 result = re
322 .replace_all(&result, format!("meta.{}", short_field))
323 .to_string();
324 }
325
326 let pattern2 = format!(r"\bmeta\.{}\b", regex::escape(long_field));
328 if let Ok(re) = regex::Regex::new(&pattern2) {
329 result = re
330 .replace_all(&result, format!("meta.{}", short_field))
331 .to_string();
332 }
333 }
334
335 result
336}
337
338pub fn get_available_fields(method_name: &str) -> Vec<&'static str> {
340 match get_field_mappings(method_name) {
341 Some(mappings) => mappings.keys().copied().collect(),
342 None => Vec::new(),
343 }
344}
345
346#[cfg(test)]
347mod tests {
348 use super::*;
349
350 #[test]
351 fn test_get_field_mappings() {
352 let mappings = get_field_mappings("subscribe_token_candles");
353 assert!(mappings.is_some());
354 let mappings = mappings.unwrap();
355 assert_eq!(mappings.get("open"), Some(&"o"));
356 assert_eq!(mappings.get("close"), Some(&"c"));
357 }
358
359 #[test]
360 fn test_replace_filter_fields() {
361 let filter = "open > 100 && close < 200";
362 let result = replace_filter_fields(filter, "subscribe_token_candles");
363 assert!(result.contains("meta.o"));
364 assert!(result.contains("meta.c"));
365 }
366
367 #[test]
368 fn test_get_available_fields() {
369 let fields = get_available_fields("subscribe_token_candles");
370 assert!(fields.contains(&"open"));
371 assert!(fields.contains(&"close"));
372 assert!(fields.contains(&"high"));
373 assert!(fields.contains(&"low"));
374 }
375}