First simple API version with autogenerated GraphQL types
This commit is contained in:
26
app/graph/exposable_field.rb
Normal file
26
app/graph/exposable_field.rb
Normal file
@@ -0,0 +1,26 @@
|
||||
class ExposableField
|
||||
attr_reader :name, :graphql_type
|
||||
|
||||
def initialize(column, options = {})
|
||||
@name = column.name
|
||||
@graphql_type = ExposableField.convert_type(column.type)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Return a GraphQL type for 'database_type'
|
||||
def self.convert_type(database_type)
|
||||
case database_type
|
||||
when :integer
|
||||
GraphQL::INT_TYPE
|
||||
when :boolean
|
||||
GraphQL::BOOLEAN_TYPE
|
||||
when :float
|
||||
GraphQL::FLOAT_TYPE
|
||||
when :double
|
||||
GraphQL::FLOAT_TYPE
|
||||
else
|
||||
GraphQL::STRING_TYPE
|
||||
end
|
||||
end
|
||||
end
|
||||
31
app/graph/exposable_model.rb
Normal file
31
app/graph/exposable_model.rb
Normal file
@@ -0,0 +1,31 @@
|
||||
class ExposableModel
|
||||
attr_reader :exposed_fields, :name, :description
|
||||
|
||||
def initialize(model_class, options = {})
|
||||
@model_class = model_class
|
||||
@filter_list = options[:filter_list] || []
|
||||
@name = model_class.name
|
||||
@description = model_class.model_name.human
|
||||
@filter_strategy = options[:filter_strategy]
|
||||
set_exposed_fields
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# determine which model fields are exposed to the API
|
||||
def set_exposed_fields
|
||||
case @filter_strategy
|
||||
when :whitelist
|
||||
@exposed_fields = @model_class.columns.select do |column|
|
||||
@filter_list.include? column.name
|
||||
end
|
||||
when :blacklist
|
||||
@exposed_fields = @model_class.columns.select do |column|
|
||||
!(@filter_list.include? column.name)
|
||||
end
|
||||
else
|
||||
@exposed_fields = []
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@@ -3,7 +3,7 @@ QueryRoot = GraphQL::ObjectType.define do
|
||||
description "The query root for this schema"
|
||||
|
||||
field :proposal do
|
||||
type ProposalType
|
||||
type TYPE_BUILDER.types[Proposal]
|
||||
description "Find a Proposal by id"
|
||||
argument :id, !types.ID
|
||||
resolve -> (object, arguments, context) {
|
||||
@@ -11,7 +11,8 @@ QueryRoot = GraphQL::ObjectType.define do
|
||||
}
|
||||
end
|
||||
|
||||
connection :proposals, ProposalType.connection_type do
|
||||
field :proposals do
|
||||
type types[TYPE_BUILDER.types[Proposal]]
|
||||
description "Find all Proposals"
|
||||
resolve -> (object, arguments, context) {
|
||||
Proposal.all
|
||||
@@ -19,7 +20,7 @@ QueryRoot = GraphQL::ObjectType.define do
|
||||
end
|
||||
|
||||
field :debate do
|
||||
type DebateType
|
||||
type TYPE_BUILDER.types[Debate]
|
||||
description "Find a Debate by id"
|
||||
argument :id, !types.ID
|
||||
resolve -> (object, arguments, context) {
|
||||
@@ -27,7 +28,8 @@ QueryRoot = GraphQL::ObjectType.define do
|
||||
}
|
||||
end
|
||||
|
||||
connection :debates, DebateType.connection_type do
|
||||
field :debates do
|
||||
type types[TYPE_BUILDER.types[Debate]]
|
||||
description "Find all Debates"
|
||||
resolve -> (object, arguments, context) {
|
||||
Debate.all
|
||||
@@ -35,7 +37,7 @@ QueryRoot = GraphQL::ObjectType.define do
|
||||
end
|
||||
|
||||
field :comment do
|
||||
type CommentType
|
||||
type TYPE_BUILDER.types[Comment]
|
||||
description "Find a Comment by id"
|
||||
argument :id, !types.ID
|
||||
resolve -> (object, arguments, context) {
|
||||
@@ -43,7 +45,8 @@ QueryRoot = GraphQL::ObjectType.define do
|
||||
}
|
||||
end
|
||||
|
||||
connection :comments, CommentType.connection_type do
|
||||
field :comments do
|
||||
type types[TYPE_BUILDER.types[Comment]]
|
||||
description "Find all Comments"
|
||||
resolve -> (object, arguments, context) {
|
||||
Comment.all
|
||||
@@ -51,7 +54,7 @@ QueryRoot = GraphQL::ObjectType.define do
|
||||
end
|
||||
|
||||
field :user do
|
||||
type UserType
|
||||
type TYPE_BUILDER.types[User]
|
||||
description "Find a User by id"
|
||||
argument :id, !types.ID
|
||||
resolve -> (object, arguments, context) {
|
||||
57
app/graph/type_builder.rb
Normal file
57
app/graph/type_builder.rb
Normal file
@@ -0,0 +1,57 @@
|
||||
class TypeBuilder
|
||||
attr_reader :filter_strategy, :graphql_models
|
||||
|
||||
def initialize(graphql_models, options = {})
|
||||
@graphql_models = graphql_models
|
||||
@graphql_types = {}
|
||||
|
||||
# determine filter strategy for this field
|
||||
if (options[:filter_strategy] == :blacklist)
|
||||
@filter_strategy = :blacklist
|
||||
else
|
||||
@filter_strategy = :whitelist
|
||||
end
|
||||
|
||||
create_all_types
|
||||
end
|
||||
|
||||
def types
|
||||
@graphql_types
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def create_all_types
|
||||
@graphql_models.keys.each do |model_class|
|
||||
@graphql_types[model_class] = create_type(model_class)
|
||||
end
|
||||
end
|
||||
|
||||
def create_type(model_class)
|
||||
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])
|
||||
|
||||
name(em.name)
|
||||
description(em.description)
|
||||
|
||||
em.exposed_fields.each do |column|
|
||||
ef = ExposableField.new(column)
|
||||
field(ef.name, ef.graphql_type)
|
||||
end
|
||||
end
|
||||
|
||||
return graphql_type
|
||||
end
|
||||
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'])
|
||||
|
||||
TYPE_BUILDER = TypeBuilder.new(graphql_models, filter_strategy: :whitelist)
|
||||
@@ -46,7 +46,7 @@ module Consul
|
||||
config.paths['app/views'].unshift(Rails.root.join('app', 'views', 'custom'))
|
||||
|
||||
# Add GraphQL directories to the autoload path
|
||||
config.autoload_paths << Rails.root.join('app', 'graph', 'types')
|
||||
config.autoload_paths << Rails.root.join('app', 'graph')
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user