search_object_graphql 0.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. checksums.yaml +5 -5
  2. data/.rubocop.yml +15 -3
  3. data/.ruby-version +1 -0
  4. data/.travis.yml +3 -2
  5. data/CHANGELOG.md +25 -0
  6. data/Gemfile +2 -0
  7. data/README.md +34 -33
  8. data/Rakefile +3 -1
  9. data/example/.ruby-version +1 -1
  10. data/example/Gemfile +3 -1
  11. data/example/README.md +3 -3
  12. data/example/Rakefile +2 -0
  13. data/example/app/controllers/application_controller.rb +2 -0
  14. data/example/app/controllers/graphql_controller.rb +22 -18
  15. data/example/app/graphql/mutations/.keep +0 -0
  16. data/example/app/graphql/resolvers/base_resolver.rb +6 -0
  17. data/example/app/graphql/resolvers/base_search_resolver.rb +3 -1
  18. data/example/app/graphql/resolvers/category_search.rb +5 -3
  19. data/example/app/graphql/resolvers/post_search.rb +6 -4
  20. data/example/app/graphql/schema.rb +3 -1
  21. data/example/app/graphql/types/base_enum.rb +6 -0
  22. data/example/app/graphql/types/base_input_object.rb +6 -0
  23. data/example/app/graphql/types/base_interface.rb +7 -0
  24. data/example/app/graphql/types/base_object.rb +6 -0
  25. data/example/app/graphql/types/base_scalar.rb +6 -0
  26. data/example/app/graphql/types/base_union.rb +6 -0
  27. data/example/app/graphql/types/category_type.rb +7 -6
  28. data/example/app/graphql/types/date_time_type.rb +3 -4
  29. data/example/app/graphql/types/mutation_type.rb +6 -0
  30. data/example/app/graphql/types/post_type.rb +13 -11
  31. data/example/app/graphql/types/query_type.rb +6 -5
  32. data/example/app/models/application_record.rb +2 -0
  33. data/example/app/models/category.rb +2 -0
  34. data/example/app/models/post.rb +2 -0
  35. data/example/bin/bundle +3 -1
  36. data/example/bin/rails +2 -0
  37. data/example/bin/rake +2 -0
  38. data/example/bin/setup +4 -2
  39. data/example/bin/update +4 -2
  40. data/example/config.ru +2 -0
  41. data/example/config/application.rb +1 -1
  42. data/example/db/migrate/20170507175133_create_demo_tables.rb +1 -1
  43. data/example/db/schema.rb +1 -1
  44. data/example/public/favicon.ico +0 -0
  45. data/lib/search_object/plugin/graphql.rb +26 -47
  46. data/lib/search_object/plugin/graphql/version.rb +3 -1
  47. data/search_object_graphql.gemspec +9 -9
  48. data/spec/search_object/plugin/graphql_spec.rb +114 -96
  49. data/spec/spec_helper.rb +2 -0
  50. data/spec/spec_helper_active_record.rb +2 -0
  51. metadata +31 -35
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Types
4
+ module BaseInterface
5
+ include GraphQL::Schema::Interface
6
+ end
7
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Types
4
+ class BaseObject < GraphQL::Schema::Object
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Types
4
+ class BaseScalar < GraphQL::Schema::Scalar
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Types
4
+ class BaseUnion < GraphQL::Schema::Union
5
+ end
6
+ end
@@ -1,8 +1,9 @@
1
- Types::CategoryType = GraphQL::ObjectType.define do
2
- name 'Category'
1
+ # frozen_string_literal: true
3
2
 
4
- field :id, !types.ID
5
- field :name, !types.String
6
-
7
- connection :posts, Types::PostType.connection_type, function: Resolvers::PostSearch
3
+ module Types
4
+ class CategoryType < BaseObject
5
+ field :id, ID, null: false
6
+ field :name, String, null: false
7
+ field :posts, resolver: Resolvers::PostSearch
8
+ end
8
9
  end
@@ -1,6 +1,5 @@
1
- Types::DateTimeType = GraphQL::ScalarType.define do
2
- name 'DateTime'
1
+ # frozen_string_literal: true
3
2
 
4
- coerce_input ->(value, _ctx) { Time.zone.parse(value) }
5
- coerce_result ->(value, _ctx) { value.utc.iso8601 }
3
+ module Types
4
+ DateTimeType = GraphQL::Types::ISO8601DateTime
6
5
  end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Types
4
+ class MutationType < Types::BaseObject
5
+ end
6
+ end
@@ -1,13 +1,15 @@
1
- Types::PostType = GraphQL::ObjectType.define do
2
- name 'Post'
1
+ # frozen_string_literal: true
3
2
 
4
- field :id, !types.ID
5
- field :title, !types.String
6
- field :body, !types.String
7
- field :category, !Types::CategoryType
8
- field :viewsCount, !types.Int, property: :views_count
9
- field :likesCount, !types.Int, property: :likes_count
10
- field :commentsCount, !types.Int, property: :comments_count
11
- field :isPublished, !types.Boolean, property: :published?
12
- field :publishedAt, !Types::DateTimeType, property: :published_at
3
+ module Types
4
+ class PostType < BaseObject
5
+ field :id, ID, null: false
6
+ field :title, String, null: false
7
+ field :body, String, null: false
8
+ field :category, CategoryType, null: false
9
+ field :views_count, Int, null: false
10
+ field :likes_count, Int, null: false
11
+ field :comments_count, Int, null: false
12
+ field :is_published, Boolean, null: false, method: :published?
13
+ field :published_at, DateTimeType, null: false
14
+ end
13
15
  end
@@ -1,7 +1,8 @@
1
- Types::QueryType = GraphQL::ObjectType.define do
2
- name 'Query'
1
+ # frozen_string_literal: true
3
2
 
4
- connection :categories, Types::CategoryType.connection_type, function: Resolvers::CategorySearch
5
-
6
- connection :posts, Types::PostType.connection_type, function: Resolvers::PostSearch
3
+ module Types
4
+ class QueryType < Types::BaseObject
5
+ field :categories, resolver: Resolvers::CategorySearch
6
+ field :posts, resolver: Resolvers::PostSearch
7
+ end
7
8
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class ApplicationRecord < ActiveRecord::Base
2
4
  self.abstract_class = true
3
5
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Category < ApplicationRecord
2
4
  validates :name, presence: true, uniqueness: true
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Post < ApplicationRecord
2
4
  validates :title, presence: true, uniqueness: true
3
5
  validates :body, presence: true
data/example/bin/bundle CHANGED
@@ -1,3 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
- ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
2
+ # frozen_string_literal: true
3
+
4
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
3
5
  load Gem.bin_path('bundler', 'bundle')
data/example/bin/rails CHANGED
@@ -1,4 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
2
4
  APP_PATH = File.expand_path('../config/application', __dir__)
3
5
  require_relative '../config/boot'
4
6
  require 'rails/commands'
data/example/bin/rake CHANGED
@@ -1,4 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
2
4
  require_relative '../config/boot'
3
5
  require 'rake'
4
6
  Rake.application.run
data/example/bin/setup CHANGED
@@ -1,10 +1,12 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
2
4
  require 'pathname'
3
5
  require 'fileutils'
4
- include FileUtils
6
+ include FileUtils # rubocop:disable Style/MixinUsage
5
7
 
6
8
  # path to your application root.
7
- APP_ROOT = Pathname.new File.expand_path('../../', __FILE__)
9
+ APP_ROOT = Pathname.new File.expand_path('..', __dir__)
8
10
 
9
11
  def system!(*args)
10
12
  system(*args) || abort("\n== Command #{args} failed ==")
data/example/bin/update CHANGED
@@ -1,10 +1,12 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
2
4
  require 'pathname'
3
5
  require 'fileutils'
4
- include FileUtils
6
+ include FileUtils # rubocop:disable Style/MixinUsage
5
7
 
6
8
  # path to your application root.
7
- APP_ROOT = Pathname.new File.expand_path('../../', __FILE__)
9
+ APP_ROOT = Pathname.new File.expand_path('..', __dir__)
8
10
 
9
11
  def system!(*args)
10
12
  system(*args) || abort("\n== Command #{args} failed ==")
data/example/config.ru CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # This file is used by Rack-based servers to start the application.
2
4
 
3
5
  require_relative 'config/environment'
@@ -3,7 +3,7 @@ require_relative 'boot'
3
3
  require "rails"
4
4
  # Pick the frameworks you want:
5
5
  require "active_model/railtie"
6
- # require "active_job/railtie"
6
+ require "active_job/railtie"
7
7
  require "active_record/railtie"
8
8
  require "action_controller/railtie"
9
9
  # require "action_mailer/railtie"
@@ -7,7 +7,7 @@ class CreateDemoTables < ActiveRecord::Migration[5.1]
7
7
  end
8
8
 
9
9
  create_table :posts do |t|
10
- t.references :category, foreign_key: true
10
+ t.references :category
11
11
  t.string :title, null: false
12
12
  t.index :title, unique: true
13
13
  t.string :body, null: false
data/example/db/schema.rb CHANGED
@@ -10,7 +10,7 @@
10
10
  #
11
11
  # It's strongly recommended that you check this file into your version control system.
12
12
 
13
- ActiveRecord::Schema.define(version: 20170507175133) do
13
+ ActiveRecord::Schema.define(version: 2017_05_07_175133) do
14
14
 
15
15
  create_table "categories", force: :cascade do |t|
16
16
  t.string "name", null: false
File without changes
@@ -1,26 +1,43 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module SearchObject
2
4
  module Plugin
3
5
  module Graphql
4
6
  def self.included(base)
7
+ raise NotIncludedInResolverError, base unless base.ancestors.include? GraphQL::Schema::Resolver
8
+
5
9
  base.include SearchObject::Plugin::Enum
6
10
  base.extend ClassMethods
7
11
  end
8
12
 
9
13
  attr_reader :object, :context
10
14
 
11
- def initialize(filters: {}, object: nil, context: {}, scope: nil)
15
+ def initialize(filters: {}, object: nil, context: {}, scope: nil, field: nil)
12
16
  @object = object
13
17
  @context = context
14
18
 
15
- super filters: filters, scope: scope
19
+ super filters: filters, scope: scope, field: field
20
+ end
21
+
22
+ # NOTE(rstankov): GraphQL::Schema::Resolver interface
23
+ # Documentation - http://graphql-ruby.org/fields/resolvers.html#using-resolver
24
+ def resolve_with_support(args = {})
25
+ self.params = args.to_h
26
+ results
16
27
  end
17
28
 
18
29
  module ClassMethods
19
30
  def option(name, options = {}, &block)
20
- argument = Helper.build_argument(name, options)
21
- arguments[argument.name] = argument
31
+ type = options.fetch(:type) { raise MissingTypeDefinitionError, name }
32
+ options[:enum] = type.values.map { |value, enum_value| enum_value.value || value } if type.respond_to?(:values)
22
33
 
23
- options[:enum] = argument.type.values.keys if argument.type.is_a? GraphQL::EnumType
34
+ argument(
35
+ name.to_s,
36
+ options[:type],
37
+ required: options[:required] || false,
38
+ description: options[:description],
39
+ camelize: options[:camelize]
40
+ )
24
41
 
25
42
  super(name, options, &block)
26
43
  end
@@ -28,35 +45,11 @@ module SearchObject
28
45
  def types
29
46
  GraphQL::Define::TypeDefiner.instance
30
47
  end
48
+ end
31
49
 
