search_object_graphql 0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.projections.json +8 -0
  4. data/.rspec +2 -0
  5. data/.rubocop.yml +39 -0
  6. data/.travis.yml +11 -0
  7. data/CHANGELOG.md +5 -0
  8. data/Gemfile +4 -0
  9. data/LICENSE.txt +22 -0
  10. data/README.md +194 -0
  11. data/Rakefile +8 -0
  12. data/example/.gitignore +20 -0
  13. data/example/.ruby-version +1 -0
  14. data/example/Gemfile +22 -0
  15. data/example/README.md +83 -0
  16. data/example/Rakefile +6 -0
  17. data/example/app/controllers/application_controller.rb +2 -0
  18. data/example/app/controllers/graphql_controller.rb +29 -0
  19. data/example/app/graphql/resolvers/base_search_resolver.rb +9 -0
  20. data/example/app/graphql/resolvers/category_search.rb +35 -0
  21. data/example/app/graphql/resolvers/post_search.rb +69 -0
  22. data/example/app/graphql/schema.rb +3 -0
  23. data/example/app/graphql/types/.keep +0 -0
  24. data/example/app/graphql/types/category_type.rb +8 -0
  25. data/example/app/graphql/types/date_time_type.rb +6 -0
  26. data/example/app/graphql/types/post_type.rb +13 -0
  27. data/example/app/graphql/types/query_type.rb +7 -0
  28. data/example/app/models/application_record.rb +3 -0
  29. data/example/app/models/category.rb +5 -0
  30. data/example/app/models/post.rb +14 -0
  31. data/example/bin/bundle +3 -0
  32. data/example/bin/rails +4 -0
  33. data/example/bin/rake +4 -0
  34. data/example/bin/setup +34 -0
  35. data/example/bin/update +29 -0
  36. data/example/config.ru +5 -0
  37. data/example/config/application.rb +36 -0
  38. data/example/config/boot.rb +3 -0
  39. data/example/config/cable.yml +10 -0
  40. data/example/config/database.yml +25 -0
  41. data/example/config/environment.rb +5 -0
  42. data/example/config/environments/development.rb +42 -0
  43. data/example/config/environments/production.rb +78 -0
  44. data/example/config/environments/test.rb +36 -0
  45. data/example/config/initializers/wrap_parameters.rb +14 -0
  46. data/example/config/puma.rb +56 -0
  47. data/example/config/routes.rb +5 -0
  48. data/example/config/secrets.yml +32 -0
  49. data/example/config/spring.rb +6 -0
  50. data/example/db/migrate/20170507175133_create_demo_tables.rb +21 -0
  51. data/example/db/schema.rb +36 -0
  52. data/example/db/seeds.rb +35 -0
  53. data/example/log/.keep +0 -0
  54. data/example/public/robots.txt +1 -0
  55. data/example/vendor/.keep +0 -0
  56. data/lib/search_object/plugin/graphql.rb +84 -0
  57. data/lib/search_object/plugin/graphql/version.rb +7 -0
  58. data/search_object_graphql.gemspec +31 -0
  59. data/spec/search_object/plugin/graphql_spec.rb +288 -0
  60. data/spec/spec_helper.rb +12 -0
  61. data/spec/spec_helper_active_record.rb +29 -0
  62. metadata +219 -0
