1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
use bigdecimal::BigDecimal;
use chrono::{DateTime, FixedOffset};
use indexmap::IndexMap;
use query_structure::PrismaValue;
use serde::Serialize;

pub type ArgumentValueObject = IndexMap<String, ArgumentValue>;

/// Represents the input values in a Document.
/// This abstraction is mostly there to hold special kind of values such as `FieldRef` which have to be disambiguated at query-validation time.
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
#[serde(untagged)]
pub enum ArgumentValue {
    Scalar(PrismaValue),
    Object(ArgumentValueObject),
    List(Vec<ArgumentValue>),
    Raw(serde_json::Value),
    FieldRef(ArgumentValueObject),
}

impl ArgumentValue {
    pub fn null() -> Self {
        Self::Scalar(PrismaValue::Null)
    }

    pub fn int(i: i64) -> Self {
        Self::Scalar(PrismaValue::Int(i))
    }

    pub fn float(dec: BigDecimal) -> Self {
        Self::Scalar(PrismaValue::Float(dec))
    }

    pub fn string(str: String) -> Self {
        Self::Scalar(PrismaValue::String(str))
    }

    pub fn bool(bool: bool) -> Self {
        Self::Scalar(PrismaValue::Boolean(bool))
    }

    pub fn r#enum(str: String) -> Self {
        Self::Scalar(PrismaValue::Enum(str))
    }

    pub fn json(str: String) -> Self {
        Self::Scalar(PrismaValue::Json(str))
    }

    pub fn raw(value: serde_json::Value) -> Self {
        Self::Raw(value)
    }

    pub fn bytes(bytes: Vec<u8>) -> Self {
        Self::Scalar(PrismaValue::Bytes(bytes))
    }

    pub fn bigint(i: i64) -> Self {
        Self::Scalar(PrismaValue::BigInt(i))
    }

    pub fn datetime(dt: DateTime<FixedOffset>) -> Self {
        Self::Scalar(PrismaValue::DateTime(dt))
    }

    pub fn object(obj: impl Into<ArgumentValueObject>) -> Self {
        Self::Object(obj.into())
    }

    pub fn list(values: impl Into<Vec<ArgumentValue>>) -> Self {
        Self::List(values.into())
    }

    pub fn into_object(self) -> Option<ArgumentValueObject> {
        match self {
            Self::Object(obj) => Some(obj),
            _ => None,
        }
    }

    pub(crate) fn should_be_parsed_as_json(&self) -> bool {
        match self {
            ArgumentValue::Object(_) => true,
            ArgumentValue::Raw(_) => true,
            ArgumentValue::List(l) => l.iter().all(|v| v.should_be_parsed_as_json()),
            ArgumentValue::Scalar(pv) => !matches!(pv, PrismaValue::Enum(_) | PrismaValue::Json(_)),
            ArgumentValue::FieldRef(_) => false,
        }
    }
}

impl From<PrismaValue> for ArgumentValue {
    fn from(value: PrismaValue) -> Self {
        match value {
            PrismaValue::List(list) => Self::List(list.into_iter().map(ArgumentValue::from).collect()),
            PrismaValue::Object(obj) => {
                Self::Object(obj.into_iter().map(|(k, v)| (k, ArgumentValue::from(v))).collect())
            }
            _ => Self::Scalar(value),
        }
    }
}