Skip to content

Implement schema merging#1443

Closed
ghost wants to merge 64 commits intosubgraph-compositionfrom
merged-schema
Closed

Implement schema merging#1443
ghost wants to merge 64 commits intosubgraph-compositionfrom
merged-schema

Conversation

@ghost
Copy link

@ghost ghost commented Jan 10, 2020

Jorge Olivero added 30 commits January 14, 2020 11:22
@ghost ghost force-pushed the subgraph-composition branch from 50fe5fb to 17f5d84 Compare January 14, 2020 17:26
@ghost ghost force-pushed the merged-schema branch from 5c92afd to 2b12994 Compare January 14, 2020 17:45
Comment on lines -1002 to +935
let document = graphql_parser::parse_schema(ROOT_SCHEMA).expect("Failed to parse root schema");
let document = graphql_parser::parse_schema(ROOT_SCHEMA).unwrap();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why drop the error message here (and in the following tests)?

pub enum SubgraphManifestValidationWarning {
#[fail(display = "schema validation produced warnings: {:?}", _0)]
SchemaValidationWarning(SchemaImportError),
SchemaImportError(SchemaImportError),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could just call this variant SchemaImport because it's already in the ...Warning enum.

Comment on lines +362 to +363
// TODO: Does anything guarantee that the introspection and subgraph query fields
// do not overlap?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would have to be checked during validation. What it needs to ensure is that no imported types (or type aliases) collide with local types / interfaces / enums. If that is the case then there will be no conflicts in the merged schema / query fields and introspection.

// If the schema is not available, then add a placeholder type to the root schema.
//
// If the schema is available, copy the type over.
// Check each field in the copied type and for non scalar fields, produce an (ImportedType, SchemaRefernce)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo: SchemaRefernce -> SchemaReference

Comment on lines +58 to +69
.find(|definition| {
if let Definition::TypeDefinition(TypeDefinition::Object(obj)) = definition
{
obj.name.eq(&original_name)
} else {
false
}
})
.map(|definition| match definition {
Definition::TypeDefinition(TypeDefinition::Object(obj)) => obj,
_ => unreachable!(),
})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hint hint: find_map will allow you to collapse these two combinators into one and only match the type definition kind once: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.find_map

let merged = merged_schema(&root_schema, schemas);

// Verify the output schema is correctl
match merged
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could make your life a whole lot easier if you just dump the merged GraphQL schema and compare it to an expected string. That'll also make it easier to understand the test. See https://docs.rs/graphql-parser/0.2.3/graphql_parser/#example-parse-and-format-schema for more info. It looks like given a GraphQL schema AST, dumping the schema is as simple as doing format!("{}", schema).

Comment on lines +421 to +442
match merged.document.get_object_type_definitions().iter().next() {
None => panic!("Failed to import placeholder for type `A`"),
Some(type_a) => {
// Has an id field
match type_a.fields.iter().find(|field| field.name.eq("id")) {
Some(_) => (),
_ => panic!("Placeholder for imported type does not have the correct fields"),
};

// Has a placeholder directive
match type_a
.directives
.iter()
.find(|directive| directive.name.eq("placeholder"))
{
Some(_) => (),
_ => {
panic!("Imported type `A` does not have a `@placeholder` directive");
}
}
}
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here (compare schema strings)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same in all other tests in this file. 😉

Comment on lines +708 to +722
// Cache entry is stale and an unstable import has changed or is now available
// TODO: Is it okay to ignore unstable imports which are no longer available?
// TODO: Make this threshold an envvar?
let requires_refresh = entry.last_refresh.elapsed().as_secs() >= 120
&& entry
.unstable_imports
.iter()
.any(|(schema_reference, subgraph_id_opt)| {
self.resolve_schema_reference(schema_reference)
.map(|schema| match subgraph_id_opt {
Some(subgraph_id) => schema.id.eq(subgraph_id),
None => true,
})
.unwrap_or(false)
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we also have to check the previously available schemas that were imported? Some of them might be gone now.

if let Some(entry) = self.schema_cache.lock().unwrap().get(&subgraph_id) {
// Cache entry is stale and an unstable import has changed or is now available
// TODO: Is it okay to ignore unstable imports which are no longer available?
// TODO: Make this threshold an envvar?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, an env var sounds good.

Comment on lines +760 to +765
.filter_map(|(schema_reference, schema)| match schema_reference {
SchemaReference::ByName(_) => {
Some((schema_reference.clone(), Some(schema.id.clone())))
}
_ => None,
})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aren't references by ID also unstable, as they may or may not be available all the time?

@ghost ghost force-pushed the subgraph-composition branch from 4e04f73 to f389c99 Compare February 10, 2020 19:03
@ghost ghost closed this Feb 13, 2020
@ghost ghost mentioned this pull request Feb 13, 2020
This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant