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([
151 ("tokenAddress", "a"),
152 ("supply", "s"),
153 ("timestamp", "ts"),
154 ]),
155 );
156
157 mappings.insert(
159 "subscribe_dex_pool_balance",
160 HashMap::from([
161 ("poolAddress", "a"),
162 ("tokenAAddress", "taa"),
163 ("tokenALiquidityInUsd", "taliu"),
164 ("tokenBAddress", "tba"),
165 ("tokenBLiquidityInUsd", "tbliu"),
166 ]),
167 );
168
169 mappings.insert(
171 "subscribe_token_liquidity",
172 HashMap::from([
173 ("tokenAddress", "a"),
174 ("metricType", "t"),
175 ("value", "v"),
176 ("timestamp", "ts"),
177 ]),
178 );
179
180 mappings.insert(
182 "subscribe_new_tokens_metadata",
183 HashMap::from([
184 ("tokenAddress", "a"),
185 ("name", "n"),
186 ("symbol", "s"),
187 ("imageUrl", "iu"),
188 ("description", "de"),
189 ("socialMedia", "sm"),
190 ("createdAtMs", "cts"),
191 ]),
192 );
193
194 mappings.insert(
196 "subscribe_token_trades",
197 HashMap::from([
198 ("tokenAddress", "a"),
199 ("timestamp", "t"),
200 ("kind", "k"),
201 ("buyAmount", "ba"),
202 ("buyAmountInUsd", "baiu"),
203 ("buyTokenAddress", "btma"),
204 ("buyTokenName", "btn"),
205 ("buyTokenSymbol", "bts"),
206 ("buyWalletAddress", "bwa"),
207 ("sellAmount", "sa"),
208 ("sellAmountInUsd", "saiu"),
209 ("sellTokenAddress", "stma"),
210 ("sellTokenName", "stn"),
211 ("sellTokenSymbol", "sts"),
212 ("sellWalletAddress", "swa"),
213 ("txHash", "h"),
214 ]),
215 );
216
217 mappings.insert(
219 "subscribe_wallet_pnl",
220 HashMap::from([
221 ("walletAddress", "a"),
222 ("tokenAddress", "ta"),
223 ("tokenPriceInUsd", "tpiu"),
224 ("timestamp", "t"),
225 ("opentime", "ot"),
226 ("lasttime", "lt"),
227 ("closetime", "ct"),
228 ("buyAmount", "ba"),
229 ("buyAmountInUsd", "baiu"),
230 ("buyCount", "bs"),
231 ("buyCount30d", "bs30d"),
232 ("buyCount7d", "bs7d"),
233 ("sellAmount", "sa"),
234 ("sellAmountInUsd", "saiu"),
235 ("sellCount", "ss"),
236 ("sellCount30d", "ss30d"),
237 ("sellCount7d", "ss7d"),
238 ("heldDurationTimestamp", "hdts"),
239 ("averageBuyPriceInUsd", "abpiu"),
240 ("averageSellPriceInUsd", "aspiu"),
241 ("unrealizedProfitInUsd", "upiu"),
242 ("unrealizedProfitRatio", "upr"),
243 ("realizedProfitInUsd", "rpiu"),
244 ("realizedProfitRatio", "rpr"),
245 ("totalRealizedProfitInUsd", "trpiu"),
246 ("totalRealizedProfitRatio", "trr"),
247 ]),
248 );
249
250 mappings.insert(
252 "subscribe_wallet_trade",
253 HashMap::from([
254 ("tokenAddress", "a"),
255 ("timestamp", "t"),
256 ("kind", "k"),
257 ("buyAmount", "ba"),
258 ("buyAmountInUsd", "baiu"),
259 ("buyTokenAddress", "btma"),
260 ("buyTokenName", "btn"),
261 ("buyTokenSymbol", "bts"),
262 ("buyWalletAddress", "bwa"),
263 ("sellAmount", "sa"),
264 ("sellAmountInUsd", "saiu"),
265 ("sellTokenAddress", "stma"),
266 ("sellTokenName", "stn"),
267 ("sellTokenSymbol", "sts"),
268 ("sellWalletAddress", "swa"),
269 ("txHash", "h"),
270 ]),
271 );
272
273 mappings.insert(
275 "subscribe_token_max_liquidity",
276 HashMap::from([
277 ("tokenAddress", "a"),
278 ("poolAddress", "p"),
279 ("liquidityInUsd", "liu"),
280 ("liquidityInNative", "lin"),
281 ("timestamp", "ts"),
282 ]),
283 );
284
285 mappings.insert(
287 "subscribe_token_total_liquidity",
288 HashMap::from([
289 ("tokenAddress", "a"),
290 ("liquidityInUsd", "liu"),
291 ("liquidityInNative", "lin"),
292 ("poolCount", "pc"),
293 ("timestamp", "ts"),
294 ]),
295 );
296
297 mappings
298});
299
300pub fn get_field_mappings(method_name: &str) -> Option<&FieldMapping> {
302 CEL_FIELD_MAPPINGS.get(method_name)
303}
304
305pub fn replace_filter_fields(filter: &str, method_name: &str) -> String {
308 if filter.is_empty() {
309 return filter.to_string();
310 }
311
312 let field_mappings = match get_field_mappings(method_name) {
313 Some(m) => m,
314 None => return filter.to_string(),
315 };
316
317 let mut result = filter.to_string();
318
319 for (long_field, short_field) in field_mappings {
321 let pattern1 = format!(r"\b{}\b", regex::escape(long_field));
324 if let Ok(re) = regex::Regex::new(&pattern1) {
325 result = re
326 .replace_all(&result, format!("meta.{}", short_field))
327 .to_string();
328 }
329
330 let pattern2 = format!(r"\bmeta\.{}\b", regex::escape(long_field));
332 if let Ok(re) = regex::Regex::new(&pattern2) {
333 result = re
334 .replace_all(&result, format!("meta.{}", short_field))
335 .to_string();
336 }
337 }
338
339 result
340}
341
342pub fn get_available_fields(method_name: &str) -> Vec<&'static str> {
344 match get_field_mappings(method_name) {
345 Some(mappings) => mappings.keys().copied().collect(),
346 None => Vec::new(),
347 }
348}
349
350#[cfg(test)]
351mod tests {
352 use super::*;
353
354 #[test]
355 fn test_get_field_mappings() {
356 let mappings = get_field_mappings("subscribe_token_candles");
357 assert!(mappings.is_some());
358 let mappings = mappings.unwrap();
359 assert_eq!(mappings.get("open"), Some(&"o"));
360 assert_eq!(mappings.get("close"), Some(&"c"));
361 }
362
363 #[test]
364 fn test_replace_filter_fields() {
365 let filter = "open > 100 && close < 200";
366 let result = replace_filter_fields(filter, "subscribe_token_candles");
367 assert!(result.contains("meta.o"));
368 assert!(result.contains("meta.c"));
369 }
370
371 #[test]
372 fn test_get_available_fields() {
373 let fields = get_available_fields("subscribe_token_candles");
374 assert!(fields.contains(&"open"));
375 assert!(fields.contains(&"close"));
376 assert!(fields.contains(&"high"));
377 assert!(fields.contains(&"low"));
378 }
379}