RStankov / SearchObjectGraphQL

GraphQL plugin for SearchObject gem
MIT License
159 stars 25 forks source link

Passing Scope as Argument #7

Closed jumichot closed 6 years ago

jumichot commented 6 years ago

Hi there,

I'm trying to build a reusable search with pagination. I followed the issue, I have a ListResolver :

  class ListBaseResolver < BaseSearchResolver
    include SearchObject.module(:kaminari)

    option :pagination, type: Types::PaginationInput, with: :pagination, default: {page: 1, per_page: 20}

    def self.call(object, args, context)
      search_object = new( filters: args.to_h, object:  object, context: context)

      results, paginate = search_object.results, args["pagination"]
      self.paginate_results(results, paginate)
    end

    private
    def self.paginate_results(results, paginate)
      records = results.page(paginate["page"]).per(paginate["per_page"])
      OpenStruct.new(
        results: records,
        current_page: records.current_page,
        total_count: records.total_count,
        pages_count: records.total_pages,
        per_page: paginate["per_page"]
      )
    end

    def pagination(scope, value); end
  end
end

An I'm using it in a search resolver :

module Resolvers
  class SiteSearch < Resolvers::ListBaseResolver

    PaginatedSites = type do
      name 'PaginatedSites'

      field :results, !types[Types::SiteType]
      field :current_page, !types.Int
      field :total_count, !types.Int
      field :pages_count, !types.Int
      field :per_page, !types.Int
    end
   ....
  end
end

In my query_type.rb file where I have my queries I tried to pass the scope :

  field :searchSites, Resolvers::SiteSearch::PaginatedSites do
    resolve ->(obj, args, ctx) {
      Resolvers::SiteSearch.new(scope: Client.first.sites)
    }
  end

But it's not working, I don't have access to pagination info, only the results key contain what I want.

What is the best way to change a resolver scope ?

If I put this in my query_type.rb file

 field :searchSites, function: Resolvers::SiteSearch

It's working perfectly but I don't know how to pass a scope dynamically that way

Thanks for your help

RStankov commented 6 years ago

Hi,

You can use the scope method from SearchObject

module Resolvers
  class SiteSearch < Resolvers::ListBaseResolver
    PaginatedSites = type do
      #...
    end

    # you can use `context` and `object` instance variables here
    # to find what scope you are needing
    scope { Client.first.sites } 
  end
end
jumichot commented 6 years ago

Thank you for your response. I know how to define scope this way but it's not dynamique. Is there a way to set the scope in my root query file where I specify the fields ?

I want to reuse my Resolvers::SiteSearch in different query fields with different scopes.

It's what I'm trying to do here but it's not working :

 field :searchSites, Resolvers::SiteSearch::PaginatedSites do
    resolve ->(obj, args, ctx) {
      Resolvers::SiteSearch.new(scope: Client.first.sites)
    }
  end

Cheers,

RStankov commented 6 years ago

I think, I get it. This is a bit tricky.

You can try something like the following:

module Resolvers
  class ListBaseResolver < BaseSearchResolver
    # ...

    # This would build new search class for that particular scope
    def self.with_scope(get_scope)
      Class.new(self) do
        scope do
        # This adds support for dynamic and static scopes
          if get_scope.respnd_to? :call
            get_scope.call(object, filters, context)
          else
            get_scope
          end
        end
      end
    end
  end
end

module Resolvers
  class SiteSearch < Resolvers::ListBaseResolver
    PaginatedSites = type do
      #...
    end
  end
end

# You can call this dynamically or statically
field :searchSites, Resolvers::SiteSearch::PaginatedSites.with_scope(->(obj, args, ctx) { Client.first.sites })
field :searchSites, Resolvers::SiteSearch::PaginatedSites.with_scope(Client.first.sites)