Read GraphQL field types from file instead of from database
This commit is contained in:
@@ -1,12 +1,84 @@
|
||||
API_TYPE_DEFINITIONS = {
|
||||
User => %I[ id username gender geozone_id geozone ],
|
||||
Debate => %I[ id title description created_at cached_votes_total cached_votes_up cached_votes_down comments_count hot_score confidence_score geozone_id geozone comments public_author ],
|
||||
Proposal => %I[ id title description external_url cached_votes_up comments_count hot_score confidence_score created_at summary video_url geozone_id retired_at retired_reason retired_explanation geozone comments proposal_notifications public_author ],
|
||||
Comment => %I[ id commentable_id commentable_type body created_at cached_votes_total cached_votes_up cached_votes_down ancestry confidence_score public_author ],
|
||||
Geozone => %I[ id name ],
|
||||
ProposalNotification => %I[ title body proposal_id created_at proposal ],
|
||||
Tag => %I[ id name taggings_count kind ],
|
||||
Vote => %I[ votable_id votable_type created_at public_voter ]
|
||||
User => {
|
||||
id: :integer,
|
||||
username: :string,
|
||||
gender: :string,
|
||||
geozone_id: :integer,
|
||||
geozone: Geozone
|
||||
},
|
||||
Debate => {
|
||||
id: :integer,
|
||||
title: :string,
|
||||
description: :string,
|
||||
created_at: :string,
|
||||
cached_votes_total: :integer,
|
||||
cached_votes_up: :integer,
|
||||
cached_votes_down: :integer,
|
||||
comments_count: :integer,
|
||||
hot_score: :integer,
|
||||
confidence_score: :integer,
|
||||
geozone_id: :integer,
|
||||
geozone: Geozone,
|
||||
comments: [Comment],
|
||||
public_author: User
|
||||
},
|
||||
Proposal => {
|
||||
id: :integer,
|
||||
title: :string,
|
||||
description: :sting,
|
||||
external_url: :string,
|
||||
cached_votes_up: :integer,
|
||||
comments_count: :integer,
|
||||
hot_score: :integer,
|
||||
confidence_score: :integer,
|
||||
created_at: :string,
|
||||
summary: :string,
|
||||
video_url: :string,
|
||||
geozone_id: :integer,
|
||||
retired_at: :string,
|
||||
retired_reason: :string,
|
||||
retired_explanation: :string,
|
||||
geozone: Geozone,
|
||||
comments: [Comment],
|
||||
proposal_notifications: [ProposalNotification],
|
||||
public_author: User
|
||||
},
|
||||
Comment => {
|
||||
id: :integer,
|
||||
commentable_id: :integer,
|
||||
commentable_type: :string,
|
||||
body: :string,
|
||||
created_at: :string,
|
||||
cached_votes_total: :integer,
|
||||
cached_votes_up: :integer,
|
||||
cached_votes_down: :integer,
|
||||
ancestry: :string,
|
||||
confidence_score: :integer,
|
||||
public_author: User
|
||||
},
|
||||
Geozone => {
|
||||
id: :integer,
|
||||
name: :string
|
||||
},
|
||||
ProposalNotification => {
|
||||
title: :string,
|
||||
body: :string,
|
||||
proposal_id: :integer,
|
||||
created_at: :string,
|
||||
proposal: Proposal
|
||||
},
|
||||
Tag => {
|
||||
id: :integer,
|
||||
name: :string,
|
||||
taggings_count: :integer,
|
||||
kind: :string
|
||||
},
|
||||
Vote => {
|
||||
votable_id: :integer,
|
||||
votable_type: :string,
|
||||
created_at: :string,
|
||||
public_voter: User
|
||||
}
|
||||
}
|
||||
|
||||
type_creator = GraphQL::TypeCreator.new
|
||||
@@ -35,7 +107,7 @@ QueryRoot = GraphQL::ObjectType.define do
|
||||
type_creator.created_types.each do |model, created_type|
|
||||
|
||||
# create an entry field to retrive a single object
|
||||
if API_TYPE_DEFINITIONS[model].include?(:id)
|
||||
if API_TYPE_DEFINITIONS[model][:id]
|
||||
field model.name.underscore.to_sym do
|
||||
type created_type
|
||||
description "Find one #{model.model_name.human} by ID"
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
module GraphQL
|
||||
class TypeCreator
|
||||
# Return a GraphQL type for a 'database_type'
|
||||
TYPES_CONVERSION = Hash.new(GraphQL::STRING_TYPE).merge(
|
||||
SCALAR_TYPES = {
|
||||
integer: GraphQL::INT_TYPE,
|
||||
boolean: GraphQL::BOOLEAN_TYPE,
|
||||
float: GraphQL::FLOAT_TYPE,
|
||||
double: GraphQL::FLOAT_TYPE
|
||||
)
|
||||
double: GraphQL::FLOAT_TYPE,
|
||||
string: GraphQL::STRING_TYPE
|
||||
}
|
||||
|
||||
attr_accessor :created_types
|
||||
|
||||
@@ -14,7 +15,7 @@ module GraphQL
|
||||
@created_types = {}
|
||||
end
|
||||
|
||||
def create(model, field_names)
|
||||
def create(model, fields)
|
||||
type_creator = self
|
||||
|
||||
created_type = GraphQL::ObjectType.define do
|
||||
@@ -23,41 +24,43 @@ module GraphQL
|
||||
description("#{model.model_name.human}")
|
||||
|
||||
# Make a field for each column, association or method
|
||||
field_names.each do |field_name|
|
||||
if model.column_names.include?(field_name.to_s)
|
||||
field(field_name.to_s, TYPES_CONVERSION[model.columns_hash[field_name.to_s].type])
|
||||
else
|
||||
association = type_creator.class.association?(model, field_name)
|
||||
target_model = association.klass
|
||||
public_elements = target_model.respond_to?(:public_for_api) ? target_model.public_for_api : target_model.all
|
||||
|
||||
if type_creator.class.needs_pagination?(association)
|
||||
connection(association.name, -> { type_creator.created_types[target_model].connection_type }) do
|
||||
resolve -> (object, arguments, context) do
|
||||
object.send(association.name).all & public_elements.all
|
||||
end
|
||||
fields.each do |name, type|
|
||||
case GraphQL::TypeCreator.type_kind(type)
|
||||
when :scalar
|
||||
field name, SCALAR_TYPES[type]
|
||||
when :simple_association
|
||||
field(name, -> { type_creator.created_types[type] }) do
|
||||
resolve -> (object, arguments, context) do
|
||||
target_public_elements = type.respond_to?(:public_for_api) ? type.public_for_api : type.all
|
||||
wanted_element = object.send(name)
|
||||
target_public_elements.include?(wanted_element) ? wanted_element : nil
|
||||
end
|
||||
else
|
||||
field(association.name, -> { type_creator.created_types[target_model] }) do
|
||||
resolve -> (object, arguments, context) do
|
||||
linked_element = object.send(field_name)
|
||||
public_elements.include?(linked_element) ? linked_element : nil
|
||||
end
|
||||
end
|
||||
when :paginated_association
|
||||
type = type.first
|
||||
connection(name, -> { type_creator.created_types[type].connection_type }) do
|
||||
resolve -> (object, arguments, context) do
|
||||
target_public_elements = type.respond_to?(:public_for_api) ? type.public_for_api : type.all
|
||||
object.send(name).all & target_public_elements.all
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
created_types[model] = created_type
|
||||
return created_type # GraphQL::ObjectType
|
||||
end
|
||||
|
||||
def self.association?(model, field_name)
|
||||
model.reflect_on_all_associations.find { |a| a.name == field_name }
|
||||
def self.type_kind(type)
|
||||
if SCALAR_TYPES[type]
|
||||
:scalar
|
||||
elsif type.class == Class
|
||||
:simple_association
|
||||
elsif type.class == Array
|
||||
:paginated_association
|
||||
end
|
||||
end
|
||||
|
||||
def self.needs_pagination?(association)
|
||||
association.macro == :has_many
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -5,7 +5,7 @@ describe GraphQL::TypeCreator do
|
||||
|
||||
describe "::create" do
|
||||
it "creates fields for Int attributes" do
|
||||
debate_type = type_creator.create(Debate, %I[ id ])
|
||||
debate_type = type_creator.create(Debate, { id: :integer })
|
||||
created_field = debate_type.fields['id']
|
||||
|
||||
expect(created_field).to be_a(GraphQL::Field)
|
||||
@@ -14,7 +14,7 @@ describe GraphQL::TypeCreator do
|
||||
end
|
||||
|
||||
it "creates fields for String attributes" do
|
||||
debate_type = type_creator.create(Debate, %I[ title ])
|
||||
debate_type = type_creator.create(Debate, { title: :string })
|
||||
created_field = debate_type.fields['title']
|
||||
|
||||
expect(created_field).to be_a(GraphQL::Field)
|
||||
@@ -23,8 +23,8 @@ describe GraphQL::TypeCreator do
|
||||
end
|
||||
|
||||
it "creates connections for :belongs_to associations" do
|
||||
user_type = type_creator.create(User, %I[ id ])
|
||||
debate_type = type_creator.create(Debate, %I[ author ])
|
||||
user_type = type_creator.create(User, { id: :integer })
|
||||
debate_type = type_creator.create(Debate, { author: User })
|
||||
|
||||
connection = debate_type.fields['author']
|
||||
|
||||
@@ -34,8 +34,8 @@ describe GraphQL::TypeCreator do
|
||||
end
|
||||
|
||||
it "creates connections for :has_one associations" do
|
||||
user_type = type_creator.create(User, %I[ organization ])
|
||||
organization_type = type_creator.create(Organization, %I[ id ])
|
||||
user_type = type_creator.create(User, { organization: Organization })
|
||||
organization_type = type_creator.create(Organization, { id: :integer })
|
||||
|
||||
connection = user_type.fields['organization']
|
||||
|
||||
@@ -45,8 +45,8 @@ describe GraphQL::TypeCreator do
|
||||
end
|
||||
|
||||
it "creates connections for :has_many associations" do
|
||||
comment_type = type_creator.create(Comment, %I[ id ])
|
||||
debate_type = type_creator.create(Debate, %I[ comments ])
|
||||
comment_type = type_creator.create(Comment, { id: :integer })
|
||||
debate_type = type_creator.create(Debate, { comments: [Comment] })
|
||||
|
||||
connection = debate_type.fields['comments']
|
||||
|
||||
|
||||
Reference in New Issue
Block a user