32
- # NOTE(rstankov): GraphQL::Function interface
33
- # Documentation - https://rmosolgo.github.io/graphql-ruby/schema/code_reuse#functions
34
- def call(object, args, context)
35
- new(filters: args.to_h, object: object, context: context).results
36
- end
37
-
38
- def arguments
39
- config[:args] ||= {}
40
- end
41
-
42
- def type(value = :default, &block)
43
- return config[:type] if value == :default && !block_given?
44
- config[:type] = block_given? ? GraphQL::ObjectType.define(&block) : value
45
- end
46
-
47
- def complexity(value = :default)
48
- return config[:complexity] || 1 if value == :default
49
- config[:complexity] = value
50
- end
51
-
52
- def description(value = :default)
53
- return config[:description] if value == :default
54
- config[:description] = value
55
- end
56
-
57
- def deprecation_reason(value = :default)
58
- return config[:deprecation_reason] if value == :default
59
- config[:deprecation_reason] = value
50
+ class NotIncludedInResolverError < ArgumentError
51
+ def initialize(base)
52
+ super "#{base.name} should inherit from GraphQL::Schema::Resolver. Current ancestors #{base.ancestors}"
60
53
  end
61
54
  end
62
55
 
@@ -65,20 +58,6 @@ module SearchObject
65
58
  super "GraphQL type has to passed as :type to '#{name}' option"
66
59
  end
67
60
  end
68
-
69
- # :api: private
70
- module Helper
71
- module_function
72
-
73
- def build_argument(name, options)
74
- argument = GraphQL::Argument.new
75
- argument.name = name.to_s
76
- argument.type = options.fetch(:type) { raise MissingTypeDefinitionError, name }
77
- argument.default_value = options[:default] if options.key? :default
78
- argument.description = options[:description] if options.key? :description
79
- argument
80
- end
81
- end
82
61
  end
83
62
  end
84
63
  end
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module SearchObject
2
4
  module Plugin
3
5
  module Graphql
4
- VERSION = '0.1'.freeze
6
+ VERSION = '1.0.0'
5
7
  end
6
8
  end
7
9
  end
@@ -1,5 +1,6 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
3
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
5
  require 'English'
5
6
  require 'search_object/plugin/graphql/version'
@@ -19,13 +20,12 @@ Gem::Specification.new do |spec|
19
20
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
21
  spec.require_paths = ['lib']
21
22
 
22
- spec.add_dependency 'search_object', '~> 1.2'
23
- spec.add_dependency 'graphql', '~> 1.5'
23
+ spec.add_dependency 'graphql', '~> 1.8'
24
+ spec.add_dependency 'search_object', '~> 1.2.2'
24
25
 
25
- spec.add_development_dependency 'bundler', '~> 1.13'
26
- spec.add_development_dependency 'rake'
27
- spec.add_development_dependency 'rspec', '~> 3.5'
28
- spec.add_development_dependency 'rubocop', '0.46.0'
29
- spec.add_development_dependency 'rubocop-rspec', '1.8.0'
30
26
  spec.add_development_dependency 'coveralls'
27
+ spec.add_development_dependency 'rake'
28
+ spec.add_development_dependency 'rspec', '~> 3.8'
29
+ spec.add_development_dependency 'rubocop', '0.62.0'
30
+ spec.add_development_dependency 'rubocop-rspec', '1.31.0'
31
31
  end
@@ -1,29 +1,29 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
  require 'graphql'
3
5
  require 'ostruct'
4
6
  require 'search_object/plugin/graphql'
5
7
 
6
- describe SearchObject::Plugin::Graphql do
7
- Post = Struct.new(:id) do
8
- def to_json
9
- { 'id' => id }
10
- end
8
+ Post = Struct.new(:id) do
9
+ def to_json(_options = {})
10
+ { 'id' => id }
11
11
  end
12
+ end
12
13
 
13
- PostType = GraphQL::ObjectType.define do
14
- name 'Post'
15
-
16
- field :id, !types.ID
17
- end
14
+ class PostType < GraphQL::Schema::Object
15
+ field :id, ID, null: false
16
+ end
18
17
 
18
+ describe SearchObject::Plugin::Graphql do
19
19
  def define_schema(&block)
20
- query_type = GraphQL::ObjectType.define do
21
- name 'Query'
20
+ query_type = Class.new(GraphQL::Schema::Object) do
21
+ graphql_name 'Query'
22
22
 
23
23
  instance_eval(&block)
24
24
  end
25
25
 
26
- GraphQL::Schema.define do
26
+ Class.new(GraphQL::Schema) do
27
27
  query query_type
28
28
 
29
29
  max_complexity 1000
