Skip to content
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

breaking(compiler): unify find_operation #447

Merged
merged 3 commits into from Feb 10, 2023
Merged

breaking(compiler): unify find_operation #447

merged 3 commits into from Feb 10, 2023

Conversation

lrlna
Copy link
Member

@lrlna lrlna commented Feb 3, 2023

Mimics spec's getOperation functionality and returns the anonymous operation if None is specified for operation name.

Mimics spec's [`getOperation`](https://spec.graphql.org/October2021/#GetOperation()) functionality and returns the anonymous operation if `None` is specified for operation name.
@lrlna lrlna self-assigned this Feb 3, 2023
Copy link
Member

@goto-bus-stop goto-bus-stop left a comment

Choose a reason for hiding this comment

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

nice this does read much better 😄

Comment on lines 42 to 48
db: &dyn HirDatabase,
file_id: FileId,
name: String,
) -> Option<Arc<OperationDefinition>> {
db.operations(file_id)
.iter()
.find(|def| def.name() == Some(&*name))
.cloned()
}

pub(crate) fn find_anonymous_operation(
pub(crate) fn find_operation(
db: &dyn HirDatabase,
file_id: FileId,
name: Option<String>,
) -> Option<Arc<OperationDefinition>> {
db.operations(file_id)
.iter()
.find(|def| def.name().is_none())
.find(|def| def.name() == name.as_deref())
Copy link
Contributor

@SimonSapin SimonSapin Feb 6, 2023

Choose a reason for hiding this comment

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

When the name parameter is None is looks for an anonymous operation. This deviates from the spec’s algorithm, which instead does something like:

let definitions = db.operations(file_id);
if let Some(name) = name {
    definitions.iter().find(|def| def.name() == Some(&*name))
} else if definitions.len() == 1 {
    // The definition’s `.name()` doesn’t matter
    definitions[0].clone()
} else {
    None
}

Copy link
Member Author

Choose a reason for hiding this comment

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

oh, good catch, i misread that entirely!

Copy link
Member Author

Choose a reason for hiding this comment

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

we don't (yet, or maybe even never?) return Result from these kinds of queries, so if None is provided and there are several operation definitions, this function will return None. Does that sound ok to everyone? @SimonSapin @goto-bus-stop?

compiler.update_executable(op_id, several_named_op);
let op = compiler.db.find_operation(op_id, Some("getName".into()));
assert!(op.is_some());
let op = compiler.db.find_operation(op_id, None);
assert!(op.is_none());

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, sounds good. Depending on whether the parameter is None (which the caller knows of course) in each case there’s only one error case, so it’s fine IMO to have a None return value represent it.

Copy link
Member Author

Choose a reason for hiding this comment

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

@SimonSapin could you re-review then?

Copy link
Contributor

@SimonSapin SimonSapin left a comment

Choose a reason for hiding this comment

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

Sorry, I think this still doesn’t quite match the spec. The path checking len() == 1 should only be taken when the name parameter is None. The path searching for a given def.name() should only be taken when the parameter is Some.

Or expressed as test cases:

  • With query A { b }, find_operation(Some("C")) should return None because we ask for a specific name that isn’t there
  • With query D { e } query { f }, find_operation(None) should return None because not specifying a name is ambiguous when there are multiple definitions.

@SimonSapin
Copy link
Contributor

By the way, as far as I can tell that second document does not raise a validation error for Operation Name Uniqueness nor for Lone Anonymous Operation, but that anonymous operation is impossible to execute!

Copy link
Contributor

@SimonSapin SimonSapin left a comment

Choose a reason for hiding this comment

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

👍

@lrlna
Copy link
Member Author

lrlna commented Feb 10, 2023

well this has been a bad week!!

By the way, as far as I can tell that second document does not raise a validation error for Operation Name Uniqueness nor for Lone Anonymous Operation, but that anonymous operation is impossible to execute!

I don't think so. It's an update_executable function, which means the executables get overwritten, so there is no name conflicts.

@lrlna lrlna merged commit 5a25060 into main Feb 10, 2023
@lrlna lrlna deleted the find_operation branch February 10, 2023 11:37
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.

None yet

3 participants