Added support for associations (WITHOUT PAGINATION)

This commit is contained in:
Alberto Miedes Garcés
2016-11-08 22:19:16 +01:00
parent 277c784234
commit 49317e2c11
3 changed files with 63 additions and 18 deletions

View File

@@ -0,0 +1,8 @@
class ExposableAssociation
attr_reader :name, :type
def initialize(association)
@name = association.name
@type = association.macro # :has_one, :belongs_to or :has_many
end
end

View File

@@ -1,30 +1,35 @@
class ExposableModel
attr_reader :exposed_fields, :name, :description
attr_reader :name, :description, :exposed_fields, :exposed_associations
def initialize(model_class, options = {})
@model_class = model_class
@filter_list = options[:filter_list] || []
@name = model_class.name
@description = model_class.model_name.human
@field_filter_list = options[:field_filter_list] || []
@assoc_filter_list = options[:assoc_filter_list] || []
@filter_strategy = options[:filter_strategy]
set_exposed_fields
set_exposed_items(model_class)
end
private
# determine which model fields are exposed to the API
def set_exposed_fields
# determine which model fields and associations are exposed to the API
def set_exposed_items(model_class)
@exposed_fields = check_against_safety_list(model_class.columns, @field_filter_list)
@exposed_associations = check_against_safety_list(model_class.reflect_on_all_associations, @assoc_filter_list)
end
def check_against_safety_list(all_items, safety_list)
case @filter_strategy
when :whitelist
@exposed_fields = @model_class.columns.select do |column|
@filter_list.include? column.name
exposed_items = all_items.select do |column|
safety_list.include? column.name.to_s # works for both symbols and strings
end
when :blacklist
@exposed_fields = @model_class.columns.select do |column|
!(@filter_list.include? column.name)
exposed_items = all_items.select do |column|
!(safety_list.include? column.name.to_s)
end
else
@exposed_fields = []
exposed_items = []
end
end

View File

@@ -1,5 +1,6 @@
class TypeBuilder
attr_reader :filter_strategy, :graphql_models
attr_accessor :graphql_types # contains all generated GraphQL types
def initialize(graphql_models, options = {})
@graphql_models = graphql_models
@@ -31,14 +32,30 @@ private
type_builder = self
graphql_type = GraphQL::ObjectType.define do
em = ExposableModel.new(model_class, filter_strategy: type_builder.filter_strategy, filter_list: type_builder.graphql_models[model_class])
em = ExposableModel.new(
model_class,
filter_strategy: type_builder.filter_strategy,
field_filter_list: type_builder.graphql_models[model_class][:fields],
assoc_filter_list: type_builder.graphql_models[model_class][:associations]
)
name(em.name)
description(em.description)
em.exposed_fields.each do |column|
ef = ExposableField.new(column)
field(ef.name, ef.graphql_type)
field(ef.name, ef.graphql_type) # returns a GraphQL::Field
end
em.exposed_associations.each do |association|
ea = ExposableAssociation.new(association)
if ea.type.in? [:has_one, :belongs_to]
field(ea.name, -> { type_builder.graphql_types[association.klass] })
elsif ea.type.in? [:has_many]
field(ea.name, -> {
types[type_builder.graphql_types[association.klass]]
})
end
end
end
@@ -48,10 +65,25 @@ end
graphql_models = {}
graphql_models.store(User, ['id', 'username'])
graphql_models.store(Proposal, ['id', 'title', 'description', 'author_id', 'created_at'])
graphql_models.store(Debate, ['id', 'title', 'description', 'author_id', 'created_at'])
graphql_models.store(Comment, ['id', 'commentable_id', 'commentable_type', 'body'])
graphql_models.store(Geozone, ['id', 'name', 'html_map_coordinates'])
graphql_models.store(User, {
fields: ['id', 'username'],
associations: ['proposals', 'debates']
})
graphql_models.store(Proposal, {
fields: ['id', 'title', 'description', 'author_id', 'created_at'],
associations: ['author']
})
graphql_models.store(Debate, {
fields: ['id', 'title', 'description', 'author_id', 'created_at'],
associations: ['author']
})
graphql_models.store(Comment, {
fields: ['id', 'commentable_id', 'commentable_type', 'body'],
associations: ['author']
})
graphql_models.store(Geozone, {
fields: ['id', 'name', 'html_map_coordinates'],
associations: []
})
TYPE_BUILDER = TypeBuilder.new(graphql_models, filter_strategy: :whitelist)