-
Notifications
You must be signed in to change notification settings - Fork 327
Use SchemaTypeRef instead of Node<ObjectType> in ConnectedElement
#8626
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: benjamn/update-shape-to-0.7.0-preview
Are you sure you want to change the base?
Use SchemaTypeRef instead of Node<ObjectType> in ConnectedElement
#8626
Conversation
✅ Docs preview has no changesThe preview was not built because there were no changes. Build ID: fe2cf9a941104165200cc725 |
f2a3d0f to
a93d0b6
Compare
1deaed9 to
10ed3b5
Compare
a93d0b6 to
f3aafe4
Compare
| } else { | ||
| Some(Err(Message { | ||
| for arg in field.arguments.iter() { | ||
| // if let Some(input_type) = self.schema.types.get(arg.ty.inner_named_type()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✂️
| @@ -247,82 +262,128 @@ impl<'schema> ArgumentVisitor<'schema> { | |||
| fn enter_root_group( | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel this function could be simplified
| @@ -1,6 +1,7 @@ | |||
| --- | |||
| source: apollo-federation/src/connectors/validation/mod.rs | |||
| expression: "format!(\"{:#?}\", errors)" | |||
| assertion_line: 325 | |||
| expression: "format!(\"{:#?}\", result.errors)" | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
instead of doing this you can do use assert_debug_snapshot
| Connect::find_on_type(node, schema, all_source_names); | ||
| connects.extend(connects_for_type); | ||
| messages.extend(messages_for_type); | ||
| for (type_name, extended_type) in schema.types.iter().filter(|(_, ty)| !ty.is_built_in()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel this for-loop could be simplified with something like:
pseudo code
let (connects, messages): (Vec<_>, Vec<_>) = schema
.types
.iter()
.filter(|(_, ty)|
!ty.is_built_in() && // maybe split in 2 filters?
matches!(
ty,
ExtendedType::Object(_)
| ExtendedType::Interface(_)
| ExtendedType::Union(_)
))
.filter_map(|(type_name, _)| {
SchemaTypeRef::new(schema.schema, type_name)
})
.map(|type_ref| Connect::find_on_type(type_ref, schema, all_source_names))
.unzip();Advantage is that you do a single allocation to the vector instead of extending it multiple times
| schema: &'schema SchemaInfo, | ||
| source_names: &'schema [SourceName], | ||
| ) -> (Vec<Self>, Vec<Message>) { | ||
| let object_category = if schema | ||
| .schema_definition | ||
| .query | ||
| .as_ref() | ||
| .is_some_and(|query| query.name == object.name) | ||
| .is_some_and(|query| query.name == *type_ref.name()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why not something like:
.is_some_and(|query| &query.name == type_ref.name())| // mark the field with a @connect directive as seen | ||
| seen.push(ResolvedField { | ||
| object_name: parent_type.name.clone(), | ||
| object_name: parent_type.name().clone(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
too many clones on this field, parent_type.name().clone(), would it make sense to use it as ref? or wrap it in an Arc?
| .last() | ||
| .and_then(|parent_name| SchemaTypeRef::new(self.0, parent_name)) | ||
| .map(|parent_ref| parent_ref.is_abstract()) | ||
| .unwrap_or(false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unwrap or default is equals to false
| self.2 | ||
| } | ||
|
|
||
| #[allow(dead_code)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why so much dead code?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe use #[expect(dead_code)] instead of allow, so we can remove the flag when it is actually in use
| .into_iter() | ||
| .flat_map(|ty| match ty { | ||
| ExtendedType::Object(o) => { | ||
| let mut map = IndexMap::default(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ExtendedType::Object(o) => {
o.fields
.get(field_name)
.map(|field_def| {
std::iter::once((o.name.clone(), field_def))
.collect::<IndexMap<_, _>>()
})
.unwrap_or_default()
}or, if you prefer if let
ExtendedType::Object(o) => {
if let Some(field_def) = o.fields.get(field_name) {
std::iter::once((o.name.clone(), field_def))
.collect()
} else {
IndexMap::new()
}
}| map | ||
| } | ||
|
|
||
| ExtendedType::Interface(i) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe something like this here as well:
Pseudo codde
ExtendedType::Interface(i) => {
self.0
.implementers_map()
.get(i.name.as_str())
.map(|implementers| {
implementers
.objects
.iter()
.chain(&implementers.interfaces)
.filter_map(|name| SchemaTypeRef::new(self.0, name.as_str()))
.flat_map(|tref| tref.get_fields(field_name).into_iter())
.collect::<IndexMap<_, _>>()
})
.unwrap_or_default()
}| let coordinate = ConnectDirectiveCoordinate { | ||
| element: ConnectedElement::Field { | ||
| parent_type: object, | ||
| parent_type: SchemaTypeRef::from_node(&schema, object).unwrap(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can this panic?
10ed3b5 to
19253d8
Compare
a77dfd2 to
8d679e0
Compare
19253d8 to
71872d5
Compare
8d679e0 to
eaf069f
Compare
71872d5 to
4fd9902
Compare
eaf069f to
e16d56d
Compare
4fd9902 to
9504be3
Compare
e16d56d to
9f44e1c
Compare
9504be3 to
6a6cfea
Compare
9f44e1c to
41756d9
Compare
A SchemaTypeRef is a reference to a &Schema as well as the &Name and &ExtendedType of some named type within the schema, all with the same 'schema lifetime. The SchemaTypeRef::new method returns an Option<SchemaTypeRef> to guarantee that SchemaTypeRef references are only created for actual schema types. Because SchemaTypeRef has access to the Schema (not just an individual element), it can perform operations that are aware of other types within the same schema, like finding all the implementing/member types of an interface or union. Because SchemaTypeRef can represent any named type in the schema, not just ObjectType, these changes should lay some of the necessary groundwork for working with abstract types, where the type in question might be an InterfaceType or UnionType. After some earlier attempts, I've decided it's important to use a type like SchemaTypeRef that still implements the Copy trait, rather than (say) ExtendedType, so we don't have to update all the data structures that assume they can implement Copy while using ConnectedElement.
Co-authored-by: copilot-swe-agent[bot] <[email protected]>
6a6cfea to
1ce8d37
Compare
41756d9 to
56ab2fc
Compare
This PR represents a combination/cherry-picking of several commits from my abstract types PR #8143 (which I am currently attempting to simplify for easier review).
A
SchemaTypeRefis a reference to a&Schemaas well as the&Nameand&ExtendedTypeof some named type within the schema, all with the same'schemalifetime. TheSchemaTypeRef::newmethod returns anOption<SchemaTypeRef>to guarantee thatSchemaTypeRefreferences are only created for actual schema types, so if you have aSchemaTypeRefyou can be sure the type it represents exists in the schema.Because
SchemaTypeRefhas access to theSchema(not just the individual element), it can perform operations that are aware of other types within the same schema, like finding all the implementing/member types of an interface or union.Further, since
SchemaTypeRefcan represent any named type in the schema, not justObjectType, these changes should lay some of the necessary groundwork for working with abstract types, where the type in question might be anInterfaceTypeorUnionType(not justObjectType).After some earlier attempts, I've decided it's important to use a type like
SchemaTypeRefthat still implements theCopytrait (by holding only references), rather than (say)ExtendedType(which must beCloned), so we don't have to update all the data structures that assume they can implementCopywhile usingConnectedElement.