Skip to content

Commit

Permalink
Add basic queries
Browse files Browse the repository at this point in the history
Ready to deploy, I think
  • Loading branch information
pletcher committed Aug 1, 2017
1 parent 5d0f8a9 commit afab0f5
Show file tree
Hide file tree
Showing 23 changed files with 279 additions and 7 deletions.
9 changes: 8 additions & 1 deletion Gemfile
Expand Up @@ -5,7 +5,6 @@ git_source(:github) do |repo_name|
"https://github.com/#{repo_name}.git"
end


# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '~> 5.1.2'
# Use postgresql as the database for Active Record
Expand All @@ -19,6 +18,7 @@ gem 'jbuilder', '~> 2.5'

gem 'dotenv-rails', require: 'dotenv/rails-now'
gem 'base32', '~> 0.3.2'
gem 'graphql'
gem "octokit", "~> 4.0"

# Use Capistrano for deployment
Expand All @@ -29,6 +29,11 @@ group :development, :test do
gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
# Adds support for Capybara system testing and selenium driver
gem 'capybara', '~> 2.13'

# These three gems are needed for the GraphiQL interface
gem 'sass-rails'
gem 'uglifier'
gem 'coffee-rails'
end

group :development do
Expand All @@ -42,3 +47,5 @@ end

# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]

gem 'graphiql-rails', group: :development
30 changes: 30 additions & 0 deletions Gemfile.lock
Expand Up @@ -52,17 +52,28 @@ GEM
rack (>= 1.0.0)
rack-test (>= 0.5.4)
xpath (~> 2.0)
coffee-rails (4.2.2)
coffee-script (>= 2.2.0)
railties (>= 4.0.0)
coffee-script (2.4.1)
coffee-script-source
execjs
coffee-script-source (1.12.2)
concurrent-ruby (1.0.5)
dotenv (2.2.1)
dotenv-rails (2.2.1)
dotenv (= 2.2.1)
railties (>= 3.2, < 5.2)
erubi (1.6.1)
execjs (2.7.0)
faraday (0.12.2)
multipart-post (>= 1.2, < 3)
ffi (1.9.18)
globalid (0.4.0)
activesupport (>= 4.2.0)
graphiql-rails (1.4.2)
rails
graphql (1.6.6)
i18n (0.8.6)
jbuilder (2.7.0)
activesupport (>= 4.2.0)
Expand Down Expand Up @@ -122,6 +133,17 @@ GEM
rb-inotify (0.9.10)
ffi (>= 0.5.0, < 2)
ruby_dep (1.5.0)
sass (3.5.1)
sass-listen (~> 4.0.0)
sass-listen (4.0.0)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
sass-rails (5.0.6)
railties (>= 4.0.0, < 6)
sass (~> 3.1)
sprockets (>= 2.8, < 4.0)
sprockets-rails (>= 2.0, < 4.0)
tilt (>= 1.1, < 3)
sawyer (0.8.1)
addressable (>= 2.3.5, < 2.6)
faraday (~> 0.8, < 1.0)
Expand All @@ -139,8 +161,11 @@ GEM
sprockets (>= 3.0.0)
thor (0.19.4)
thread_safe (0.3.6)
tilt (2.0.8)
tzinfo (1.2.3)
thread_safe (~> 0.1)
uglifier (3.2.0)
execjs (>= 0.3.0, < 3)
web-console (3.5.1)
actionview (>= 5.0)
activemodel (>= 5.0)
Expand All @@ -159,16 +184,21 @@ DEPENDENCIES
base32 (~> 0.3.2)
byebug
capybara (~> 2.13)
coffee-rails
dotenv-rails
graphiql-rails
graphql
jbuilder (~> 2.5)
listen (>= 3.0.5, < 3.2)
octokit (~> 4.0)
pg (~> 0.18)
puma (~> 3.7)
rails (~> 5.1.2)
sass-rails
spring
spring-watcher-listen (~> 2.0.0)
tzinfo-data
uglifier
web-console (>= 3.3.0)

BUNDLED WITH
Expand Down
33 changes: 33 additions & 0 deletions app/controllers/graphql_controller.rb
@@ -0,0 +1,33 @@
class GraphqlController < ApplicationController
def execute
variables = ensure_hash(params[:variables])
query = params[:query]
operation_name = params[:operationName]
context = {
# Query context goes here, for example:
# current_user: current_user,
}
result = TextsServerSchema.execute(query, variables: variables, context: context, operation_name: operation_name)
render json: result
end

private

# Handle form data, JSON body, or a blank value
def ensure_hash(ambiguous_param)
case ambiguous_param
when String
if ambiguous_param.present?
ensure_hash(JSON.parse(ambiguous_param))
else
{}
end
when Hash, ActionController::Parameters
ambiguous_param
when nil
{}
else
raise ArgumentError, "Unexpected parameter: #{ambiguous_param}"
end
end
end
17 changes: 17 additions & 0 deletions app/graphql/functions/pagination.rb
@@ -0,0 +1,17 @@
class Functions::Pagination < GraphQL::Function
attr_reader :type

description "Provide pagination boilerplate for common lists of records"

argument :limit, types.Int, default_value: 20, prepare: -> (limit, ctx) { [limit, 50].min }
argument :offset, types.Int, default_value: 0

def initialize(children: :itself, type:)
@children = children
@type = type
end

def call(obj, args, ctx)
obj.send(@children).limit(args[:limit]).offset(args[:offset])
end
end
Empty file added app/graphql/mutations/.keep
Empty file.
4 changes: 4 additions & 0 deletions app/graphql/texts_server_schema.rb
@@ -0,0 +1,4 @@
TextsServerSchema = GraphQL::Schema.define do
# mutation(Types::MutationType)
query(Types::QueryType)
end
25 changes: 25 additions & 0 deletions app/graphql/types/author_type.rb
@@ -0,0 +1,25 @@
Types::AuthorType = GraphQL::ObjectType.define do
name "Author"

field :id, !types.ID
field :name, !types.String
field :slug, !types.String
field :works,
function: Functions::Pagination.new(children: :works, type: types[Types::WorkType])
field :work_by_id, Types::WorkType do
argument :id, !types.ID

description "Find a work by this author with the given (integer) ID"
resolve -> (obj, args, ctx) do
puts args[:id]
puts obj.id
Work.find_by(author_id: obj.id, id: args[:id].to_i)
end
end
field :work_by_slug, Types::WorkType do
argument :slug, !types.String

description "Find a work by this author with the given slug"
resolve -> (obj, args, ctx) { Work.find_by(author_id: obj.id, slug: args[:slug]) }
end
end
10 changes: 10 additions & 0 deletions app/graphql/types/corpus_type.rb
@@ -0,0 +1,10 @@
Types::CorpusType = GraphQL::ObjectType.define do
name "Corpus"

field :id, !types.ID
field :link, types.String
field :slug, !types.String
field :title, !types.String
field :works,
function: Functions::Pagination.new(children: :works, type: types[Types::WorkType])
end
6 changes: 6 additions & 0 deletions app/graphql/types/json_type.rb
@@ -0,0 +1,6 @@
Types::JsonType = GraphQL::ScalarType.define do
name "JSON"

coerce_input -> (json, ctx) { JSON.parse(json) }
coerce_result -> (json, ctx) { JSON.dump(json) }
end
11 changes: 11 additions & 0 deletions app/graphql/types/language_type.rb
@@ -0,0 +1,11 @@
Types::LanguageType = GraphQL::ObjectType.define do
name "Language"

field :id, !types.ID
field :authors, types[Types::AuthorType]
field :corpora, types[Types::CorpusType]
field :slug, !types.String
field :title, !types.String
field :works,
function: Functions::Pagination.new(children: :works, type: types[Types::WorkType])
end
5 changes: 5 additions & 0 deletions app/graphql/types/mutation_type.rb
@@ -0,0 +1,5 @@
Types::MutationType = GraphQL::ObjectType.define do
name "Mutation"

# TODO: Add Mutations as fields
end
91 changes: 91 additions & 0 deletions app/graphql/types/query_type.rb
@@ -0,0 +1,91 @@
Types::QueryType = GraphQL::ObjectType.define do
name "Query"

field :authors do
type types[Types::AuthorType]

argument :limit, types.Int, default_value: 20
argument :offset, types.Int, default_value: 0

description "List all authors"
resolve -> (obj, args, ctx) { Author.limit(args[:limit]).offset(args[:offset]) }
end

field :author_by_id do
type Types::AuthorType

argument :id, !types.ID
description "Find an author by its (integer) ID"
resolve -> (obj, args, ctx) { Author.find(args[:id]) }
end

field :author_by_slug do
type Types::AuthorType

argument :slug, !types.String
description "Find an author by its slug"
resolve -> (obj, args, ctx) { Author.find_by(slug: args[:slug]) }
end

field :corpora do
type types[Types::CorpusType]

description "List all corpora"
resolve -> (obj, args, ctx) { Corpus.all }
end

field :corpus_by_id do
type Types::CorpusType

argument :id, !types.ID
description "Find a corpus by its (integer) ID"
resolve -> (obj, args, ctx) { Corpus.find(args[:id]) }
end

field :corpus_by_slug do
type Types::CorpusType

argument :slug, !types.String
description "Find a corpus by its slug"
resolve -> (obj, args, ctx) { Corpus.find_by(slug: args[:slug]) }
end

field :languages do
type types[Types::LanguageType]

description "List all languages"
resolve -> (obj, args, ctx) { Language.all }
end

field :language_by_id do
type Types::LanguageType

argument :id, !types.ID
description "Find a language by its (integer) ID"
resolve -> (obj, args, ctx) { Language.find(args[:id]) }
end

field :language_by_slug do
type Types::LanguageType

argument :slug, !types.String
description "Find a language by its slug"
resolve -> (obj, args, ctx) { Language.find_by(slug: args[:slug]) }
end

field :work_by_id do
type Types::WorkType

argument :id, !types.ID
description "Find a work by its (integer) ID"
resolve -> (obj, args, ctx) { Work.find(args[:id]) }
end

field :work_by_slug do
type Types::WorkType

argument :slug, !types.String
description "Find a work by its slug"
resolve -> (obj, args, ctx) { Work.find_by(slug: args[:slug]) }
end
end
13 changes: 13 additions & 0 deletions app/graphql/types/text_node_type.rb
@@ -0,0 +1,13 @@
Types::TextNodeType = GraphQL::ObjectType.define do
name "TextNode"

field :id, !types.ID
field :index, !types.Int
field :location, !types[types.Int]
field :data, Types::JsonType
field :entity_ranges, types[Types::JsonType]
field :inline_style_ranges, types[Types::JsonType]
field :text_node_type, !types.String
field :key, !types.String
field :text, types.String
end
13 changes: 13 additions & 0 deletions app/graphql/types/work_type.rb
@@ -0,0 +1,13 @@
Types::WorkType = GraphQL::ObjectType.define do
name "Work"

field :id, !types.ID
field :english_title, types.String
field :form, types.String
field :original_title, !types.String
field :slug, !types.String
field :structure, types.String
field :urn, types.String
field :text_nodes,
function: Functions::Pagination.new(children: :text_nodes, type: types[Types::TextNodeType])
end
1 change: 1 addition & 0 deletions app/models/author.rb
@@ -1,2 +1,3 @@
class Author < ApplicationRecord
has_many :works
end
1 change: 1 addition & 0 deletions app/models/corpus.rb
@@ -1,2 +1,3 @@
class Corpus < ApplicationRecord
has_many :works
end
1 change: 1 addition & 0 deletions app/models/language.rb
@@ -1,2 +1,3 @@
class Language < ApplicationRecord
has_many :works
end
2 changes: 2 additions & 0 deletions app/models/work.rb
@@ -1,2 +1,4 @@
class Work < ApplicationRecord
has_many :text_nodes

end
2 changes: 1 addition & 1 deletion config/application.rb
Expand Up @@ -9,7 +9,7 @@
# require "action_mailer/railtie"
require "action_view/railtie"
# require "action_cable/engine"
# require "sprockets/railtie"
require "sprockets/railtie"
require "rails/test_unit/railtie"

# Require the gems listed in Gemfile, including any gems
Expand Down
5 changes: 5 additions & 0 deletions config/routes.rb
@@ -1,3 +1,8 @@
Rails.application.routes.draw do
if Rails.env.development?
mount GraphiQL::Rails::Engine, at: "/graphiql", graphql_path: "/graphql"
end

post "/graphql", to: "graphql#execute"
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end
1 change: 0 additions & 1 deletion db/migrate/2_create_authors.rb
@@ -1,7 +1,6 @@
class CreateAuthors < ActiveRecord::Migration[5.1]
def change
create_table :authors do |t|
# references language, see language migration
t.string :name, null: false
t.string :slug, null: false

Expand Down

0 comments on commit afab0f5

Please sign in to comment.