Skip to content

Commit 2a0f5e2

Browse files
committed
refactor(qc): move generator call parsing to a more appropriate place (#5739)
Generator calls should only be parsed when we expect a scalar. This change also adds some debug assertions to ensure that the return types are correct. For performance and size reasons, we do not compile these checks in release builds because generators do not come from user input and cannot be represented in the JSON protocol.
1 parent 8eff7f5 commit 2a0f5e2

1 file changed

Lines changed: 46 additions & 3 deletions

File tree

  • query-compiler/core/src/query_document

query-compiler/core/src/query_document/parser.rs

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ use bigdecimal::{BigDecimal, ToPrimitive};
44
use chrono::prelude::*;
55
use core::fmt;
66
use indexmap::{IndexMap, IndexSet};
7+
#[cfg(debug_assertions)]
8+
use query_structure::PrismaValueType;
79
use query_structure::{DefaultKind, PrismaValue};
810
use std::{borrow::Cow, convert::TryFrom, rc::Rc, str::FromStr};
911
use user_facing_errors::query_engine::validation::ValidationError;
@@ -256,9 +258,6 @@ impl QueryDocumentParser {
256258
if let ArgumentValue::Scalar(pv @ PrismaValue::Placeholder { .. }) = &value {
257259
return Ok(ParsedInputValue::Single(pv.clone()));
258260
}
259-
if let ArgumentValue::Scalar(pv @ PrismaValue::GeneratorCall { .. }) = &value {
260-
return Ok(ParsedInputValue::Single(pv.clone()));
261-
}
262261

263262
let mut failures = Vec::new();
264263

@@ -442,6 +441,28 @@ impl QueryDocumentParser {
442441
// UUID coercion matchers
443442
(PrismaValue::Uuid(uuid), ScalarType::String) => Ok(PrismaValue::String(uuid.to_string())),
444443

444+
// Generator calls cannot be encoded in the JSON protocol and can
445+
// only be injected by the query parser when evaluating the default
446+
// values of optional fields, so it should not be possible for them
447+
// to be used in unexpected places or with wrong types. Therefore
448+
// we only verify the return type in debug builds and in tests but
449+
// not in release builds.
450+
#[cfg(debug_assertions)]
451+
(
452+
PrismaValue::GeneratorCall {
453+
name,
454+
args,
455+
return_type,
456+
},
457+
scalar_type,
458+
) if prisma_value_type_matches_scalar_type(&return_type, scalar_type) => Ok(PrismaValue::GeneratorCall {
459+
name,
460+
args,
461+
return_type,
462+
}),
463+
#[cfg(not(debug_assertions))]
464+
(pv @ PrismaValue::GeneratorCall { .. }, _) => Ok(pv),
465+
445466
// All other combinations are value type mismatches.
446467
(_, _) => Err(ValidationError::invalid_argument_type(
447468
selection_path.segments(),
@@ -817,6 +838,28 @@ impl QueryDocumentParser {
817838
}
818839
}
819840

841+
#[cfg(debug_assertions)]
842+
fn prisma_value_type_matches_scalar_type(pv_type: &PrismaValueType, scalar_type: ScalarType) -> bool {
843+
match pv_type {
844+
PrismaValueType::String => scalar_type == ScalarType::String,
845+
PrismaValueType::Boolean => scalar_type == ScalarType::Boolean,
846+
PrismaValueType::Enum => false,
847+
PrismaValueType::Int => scalar_type == ScalarType::Int,
848+
PrismaValueType::Uuid => scalar_type == ScalarType::UUID,
849+
PrismaValueType::List(prisma_value_type) => {
850+
matches!(**prisma_value_type, PrismaValueType::Json | PrismaValueType::Object)
851+
&& scalar_type == ScalarType::JsonList
852+
}
853+
PrismaValueType::Json => scalar_type == ScalarType::Json,
854+
PrismaValueType::Object => scalar_type == ScalarType::Json,
855+
PrismaValueType::DateTime => scalar_type == ScalarType::DateTime,
856+
PrismaValueType::Float => scalar_type == ScalarType::Float,
857+
PrismaValueType::BigInt => scalar_type == ScalarType::BigInt,
858+
PrismaValueType::Bytes => scalar_type == ScalarType::Bytes,
859+
PrismaValueType::Any => true,
860+
}
861+
}
862+
820863
pub(crate) mod conversions {
821864
use std::borrow::Cow;
822865

0 commit comments

Comments
 (0)