Skip to main content

mpl_lang/
types.rs

1//! Generic datatypes for `MPL`
2use std::ops::Deref;
3
4use miette::SourceSpan;
5use serde::{Deserialize, Serialize};
6pub use strumbra::Error as StrumbraError;
7use strumbra::SharedString;
8
9use crate::{
10    linker::{Arg, ArgType, FunctionTrait},
11    query::Param,
12};
13
14/// A dataset identifier
15#[derive(
16    Debug,
17    Clone,
18    PartialEq,
19    Eq,
20    Hash,
21    // needed for the axum path extractor
22    serde::Serialize,
23    serde::Deserialize,
24)]
25#[cfg_attr(feature = "bincode", derive(bincode::Decode, bincode::Encode))]
26#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
27#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
28pub struct Dataset(String);
29
30impl From<&str> for Dataset {
31    fn from(value: &str) -> Self {
32        Dataset(value.to_string())
33    }
34}
35impl PartialEq<str> for Dataset {
36    fn eq(&self, other: &str) -> bool {
37        self.0 == *other
38    }
39}
40
41impl PartialEq<&str> for Dataset {
42    fn eq(&self, other: &&str) -> bool {
43        &*self.0 == *other
44    }
45}
46
47impl Dataset {
48    /// Creates a new dataset.
49    #[must_use]
50    pub fn new(name: String) -> Self {
51        Self(name)
52    }
53}
54
55impl Deref for Dataset {
56    type Target = String;
57
58    fn deref(&self) -> &Self::Target {
59        &self.0
60    }
61}
62
63impl std::fmt::Display for Dataset {
64    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
65        self.0.fmt(f)
66    }
67}
68
69/// A type that can either be concrete or a param.
70#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Eq, PartialEq)]
71#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
72#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
73pub enum Parameterized<T> {
74    /// A concrete type
75    Concrete(T),
76    /// A parameter and the location where it's used (for type checking)
77    Param {
78        /// The location where the param is used
79        #[cfg_attr(feature = "wasm", tsify(type = "{ offset: number, length: number }"))]
80        span: SourceSpan,
81        /// The param
82        param: Param,
83    },
84}
85
86impl<T> std::fmt::Display for Parameterized<T>
87where
88    T: std::fmt::Display,
89{
90    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
91        match self {
92            Parameterized::Concrete(inner) => write!(f, "{inner}"),
93            Parameterized::Param { span: _, param } => write!(f, "${}", param.name),
94        }
95    }
96}
97
98impl<T> Parameterized<T> {
99    /// Map the concrete value.
100    pub fn map_concrete<O, F: Fn(T) -> O>(self, f: F) -> Parameterized<O> {
101        match self {
102            Parameterized::Concrete(inner) => Parameterized::Concrete(f(inner)),
103            Parameterized::Param { span, param } => Parameterized::Param { span, param },
104        }
105    }
106
107    /// Try to map the concrete value.
108    pub fn try_map_concrete<O, E, F: Fn(T) -> Result<O, E>>(
109        self,
110        f: F,
111    ) -> Result<Parameterized<O>, E> {
112        Ok(match self {
113            Parameterized::Concrete(inner) => Parameterized::Concrete(f(inner)?),
114            Parameterized::Param { span, param } => Parameterized::Param { span, param },
115        })
116    }
117
118    /// Returns true if the type is a param.
119    pub fn is_param(&self) -> bool {
120        matches!(self, Parameterized::Param { .. })
121    }
122
123    /// Returns true if the type is a concrete value.
124    pub fn is_concrete(&self) -> bool {
125        matches!(self, Parameterized::Concrete(_))
126    }
127}
128
129/// A metric identifier
130#[derive(
131    Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, serde::Deserialize, serde::Serialize,
132)]
133#[cfg_attr(feature = "bincode", derive(bincode::Encode, bincode::Decode))]
134#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
135#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
136pub struct Metric(
137    #[cfg_attr(feature = "wasm", tsify(type = "String"))]
138    #[cfg_attr(feature = "bincode", bincode(with_serde))]
139    SharedString,
140);
141
142impl std::fmt::Display for Metric {
143    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
144        self.0.fmt(f)
145    }
146}
147
148impl PartialEq<str> for Metric {
149    fn eq(&self, other: &str) -> bool {
150        &*self.0 == other
151    }
152}
153
154impl Deref for Metric {
155    type Target = str;
156
157    fn deref(&self) -> &Self::Target {
158        &self.0
159    }
160}
161
162impl Metric {
163    /// Creates a new metric.
164    pub fn new(name: &str) -> Result<Self, StrumbraError> {
165        Ok(Self(SharedString::try_from(name)?))
166    }
167}
168
169impl TryFrom<String> for Metric {
170    type Error = StrumbraError;
171
172    fn try_from(s: String) -> Result<Self, Self::Error> {
173        Ok(Metric(SharedString::try_from(s)?))
174    }
175}
176
177impl TryFrom<&'_ str> for Metric {
178    type Error = StrumbraError;
179
180    fn try_from(s: &str) -> Result<Self, Self::Error> {
181        Ok(Metric(SharedString::try_from(s)?))
182    }
183}
184
185impl PartialEq<&str> for Metric {
186    fn eq(&self, other: &&str) -> bool {
187        &*self.0 == *other
188    }
189}
190
191/// The method for cumulative-to-delta conversion
192#[derive(Debug, Clone, Copy, Default, PartialEq, Serialize, Deserialize)]
193#[cfg_attr(feature = "bincode", derive(bincode::Encode, bincode::Decode))]
194#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
195#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
196pub enum ConversionMethod {
197    /// Use rate to convert cumulative to delta
198    #[default]
199    Rate,
200    /// Use increase to convert cumulative to delta
201    Increase,
202}
203
204impl std::fmt::Display for ConversionMethod {
205    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
206        match self {
207            ConversionMethod::Rate => write!(f, "rate"),
208            ConversionMethod::Increase => write!(f, "increase"),
209        }
210    }
211}
212
213/// Aggregation type
214#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
215#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
216#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
217pub enum BucketType {
218    /// Histogram
219    Histogram,
220    /// Interpolate delta histogram based on histogram data in the store
221    InterpolateDeltaHistogram,
222    /// Interpolate cumulative histogram with a specified conversion mode
223    InterpolateCumulativeHistogram(ConversionMethod),
224}
225
226impl FunctionTrait for BucketType {
227    fn doc(&self) -> &str {
228        match self {
229            BucketType::Histogram => {
230                "Aggregates non-histogram input series using the provided bucket specs (including histogram quantile calculation)."
231            }
232            BucketType::InterpolateDeltaHistogram => {
233                "Aggregates delta-temporality histogram input series using the provided bucket specs (including histogram quantile calculation via interpolation)."
234            }
235            BucketType::InterpolateCumulativeHistogram(_) => {
236                "Aggregates cumulative-temporality histogram input series after converting to delta using a conversion mode (including histogram quantile calculation via interpolation)."
237            }
238        }
239    }
240
241    fn args(&self) -> Vec<Arg> {
242        match self {
243            BucketType::InterpolateCumulativeHistogram(_) => vec![
244                Arg::new("mode", ArgType::Enum(&["rate", "increase"])),
245                Arg::new(
246                    "specs",
247                    ArgType::Repeated {
248                        typ: Box::new(ArgType::OneOf(vec![
249                            // cumulative does not support min/max as bucket spec
250                            ArgType::Enum(&["count", "avg", "sum"]),
251                            ArgType::Float,
252                        ])),
253                        min: 1,
254                        max: None,
255                    },
256                ),
257            ],
258            BucketType::Histogram | BucketType::InterpolateDeltaHistogram => vec![Arg::new(
259                "specs",
260                ArgType::Repeated {
261                    typ: Box::new(ArgType::OneOf(vec![
262                        ArgType::Enum(&["count", "avg", "sum", "min", "max"]),
263                        ArgType::Float,
264                    ])),
265                    min: 1,
266                    max: None,
267                },
268            )],
269        }
270    }
271}
272
273impl std::fmt::Display for BucketType {
274    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
275        match self {
276            BucketType::Histogram => write!(f, "histogram"),
277            BucketType::InterpolateDeltaHistogram => write!(f, "interpolate_delta_histogram"),
278            BucketType::InterpolateCumulativeHistogram(_) => {
279                write!(f, "interpolate_cumulative_histogram")
280            }
281        }
282    }
283}
284
285/// Aggregation type
286#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
287#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
288#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
289pub enum MapType {
290    /// Min
291    Min,
292    /// Max
293    Max,
294    /// Rate
295    Rate,
296    /// Add
297    Add,
298    /// Sub
299    Sub,
300    /// Mul
301    Mul,
302    /// Div
303    Div,
304    /// Abs
305    Abs,
306    /// fill with constant
307    FillConst,
308    /// fill with previous value
309    FillPrev,
310    /// Increase between points
311    Increase,
312    /// lesser than
313    FilterLt,
314    /// greater than
315    FilterGt,
316    /// equal to
317    FilterEq,
318    /// not equal to
319    FilterNe,
320    /// greater than or equal to
321    FilterGe,
322    /// less than or equal to
323    FilterLe,
324    /// lesser than
325    IsLt,
326    /// greater than
327    IsGt,
328    /// equal to
329    IsEq,
330    /// not equal to
331    IsNe,
332    /// greater than or equal to
333    IsGe,
334    /// less than or equal to
335    IsLe,
336    /// Linear interpolation
337    InterpolateLinear,
338}
339
340impl FunctionTrait for MapType {
341    fn doc(&self) -> &str {
342        match self {
343            MapType::Min => "Minimum between the argument and the datapoint",
344            MapType::Max => "Maximum between the argument and the datapoint",
345            MapType::Add => "Adds the argument to the datapoint",
346            MapType::Sub => "Subtracts the argument from the datapoint",
347            MapType::Mul => "Multiplies the argument with the datapoint",
348            MapType::Div => "Divides the datapoint by the argument",
349            MapType::Abs => "Absolute value of the datapoint",
350            MapType::Rate => {
351                "Per second rate of change between the datapoint and the previous datapoint"
352            }
353            MapType::FillConst => "Fills unset datapoints with the given constant",
354            MapType::FillPrev => "Fills unset datapoints with the previous datapoint",
355            MapType::Increase => {
356                "Calculates the increase between the datapoint and the previous datapoint"
357            }
358            MapType::FilterLt => {
359                "Filters for datapoints that are less than the argument all datapoints not less than the argument are removed"
360            }
361            MapType::FilterGt => {
362                "Filters for datapoints that are greater than the argument all datapoints not greater than the argument are removed"
363            }
364            MapType::FilterEq => {
365                "Filters for datapoints that are equal to the argument all datapoints not equal to the argument are removed"
366            }
367            MapType::FilterNe => {
368                "Filters for datapoints that are not equal to the argument all datapoints equal to the argument are removed"
369            }
370            MapType::FilterGe => {
371                "Filters for datapoints that are greater than or equal to the argument all datapoints not greater than or equal to the argument are removed"
372            }
373            MapType::FilterLe => {
374                "Filters for datapoints that are less than or equal to the argument all datapoints not less than or equal to the argument are removed"
375            }
376            MapType::IsLt => {
377                "Sets the datapoint to 1.0 if the datapoint is less than the argument otherwise sets it to 0.0"
378            }
379            MapType::IsGt => {
380                "Sets the datapoint to 1.0 if the datapoint is greater than the argument otherwise sets it to 0.0"
381            }
382            MapType::IsEq => {
383                "Sets the datapoint to 1.0 if the datapoint is equal to the argument otherwise sets it to 0.0"
384            }
385            MapType::IsNe => {
386                "Sets the datapoint to 1.0 if the datapoint is not equal to the argument otherwise sets it to 0.0"
387            }
388            MapType::IsLe => {
389                "Sets the datapoint to 1.0 if the datapoint is less than or equal to the argument otherwise sets it to 0.0"
390            }
391            MapType::IsGe => {
392                "Sets the datapoint to 1.0 if the datapoint is greater than or equal to the argument otherwise sets it to 0.0"
393            }
394            MapType::InterpolateLinear => {
395                "Performs linear interpolation between two datapoints filling unset values with the interpolated value"
396            }
397        }
398    }
399    fn args(&self) -> Vec<Arg> {
400        match self {
401            MapType::FilterLt
402            | MapType::FilterGt
403            | MapType::FilterEq
404            | MapType::FilterNe
405            | MapType::FilterGe
406            | MapType::FilterLe
407            | MapType::IsLt
408            | MapType::IsGt
409            | MapType::IsEq
410            | MapType::IsNe
411            | MapType::IsGe
412            | MapType::IsLe
413            | MapType::Add
414            | MapType::Sub
415            | MapType::Mul
416            | MapType::Div
417            | MapType::FillConst => vec![Arg::new("value", ArgType::Float)],
418            MapType::Min => vec![Arg::new("min", ArgType::Float)],
419            MapType::Max => vec![Arg::new("max", ArgType::Float)],
420            MapType::Abs
421            | MapType::Rate
422            | MapType::FillPrev
423            | MapType::Increase
424            | MapType::InterpolateLinear => {
425                vec![]
426            }
427        }
428    }
429}
430
431impl std::fmt::Display for MapType {
432    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
433        match self {
434            MapType::Min => write!(f, "min"),
435            MapType::Max => write!(f, "max"),
436            MapType::Rate => write!(f, "rate"),
437            MapType::Add => write!(f, "+"),
438            MapType::Sub => write!(f, "-"),
439            MapType::Mul => write!(f, "*"),
440            MapType::Div => write!(f, "/"),
441            MapType::Abs => write!(f, "abs"),
442            MapType::FillConst => write!(f, "fill::const"),
443            MapType::FillPrev => write!(f, "fill::prev"),
444            MapType::Increase => write!(f, "increase"),
445            MapType::FilterLt => write!(f, "filter::lt"),
446            MapType::FilterGt => write!(f, "filter::gt"),
447            MapType::FilterEq => write!(f, "filter::eq"),
448            MapType::FilterNe => write!(f, "filter::ne"),
449            MapType::FilterGe => write!(f, "filter::ge"),
450            MapType::FilterLe => write!(f, "filter::le"),
451            MapType::IsLt => write!(f, "Is::lt"),
452            MapType::IsGt => write!(f, "Is::gt"),
453            MapType::IsEq => write!(f, "Is::eq"),
454            MapType::IsNe => write!(f, "Is::ne"),
455            MapType::IsGe => write!(f, "Is::ge"),
456            MapType::IsLe => write!(f, "Is::le"),
457            MapType::InterpolateLinear => write!(f, "linear"),
458        }
459    }
460}
461
462/// Aggregation type
463#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
464#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
465#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
466pub enum TimeType {
467    /// Count
468    Count,
469    /// Sum
470    Sum,
471    /// Average
472    Avg,
473    /// Min
474    Min,
475    /// Max
476    Max,
477    /// average rate over time
478    Rate,
479    /// Last observed
480    Last,
481}
482impl FunctionTrait for TimeType {
483    fn doc(&self) -> &str {
484        match self {
485            TimeType::Count => "Count the number of elements",
486            TimeType::Sum => "Sum the elements",
487            TimeType::Avg => "Average the elements",
488            TimeType::Min => "Minimum of the elements",
489            TimeType::Max => "Maximum of the elements",
490            TimeType::Rate => "Average per second rate over a time window",
491            TimeType::Last => "Last observed value",
492        }
493    }
494
495    fn args(&self) -> Vec<Arg> {
496        vec![]
497    }
498}
499
500impl std::fmt::Display for TimeType {
501    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
502        match self {
503            TimeType::Count => write!(f, "count"),
504            TimeType::Sum => write!(f, "sum"),
505            TimeType::Avg => write!(f, "avg"),
506            TimeType::Min => write!(f, "min"),
507            TimeType::Max => write!(f, "max"),
508            TimeType::Rate => write!(f, "rate"),
509            TimeType::Last => write!(f, "last"),
510        }
511    }
512}
513
514/// Aggregation type
515#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
516#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
517#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
518pub enum TagsType {
519    /// Count
520    Count,
521    /// Sum
522    Sum,
523    /// Average
524    Avg,
525    /// Min
526    Min,
527    /// Max
528    Max,
529}
530
531impl FunctionTrait for TagsType {
532    fn doc(&self) -> &str {
533        match self {
534            TagsType::Count => "Counts the number of set values",
535            TagsType::Sum => "Sums the datapoints",
536            TagsType::Avg => "Averages the datapoints",
537            TagsType::Min => "The minimum value",
538            TagsType::Max => "The maximum value",
539        }
540    }
541    fn args(&self) -> Vec<Arg> {
542        match self {
543            TagsType::Count | TagsType::Sum | TagsType::Avg | TagsType::Min | TagsType::Max => {
544                vec![]
545            }
546        }
547    }
548}
549
550impl std::fmt::Display for TagsType {
551    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
552        match self {
553            TagsType::Count => write!(f, "count"),
554            TagsType::Sum => write!(f, "sum"),
555            TagsType::Avg => write!(f, "avg"),
556            TagsType::Min => write!(f, "min"),
557            TagsType::Max => write!(f, "max"),
558        }
559    }
560}
561
562/// Aggregation type used in Compute
563#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
564#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
565#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
566pub enum ComputeType {
567    /// Average
568    Avg,
569    /// Min
570    Min,
571    /// Max
572    Max,
573    /// Add
574    Add,
575    /// Subtraction
576    Sub,
577    /// Multiplication
578    Mul,
579    /// Division
580    Div,
581}
582
583impl FunctionTrait for ComputeType {
584    fn doc(&self) -> &str {
585        match self {
586            ComputeType::Add => "Sums the datapoints",
587            ComputeType::Avg => "Averages the datapoints",
588            ComputeType::Min => "The minimum value",
589            ComputeType::Max => "The maximum value",
590            ComputeType::Div => "Divides the datapoints, removes datapoints if the divisor is zero",
591            ComputeType::Mul => "Multiplies the datapoints",
592            ComputeType::Sub => "Subtracts the datapoints",
593        }
594    }
595    fn args(&self) -> Vec<Arg> {
596        match self {
597            ComputeType::Add
598            | ComputeType::Avg
599            | ComputeType::Min
600            | ComputeType::Max
601            | ComputeType::Div
602            | ComputeType::Mul
603            | ComputeType::Sub => vec![],
604        }
605    }
606}
607
608impl std::fmt::Display for ComputeType {
609    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
610        match self {
611            ComputeType::Avg => write!(f, "avg"),
612            ComputeType::Min => write!(f, "min"),
613            ComputeType::Max => write!(f, "max"),
614            ComputeType::Div => write!(f, "/"),
615            ComputeType::Mul => write!(f, "*"),
616            ComputeType::Add => write!(f, "+"),
617            ComputeType::Sub => write!(f, "-"),
618        }
619    }
620}
621
622/// Bucket aggregation Histogram bucket sepcification
623#[derive(Clone, Copy, Debug, Default, PartialEq, Serialize, Deserialize)]
624#[cfg_attr(feature = "bincode", derive(bincode::Encode, bincode::Decode))]
625#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
626#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
627pub enum BucketSpec {
628    /// Number of elements
629    #[default]
630    Count,
631    /// Average of elemetns
632    Avg,
633    /// Sum of all elements
634    Sum,
635    /// Minimal value
636    Min,
637    /// Maximal value
638    Max,
639    /// Percentile
640    Percentile(f64),
641}
642
643impl std::fmt::Display for BucketSpec {
644    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
645        match self {
646            BucketSpec::Count => write!(f, "count"),
647            BucketSpec::Avg => write!(f, "avg"),
648            BucketSpec::Sum => write!(f, "sum"),
649            BucketSpec::Min => write!(f, "min"),
650            BucketSpec::Max => write!(f, "max"),
651            BucketSpec::Percentile(p) => write!(f, "{p}"),
652        }
653    }
654}