Я следовал абсолютно звездному руководству по созданию API GraphQL на https://www.howtographql.com/graphql-ruby/0-introduction/
Моя структура API - Grape, а Mongoid - моя база данных, но она очень похожа на rails, поскольку использует ActiveRecord
После того, как моя конечная точка API заработала и определив некоторые модели в существующем API REST, я понял, что не могу писать методы и фильтры для дочерних записей (массив).Мне кажется, что если я добавлю аргумент function
в поле cost_codes
в классе JOBDATA::Types::JobType
, он будет разрешать аргументы, однако из-за порядка загрузки это невозможно.В других средах для решения такого рода проблем вы можете заключить ваш класс в строку, чтобы он загружался по требованию после загрузки приложения, но это не поддерживается в GraphQL.
updated: я могу разрешить загрузкупроблема с requirelative, но тогда мой класс поиска больше не фильтрует дочерние элементы родителя, вместо этого он вызывает 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