Ruby GraphQL:在嵌入式对象上运行筛选器并调用自定义方法

时间:2019-03-17 03:43:42

标签: ruby graphql grape

我正在遵循在https://www.howtographql.com/graphql-ruby/0-introduction/上构建GraphQL API的绝对出色的教程

我的API框架是Grape,而Mongoid是我的数据库框架,但由于它使用ActiveRecord,因此其工作原理与rails非常相似

在使API端点正常工作并在现有REST API上定义了一些模型之后,我意识到我无法在子记录(数组)上编写方法和过滤器。我的感觉是,如果我在function类的cost_codes字段中添加JOBDATA::Types::JobType参数,它将解析参数,但是由于加载顺序,这是不可能的。在解决此类问题的其他框架中,您可以将类包装为字符串,以便在加载应用程序后按需加载,但graphql不支持。

已更新:我可以使用require相对值解决加载问题,但是搜索类不再过滤父级的子级元素,而是调用JOBDATA::CostCode.all并尝试加载整个集合

## this works on the parent, I have a custom method "orderBy"

{
  allJobs(orderBy: ["jobNumber:asc"]) {
    id,
    createdAt,
    updatedAt,
    jobNumber,
    description,
    status,
    costCodes { ## <-- by default returns the order of cost codes on the database
      id,
      createdAt,
      updatedAt,
      costCode,
      description
    }
  }
}

我需要做什么

{
  allJobs(orderBy: ["jobNumber:asc"]) {
    id,
    createdAt,
    updatedAt,
    jobNumber,
    description,
    status,
    costCodes(orderBy: ["costCode:asc"]) {
      id,
      createdAt,
      updatedAt,
      costCode,
      description
    }
  }
}

代码:

文件按以下顺序加载

module JOBDATA
  ## . . .

  ## GraphQL Files
  Dir.glob('./graphql/types/*.rb') { |file| load file }
  Dir.glob('./graphql/search_filters/*.rb') { |file| load file }
  Dir.glob('./graphql/resolvers/*.rb') { |file| load file }
  Dir.glob('./graphql/schemas/*.rb') { |file| load file }
end

首先加载的是'./graphql/types/cost_code_type.rb'

module JOBDATA
  module Types
    class CostCodeType < GraphQL::Introspection::BaseObject
      field :id, GraphQL::Types::ID, null: false
      field :created_at, GraphQL::Types::ISO8601DateTime, null: false
      field :updated_at, GraphQL::Types::ISO8601DateTime, null: false
      field :cost_code, GraphQL::Types::String, null: false
      field :description, GraphQL::Types::String, null: true
      field :status, GraphQL::Types::String, null: false
    end
  end
end

第二'./graphql/types/job_type.rb'

module JOBDATA
  module Types
    class JobType < GraphQL::Introspection::BaseObject
      field :id, GraphQL::Types::ID, null: false
      field :created_at, GraphQL::Types::ISO8601DateTime, null: false
      field :updated_at, GraphQL::Types::ISO8601DateTime, null: false
      field :job_number, GraphQL::Types::String, null: false
      field :description, GraphQL::Types::String, null: true
      field :status, GraphQL::Types::String, null: false
      field :cost_codes, [JOBDATA::Types::CostCodeType], null: false

      ## this seems like it should work - but because of the required load order I 
      ## I can force it using require relative, but rather than returning only the 
      ## parents children it returns everything for that collection agnostic to the 
      ## parent (its connected via has_many relationship on the parent) 
      # field :cost_codes, [JOBDATA::Types::CostCodeType], null: false, function: JOBDATA::SearchFilters::CostCode
    end
  end
end

第三'./graphql/search_filters/cost_code_search_filter.rb'

module JOBDATA
  module SearchFilters
    class CostCode
      include SearchObject.module(:graphql)
      scope { JOBDATA::CostCode.all }
      type types[JOBDATA::Types::CostCodeType]

      option :orderBy, type: types[types.String], with: :apply_order_by, default: ['cost_code:asc']

      def apply_order_by(scope, value)
        order_by = []
        value.each do |field|
          pair = field.split(':')
          order_by.push([pair[0].underscore, pair[1].downcase])
        end
        scope.order_by(order_by)
      end
    end
  end
end

第四'./graphql/search_filters/job_search_filter.rb'

module JOBDATA
  module SearchFilters
    class Job
      include SearchObject.module(:graphql)
      scope { JOBDATA::Job.all }
      type types[JOBDATA::Types::JobType]

      option :orderBy, type: types[types.String], with: :apply_order_by, default: ['job_number:asc']

      def apply_order_by(scope, value)
        order_by = []
        value.each do |field|
          pair = field.split(':')
          order_by.push([pair[0].underscore, pair[1].downcase])
        end
        scope.order_by(order_by)
      end
    end
  end
end

0 个答案:

没有答案