1#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
20pub enum FunctionCategory {
21 Existence,
23 Filtering,
25 Subsetting,
27 Combining,
29 Conversion,
31 String,
33 Math,
35 Tree,
37 Utility,
39 Boolean,
41 Datetime,
43 Types,
45 SqlOnFhir,
49 Terminology,
51 Other,
53}
54
55impl FunctionCategory {
56 pub const fn as_str(self) -> &'static str {
60 match self {
61 FunctionCategory::Existence => "existence",
62 FunctionCategory::Filtering => "filtering",
63 FunctionCategory::Subsetting => "subsetting",
64 FunctionCategory::Combining => "combining",
65 FunctionCategory::Conversion => "conversion",
66 FunctionCategory::String => "string",
67 FunctionCategory::Math => "math",
68 FunctionCategory::Tree => "tree",
69 FunctionCategory::Utility => "utility",
70 FunctionCategory::Boolean => "boolean",
71 FunctionCategory::Datetime => "datetime",
72 FunctionCategory::Types => "types",
73 FunctionCategory::SqlOnFhir => "sql-on-fhir",
74 FunctionCategory::Terminology => "terminology",
75 FunctionCategory::Other => "other",
76 }
77 }
78}
79
80impl std::fmt::Display for FunctionCategory {
81 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
82 f.write_str(self.as_str())
83 }
84}
85
86#[derive(Debug, Clone, Copy, PartialEq, Eq)]
88pub struct FunctionInfo {
89 pub name: &'static str,
92 pub signature: &'static str,
97 pub category: FunctionCategory,
99}
100
101pub fn builtin_functions() -> &'static [FunctionInfo] {
124 use FunctionCategory::*;
125
126 const CATALOG: &[FunctionInfo] = &[
127 FunctionInfo {
128 name: "abs",
129 signature: "abs()",
130 category: Math,
131 },
132 FunctionInfo {
133 name: "aggregate",
134 signature: "aggregate(aggregator, [init])",
135 category: Utility,
136 },
137 FunctionInfo {
138 name: "all",
139 signature: "all([criteria])",
140 category: Existence,
141 },
142 FunctionInfo {
143 name: "allFalse",
144 signature: "allFalse()",
145 category: Existence,
146 },
147 FunctionInfo {
148 name: "allTrue",
149 signature: "allTrue()",
150 category: Existence,
151 },
152 FunctionInfo {
153 name: "anyFalse",
154 signature: "anyFalse()",
155 category: Existence,
156 },
157 FunctionInfo {
158 name: "anyTrue",
159 signature: "anyTrue()",
160 category: Existence,
161 },
162 FunctionInfo {
163 name: "avg",
164 signature: "avg()",
165 category: Math,
166 },
167 FunctionInfo {
168 name: "ceiling",
169 signature: "ceiling()",
170 category: Math,
171 },
172 FunctionInfo {
173 name: "children",
174 signature: "children()",
175 category: Tree,
176 },
177 FunctionInfo {
178 name: "coalesce",
179 signature: "coalesce(value, ...)",
180 category: Filtering,
181 },
182 FunctionInfo {
183 name: "combine",
184 signature: "combine(other)",
185 category: Combining,
186 },
187 FunctionInfo {
188 name: "comparable",
189 signature: "comparable(other)",
190 category: Other,
191 },
192 FunctionInfo {
193 name: "contains",
194 signature: "contains(substring)",
195 category: String,
196 },
197 FunctionInfo {
198 name: "convertsToBoolean",
199 signature: "convertsToBoolean()",
200 category: Conversion,
201 },
202 FunctionInfo {
203 name: "convertsToDate",
204 signature: "convertsToDate()",
205 category: Conversion,
206 },
207 FunctionInfo {
208 name: "convertsToDateTime",
209 signature: "convertsToDateTime()",
210 category: Conversion,
211 },
212 FunctionInfo {
213 name: "convertsToDecimal",
214 signature: "convertsToDecimal()",
215 category: Conversion,
216 },
217 FunctionInfo {
218 name: "convertsToInteger",
219 signature: "convertsToInteger()",
220 category: Conversion,
221 },
222 FunctionInfo {
223 name: "convertsToLong",
224 signature: "convertsToLong()",
225 category: Conversion,
226 },
227 FunctionInfo {
228 name: "convertsToQuantity",
229 signature: "convertsToQuantity([unit])",
230 category: Conversion,
231 },
232 FunctionInfo {
233 name: "convertsToString",
234 signature: "convertsToString()",
235 category: Conversion,
236 },
237 FunctionInfo {
238 name: "convertsToTime",
239 signature: "convertsToTime()",
240 category: Conversion,
241 },
242 FunctionInfo {
243 name: "count",
244 signature: "count()",
245 category: Existence,
246 },
247 FunctionInfo {
248 name: "decode",
249 signature: "decode(format)",
250 category: String,
251 },
252 FunctionInfo {
253 name: "defineVariable",
254 signature: "defineVariable(name, [expr])",
255 category: Utility,
256 },
257 FunctionInfo {
258 name: "descendants",
259 signature: "descendants()",
260 category: Tree,
261 },
262 FunctionInfo {
263 name: "difference",
264 signature: "difference(value, precision)",
265 category: Datetime,
266 },
267 FunctionInfo {
268 name: "distinct",
269 signature: "distinct()",
270 category: Existence,
271 },
272 FunctionInfo {
273 name: "duration",
274 signature: "duration(value, precision)",
275 category: Datetime,
276 },
277 FunctionInfo {
278 name: "empty",
279 signature: "empty()",
280 category: Existence,
281 },
282 FunctionInfo {
283 name: "encode",
284 signature: "encode(format)",
285 category: String,
286 },
287 FunctionInfo {
288 name: "endsWith",
289 signature: "endsWith(suffix)",
290 category: String,
291 },
292 FunctionInfo {
293 name: "escape",
294 signature: "escape(target)",
295 category: String,
296 },
297 FunctionInfo {
298 name: "exclude",
299 signature: "exclude(other)",
300 category: Subsetting,
301 },
302 FunctionInfo {
303 name: "exists",
304 signature: "exists([criteria])",
305 category: Existence,
306 },
307 FunctionInfo {
308 name: "exp",
309 signature: "exp()",
310 category: Math,
311 },
312 FunctionInfo {
313 name: "extension",
314 signature: "extension(url)",
315 category: Tree,
316 },
317 FunctionInfo {
318 name: "first",
319 signature: "first()",
320 category: Subsetting,
321 },
322 FunctionInfo {
323 name: "floor",
324 signature: "floor()",
325 category: Math,
326 },
327 FunctionInfo {
328 name: "getReferenceKey",
329 signature: "getReferenceKey([type])",
330 category: SqlOnFhir,
331 },
332 FunctionInfo {
333 name: "getResourceKey",
334 signature: "getResourceKey()",
335 category: SqlOnFhir,
336 },
337 FunctionInfo {
338 name: "hasValue",
339 signature: "hasValue()",
340 category: Existence,
341 },
342 FunctionInfo {
343 name: "highBoundary",
344 signature: "highBoundary([precision])",
345 category: Utility,
346 },
347 FunctionInfo {
348 name: "iif",
349 signature: "iif(criterion, trueResult, [otherwiseResult])",
350 category: Conversion,
351 },
352 FunctionInfo {
353 name: "indexOf",
354 signature: "indexOf(substring)",
355 category: String,
356 },
357 FunctionInfo {
358 name: "intersect",
359 signature: "intersect(other)",
360 category: Subsetting,
361 },
362 FunctionInfo {
363 name: "isDistinct",
364 signature: "isDistinct()",
365 category: Existence,
366 },
367 FunctionInfo {
368 name: "join",
369 signature: "join([separator])",
370 category: String,
371 },
372 FunctionInfo {
373 name: "last",
374 signature: "last()",
375 category: Subsetting,
376 },
377 FunctionInfo {
378 name: "lastIndexOf",
379 signature: "lastIndexOf(substring)",
380 category: String,
381 },
382 FunctionInfo {
383 name: "length",
384 signature: "length()",
385 category: String,
386 },
387 FunctionInfo {
388 name: "ln",
389 signature: "ln()",
390 category: Math,
391 },
392 FunctionInfo {
393 name: "log",
394 signature: "log(base)",
395 category: Math,
396 },
397 FunctionInfo {
398 name: "lowBoundary",
399 signature: "lowBoundary([precision])",
400 category: Utility,
401 },
402 FunctionInfo {
403 name: "lower",
404 signature: "lower()",
405 category: String,
406 },
407 FunctionInfo {
408 name: "matches",
409 signature: "matches(regex, [flags])",
410 category: String,
411 },
412 FunctionInfo {
413 name: "matchesFull",
414 signature: "matchesFull(regex, [flags])",
415 category: String,
416 },
417 FunctionInfo {
418 name: "max",
419 signature: "max()",
420 category: Math,
421 },
422 FunctionInfo {
423 name: "memberOf",
424 signature: "memberOf(valueSet)",
425 category: Terminology,
426 },
427 FunctionInfo {
428 name: "min",
429 signature: "min()",
430 category: Math,
431 },
432 FunctionInfo {
433 name: "not",
434 signature: "not()",
435 category: Boolean,
436 },
437 FunctionInfo {
438 name: "now",
439 signature: "now()",
440 category: Utility,
441 },
442 FunctionInfo {
443 name: "ofType",
444 signature: "ofType(type)",
445 category: Filtering,
446 },
447 FunctionInfo {
448 name: "power",
449 signature: "power(exponent)",
450 category: Math,
451 },
452 FunctionInfo {
453 name: "precision",
454 signature: "precision()",
455 category: Utility,
456 },
457 FunctionInfo {
458 name: "repeat",
459 signature: "repeat(projection)",
460 category: Filtering,
461 },
462 FunctionInfo {
463 name: "repeatAll",
464 signature: "repeatAll(projection)",
465 category: Filtering,
466 },
467 FunctionInfo {
468 name: "replace",
469 signature: "replace(pattern, substitution)",
470 category: String,
471 },
472 FunctionInfo {
473 name: "replaceMatches",
474 signature: "replaceMatches(regex, substitution, [flags])",
475 category: String,
476 },
477 FunctionInfo {
478 name: "resolve",
479 signature: "resolve()",
480 category: Other,
481 },
482 FunctionInfo {
483 name: "round",
484 signature: "round([precision])",
485 category: Math,
486 },
487 FunctionInfo {
488 name: "select",
489 signature: "select(projection)",
490 category: Filtering,
491 },
492 FunctionInfo {
493 name: "single",
494 signature: "single()",
495 category: Subsetting,
496 },
497 FunctionInfo {
498 name: "skip",
499 signature: "skip(num)",
500 category: Subsetting,
501 },
502 FunctionInfo {
503 name: "sort",
504 signature: "sort([criteria])",
505 category: Filtering,
506 },
507 FunctionInfo {
508 name: "split",
509 signature: "split(separator)",
510 category: String,
511 },
512 FunctionInfo {
513 name: "sqrt",
514 signature: "sqrt()",
515 category: Math,
516 },
517 FunctionInfo {
518 name: "startsWith",
519 signature: "startsWith(prefix)",
520 category: String,
521 },
522 FunctionInfo {
523 name: "subsetOf",
524 signature: "subsetOf(other)",
525 category: Existence,
526 },
527 FunctionInfo {
528 name: "substring",
529 signature: "substring(start, [length])",
530 category: String,
531 },
532 FunctionInfo {
533 name: "sum",
534 signature: "sum()",
535 category: Math,
536 },
537 FunctionInfo {
538 name: "supersetOf",
539 signature: "supersetOf(other)",
540 category: Existence,
541 },
542 FunctionInfo {
543 name: "tail",
544 signature: "tail()",
545 category: Subsetting,
546 },
547 FunctionInfo {
548 name: "take",
549 signature: "take(num)",
550 category: Subsetting,
551 },
552 FunctionInfo {
553 name: "timeOfDay",
554 signature: "timeOfDay()",
555 category: Utility,
556 },
557 FunctionInfo {
558 name: "toBoolean",
559 signature: "toBoolean()",
560 category: Conversion,
561 },
562 FunctionInfo {
563 name: "toChars",
564 signature: "toChars()",
565 category: String,
566 },
567 FunctionInfo {
568 name: "toDate",
569 signature: "toDate([format])",
570 category: Conversion,
571 },
572 FunctionInfo {
573 name: "toDateTime",
574 signature: "toDateTime([format])",
575 category: Conversion,
576 },
577 FunctionInfo {
578 name: "today",
579 signature: "today()",
580 category: Utility,
581 },
582 FunctionInfo {
583 name: "toDecimal",
584 signature: "toDecimal()",
585 category: Conversion,
586 },
587 FunctionInfo {
588 name: "toInteger",
589 signature: "toInteger()",
590 category: Conversion,
591 },
592 FunctionInfo {
593 name: "toLong",
594 signature: "toLong()",
595 category: Conversion,
596 },
597 FunctionInfo {
598 name: "toQuantity",
599 signature: "toQuantity([unit])",
600 category: Conversion,
601 },
602 FunctionInfo {
603 name: "toString",
604 signature: "toString([format])",
605 category: Conversion,
606 },
607 FunctionInfo {
608 name: "toTime",
609 signature: "toTime()",
610 category: Conversion,
611 },
612 FunctionInfo {
613 name: "trace",
614 signature: "trace(name, [projection])",
615 category: Utility,
616 },
617 FunctionInfo {
618 name: "trim",
619 signature: "trim()",
620 category: String,
621 },
622 FunctionInfo {
623 name: "truncate",
624 signature: "truncate()",
625 category: Math,
626 },
627 FunctionInfo {
628 name: "type",
629 signature: "type()",
630 category: Types,
631 },
632 FunctionInfo {
633 name: "unescape",
634 signature: "unescape(target)",
635 category: String,
636 },
637 FunctionInfo {
638 name: "union",
639 signature: "union(other)",
640 category: Combining,
641 },
642 FunctionInfo {
643 name: "upper",
644 signature: "upper()",
645 category: String,
646 },
647 FunctionInfo {
648 name: "where",
649 signature: "where(criteria)",
650 category: Filtering,
651 },
652 ];
653 CATALOG
654}
655
656#[cfg(test)]
657mod tests {
658 use super::*;
659
660 #[test]
661 fn catalog_is_sorted_case_insensitively_by_name() {
662 let names: Vec<String> = builtin_functions()
663 .iter()
664 .map(|f| f.name.to_lowercase())
665 .collect();
666 let mut sorted = names.clone();
667 sorted.sort();
668 assert_eq!(
669 names, sorted,
670 "builtin_functions() must be sorted alphabetically (case-insensitively) by name"
671 );
672 }
673
674 #[test]
675 fn catalog_has_no_duplicate_names() {
676 let mut names: Vec<&str> = builtin_functions().iter().map(|f| f.name).collect();
677 let original_len = names.len();
678 names.sort_unstable();
679 names.dedup();
680 assert_eq!(names.len(), original_len, "duplicate function name found");
681 }
682
683 #[test]
684 fn every_category_string_is_from_the_closed_set() {
685 const ALLOWED: &[&str] = &[
686 "existence",
687 "filtering",
688 "subsetting",
689 "combining",
690 "conversion",
691 "string",
692 "math",
693 "tree",
694 "utility",
695 "boolean",
696 "datetime",
697 "types",
698 "sql-on-fhir",
699 "terminology",
700 "other",
701 ];
702 for f in builtin_functions() {
703 assert!(
704 ALLOWED.contains(&f.category.as_str()),
705 "function {:?} has category {:?} outside the closed set",
706 f.name,
707 f.category.as_str()
708 );
709 }
710 }
711}