3

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.

Alexis Delahaye
  • 644
  • 5
  • 18
  • I don't actually know GraphQL but one thing that popped out on me when reading the code is that `scope = scope.where('color_id = ?', value[:color_id])` will just set the local variable scope inside that method which is GC:ed instantly. You most likely want to use `self.scope = `. – max Mar 27 '20 at 09:49
  • yes good catch, in fact I simplified code, and I don't even need to assign scope in this dummy example, last value computed will be returned and all I need here is `scope.where`. In my real example I have several other filters so I assign scope everytime, and `.where` continuously and at the end of the filter method I return the variable – Alexis Delahaye Mar 27 '20 at 09:55

0 Answers0