1#![doc = include_str!("../../../docs/expressions.md")]
14#![cfg_attr(not(feature = "omit_metadata"), doc = include_str!("../../../docs/expression_gen.md"))]
15
16use std::borrow::Cow;
17use std::collections::HashMap;
18
19use serde::{Deserialize, Serialize};
20use ts_rs::TS;
21
22#[derive(Deserialize, Clone, PartialEq, Debug)]
23#[serde(untagged)]
24pub enum ExpressionsDeserde {
25 Array(Vec<String>),
26 Map(HashMap<String, String>),
27}
28
29#[derive(Deserialize, Serialize, Clone, PartialEq, Debug, Default, TS)]
30#[serde(from = "ExpressionsDeserde")]
31pub struct Expressions(pub HashMap<String, String>);
32
33impl std::ops::Deref for Expressions {
34 type Target = HashMap<String, String>;
35
36 fn deref(&self) -> &Self::Target {
37 &self.0
38 }
39}
40
41impl std::ops::DerefMut for Expressions {
42 fn deref_mut(&mut self) -> &mut Self::Target {
43 &mut self.0
44 }
45}
46
47fn upgrade_legacy_format(expressions: &[String]) -> HashMap<String, String> {
48 tracing::debug!("Legacy `expressions` format: {:?}", expressions);
49 expressions
50 .iter()
51 .map(|s| {
52 if let Some((name, expression)) = s.split_once('\n') {
53 if !expression.is_empty() && name.starts_with("//") {
54 (name.split_at(2).1.trim().to_owned(), expression.to_owned())
55 } else {
56 (s.to_owned(), s.to_owned())
57 }
58 } else {
59 (s.to_owned(), s.to_owned())
60 }
61 })
62 .collect::<HashMap<_, _>>()
63}
64
65impl From<ExpressionsDeserde> for Expressions {
66 fn from(value: ExpressionsDeserde) -> Self {
67 match value {
68 ExpressionsDeserde::Array(arr) => Self(upgrade_legacy_format(&arr)),
69 ExpressionsDeserde::Map(map) => Self(map),
70 }
71 }
72}
73
74#[derive(Clone, Debug, PartialEq, TS)]
75pub struct Expression<'a> {
76 pub name: Cow<'a, str>,
77 pub expression: Cow<'a, str>,
78}
79
80impl<'a> Expression<'a> {
81 pub fn new(name: Option<Cow<'a, str>>, expression: Cow<'a, str>) -> Self {
83 Self {
84 name: name.unwrap_or_else(|| expression.clone()),
85 expression,
86 }
87 }
88}
89
90impl<'a> FromIterator<Expression<'a>> for Expressions {
91 fn from_iter<T: IntoIterator<Item = Expression<'a>>>(iter: T) -> Self {
92 Self(
93 iter.into_iter()
94 .map(|x| (x.name.as_ref().to_owned(), x.expression.as_ref().to_owned()))
95 .collect(),
96 )
97 }
98}
99
100impl Expressions {
101 pub fn insert(&mut self, expr: &Expression) {
102 self.0.insert(
103 expr.name.as_ref().to_owned(),
104 expr.expression.as_ref().to_owned(),
105 );
106 }
107}
108
109#[doc(hidden)]
110#[derive(Serialize, Clone, Copy)]
111pub struct CompletionItemSuggestion {
112 pub label: &'static str,
113 pub insert_text: &'static str,
114 pub documentation: &'static str,
115}
116
117#[doc(hidden)]
118pub static COMPLETIONS: [CompletionItemSuggestion; 77] = [
119 CompletionItemSuggestion {
120 label: "var",
121 insert_text: "var ${1:x := 1}",
122 documentation: "Declare a new local variable",
123 },
124 CompletionItemSuggestion {
125 label: "abs",
126 insert_text: "abs(${1:x})",
127 documentation: "Absolute value of x",
128 },
129 CompletionItemSuggestion {
130 label: "avg",
131 insert_text: "avg(${1:x})",
132 documentation: "Average of all inputs",
133 },
134 CompletionItemSuggestion {
135 label: "bucket",
136 insert_text: "bucket(${1:x}, ${2:y})",
137 documentation: "Bucket x by y",
138 },
139 CompletionItemSuggestion {
140 label: "ceil",
141 insert_text: "ceil(${1:x})",
142 documentation: "Smallest integer >= x",
143 },
144 CompletionItemSuggestion {
145 label: "exp",
146 insert_text: "exp(${1:x})",
147 documentation: "Natural exponent of x (e ^ x)",
148 },
149 CompletionItemSuggestion {
150 label: "floor",
151 insert_text: "floor(${1:x})",
152 documentation: "Largest integer <= x",
153 },
154 CompletionItemSuggestion {
155 label: "frac",
156 insert_text: "frac(${1:x})",
157 documentation: "Fractional portion (after the decimal) of x",
158 },
159 CompletionItemSuggestion {
160 label: "iclamp",
161 insert_text: "iclamp(${1:x})",
162 documentation: "Inverse clamp x within a range",
163 },
164 CompletionItemSuggestion {
165 label: "inrange",
166 insert_text: "inrange(${1:x})",
167 documentation: "Returns whether x is within a range",
168 },
169 CompletionItemSuggestion {
170 label: "log",
171 insert_text: "log(${1:x})",
172 documentation: "Natural log of x",
173 },
174 CompletionItemSuggestion {
175 label: "log10",
176 insert_text: "log10(${1:x})",
177 documentation: "Base 10 log of x",
178 },
179 CompletionItemSuggestion {
180 label: "log1p",
181 insert_text: "log1p(${1:x})",
182 documentation: "Natural log of 1 + x where x is very small",
183 },
184 CompletionItemSuggestion {
185 label: "log2",
186 insert_text: "log2(${1:x})",
187 documentation: "Base 2 log of x",
188 },
189 CompletionItemSuggestion {
190 label: "logn",
191 insert_text: "logn(${1:x}, ${2:N})",
192 documentation: "Base N log of x where N >= 0",
193 },
194 CompletionItemSuggestion {
195 label: "max",
196 insert_text: "max(${1:x})",
197 documentation: "Maximum value of all inputs",
198 },
199 CompletionItemSuggestion {
200 label: "min",
201 insert_text: "min(${1:x})",
202 documentation: "Minimum value of all inputs",
203 },
204 CompletionItemSuggestion {
205 label: "mul",
206 insert_text: "mul(${1:x})",
207 documentation: "Product of all inputs",
208 },
209 CompletionItemSuggestion {
210 label: "percent_of",
211 insert_text: "percent_of(${1:x})",
212 documentation: "Percent y of x",
213 },
214 CompletionItemSuggestion {
215 label: "pow",
216 insert_text: "pow(${1:x}, ${2:y})",
217 documentation: "x to the power of y",
218 },
219 CompletionItemSuggestion {
220 label: "root",
221 insert_text: "root(${1:x}, ${2:N})",
222 documentation: "N-th root of x where N >= 0",
223 },
224 CompletionItemSuggestion {
225 label: "round",
226 insert_text: "round(${1:x})",
227 documentation: "Round x to the nearest integer",
228 },
229 CompletionItemSuggestion {
230 label: "sgn",
231 insert_text: "sgn(${1:x})",
232 documentation: "Sign of x: -1, 1, or 0",
233 },
234 CompletionItemSuggestion {
235 label: "sqrt",
236 insert_text: "sqrt(${1:x})",
237 documentation: "Square root of x",
238 },
239 CompletionItemSuggestion {
240 label: "sum",
241 insert_text: "sum(${1:x})",
242 documentation: "Sum of all inputs",
243 },
244 CompletionItemSuggestion {
245 label: "trunc",
246 insert_text: "trunc(${1:x})",
247 documentation: "Integer portion of x",
248 },
249 CompletionItemSuggestion {
250 label: "acos",
251 insert_text: "acos(${1:x})",
252 documentation: "Arc cosine of x in radians",
253 },
254 CompletionItemSuggestion {
255 label: "acosh",
256 insert_text: "acosh(${1:x})",
257 documentation: "Inverse hyperbolic cosine of x in radians",
258 },
259 CompletionItemSuggestion {
260 label: "asin",
261 insert_text: "asin(${1:x})",
262 documentation: "Arc sine of x in radians",
263 },
264 CompletionItemSuggestion {
265 label: "asinh",
266 insert_text: "asinh(${1:x})",
267 documentation: "Inverse hyperbolic sine of x in radians",
268 },
269 CompletionItemSuggestion {
270 label: "atan",
271 insert_text: "atan(${1:x})",
272 documentation: "Arc tangent of x in radians",
273 },
274 CompletionItemSuggestion {
275 label: "atanh",
276 insert_text: "atanh(${1:x})",
277 documentation: "Inverse hyperbolic tangent of x in radians",
278 },
279 CompletionItemSuggestion {
280 label: "cos",
281 insert_text: "cos(${1:x})",
282 documentation: "Cosine of x",
283 },
284 CompletionItemSuggestion {
285 label: "cosh",
286 insert_text: "cosh(${1:x})",
287 documentation: "Hyperbolic cosine of x",
288 },
289 CompletionItemSuggestion {
290 label: "cot",
291 insert_text: "cot(${1:x})",
292 documentation: "Cotangent of x",
293 },
294 CompletionItemSuggestion {
295 label: "sin",
296 insert_text: "sin(${1:x})",
297 documentation: "Sine of x",
298 },
299 CompletionItemSuggestion {
300 label: "sinc",
301 insert_text: "sinc(${1:x})",
302 documentation: "Sine cardinal of x",
303 },
304 CompletionItemSuggestion {
305 label: "sinh",
306 insert_text: "sinh(${1:x})",
307 documentation: "Hyperbolic sine of x",
308 },
309 CompletionItemSuggestion {
310 label: "tan",
311 insert_text: "tan(${1:x})",
312 documentation: "Tangent of x",
313 },
314 CompletionItemSuggestion {
315 label: "tanh",
316 insert_text: "tanh(${1:x})",
317 documentation: "Hyperbolic tangent of x",
318 },
319 CompletionItemSuggestion {
320 label: "deg2rad",
321 insert_text: "deg2rad(${1:x})",
322 documentation: "Convert x from degrees to radians",
323 },
324 CompletionItemSuggestion {
325 label: "deg2grad",
326 insert_text: "deg2grad(${1:x})",
327 documentation: "Convert x from degrees to gradians",
328 },
329 CompletionItemSuggestion {
330 label: "rad2deg",
331 insert_text: "rad2deg(${1:x})",
332 documentation: "Convert x from radians to degrees",
333 },
334 CompletionItemSuggestion {
335 label: "grad2deg",
336 insert_text: "grad2deg(${1:x})",
337 documentation: "Convert x from gradians to degrees",
338 },
339 CompletionItemSuggestion {
340 label: "concat",
341 insert_text: "concat(${1:x}, ${2:y})",
342 documentation: "Concatenate string columns and string literals, such \
343 as:\nconcat(\"State\" ', ', \"City\")",
344 },
345 CompletionItemSuggestion {
346 label: "order",
347 insert_text: "order(${1:input column}, ${2:value}, ...)",
348 documentation: "Generates a sort order for a string column based on the input order of \
349 the parameters, such as:\norder(\"State\", 'Texas', 'New York')",
350 },
351 CompletionItemSuggestion {
352 label: "upper",
353 insert_text: "upper(${1:x})",
354 documentation: "Uppercase of x",
355 },
356 CompletionItemSuggestion {
357 label: "lower",
358 insert_text: "lower(${1:x})",
359 documentation: "Lowercase of x",
360 },
361 CompletionItemSuggestion {
362 label: "hour_of_day",
363 insert_text: "hour_of_day(${1:x})",
364 documentation: "Return a datetime's hour of the day as a string",
365 },
366 CompletionItemSuggestion {
367 label: "month_of_year",
368 insert_text: "month_of_year(${1:x})",
369 documentation: "Return a datetime's month of the year as a string",
370 },
371 CompletionItemSuggestion {
372 label: "day_of_week",
373 insert_text: "day_of_week(${1:x})",
374 documentation: "Return a datetime's day of week as a string",
375 },
376 CompletionItemSuggestion {
377 label: "now",
378 insert_text: "now()",
379 documentation: "The current datetime in local time",
380 },
381 CompletionItemSuggestion {
382 label: "today",
383 insert_text: "today()",
384 documentation: "The current date in local time",
385 },
386 CompletionItemSuggestion {
387 label: "is_null",
388 insert_text: "is_null(${1:x})",
389 documentation: "Whether x is a null value",
390 },
391 CompletionItemSuggestion {
392 label: "is_not_null",
393 insert_text: "is_not_null(${1:x})",
394 documentation: "Whether x is not a null value",
395 },
396 CompletionItemSuggestion {
397 label: "not",
398 insert_text: "not(${1:x})",
399 documentation: "not x",
400 },
401 CompletionItemSuggestion {
402 label: "true",
403 insert_text: "true",
404 documentation: "Boolean value true",
405 },
406 CompletionItemSuggestion {
407 label: "false",
408 insert_text: "false",
409 documentation: "Boolean value false",
410 },
411 CompletionItemSuggestion {
412 label: "if",
413 insert_text: "if (${1:condition}) {} else if (${2:condition}) {} else {}",
414 documentation: "An if/else conditional, which evaluates a condition such as:\n if \
415 (\"Sales\" > 100) { true } else { false }",
416 },
417 CompletionItemSuggestion {
418 label: "for",
419 insert_text: "for (${1:expression}) {}",
420 documentation: "A for loop, which repeatedly evaluates an incrementing expression such \
421 as:\nvar x := 0; var y := 1; for (x < 10; x += 1) { y := x + y }",
422 },
423 CompletionItemSuggestion {
424 label: "string",
425 insert_text: "string(${1:x})",
426 documentation: "Converts the given argument to a string",
427 },
428 CompletionItemSuggestion {
429 label: "integer",
430 insert_text: "integer(${1:x})",
431 documentation: "Converts the given argument to a 32-bit integer. If the result \
432 over/under-flows, null is returned",
433 },
434 CompletionItemSuggestion {
435 label: "float",
436 insert_text: "float(${1:x})",
437 documentation: "Converts the argument to a float",
438 },
439 CompletionItemSuggestion {
440 label: "date",
441 insert_text: "date(${1:year}, ${1:month}, ${1:day})",
442 documentation: "Given a year, month (1-12) and day, create a new date",
443 },
444 CompletionItemSuggestion {
445 label: "datetime",
446 insert_text: "datetime(${1:timestamp})",
447 documentation: "Given a POSIX timestamp of milliseconds since epoch, create a new datetime",
448 },
449 CompletionItemSuggestion {
450 label: "boolean",
451 insert_text: "boolean(${1:x})",
452 documentation: "Converts the given argument to a boolean",
453 },
454 CompletionItemSuggestion {
455 label: "random",
456 insert_text: "random()",
457 documentation: "Returns a random float between 0 and 1, inclusive.",
458 },
459 CompletionItemSuggestion {
460 label: "match",
461 insert_text: "match(${1:string}, ${2:pattern})",
462 documentation: "Returns True if any part of string matches pattern, and False otherwise.",
463 },
464 CompletionItemSuggestion {
465 label: "match_all",
466 insert_text: "match_all(${1:string}, ${2:pattern})",
467 documentation: "Returns True if the whole string matches pattern, and False otherwise.",
468 },
469 CompletionItemSuggestion {
470 label: "search",
471 insert_text: "search(${1:string}, ${2:pattern})",
472 documentation: "Returns the substring that matches the first capturing group in pattern, \
473 or null if there are no capturing groups in the pattern or if there are \
474 no matches.",
475 },
476 CompletionItemSuggestion {
477 label: "indexof",
478 insert_text: "indexof(${1:string}, ${2:pattern}, ${3:output_vector})",
479 documentation: "Writes into index 0 and 1 of output_vector the start and end indices of \
480 the substring that matches the first capturing group in \
481 pattern.\n\nReturns true if there is a match and output was written, or \
482 false if there are no capturing groups in the pattern, if there are no \
483 matches, or if the indices are invalid.",
484 },
485 CompletionItemSuggestion {
486 label: "substring",
487 insert_text: "substring(${1:string}, ${2:start_idx}, ${3:length})",
488 documentation: "Returns a substring of string from start_idx with the given length. If \
489 length is not passed in, returns substring from start_idx to the end of \
490 the string. Returns null if the string or any indices are invalid.",
491 },
492 CompletionItemSuggestion {
493 label: "replace",
494 insert_text: "replace(${1:string}, ${2:pattern}, ${3:replacer})",
495 documentation: "Replaces the first match of pattern in string with replacer, or return \
496 the original string if no replaces were made.",
497 },
498 CompletionItemSuggestion {
499 label: "replace_all",
500 insert_text: "replace(${1:string}, ${2:pattern}, ${3:replacer})",
501 documentation: "Replaces all non-overlapping matches of pattern in string with replacer, \
502 or return the original string if no replaces were made.",
503 },
504 CompletionItemSuggestion {
505 label: "index",
506 insert_text: "index()",
507 documentation: "Looks up the index value of the current row",
508 },
509 CompletionItemSuggestion {
510 label: "col",
511 insert_text: "col(${1:string})",
512 documentation: "Looks up a column value by name",
513 },
514 CompletionItemSuggestion {
515 label: "vlookup",
516 insert_text: "vlookup(${1:string}, ${2:uint64})",
517 documentation: "Looks up a value in another column by index",
518 },
519];