Skip to content

Commit 0940115

Browse files
committed
feat(schema): add suppport for marking fields as parameterizable (#5730)
Add support for marking fields as parameterizable in the query schema.
1 parent 9d6ad21 commit 0940115

1 file changed

Lines changed: 66 additions & 0 deletions

File tree

query-compiler/schema/src/input_types.rs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ pub struct InputField<'a> {
127127
field_types: Vec<InputType<'a>>,
128128
is_required: bool,
129129
requires_other_fields: Vec<Cow<'a, str>>,
130+
is_parameterizable: bool,
130131
}
131132

132133
impl<'a> InputField<'a> {
@@ -142,6 +143,7 @@ impl<'a> InputField<'a> {
142143
field_types,
143144
is_required,
144145
requires_other_fields: Vec::new(),
146+
is_parameterizable: false,
145147
}
146148
}
147149

@@ -204,6 +206,30 @@ impl<'a> InputField<'a> {
204206
pub(crate) fn nullable_if(self, condition: bool) -> Self {
205207
if condition { self.nullable() } else { self }
206208
}
209+
210+
/// Returns whether this field accepts placeholder values for parameterized queries.
211+
pub fn is_parameterizable(&self) -> bool {
212+
self.is_parameterizable
213+
}
214+
215+
/// Marks the field as parameterizable (accepts placeholder values in queries).
216+
///
217+
/// Parameterizable fields can have their values substituted with placeholders
218+
/// for query plan caching. This is typically used for filter values and data
219+
/// fields, but not for structural fields like `take`, `skip`, `orderBy`, etc.
220+
#[allow(dead_code)] // Used in a follow-up change
221+
pub(crate) fn parameterizable(mut self) -> Self {
222+
self.is_parameterizable = true;
223+
self
224+
}
225+
226+
/// Marks the field as parameterizable if the condition is true.
227+
///
228+
/// See [`Self::parameterizable`].
229+
#[allow(dead_code)] // Used in a follow-up change
230+
pub(crate) fn parameterizable_if(self, condition: bool) -> Self {
231+
if condition { self.parameterizable() } else { self }
232+
}
207233
}
208234

209235
#[derive(Clone)]
@@ -320,3 +346,43 @@ impl<'a> InputType<'a> {
320346
}
321347
}
322348
}
349+
350+
#[cfg(test)]
351+
mod tests {
352+
use super::*;
353+
354+
#[test]
355+
fn input_field_default_not_parameterizable() {
356+
let field = InputField::new("test".into(), vec![InputType::int()], None, true);
357+
assert!(!field.is_parameterizable());
358+
}
359+
360+
#[test]
361+
fn input_field_parameterizable_builder() {
362+
let field = InputField::new("test".into(), vec![InputType::int()], None, true).parameterizable();
363+
assert!(field.is_parameterizable());
364+
}
365+
366+
#[test]
367+
fn input_field_parameterizable_if_true() {
368+
let field = InputField::new("test".into(), vec![InputType::int()], None, true).parameterizable_if(true);
369+
assert!(field.is_parameterizable());
370+
}
371+
372+
#[test]
373+
fn input_field_parameterizable_if_false() {
374+
let field = InputField::new("test".into(), vec![InputType::int()], None, true).parameterizable_if(false);
375+
assert!(!field.is_parameterizable());
376+
}
377+
378+
#[test]
379+
fn input_field_builder_chain_preserves_parameterizable() {
380+
let field = InputField::new("test".into(), vec![InputType::int()], None, true)
381+
.parameterizable()
382+
.optional()
383+
.nullable();
384+
385+
assert!(field.is_parameterizable());
386+
assert!(!field.is_required());
387+
}
388+
}

0 commit comments

Comments
 (0)