Conversation
b76e355 to
ce88b46
Compare
ce88b46 to
e713a29
Compare
e713a29 to
381b7d6
Compare
| #[derive(Debug, Clone, PartialEq, Eq)] | ||
| pub enum SignatureError { | ||
| OperationNotFound(String), | ||
| AmbiguousOperation, | ||
| NoOperations, | ||
| } | ||
|
|
||
| impl std::fmt::Display for SignatureError { | ||
| fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||
| match self { | ||
| Self::OperationNotFound(name) => write!(f, "operation not found: {name}"), | ||
| Self::AmbiguousOperation => { | ||
| write!(f, "multiple operations found; specify operation name") | ||
| } | ||
| Self::NoOperations => write!(f, "no operations in document"), | ||
| } | ||
| } | ||
| } | ||
|
|
||
| impl std::error::Error for SignatureError {} |
There was a problem hiding this comment.
We could use thiserror to do this all in the enum definition I think
| OperationType::Query => "query", | ||
| OperationType::Mutation => "mutation", | ||
| OperationType::Subscription => "subscription", |
There was a problem hiding this comment.
We might be able to add strum::IntoStaticStr to the derive on OperationType and then this would just become .into()
| fn write_variable_type<E: ExecutableDocument>( | ||
| out: &mut String, | ||
| vt: &VariableTypeReference<'_, E::VariableType>, | ||
| ) { | ||
| match vt { | ||
| VariableTypeReference::Named(name, required) => { | ||
| out.push_str(name); | ||
| if *required { | ||
| out.push('!'); | ||
| } | ||
| } | ||
| VariableTypeReference::List(inner, required) => { | ||
| out.push('['); | ||
| write_variable_type::<E>(out, &inner.as_ref()); | ||
| out.push(']'); | ||
| if *required { | ||
| out.push('!'); | ||
| } | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
We do have VariableTypeReference::display_name which you could use I think, unless it is less performant due to allocating more strings
|
I'll chat more with @ravangen next week or so about this but there are a few more decisions we can make:
There's also a semantic and functional difference between normalizing for identity (like persisted operations) vs normalization as an execution view (does this operation fetch the same data at runtime?). The latter would require the schema but could include features like We could offer both in the future but I prefer to keep this simpler and static for now, operating on just the AST. |
Summary
Add
bluejay-operation-normalizercrate that produces canonical operation signatures following Apollo's enhanced operation signature algorithmOperation normalizer
Public API is two functions:
normalize(doc, op_name) -> Result<String, SignatureError>— canonical normalized stringsignature(doc, op_name) -> Result<String, SignatureError>— BLAKE3 hash of the normalized stringNormalization rules (Apollo enhanced mode):
0, strings →"", lists →[], object keys preserved with values normalized recursively, booleans/enums/null/variables preserved as-isBenchmarks: