-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add basic query support with Mongoid extension
- Loading branch information
1 parent
6d75b8c
commit 0398e80
Showing
13 changed files
with
371 additions
and
16 deletions.
There are no files selected for viewing
10 changes: 7 additions & 3 deletions
10
...ntrollers/graphql/rails/api_controller.rb → ...ollers/graphql/rails/schema_controller.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
GraphiQL::Rails.config.csrf = true |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,11 @@ | ||
Rails.application.routes.draw do | ||
# TODO: Support all verbs | ||
# TODO: Load path from configuration | ||
post '/api/graph' => 'graphql/rails/api#execute' | ||
module GraphQL | ||
module Rails | ||
Engine.routes.draw do | ||
if Rails.config.graphiql | ||
mount GraphiQL::Rails::Engine => '/', :graphql_path => :self | ||
end | ||
|
||
post '/' => 'schema#execute' | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,12 @@ | ||
require 'rails' | ||
require 'graphql' | ||
require 'graphql/relay' | ||
require 'rails' | ||
require 'graphiql/rails' | ||
|
||
require 'graphql/rails/version' | ||
require 'graphql/rails/dsl' | ||
require 'graphql/rails/engine' | ||
require 'graphql/rails/config' | ||
require 'graphql/rails/types' | ||
require 'graphql/rails/schema' | ||
require 'graphql/rails/operations' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
module GraphQL | ||
module Rails | ||
extend self | ||
|
||
def configure | ||
yield config | ||
end | ||
|
||
def config | ||
@config ||= OpenStruct.new({ | ||
# Should the GraphiQL web interface be served? | ||
:graphiql => ::Rails.env.development?, | ||
|
||
# Should the /app/graph directory automatically reload upon changes? | ||
:autoload => ::Rails.env.development?, | ||
|
||
# Should names be converted to lowerCamelCase per GraphQL convention? | ||
# For example, should :get_user_tasks become 'getUserTasks'? | ||
:camel_case => true, | ||
|
||
# Should Mongoid type extensions be loaded? | ||
:mongoid => defined?(::Mongoid) | ||
}) | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
module GraphQL | ||
module Rails | ||
class DSL < BasicObject | ||
def run(&block) | ||
case block.arity | ||
when 0 | ||
@self = eval('self', block.binding) | ||
instance_eval(&block) | ||
when 1 | ||
yield self | ||
else | ||
raise 'Block accepts too many arguments (expected 0 or 1).' | ||
end | ||
end | ||
|
||
def method_missing(method, *args, &block) | ||
@self.send(method, *args, &block) | ||
end | ||
end | ||
|
||
class HashDSL < DSL | ||
def initialize(hash) | ||
@struct = ::OpenStruct.new(hash) | ||
end | ||
|
||
def method_missing(method, *args, &block) | ||
begin | ||
@struct.send(method, *args, &block) | ||
rescue | ||
super | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,56 @@ | ||
class GraphQL::Rails::Engine < ::Rails::Engine | ||
initializer 'graphql-rails.autoload', :before => :set_autoload_paths do |app| | ||
app.config.autoload_paths += %W(#{app.config.root}/app/graph/fields) | ||
app.config.autoload_paths += %W(#{app.config.root}/app/graph/types) | ||
# Inflections must be added before the namespace is isolated, because the | ||
# namespace's route prefix is calculated and cached at that time. | ||
ActiveSupport::Inflector.inflections do |inflect| | ||
inflect.acronym 'GraphQL' | ||
end | ||
|
||
module GraphQL | ||
module Rails | ||
mattr_accessor :logger | ||
|
||
class Engine < ::Rails::Engine | ||
isolate_namespace GraphQL::Rails | ||
|
||
initializer 'graphql-rails' do |app| | ||
@graph_path = app.root.join('app', 'graph') | ||
|
||
# Initialize logger. | ||
# TODO: Fix tagging issues. | ||
logger = ActiveSupport::TaggedLogging.new(::Rails.logger.clone) | ||
logger.push_tags 'graphql' | ||
Rails.logger = logger | ||
Rails.logger.debug 'Initialized logger' | ||
|
||
# Load extensions. | ||
extensions = File.join(File.dirname(__FILE__), 'extensions', '*.rb') | ||
Dir[extensions].each do |file| | ||
require file | ||
end | ||
|
||
# Watch for changes to the /app/graph directory. | ||
if Rails.config.autoload | ||
dirs = {@graph_path.to_s => [:rb]} | ||
checker = ActiveSupport::FileUpdateChecker.new([], dirs) do | ||
Rails.logger.debug 'Detected changes to /app/graph directory' | ||
reload! | ||
end | ||
ActionDispatch::Reloader.to_prepare do | ||
checker.execute_if_updated | ||
end | ||
end | ||
|
||
# Perform initial load of files under the /app/graph directory. | ||
reload! | ||
end | ||
|
||
# TODO: Assess whether changes to a model class requires Types to be invalidated. | ||
def reload! | ||
Schema.clear | ||
Dir[@graph_path.join('**', '*.rb')].each do |file| | ||
Rails.logger.debug "Loading file: #{file}" | ||
load file | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
# TODO: Limit to one ORM, then support multiple ORMs. | ||
module GraphQL | ||
module Rails | ||
if Rails.config.mongoid | ||
module Mongoid | ||
Rails.logger.debug 'Loading Mongoid extensions' | ||
|
||
Types.add_type ::Mongoid::Boolean, Boolean | ||
Types.add_type BSON::ObjectId, String | ||
Types.add_type DateTime, String | ||
Types.add_type Object, String | ||
Types.add_type Hash, String | ||
|
||
Types.add_builder do |type| | ||
next unless type.included_modules.include?(::Mongoid::Document) | ||
Rails.logger.debug "Building Mongoid::Document type: #{type.name}" | ||
|
||
# TODO: Support parent types/interfaces. | ||
GraphQL::ObjectType.define do | ||
name type.name | ||
|
||
type.fields.each_value do |field_value| | ||
field field_value.name do | ||
type -> { Types.resolve(field_value.type) } | ||
description field_value.label unless field_value.label.blank? | ||
end | ||
end | ||
|
||
type.relations.each_value do |relationship| | ||
# TODO: Add polymorphic support. | ||
if relationship.polymorphic? | ||
msg = "Skipping polymorphic relationship: #{relationship.name}" | ||
Rails.logger.warn msg | ||
next | ||
end | ||
|
||
if relationship.many? | ||
connection relationship.name do | ||
type -> { Types.resolve(relationship.klass).connection_type } | ||
end | ||
else | ||
field relationship.name do | ||
type -> { Types.resolve(relationship.klass) } | ||
end | ||
end | ||
end | ||
end | ||
end | ||
|
||
GraphQL::Relay::BaseConnection.register_connection_implementation( | ||
::Mongoid::Relations::Targets::Enumerable, | ||
GraphQL::Relay::RelationConnection | ||
) | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
module GraphQL | ||
module Rails | ||
class Operations | ||
def self.query(hash, &block) | ||
hash = extract_pair(hash) | ||
Rails.logger.debug "Adding query: #{to_name(hash[:name])}" | ||
|
||
definition = QueryDefinition.new | ||
definition.run(&block) | ||
definition.run do | ||
name hash[:name] | ||
type hash[:type] | ||
end | ||
Schema.add_query definition.field | ||
end | ||
|
||
private | ||
|
||
def self.extract_pair(hash) | ||
unless hash.length == 1 | ||
raise 'Hash must contain a single :name => Type pair.' | ||
end | ||
{name: hash.keys.first, type: hash.values.first} | ||
end | ||
|
||
def self.to_name(symbol) | ||
if Rails.config.camel_case | ||
symbol.to_s.camelize(:lower) | ||
else | ||
symbol.to_s | ||
end | ||
end | ||
|
||
class QueryDefinition < DSL | ||
attr_reader :field | ||
|
||
def initialize | ||
# TODO: Determine why root scoping is necessary. | ||
@field = ::GraphQL::Field.new | ||
end | ||
|
||
def name(name) | ||
@field.name = to_name(name) | ||
end | ||
|
||
def type(type) | ||
@field.type = Types.resolve(type) | ||
end | ||
|
||
def argument(name, type, required = false) | ||
# TODO: Determine why root scoping is necessary. | ||
argument = ::GraphQL::Argument.new | ||
argument.name = to_name(name) | ||
argument.type = Types.resolve(type, required == :required) | ||
@field.arguments[argument.name] = argument | ||
end | ||
|
||
def execute(&block) | ||
field.resolve = -> (obj, args, ctx) do | ||
HashDSL.new({obj: obj, args: args, ctx: ctx}).run(&block) | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
module GraphQL | ||
module Rails | ||
module Schema | ||
extend self | ||
|
||
def clear | ||
@schema = nil | ||
@fields = Hash.new { |hash, key| hash[key] = [] } | ||
end | ||
|
||
TYPES = [:query, :mutation, :subscription] | ||
|
||
TYPES.each do |type| | ||
define_method "add_#{type.to_s}" do |field| | ||
@schema = nil # Invalidate cached schema. | ||
@fields[type].push field | ||
end | ||
end | ||
|
||
def instance | ||
#TODO: Support max_depth and types. | ||
@schema ||= GraphQL::Schema.new begin | ||
TYPES.reduce({}) do |schema, type| | ||
fields = @fields[type] | ||
unless fields.empty? | ||
schema[type] = GraphQL::ObjectType.define do | ||
name type.to_s.capitalize | ||
description "Root #{type.to_s} for this schema" | ||
fields.each do |value| | ||
field value.name, field: value | ||
end | ||
end | ||
end | ||
schema | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end |
Oops, something went wrong.