Skip to content

Commit

Permalink
Merge pull request #4 from paidy/AIM-1482-limit-allowed-aliases
Browse files Browse the repository at this point in the history
[AIM-1482] limit number of aliases per query
  • Loading branch information
aneesh-reddy-paidy authored Oct 9, 2024
2 parents 7fd58bc + b48a126 commit eb8a575
Show file tree
Hide file tree
Showing 2 changed files with 184 additions and 1 deletion.
181 changes: 181 additions & 0 deletions juniper/src/validation/rules/limit_number_of_aliases.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
use crate::{
ast::{Field, Operation},
parser::Spanning,
validation::{ValidatorContext, Visitor},
value::ScalarValue,
};

pub struct Aliases {
alias_count: u8,
max_allowed: u8,
}

pub fn factory<'a>() -> Aliases {
Aliases {
alias_count: 0,
max_allowed: 3,
}
}

impl<'a, S> Visitor<'a, S> for Aliases
where
S: ScalarValue,
{
fn enter_operation_definition(
&mut self,
_ctx: &mut ValidatorContext<'a, S>,
_op: &'a Spanning<Operation<'a, S>>,
) {
self.alias_count = 0; // Reset for each operation
}

fn enter_field(
&mut self,
ctx: &mut ValidatorContext<'a, S>,
field: &'a Spanning<Field<'a, S>>,
) {
let alias_name = &field.item.alias; // Get the Spanning<String> for the alias

if let Some(alias) = alias_name {
self.alias_count += 1;
if self.alias_count > self.max_allowed {
ctx.report_error(&error_message(&alias.item), &[alias.start]);
}
}
}
}

fn error_message(alias_name: &str) -> String {
format!("Illegal number of aliases, {} is not allowed", alias_name)
}

#[cfg(test)]
mod tests {
use super::{error_message, factory};

use crate::{
parser::SourcePosition,
validation::{expect_fails_rule, expect_passes_rule, RuleError},
value::DefaultScalarValue,
};

#[test]
fn single_alias_allowed() {
expect_passes_rule::<_, _, DefaultScalarValue>(
factory,
r#"
mutation CreateLiquidToken {
liquidApplication: createLiquidSdkApplication {
token
applicantId
}
}
"#,
);

expect_passes_rule::<_, _, DefaultScalarValue>(
factory,
r#"
mutation UpdateLiquidToken {
liquidApplication: createLiquidSdkUpdateApplication {
token
applicantId
}
}
"#,
);
}

#[test]
fn multiple_alias_allowed() {
expect_passes_rule::<_, _, DefaultScalarValue>(
factory,
r#"
query Hero {
empireHero: hero(episode: EMPIRE) {
name
}
jediHero: hero(episode: JEDI) {
name
}
republicHero: hero(episode: REPUBLIC) {
name
}
"#,
);
}

#[test]
fn multiple_field_aliases_not_allowed() {
expect_fails_rule::<_, _, DefaultScalarValue>(
factory,
r#"
query MyQuery {
myField1: my_field,
myField2: my_field,
myField3: my_field,
myField4: my_field,
myField5: my_field
}
"#,
&[
RuleError::new(
&error_message("myField4"),
&[SourcePosition::new(133, 5, 12)],
),
RuleError::new(
&error_message("myField5"),
&[SourcePosition::new(165, 6, 12)],
),
],
);
}

#[test]
fn multiple_query_aliases_not_allowed() {
expect_fails_rule::<_, _, DefaultScalarValue>(
factory,
r#"
query Hero {
empireHero: hero(episode: EMPIRE) {
name
}
jediHero: hero(episode: JEDI) {
name
}
republicHero: hero(episode: REPUBLIC) {
name
}
republicH3ro: hero(episode: REPUBLIC) {
name
}
republicH4ro: hero(episode: REPUBLIC) {
name
}
}
"#,
&[
RuleError::new(
&error_message("republicH3ro"),
&[SourcePosition::new(268, 8, 12)],
),
RuleError::new(
&error_message("republicH4ro"),
&[SourcePosition::new(342, 8, 12)],
),
],
);
}

#[test]
fn no_aliases() {
expect_passes_rule::<_, _, DefaultScalarValue>(
factory,
r#"
query MyQuery {
my_field
}
"#,
);
}
}
4 changes: 3 additions & 1 deletion juniper/src/validation/rules/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ mod known_argument_names;
mod known_directives;
mod known_fragment_names;
mod known_type_names;
mod limit_number_of_aliases;
mod lone_anonymous_operation;
mod no_fragment_cycles;
mod no_undefined_variables;
Expand Down Expand Up @@ -65,7 +66,8 @@ where
.with(self::unique_operation_names::factory())
.with(self::unique_variable_names::factory())
.with(self::variables_are_input_types::factory())
.with(self::variables_in_allowed_position::factory());
.with(self::variables_in_allowed_position::factory())
.with(self::limit_number_of_aliases::factory());
visit(&mut stage1, ctx, doc);
if ctx.has_errors() {
return;
Expand Down

0 comments on commit eb8a575

Please sign in to comment.