Skip to content

Commit

Permalink
Run schema validation in parallel
Browse files Browse the repository at this point in the history
Reviewed By: monicatang

Differential Revision: D58431025

fbshipit-source-id: 85bdd0d01d424e98f75ed22a259ad48da8ec5a27
  • Loading branch information
captbaritone authored and facebook-github-bot committed Jun 12, 2024
1 parent 5f82667 commit ef22ae6
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 41 deletions.
1 change: 1 addition & 0 deletions compiler/crates/schema-validate/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ fnv = "1.0"
graphql-cli = { path = "../graphql-cli" }
intern = { path = "../intern" }
lazy_static = "1.4"
rayon = "1.9.0"
regex = "1.9.2"
schema = { path = "../schema" }
serde = { version = "1.0.185", features = ["derive", "rc"] }
Expand Down
93 changes: 52 additions & 41 deletions compiler/crates/schema-validate/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use intern::string_key::Intern;
use intern::string_key::StringKey;
use intern::Lookup;
use lazy_static::lazy_static;
use rayon::prelude::*;
use regex::Regex;
use schema::EnumID;
use schema::Field;
Expand Down Expand Up @@ -58,7 +59,7 @@ pub struct SchemaValidationOptions {
}

pub fn validate(schema: &SDLSchema, options: SchemaValidationOptions) -> DiagnosticsResult<()> {
let mut validation_context = ValidationContext::new(schema, options);
let mut validation_context = ValidationContext::new(schema, &options);
validation_context.validate();
if validation_context.diagnostics.is_empty() {
Ok(())
Expand All @@ -72,12 +73,12 @@ pub fn validate(schema: &SDLSchema, options: SchemaValidationOptions) -> Diagnos

pub struct ValidationContext<'schema> {
schema: &'schema SDLSchema,
options: SchemaValidationOptions,
options: &'schema SchemaValidationOptions,
diagnostics: Vec<Diagnostic>,
}

impl<'schema> ValidationContext<'schema> {
pub fn new(schema: &'schema SDLSchema, options: SchemaValidationOptions) -> Self {
pub fn new(schema: &'schema SDLSchema, options: &'schema SchemaValidationOptions) -> Self {
Self {
schema,
options,
Expand Down Expand Up @@ -143,47 +144,57 @@ impl<'schema> ValidationContext<'schema> {
}

fn validate_types(&mut self) {
let types = self.schema.get_type_map();
for (type_name, type_) in types {
// Ensure it is named correctly (excluding introspection types).
if !is_introspection_type(type_, *type_name) {
self.validate_name(*type_name, self.get_type_definition_location(*type_));
let diagnostics = self
.schema
.get_type_map_par_iter()
.flat_map(|(type_name, type_)| {
let mut child_visitor = Self::new(self.schema, self.options);
child_visitor.validate_type(*type_name, type_);
child_visitor.diagnostics
})
.collect::<Vec<Diagnostic>>();
self.diagnostics.extend(diagnostics);
}

fn validate_type(&mut self, type_name: StringKey, type_: &Type) {
// Ensure it is named correctly (excluding introspection types).
if !is_introspection_type(type_, type_name) {
self.validate_name(type_name, self.get_type_definition_location(*type_));
}
match type_ {
Type::Enum(id) => {
// Ensure Enums have valid values.
self.validate_enum_type(*id);
}
match type_ {
Type::Enum(id) => {
// Ensure Enums have valid values.
self.validate_enum_type(*id);
}
Type::InputObject(id) => {
// Ensure Input Object fields are valid.
self.validate_input_object_fields(*id);
}
Type::Interface(id) => {
let interface = self.schema.interface(*id);
// Ensure fields are valid
self.validate_fields(*type_name, &interface.fields);

// Validate cyclic references
if !self.validate_cyclic_implements_reference(interface) {
// Ensure interface implement the interfaces they claim to.
self.validate_type_with_interfaces(interface);
}
Type::InputObject(id) => {
// Ensure Input Object fields are valid.
self.validate_input_object_fields(*id);
}
Type::Interface(id) => {
let interface = self.schema.interface(*id);
// Ensure fields are valid
self.validate_fields(type_name, &interface.fields);

// Validate cyclic references
if !self.validate_cyclic_implements_reference(interface) {
// Ensure interface implement the interfaces they claim to.
self.validate_type_with_interfaces(interface);
}
Type::Object(id) => {
let object = self.schema.object(*id);
// Ensure fields are valid
self.validate_fields(*type_name, &object.fields);
}
Type::Object(id) => {
let object = self.schema.object(*id);
// Ensure fields are valid
self.validate_fields(type_name, &object.fields);

// Ensure objects implement the interfaces they claim to.
self.validate_type_with_interfaces(object);
}
Type::Union(id) => {
// Ensure Unions include valid member types.
self.validate_union_members(*id);
}
Type::Scalar(_id) => {}
};
}
// Ensure objects implement the interfaces they claim to.
self.validate_type_with_interfaces(object);
}
Type::Union(id) => {
// Ensure Unions include valid member types.
self.validate_union_members(*id);
}
Type::Scalar(_id) => {}
};
}

fn validate_fields(&mut self, type_name: StringKey, fields: &[FieldID]) {
Expand Down
6 changes: 6 additions & 0 deletions compiler/crates/schema/src/in_memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ use graphql_syntax::*;
use intern::string_key::Intern;
use intern::string_key::StringKey;
use intern::Lookup;
use rayon::iter::IntoParallelRefIterator;
use rayon::iter::ParallelIterator;

use crate::definitions::Argument;
use crate::definitions::Directive;
Expand Down Expand Up @@ -334,6 +336,10 @@ impl InMemorySchema {
self.type_map.iter()
}

pub fn get_type_map_par_iter(&self) -> impl ParallelIterator<Item = (&StringKey, &Type)> {
self.type_map.par_iter()
}

pub fn get_directives(&self) -> impl Iterator<Item = &Directive> {
self.directives.values()
}
Expand Down
8 changes: 8 additions & 0 deletions compiler/crates/schema/src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use common::DirectiveName;
use common::SourceLocationKey;
use graphql_syntax::*;
use intern::string_key::StringKey;
use rayon::iter::ParallelIterator;

use crate::definitions::Directive;
use crate::definitions::*;
Expand Down Expand Up @@ -345,6 +346,13 @@ impl SDLSchema {
}
}

pub fn get_type_map_par_iter(&self) -> impl ParallelIterator<Item = (&StringKey, &Type)> {
match self {
SDLSchema::FlatBuffer(_schema) => todo!(),
SDLSchema::InMemory(schema) => schema.get_type_map_par_iter(),
}
}

pub fn get_directives(&self) -> impl Iterator<Item = &Directive> {
match self {
SDLSchema::FlatBuffer(_schema) => todo!(),
Expand Down

0 comments on commit ef22ae6

Please sign in to comment.