@@ -31,7 +31,7 @@ describe SearchObject::Plugin::Graphql do
31
31
  end
32
32
 
33
33
  def define_search_class(&block)
34
- Class.new do
34
+ Class.new(GraphQL::Schema::Resolver) do
35
35
  include SearchObject.module(:graphql)
36
36
 
37
37
  scope { [] }
@@ -45,20 +45,38 @@ describe SearchObject::Plugin::Graphql do
45
45
 
46
46
  define_schema do
47
47
  if search_object.type.nil?
48
- field :posts, types[PostType], function: search_object
48
+ field :posts, [PostType], resolver: search_object
49
49
  else
50
- field :posts, function: search_object
50
+ field :posts, resolver: search_object
51
51
  end
52
52
  end
53
53
  end
54
54
 
55
- it 'can be used as GraphQL::Function' do
56
- schema = define_search_class_and_return_schema do
55
+ it 'requires class to inherit from GraphQL::Schema::Resolver' do
56
+ expect do
57
+ Class.new { include SearchObject.module(:graphql) }
58
+ end.to raise_error SearchObject::Plugin::Graphql::NotIncludedInResolverError
59
+ end
60
+
61
+ it 'can be used as GraphQL::Schema::Resolver' do
62
+ post_type = Class.new(GraphQL::Schema::Object) do
63
+ graphql_name 'Post'
64
+
65
+ field :id, GraphQL::Types::ID, null: false
66
+ end
67
+
68
+ search_object = define_search_class do
57
69
  scope { [Post.new('1'), Post.new('2'), Post.new('3')] }
58
70
 
71
+ type [post_type], null: 1
72
+
59
73
  option(:id, type: !types.ID) { |scope, value| scope.select { |p| p.id == value } }
60
74
  end
61
75
 
76
+ schema = define_schema do
77
+ field :posts, resolver: search_object
78
+ end
79
+
62
80
  result = schema.execute '{ posts(id: "2") { id } }'
63
81
 
