change value of a type's field depending on resolver argument in graphql-ruby

Viewed 1092

I'm trying to calculate a field's value of a Type, but I have to take in account the argument passed to my resolver by the user (query).

A dummy example:

Let's say I have two models in my rails app : Dog and Price (a Dog has_many prices, depending on it's color). So I have a calculated field on DogType : field :price, Float, null: true where I take object.prices.minimum(:price) , so far so good.

But when a user queries allDogs with an argument color: black (in order to have list with only black dogs), I do not want my calculated field price to return the wrong price of all dogs, so I have to take in account that a filter was given in my resolver, and therefore filter the prices in the type as well.

My question is concerning graphql-ruby but I'm interested in general about how to address such problems with GraphQL boilerplate : how to know properly in the object type, what filters were applied by the resolver ?

I followed this learn to do filtering so I have resolvers that look like this :

class Resolvers::DogsSearch < Resolvers::Base
  # scope is starting point for search
  scope { Dog.all }

  type types[Types::DogType]

  # inline input type definition for the advance filter
  class DogFilter < ::Types::BaseInputObject
    argument :color_id, ID, required: false
  end

  # when "filter" is passed "apply_filter" would be called to narrow the scope
  option :filter, type: DogFilter, with: :apply_filter

  def apply_filter(scope, value)
    if value[:color_id]
     # here's my take on how to do this : I store the filter in the context so I may access it later
     context[:color_id] = value[:color_id]
     self.scope = scope.where('color_id = ?', value[:color_id])
    end
  end
end
module Types
  class DogType < Types::BaseObject
    field :color_id, ID, null: false
    ...

    field :price, Float, null: true

    def price
      # I have to retrieve filter from context if any
      if context[:color_id]
        Price.where(dog: object, color_id: context[:color_id]).minimum(:price)
      else
        object.prices.minimum(:price)
      end
    end
  end
end

module Types
  class QueryType < BaseObject
    field :all_dogs, resolver: Resolvers::DogsSearch
  end
end

This works but seems really inefficient, not Rail's way and definitely prone to errors. I have to do this in multiple places of my app, and fear that it won't scale well.

Is there any official way of handling this ?

I simplified the real example I'm facing for comprehension's sake but I think my core problem revolve in this.

0 Answers
Related