Skip to content

Conversation

@rmosolgo
Copy link
Owner

@rmosolgo rmosolgo commented Feb 6, 2026

In a lot of cases, GraphQL schema configurations can be automatically future-proofed. I'm hoping to write development utility to do this.

It will require moving some instance methods to class methods, and replacing the instance method body to a class method.

It would also be nice to have a clean-up method that removed the instance methods once they are unused

I think it will need access to the in-memory Schema definition. That would allow it to search for inherited methods.

  • hash_key:
      • actually, GraphQL-Ruby currently tries both Symbol and String, regardless of what you pass here, but in the future, it will only use the given value, verbatim -- no conversion
  • method:
    • This is object.public_send(method_sym), it will work as written, no conversion required
  • resolver_method:
    • This can be preserved for legacy and possibly copied into a resolve_{each, batch, static}: class method. Calls methods on self or references to instance variables prevent auto-migration.
  • Implicit default
    • This can be migrated with an explicit multi-step resolve_each method, but first choice is to have the owner audit the application and choose either hash key or method.
  • resolver:, mutation:, subscription:
    • TODO: preserve forward-compatibility by resolving this out of the box, albeit with slightly different lifetime semantics, currently in the field compatibility shim
  • extras:
    • Some can be preserved; others cannot
  • extensions:
    • No forward compatibility here -- TODO what is the equivalent semantic for scope: true and connection: true in the gem? FutureStream also uses this. Can we use prepend to intercept the method call? Field singleton classes have a dedicated ::PreResolve module which contains these prepended methods? (This would create singleton classes for each field that uses it though, which is yuck, at least on old Ruby versions) Generate a method which calls the resolve_{each,batch,static} method?
  • dig:
    • TODO future compatibility for this is possible but not implemented
  • connection:, scope:
    • See todos for extensions: - not currently supportable but lots of possibilities
  • custom keywords
    • This should log a warning with some way to manually ignore this keyword and continue the migration
  • dataload(...), dataload_record(...), and dataload_association(...)
    • TODO implement new keywords for these eg field :post, Types::PostType, dataload_assocation: true # or dataload_association: :post

@gmac
Copy link
Contributor

gmac commented Feb 8, 2026

Something we’d highly recommend would be to have a migration path off the default resolver strategy that “figures out” what to do with an object. The decision tree has execution cost, although probably the bigger cost is in the upstream codebase where there are no consistency regulations for an object. For example, we have a prolific “Money” type that defines a value and currency. It gets resolved all over the place, except that some fields may resolve a formal Money object, others may resolve a hash of the relevant shape, etc. It’s a bit of a mess, and we realize now that it was the permissiveness of the default resolver that allowed us to be so sloppy. We have the same situation with lists where the engine permits anything that implements “each” as a list result, though this leads to frequent misuses where an each-able object is used as an array and results in error.

@rmosolgo
Copy link
Owner Author

rmosolgo commented Feb 9, 2026

Yes, agreed -- the new default behavior will be objects.map { |o| o.public_send(field_name_sym) } -- no falling back to hash key lookups.

For the migration, it will flag implicit-resolve-behavior fields with a note that the default behavior is changing and the field can be migrated by:

  • doing nothing and getting the .public_send(field_name) behavior
  • adding a hash_key: :field_name config
  • or preserving the current default by generating a method that checks for respond_to? or Hash.

@rmosolgo rmosolgo modified the milestone: 2.6.0 Feb 9, 2026
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.

2 participants