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

GraphQL Changeset API to rename a type #4211

Open
bessey opened this issue Sep 28, 2022 · 3 comments
Open

GraphQL Changeset API to rename a type #4211

bessey opened this issue Sep 28, 2022 · 3 comments

Comments

@bessey
Copy link
Contributor

bessey commented Sep 28, 2022

Is your feature request related to a problem? Please describe.

I am trying to change the graphql_name of a type using a Changeset, but the syntax is not valid

undefined method `graphql_name' for #<GraphQL::Enterprise::Changeset::Modification:0x0000ffff76e84fb0 @schema_member=Voyager::Types::Enums::AttemptServiceName, @changeset=Changesets::VoyagerAttemptServiceRename>

Describe the solution you'd like

class Changesets::ServiceNameRename < GraphQL::Enterprise::Changeset
  release "2022-09-28"

  modifies Types::Enums::ServiceName do
    graphql_name "BetterName"
  end
end

Describe alternatives you've considered

I guess this can also be achieved by creating a new type constant which extends the original, but call graphql_name to rename the new constant (or just relies on the new constant's name reflecting what we want the graphql_name to be). This seems needlessly laborious to me though.

@rmosolgo
Copy link
Owner

creating a new type constant which extends the original

Yep, that's the only way to do it currently. Under the hood, the idea that each type has exactly one name is used pretty strongly. However, it might be possible to introduce multiple-names-per-type -- I can take a look in the next couple of days and follow up here.

My thought would be to follow the same approach used for the other dynamic schema structure methods: add a context = GraphQL::Query::NullContext argument to def graphql_name, so that it can switch it return value on a per-query basis. Then update the underlying storage to support multiple names. Then update the code that builds Schema.types to check all graphql names when building that { name => [types] } map. This would also require a new method, for example, def all_graphql_names. Finally, Changeset would need a new method, def graphql_name, that registers the new name along with the changeset, and it would need an implementation of def graphql_name(context = GraphQL::Query::NullContext) that picks the right name for the incoming context.

So, it seems possible, but it'll require a bit of work 😅 !

@bessey
Copy link
Contributor Author

bessey commented Sep 29, 2022

👍 Well I've already handled this one case the type extension way. It's not too bad.

It did take me a while to wrap my head around the fact that to change a mutation's argument, I was not supposed to modify the individual mutation's class (extending GraphQL::Schema::Mutation), but instead modify the argument on the mutation field on the Mutation type 🤯. Some mutation specific pointers on https://graphql-ruby.org/changesets/definition.html wouldn't go amiss.

@bessey
Copy link
Contributor Author

bessey commented Jul 24, 2023

I ran into #4564 while working on a solution to this issue. In case it inspires an upstream API to get built heres ours:

We built a mixin for all object classes that wraps the built in GraphQL Enterprise Changesets API to make it a bit less laborious to replace a type throughout the entire schema, at once. Renaming a type is done by replacing it with an identical type by a different name, so this
is also useful for just renaming types.

Example: renaming an object Bovine to Cow

# Leave your existing type alone, and create a new type with the new name
class BovineType < Types::BaseObject
  field :name, String, null: false
end

# Since you want the same logic, you can extend your old type for DRY-ness
class CowType < BovineType
  replaces BovineType, in: Changesets::BovineToCowChangeset
end

class QueryType < Types::BaseObject
  # Now switch any references to the old type to the new type.
  # The framework will see that CowType.replaces is defined, and generate a backwards compatible API.
  # Note: If you want to rename the field as well, you're probably better off using plain GraphQL Ent Changesets.
  field :best_farm_animal, CowType, null: false
end

Under the hood we override field to generate two fields, one added_in: and one removed_in:. We also override visible? on both types to hide the appropriate type with Changeset's active? call.

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

No branches or pull requests

2 participants