@@ -0,0 +1,288 @@
1
+ require 'spec_helper'
2
+ require 'graphql'
3
+ require 'ostruct'
4
+ require 'search_object/plugin/graphql'
5
+
6
+ describe SearchObject::Plugin::Graphql do
7
+ Post = Struct.new(:id) do
8
+ def to_json
9
+ { 'id' => id }
10
+ end
11
+ end
12
+
13
+ PostType = GraphQL::ObjectType.define do
14
+ name 'Post'
15
+
16
+ field :id, !types.ID
17
+ end
18
+
19
+ def define_schema(&block)
20
+ query_type = GraphQL::ObjectType.define do
21
+ name 'Query'
22
+
23
+ instance_eval(&block)
24
+ end
25
+
26
+ GraphQL::Schema.define do
27
+ query query_type
28
+
29
+ max_complexity 1000
30
+ end
31
+ end
32
+
33
+ def define_search_class(&block)
34
+ Class.new do
35
+ include SearchObject.module(:graphql)
36
+
37
+ scope { [] }
38
+
39
+ instance_eval(&block) if block_given?
40
+ end
41
+ end
42
+
43
+ def define_search_class_and_return_schema(&block)
44
+ search_object = define_search_class(&block)
45
+
46
+ define_schema do
47
+ if search_object.type.nil?
48
+ field :posts, types[PostType], function: search_object
49
+ else
50
+ field :posts, function: search_object
51
+ end
52
+ end
53
+ end
54
+
55
+ it 'can be used as GraphQL::Function' do
56
+ schema = define_search_class_and_return_schema do
57
+ scope { [Post.new('1'), Post.new('2'), Post.new('3')] }
58
+
59
+ option(:id, type: !types.ID) { |scope, value| scope.select { |p| p.id == value } }
60
+ end
61
+
62
+ result = schema.execute '{ posts(id: "2") { id } }'
63
+
64
+ expect(result).to eq(
65
+ 'data' => {
66
+ 'posts' => [Post.new('2').to_json]
67
+ }
68
+ )
69
+ end
70
+
71
+ it 'can access to parent object' do
72
+ search_object = define_search_class do
73
+ scope { object.posts }
74
+ end
75
+
76
+ parent_type = GraphQL::ObjectType.define do
77
+ name 'ParentType'
78
+
79
+ field :posts, types[PostType], function: search_object
80
+ end
81
+
82
+ schema = define_schema do
83
+ field :parent, parent_type do
84
+ resolve ->(_obj, _args, _ctx) { OpenStruct.new posts: [Post.new('from_parent')] }
85
+ end
86
+ end
87
+
88
+ result = schema.execute '{ parent { posts { id } } }'
89
+
90
+ expect(result).to eq(
91
+ 'data' => {
92
+ 'parent' => {
93
+ 'posts' => [Post.new('from_parent').to_json]
94
+ }
95
+ }
96
+ )
97
+ end
98
+
99
+ it 'can access to context object' do
100
+ schema = define_search_class_and_return_schema do
101
+ scope { [Post.new(context[:value])] }
102
+ end
103
+
104
+ result = schema.execute('{ posts { id } }', context: { value: 'context' })
105
+
106
+ expect(result).to eq(
107
+ 'data' => {
108
+ 'posts' => [Post.new('context').to_json]
109
+ }
110
+ )
111
+ end
112
+
113
+ it 'can define complexity' do
114
+ schema = define_search_class_and_return_schema do
115
+ complexity 10_000
116
+ end
117
+
118
+ result = schema.execute '{ posts { id } }'
119
+
120
+ expect(result).to eq(
121
+ 'errors' => [{
122
+ 'message' => 'Query has complexity of 10001, which exceeds max complexity of 1000'
123
+ }]
124
+ )
125
+ end
126
+
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
134
+
135
+ description 'Test description'
136
+ end
137
+
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
+
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
174
+
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
180
+
181
+ result = schema.execute <<-QUERY
182
+ {
183
+ __type(name: "Query") {
184
+ name
185
+ fields {
186
+ name
187
+ }
188
+ }
189
+ }
190
+ QUERY
191
+
192
+ expect(result).to eq(
193
+ 'data' => {
194
+ '__type' => {
195
+ 'name' => 'Query',
196
+ 'fields' => []
197
+ }
198
+ }
199
+ )
200
+ end
201
+
202
+ describe 'option' do
203
+ it 'converts GraphQL::EnumType to SearchObject enum' do
204
+ schema = define_search_class_and_return_schema do
205
+ enum_type = GraphQL::EnumType.define do
206
+ name 'TestEnum'
207
+
208
+ value 'PRICE'
209
+ value 'DATE'
210
+ end
211
+
212
+ option(:order, type: enum_type)
213
+
214
+ define_method(:apply_order_with_price) do |_scope|
215
+ [Post.new('price')]
216
+ end
217
+
218
+ define_method(:apply_order_with_date) do |_scope|
219
+ [Post.new('date')]
220
+ end
221
+ end
222
+
223
+ result = schema.execute '{ posts(order: PRICE) { id } }'
224
+
225
+ expect(result).to eq(
226
+ 'data' => {
227
+ 'posts' => [Post.new('price').to_json]
228
+ }
229
+ )
230
+ end
231
+
232
+ it 'accepts default type' do
233
+ schema = define_search_class_and_return_schema do
234
+ option(:id, type: types.String, default: 'default') do |_scope, value|
235
+ [Post.new(value)]
236
+ end
237
+ end
238
+
239
+ result = schema.execute '{ posts { id } }'
240
+
241
+ expect(result).to eq(
242
+ 'data' => {
243
+ 'posts' => [Post.new('default').to_json]
244
+ }
245
+ )
246
+ end
247
+
248
+ it 'accepts description' do
249
+ schema = define_search_class_and_return_schema do
250
+ type PostType
251
+
252
+ option('option', type: types.String, description: 'what this argument does') { [] }
253
+ end
254
+
255
+ result = schema.execute <<-SQL
256
+ {
257
+ __type(name: "Query") {
258
+ name
259
+ fields {
260
+ args {
261
+ name
262
+ description
263
+ }
264
+ }
265
+ }
266
+ }
267
+ SQL
268
+
269
+ expect(result).to eq(
270
+ 'data' => {
271
+ '__type' => {
272
+ 'name' => 'Query',
273
+ 'fields' => [{
274
+ 'args' => [{
275
+ 'name' => 'option',
276
+ 'description' => 'what this argument does'
277
+ }]
278
+ }]
279
+ }
280
+ }
281
+ )
282
+ end
283
+
284
+ it 'raises error when no type is given' do
285
+ expect { define_search_class { option :name } }.to raise_error described_class::MissingTypeDefinitionError
286
+ end
287
+ end
288
+ end
@@ -0,0 +1,12 @@
1
+ require 'bundler/setup'
2
+
3
+ if ENV['TRAVIS']
4
+ require 'coveralls'
5
+ Coveralls.wear!
6
+ end
7
+
8
+ require 'search_object'
9
+
10
+ RSpec.configure do |config|
11
+ config.expect_with(:rspec) { |c| c.syntax = :expect }
12
+ end
@@ -0,0 +1,29 @@
1
+ require_relative 'spec_helper'
2
+ require 'active_record'
3
+
4
+ ActiveRecord::Base.establish_connection adapter: 'sqlite3', database: ':memory:'
5
+
6
+ ActiveRecord::Schema.define do
7
+ self.verbose = false
8
+
9
+ create_table :products, force: true do |t|
10
+ t.string :name
11
+ t.integer :category_id
12
+ t.integer :price
13
+
14
+ t.timestamps null: true
15
+ end
16
+
17
+ create_table :categories, force: true do |t|
18
+ t.string :name
19
+
20
+ t.timestamps null: true
21
+ end
22
+ end
23
+
24
+ class Product < ActiveRecord::Base
25
+ belongs_to :category
26
+ end
27
+
28
+ class Category < ActiveRecord::Base
29
+ end
metadata ADDED
@@ -0,0 +1,219 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: search_object_graphql
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ platform: ruby
6
+ authors:
7
+ - Radoslav Stankov
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-05-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: search_object
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: graphql
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.5'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.5'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.13'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.13'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '3.5'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '3.5'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '='
88
+ - !ruby/object:Gem::Version
89
+ version: 0.46.0
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '='
95
+ - !ruby/object:Gem::Version
96
+ version: 0.46.0
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop-rspec
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '='
102
+ - !ruby/object:Gem::Version
103
+ version: 1.8.0
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '='
109
+ - !ruby/object:Gem::Version
110
+ version: 1.8.0
111
+ - !ruby/object:Gem::Dependency
112
+ name: coveralls
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ description: Search Object plugin to working with GraphQL
126
+ email:
127
+ - rstankov@gmail.com
128
+ executables: []
129
+ extensions: []
130
+ extra_rdoc_files: []
131
+ files:
132
+ - ".gitignore"
133
+ - ".projections.json"
134
+ - ".rspec"
135
+ - ".rubocop.yml"
136
+ - ".travis.yml"
137
+ - CHANGELOG.md
138
+ - Gemfile
139
+ - LICENSE.txt
140
+ - README.md
141
+ - Rakefile
142
+ - example/.gitignore
143
+ - example/.ruby-version
144
+ - example/Gemfile
145
+ - example/README.md
146
+ - example/Rakefile
147
+ - example/app/controllers/application_controller.rb
148
+ - example/app/controllers/graphql_controller.rb
149
+ - example/app/graphql/resolvers/base_search_resolver.rb
150
+ - example/app/graphql/resolvers/category_search.rb
151
+ - example/app/graphql/resolvers/post_search.rb
152
+ - example/app/graphql/schema.rb
153
+ - example/app/graphql/types/.keep
154
+ - example/app/graphql/types/category_type.rb
155
+ - example/app/graphql/types/date_time_type.rb
156
+ - example/app/graphql/types/post_type.rb
157
+ - example/app/graphql/types/query_type.rb
158
+ - example/app/models/application_record.rb
159
+ - example/app/models/category.rb
160
+ - example/app/models/post.rb
161
+ - example/bin/bundle
162
+ - example/bin/rails
163
+ - example/bin/rake
164
+ - example/bin/setup
165
+ - example/bin/update
166
+ - example/config.ru
167
+ - example/config/application.rb
168
+ - example/config/boot.rb
169
+ - example/config/cable.yml
170
+ - example/config/database.yml
171
+ - example/config/environment.rb
172
+ - example/config/environments/development.rb
173
+ - example/config/environments/production.rb
174
+ - example/config/environments/test.rb
175
+ - example/config/initializers/wrap_parameters.rb
176
+ - example/config/puma.rb
177
+ - example/config/routes.rb
178
+ - example/config/secrets.yml
179
+ - example/config/spring.rb
180
+ - example/db/migrate/20170507175133_create_demo_tables.rb
181
+ - example/db/schema.rb
182
+ - example/db/seeds.rb
183
+ - example/log/.keep
184
+ - example/public/robots.txt
185
+ - example/vendor/.keep
186
+ - lib/search_object/plugin/graphql.rb
187
+ - lib/search_object/plugin/graphql/version.rb
188
+ - search_object_graphql.gemspec
189
+ - spec/search_object/plugin/graphql_spec.rb
190
+ - spec/spec_helper.rb
191
+ - spec/spec_helper_active_record.rb
192
+ homepage: https://github.com/RStankov/SearchObjectGraphQL
193
+ licenses:
194
+ - MIT
195
+ metadata: {}
196
+ post_install_message:
197
+ rdoc_options: []
198
+ require_paths:
199
+ - lib
200
+ required_ruby_version: !ruby/object:Gem::Requirement
201
+ requirements:
202
+ - - ">="
203
+ - !ruby/object:Gem::Version
204
+ version: '0'
205
+ required_rubygems_version: !ruby/object:Gem::Requirement
206
+ requirements:
207
+ - - ">="
208
+ - !ruby/object:Gem::Version
209
+ version: '0'
210
+ requirements: []
211
+ rubyforge_project:
212
+ rubygems_version: 2.4.5
213
+ signing_key:
214
+ specification_version: 4
215
+ summary: Maps search objects to GraphQL resolvers
216
+ test_files:
217
+ - spec/search_object/plugin/graphql_spec.rb
218
+ - spec/spec_helper.rb
219
+ - spec/spec_helper_active_record.rb