Skip to content

Commit

Permalink
chore: remove QueryValue and replace with PrismaValue (#3610)
Browse files Browse the repository at this point in the history
  • Loading branch information
Weakky authored Jan 19, 2023
1 parent eff985a commit 1df3eac
Show file tree
Hide file tree
Showing 12 changed files with 205 additions and 227 deletions.
23 changes: 18 additions & 5 deletions libs/prisma-value/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ pub use error::ConversionFailure;
pub type PrismaValueResult<T> = std::result::Result<T, ConversionFailure>;
pub type PrismaListValue = Vec<PrismaValue>;

#[derive(Debug, PartialEq, Clone, Eq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
#[serde(untagged)]
pub enum PrismaValue {
String(String),
Expand Down Expand Up @@ -46,12 +46,18 @@ pub enum PrismaValue {

/// Stringify a date to the following format
/// 1999-05-01T00:00:00.000Z
pub fn stringify_date(date: &DateTime<FixedOffset>) -> String {
pub fn stringify_datetime(datetime: &DateTime<FixedOffset>) -> String {
// Warning: Be careful if you plan on changing the code below
// The findUnique batch optimization expects date inputs to have exactly the same format as date outputs
// This works today because clients always send date inputs in the same format as the serialized format below
// Updating this without transforming date inputs to the same format WILL break the findUnique batch optimization
date.to_rfc3339_opts(SecondsFormat::Millis, true)
datetime.to_rfc3339_opts(SecondsFormat::Millis, true)
}

/// Parses an RFC 3339 and ISO 8601 date and time string such as 1996-12-19T16:39:57-08:00,
/// then returns a new DateTime with a parsed FixedOffset.
pub fn parse_datetime(datetime: &str) -> chrono::ParseResult<DateTime<FixedOffset>> {
DateTime::parse_from_rfc3339(datetime)
}

pub fn encode_bytes(bytes: &[u8]) -> String {
Expand Down Expand Up @@ -135,7 +141,7 @@ fn serialize_date<S>(date: &DateTime<FixedOffset>, serializer: S) -> Result<S::O
where
S: Serializer,
{
stringify_date(date).serialize(serializer)
stringify_datetime(date).serialize(serializer)
}

fn serialize_bytes<S>(bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error>
Expand Down Expand Up @@ -258,12 +264,19 @@ impl PrismaValue {
}
}

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

pub fn new_float(float: f64) -> PrismaValue {
PrismaValue::Float(BigDecimal::from_f64(float).unwrap())
}

pub fn new_datetime(datetime: &str) -> PrismaValue {
PrismaValue::DateTime(DateTime::parse_from_rfc3339(datetime).unwrap())
PrismaValue::DateTime(parse_datetime(datetime).unwrap())
}

pub fn as_boolean(&self) -> Option<&bool> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ mod to_many {
}
}"#,
2009,
"Query parsing/validation error at `Query.findManyTestModel.where.TestModelWhereInput.to_many_as.CompositeACompositeListFilter.equals`: Value types mismatch. Have: Object({\"a_1\": String(\"Test\"), \"a_2\": Int(0)}), want: Object(CompositeAObjectEqualityInput)"
"`Query.findManyTestModel.where.TestModelWhereInput.to_many_as.CompositeACompositeListFilter.equals`: Value types mismatch. Have: Object([(\"a_1\", String(\"Test\")), (\"a_2\", Int(0))]), want: Object(CompositeAObjectEqualityInput)"
);

Ok(())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,14 +216,14 @@ mod json {
&runner,
r#"query { findManyTestModel(where: { json: { not: { equals: "{}" }}}) { id }}"#,
2009,
"`Query.findManyTestModel.where.TestModelWhereInput.json.JsonNullableFilter.not`: Value types mismatch. Have: Object({\"equals\": String(\"{}\")}), want: Json"
"`Query.findManyTestModel.where.TestModelWhereInput.json.JsonNullableFilter.not`: Value types mismatch. Have: Object([(\"equals\", String(\"{}\"))]), want: Json"
);

assert_error!(
&runner,
r#"query { findManyTestModel(where: { json: { not: { equals: null }}}) { id }}"#,
2009,
"`Query.findManyTestModel.where.TestModelWhereInput.json.JsonNullableFilter.not`: Value types mismatch. Have: Object({\"equals\": Null}), want: Json"
"`Query.findManyTestModel.where.TestModelWhereInput.json.JsonNullableFilter.not`: Value types mismatch. Have: Object([(\"equals\", Null)]), want: Json"
);

Ok(())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -414,15 +414,15 @@ mod update {
runner,
query,
2009,
"`Mutation.updateOneTestModel.data.TestModelUpdateInput.to_many_as.CompositeAListUpdateEnvelopeInput.set.CompositeACreateInput.a_2`: Value types mismatch. Have: Object({\"update\": Object({\"increment\": Int(3)})}), want: Int"
"`Mutation.updateOneTestModel.data.TestModelUpdateInput.to_many_as.CompositeAListUpdateEnvelopeInput.set.CompositeACreateInput.a_2`: Value types mismatch. Have: Object([(\"update\", Object([(\"increment\", Int(3))]))]), want: Int"
);

// Ensure `update` cannot be used in the Unchecked type
assert_error!(
runner,
query,
2009,
"`Mutation.updateOneTestModel.data.TestModelUpdateInput.to_many_as.CompositeAListUpdateEnvelopeInput.set.CompositeACreateInput.a_2`: Value types mismatch. Have: Object({\"update\": Object({\"increment\": Int(3)})}), want: Int"
"`Mutation.updateOneTestModel.data.TestModelUpdateInput.to_many_as.CompositeAListUpdateEnvelopeInput.set.CompositeACreateInput.a_2`: Value types mismatch. Have: Object([(\"update\", Object([(\"increment\", Int(3))]))]), want: Int"
);

Ok(())
Expand Down
4 changes: 2 additions & 2 deletions query-engine/core/src/query_document/error.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{query_document::QueryValue, schema::InputType};
use crate::{query_document::PrismaValue, schema::InputType};
use fmt::Display;
use itertools::Itertools;
use std::fmt;
Expand Down Expand Up @@ -63,7 +63,7 @@ pub enum QueryParserErrorKind {
ArgumentNotFoundError,
FieldCountError(FieldCountError),
ValueParseError(String),
ValueTypeMismatchError { have: QueryValue, want: InputType },
ValueTypeMismatchError { have: PrismaValue, want: InputType },
InputUnionParseError { parsing_errors: Vec<QueryParserError> },
ValueFitError(String),
}
Expand Down
28 changes: 14 additions & 14 deletions query-engine/core/src/query_document/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,18 @@ mod error;
mod operation;
mod parse_ast;
mod parser;
mod query_value;
mod selection;
mod transformers;

pub use error::*;
pub use operation::*;
pub use parse_ast::*;
pub use parser::*;
pub use query_value::*;
pub use selection::*;
pub use transformers::*;

use crate::resolve_compound_field;
use indexmap::IndexMap;
use prisma_models::ModelRef;
use prisma_models::{ModelRef, PrismaValue};
use schema::QuerySchemaRef;
use schema_builder::constants::*;
use std::collections::HashMap;
Expand Down Expand Up @@ -82,12 +79,12 @@ impl BatchDocument {

where_obj.iter().any(|(key, val)| match val {
// If it's a compound, then it's still considered as scalar
QueryValue::Object(_) if resolve_compound_field(key, model).is_some() => false,
PrismaValue::Object(_) if resolve_compound_field(key, model).is_some() => false,
// Otherwise, we just look for a scalar field inside the model. If it's not one, then we break.
val => match model.fields().find_from_scalar(&key) {
Ok(_) => match val {
// Consider scalar _only_ if the filter object contains "equals". eg: `{ scalar_field: { equals: 1 } }`
QueryValue::Object(obj) => !obj.contains_key(filters::EQUALS),
PrismaValue::Object(obj) => !obj.iter().any(|(k, _)| k.as_str() == filters::EQUALS),
_ => false,
},
Err(_) => true,
Expand Down Expand Up @@ -158,7 +155,7 @@ impl BatchDocumentTransaction {

#[derive(Debug, Clone)]
pub struct CompactedDocument {
pub arguments: Vec<HashMap<String, QueryValue>>,
pub arguments: Vec<HashMap<String, PrismaValue>>,
pub nested_selection: Vec<String>,
pub operation: Operation,
pub keys: Vec<String>,
Expand Down Expand Up @@ -246,11 +243,11 @@ impl CompactedDocument {

// Convert the selections into a map of arguments. This defines the
// response order and how we fetch the right data from the response set.
let arguments: Vec<HashMap<String, QueryValue>> = selections
let arguments: Vec<HashMap<String, PrismaValue>> = selections
.into_iter()
.map(|mut sel| {
let where_obj = sel.pop_argument().unwrap().1.into_object().unwrap();
let filter_map: HashMap<String, QueryValue> = extract_filter(where_obj, model).into_iter().collect();
let filter_map: HashMap<String, PrismaValue> = extract_filter(where_obj, model).into_iter().collect();

filter_map
})
Expand All @@ -260,7 +257,7 @@ impl CompactedDocument {
let keys: Vec<_> = arguments[0]
.iter()
.flat_map(|pair| match pair {
(_, QueryValue::Object(obj)) => obj.keys().map(ToOwned::to_owned).collect(),
(_, PrismaValue::Object(obj)) => obj.iter().map(|(key, _)| key.to_owned()).collect(),
(key, _) => vec![key.to_owned()],
})
.collect();
Expand All @@ -284,16 +281,19 @@ impl CompactedDocument {
/// Furthermore, this list is used to match the results of the findMany query back to the original findUnique queries.
/// Consequently, we only extract EQUALS filters or else we would have to manually implement other filters.
/// This is a limitation that _could_ technically be lifted but that's not worth it for now.
fn extract_filter(where_obj: IndexMap<String, QueryValue>, model: &ModelRef) -> Vec<(String, QueryValue)> {
fn extract_filter(where_obj: Vec<SelectionArgument>, model: &ModelRef) -> Vec<SelectionArgument> {
where_obj
.into_iter()
.flat_map(|(key, val)| match val {
// This means our query has a compound field in the form of: {co1_col2: { col1_col2: { col1: <val>, col2: <val> } }}
QueryValue::Object(obj) if resolve_compound_field(&key, model).is_some() => obj.into_iter().collect(),
PrismaValue::Object(obj) if resolve_compound_field(&key, model).is_some() => obj.into_iter().collect(),
// This means our query has a scalar filter in the form of {col1: { equals: <val> }}
QueryValue::Object(obj) => {
PrismaValue::Object(obj) => {
// This is safe because it's been validated before in the `.can_compact` method.
let equal_val = obj.get(filters::EQUALS).expect("we only support scalar equals filters");
let (_, equal_val) = obj
.iter()
.find(|(k, _)| k == filters::EQUALS)
.expect("we only support scalar equals filters");

vec![(key, equal_val.clone())]
}
Expand Down
Loading

0 comments on commit 1df3eac

Please sign in to comment.