64
82
  expect(result).to eq(
@@ -73,19 +91,19 @@ describe SearchObject::Plugin::Graphql do
73
91
  scope { object.posts }
74
92
  end
75
93
 
76
- parent_type = GraphQL::ObjectType.define do
77
- name 'ParentType'
94
+ parent_type = Class.new(GraphQL::Schema::Object) do
95
+ graphql_name 'Parent'
78
96
 
79
- field :posts, types[PostType], function: search_object
97
+ field :posts, [PostType], resolver: search_object
80
98
  end
81
99
 
82
100
  schema = define_schema do
83
- field :parent, parent_type do
84
- resolve ->(_obj, _args, _ctx) { OpenStruct.new posts: [Post.new('from_parent')] }
85
- end
101
+ field :parent, parent_type, null: false
86
102
  end
87
103
 
88
- result = schema.execute '{ parent { posts { id } } }'
104
+ root = OpenStruct.new(parent: OpenStruct.new(posts: [Post.new('from_parent')]))
105
+
106
+ result = schema.execute '{ parent { posts { id } } }', root_value: root
89
107
 
90
108
  expect(result).to eq(
91
109
  'data' => {
@@ -124,86 +142,40 @@ describe SearchObject::Plugin::Graphql do
124
142
  )
125
143
  end
126
144
 
127
- it 'can define a custom type' do
128
- schema = define_search_class_and_return_schema do
129
- type do
130
- name 'Test'
131
-
132
- field :title, types.String
133
- end
145
+ describe 'option' do
146
+ it 'converts GraphQL::Schema::Enum to SearchObject enum' do
147
+ schema = define_search_class_and_return_schema do
148
+ enum_type = Class.new(GraphQL::Schema::Enum) do
149
+ graphql_name 'PostOrder'
134
150
 
135
- description 'Test description'
136
- end
151
+ value 'PRICE'
152
+ value 'DATE'
153
+ end
137
154
 
138
- result = schema.execute <<-SQL
139
- {
140
- __type(name: "Query") {
141
- name
142
- fields {
143
- name
144
- deprecationReason
145
- type {
146
- name
147
- fields {
148
- name
149
- }
150
- }
151
- }
152
- }
153
- }
154
- SQL
155
+ option(:order, type: enum_type)
155
156
 
156
- expect(result).to eq(
157
- 'data' => {
158
- '__type' => {
159
- 'name' => 'Query',
160
- 'fields' => [{
161
- 'name' => 'posts',
162
- 'deprecationReason' => nil,
163
- 'type' => {
164
- 'name' => 'Test',
165
- 'fields' => [{
166
- 'name' => 'title'
167
- }]
168
- }
169
- }]
170
- }
171
- }
172
- )
173
- end
157
+ define_method(:apply_order_with_price) do |_scope|
158
+ [Post.new('price')]
159
+ end
174
160
 
175
- it 'can be marked as deprecated' do
176
- schema = define_search_class_and_return_schema do
177
- type types[PostType]
178
- deprecation_reason 'Not needed any more'
179
- end
161
+ define_method(:apply_order_with_date) do |_scope|
162
+ [Post.new('date')]
163
+ end
164
+ end
180
165
 
181
- result = schema.execute <<-QUERY
182
- {
183
- __type(name: "Query") {
184
- name
185
- fields {
186
- name
187
- }
188
- }
189
- }
190
- QUERY
166
+ result = schema.execute '{ posts(order: PRICE) { id } }'
191
167
 
192
- expect(result).to eq(
193
- 'data' => {
194
- '__type' => {
195
- 'name' => 'Query',
196
- 'fields' => []
168
+ expect(result).to eq(
169
+ 'data' => {
170
+ 'posts' => [Post.new('price').to_json]
197
171
  }
198
- }
199
- )
200
- end
172
+ )
173
+ end
201
174
 
202
- describe 'option' do
203
175
  it 'converts GraphQL::EnumType to SearchObject enum' do
204
176
  schema = define_search_class_and_return_schema do
205
- enum_type = GraphQL::EnumType.define do
206
- name 'TestEnum'
177
+ enum_type = Class.new(GraphQL::Schema::Enum) do
178
+ graphql_name 'TestEnum'
207
179
 
208
180
  value 'PRICE'
209
181
  value 'DATE'
@@ -245,9 +217,21 @@ describe SearchObject::Plugin::Graphql do
245
217
  )
246
218
  end
247
219
 
220
+ it 'accepts "required"' do
221
+ schema = define_search_class_and_return_schema do
222
+ option(:id, type: types.String, required: true) do |_scope, value|
223
+ [Post.new(value)]
224
+ end
225
+ end
226
+
227
+ result = schema.execute '{ posts { id } }'
228
+
229
+ expect(result['errors'][0]['message']).to eq("Field 'posts' is missing required arguments: id")
230
+ end
231
+
248
232
  it 'accepts description' do
249
233
  schema = define_search_class_and_return_schema do
250
- type PostType
234
+ type PostType, null: true
251
235
 
252
236
  option('option', type: types.String, description: 'what this argument does') { [] }
253
237
  end
@@ -281,6 +265,40 @@ describe SearchObject::Plugin::Graphql do
281
265
  )
282
266
  end
283
267
 
268
+ it 'accepts camelize' do
269
+ schema = define_search_class_and_return_schema do
270
+ type PostType, null: true
271
+
272
+ option('option_field', type: types.String, camelize: false)
273
+ end
274
+
275
+ result = schema.execute <<-SQL
276
+ {
277
+ __type(name: "Query") {
278
+ name
279
+ fields {
280
+ args {
281
+ name
282
+ }
283
+ }
284
+ }
285
+ }
286
+ SQL
287
+
288
+ expect(result.to_h).to eq(
289
+ 'data' => {
290
+ '__type' => {
291
+ 'name' => 'Query',
292
+ 'fields' => [{
293
+ 'args' => [{
294
+ 'name' => 'option_field'
295
+ }]
296
+ }]
297
+ }
298
+ }
299
+ )
300
+ end
301
+
284
302
  it 'raises error when no type is given' do
285
303
  expect { define_search_class { option :name } }.to raise_error described_class::MissingTypeDefinitionError
286
304
  end