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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 20d420d2ee1dd08bdfe48da2c5e1e3ba0a3a8233
4
- data.tar.gz: 57a5009d415d6fad948001d18d428676dbd1471c
2
+ SHA256:
3
+ metadata.gz: 49fd6817f69aa33a15ce7cc2e768bd239020c3f7f6b6e385e1f12d3c9d5c30ff
4
+ data.tar.gz: c6c4a8d82f1d5afa85519a1e8aee726b321495b2305e63fa0d5e986db75066fb
5
5
  SHA512:
6
- metadata.gz: d25a679fad52b5605c5720a774f2bee6d273abc369dbfd90cc48a75793d7fd3cc6359092406d178aecd0ae97fdb6e2f938f891b764b2ebfb26c47bf99fc63605
7
- data.tar.gz: f7d5f5e368c50e3bc274b8d665c83ca975f1093e55a7059c906f17e93a40388c097d51ce7288b99394b3d8268913bfe0ea1ef1d2a611bedaa0e7df9380160f5f
6
+ metadata.gz: a71588bac7cc2fba645d1e4007bfeed111749c0016d4a2de7e832990ff33f37e1656c08a47fd3a52f18664e594bbefee3939d1412aa3fc5d679dd9c3d875d533
7
+ data.tar.gz: 4c9bfd49332eafbd37b10be48bc58c65bfffa0546dc7c394a7b77e3e146769ee77083f39bbd40f101302ad7ffb967d8b7e0054b6512c35febdcedc0e00c94855
data/.rubocop.yml CHANGED
@@ -7,15 +7,15 @@ AllCops:
7
7
  - search_object.gemspec
8
8
 
9
9
  # Disables "Line is too long"
10
- LineLength:
10
+ Metrics/LineLength:
11
11
  Enabled: false
12
12
 
13
13
  # Disables Module has too many lines
14
- ModuleLength:
14
+ Metrics/ModuleLength:
15
15
  Enabled: false
16
16
 
17
17
  # Disables "Missing top-level class documentation comment"
18
- Documentation:
18
+ Style/Documentation:
19
19
  Enabled: false
20
20
 
21
21
  # Disables "Use each_with_object instead of inject"
@@ -26,10 +26,22 @@ Style/EachWithObject:
26
26
  Style/CollectionMethods:
27
27
  Enabled: false
28
28
 
29
+ # Disables "Avoid the use of double negation (!!)."
30
+ Style/DoubleNegation:
31
+ Enabled: false
32
+
29
33
  # Disables "Block has too many lines."
30
34
  Metrics/BlockLength:
31
35
  Enabled: false
32
36
 
37
+ # Disables "Assignment Branch Condition size for field_options is too high."
38
+ Metrics/AbcSize:
39
+ Enabled: false
40
+
41
+ # Disables "Method has too many line."
42
+ Metrics/MethodLength:
43
+ Enabled: false
44
+
33
45
  # Disables "Example has too many lines."
34
46
  RSpec/ExampleLength:
35
47
  Enabled: false
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.6.2
data/.travis.yml CHANGED
@@ -1,7 +1,8 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.2
4
- - 2.3.0
3
+ - 2.4.1
4
+ - 2.5.2
5
+ - 2.6.0
5
6
  script:
6
7
  - bundle exec rubocop
7
8
  - bundle exec rspec spec
data/CHANGELOG.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # Changelog
2
2
 
3
+ ## Version 1.0.0 (unreleased)
4
+
5
+ * __[break]__ Removed support for defining types via `type` method (@rstankov)
6
+ * __[break]__ Require `GraphQL::Schema::Resolver` inheritance (@rstankov)
7
+ * __[break]__ Removed support for legacy `GraphQL::Function` (@rstankov)
8
+ * __[break]__ `type` creates type based on `GraphQL::Schema::Object`, not the deprecated `GraphQL::ObjectType.define` (@rstankov)
9
+
10
+ ## Version 0.3.2
11
+
12
+ * __[feature]__ Added `camelize` argument to `option`, *`true` by default* (@glenbray)
13
+
14
+ ## Version 0.3.1
15
+
16
+ * __[fix]__ Support for GraphQL gem version v1.9.16 (@ardinusawan)
17
+
18
+ ## Version 0.3
19
+
20
+ * __[feature]__ Allow passing `required` key to option definition (@vfonic)
21
+ * __[fix]__ Support for GraphQL gem enums (@Postmodum37)
22
+
23
+ ## Version 0.2
24
+
25
+ * Added support for GraphQL::Schema::Resolver (@rstankov)
26
+ * Added support for GraphQL 1.8 class API (@rstankov)
27
+
3
28
  ## Version 0.1
4
29
 
5
30
  * Initial release (@rstankov)
data/Gemfile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source 'https://rubygems.org'
2
4
 
3
5
  # Specify your gem's dependencies in search_object.gemspec
data/README.md CHANGED
@@ -1,3 +1,4 @@
1
+ [![Gem Version](https://badge.fury.io/rb/search_object_graphql.svg)](http://badge.fury.io/rb/search_object_graphql)
1
2
  [![Code Climate](https://codeclimate.com/github/RStankov/SearchObjectGraphQL.svg)](https://codeclimate.com/github/RStankov/SearchObjectGraphQL)
2
3
  [![Build Status](https://secure.travis-ci.org/RStankov/SearchObjectGraphQL.svg)](http://travis-ci.org/RStankov/SearchObjectGraphQL)
3
4
  [![Code coverage](https://coveralls.io/repos/RStankov/SearchObjectGraphQL/badge.svg?branch=master#2)](https://coveralls.io/r/RStankov/SearchObjectGraphQL)
@@ -19,13 +20,15 @@
19
20
  * [Accessing Parent Object](#accessing-parent-object)
20
21
  * [Enums Support](#enums-support)
21
22
  * [Relay Support](#relay-support)
23
+ * [Contributing](#contributing)
24
+ * [License](#license)
22
25
 
23
26
  ## Installation
24
27
 
25
28
  Add this line to your application's Gemfile:
26
29
 
27
30
  ```ruby
28
- gem 'search_object'
31
+ gem 'search_object_graphql'
29
32
  ```
30
33
 
31
34
  And then execute:
@@ -34,7 +37,15 @@ And then execute:
34
37
 
35
38
  Or install it yourself as:
36
39
 
37
- $ gem install search_object
40
+ $ gem install search_object_graphql
41
+
42
+
43
+ **Require manually in your project**
44
+
45
+ ```ruby
46
+ require 'search_object'
47
+ require 'search_object/plugin/graphql'
48
+ ```
38
49
 
39
50
  ## Dependencies
40
51
 
@@ -46,22 +57,22 @@ Or install it yourself as:
46
57
  Just include the ```SearchObject.module``` and define your search options and their types:
47
58
 
48
59
  ```ruby
49
- class PostResolver
60
+ class PostResolver < GraphQL::Schema::Resolver
50
61
  include SearchObject.module(:graphql)
51
62
 
52
- type PostType
63
+ type [PostType], null: false
53
64
 
54
65
  scope { Post.all }
55
66
 
56
- option(:name, type: types.String) { |scope, value| scope.where name: value }
57
- option(:published, type: types.Boolean) { |scope, value| value ? scope.published : scope.unpublished }
67
+ option(:name, type: String) { |scope, value| scope.where name: value }
68
+ option(:published, type: Boolean) { |scope, value| value ? scope.published : scope.unpublished }
58
69
  end
59
70
  ```
60
71
 
61
- Then you can just use `PostResolver` as [GraphQL::Function](https://rmosolgo.github.io/graphql-ruby/schema/code_reuse#functions):
72
+ Then you can just use `PostResolver` as [GraphQL::Schema::Resolver](https://graphql-ruby.org/fields/resolvers.html):
62
73
 
63
74
  ```ruby
64
- field :posts, function: PostResolver
75
+ field :posts, resolver: PostResolver
65
76
  ```
66
77
 
67
78
  Options are exposed as arguments in the GraphQL query:
@@ -78,32 +89,12 @@ You can find example of most important features and plugins - [here](https://git
78
89
 
79
90
  ## Features
80
91
 
81
- ### Custom Types
82
-
83
- Custom types can be define inside the search object:
84
-
85
- ```ruby
86
- class PostResolver
87
- include SearchObject.module(:graphql)
88
-
89
- type do
90
- name 'Custom Type'
91
-
92
- field :id, !types.ID
93
- field :title, !types.String
94
- field :body, !types.String
95
- end
96
-
97
- # ...
98
- end
99
- ```
100
-
101
92
  ### Documentation
102
93
 
103
94
  Search object itself can be documented, as well as its options:
104
95
 
105
96
  ```ruby
106
- class PostResolver
97
+ class PostResolver < GraphQL::Schema::Resolver
107
98
  include SearchObject.module(:graphql)
108
99
 
109
100
  description 'Lists all posts'
@@ -116,7 +107,7 @@ end
116
107
  ### Default Values
117
108
 
118
109
  ```ruby
119
- class PostResolver
110
+ class PostResolver < GraphQL::Schema::Resolver
120
111
  include SearchObject.module(:graphql)
121
112
 
122
113
  scope { Post.all }
@@ -130,7 +121,7 @@ end
130
121
  Sometimes you want to scope posts based on parent object, it is accessible as `object` property:
131
122
 
132
123
  ```ruby
133
- class PostResolver
124
+ class PostResolver < GraphQL::Schema::Resolver
134
125
  include SearchObject.module(:graphql)
135
126
 
136
127
  # lists only posts from certain category
@@ -174,10 +165,20 @@ end
174
165
 
175
166
  ### Relay Support
176
167
 
177
- Search objects can be used as [Relay Connections](https://rmosolgo.github.io/graphql-ruby/relay/connections):
168
+ Search objects can be used as [Relay Connections](https://graphql-ruby.org/relay/connections.html):
169
+
170
+ ```ruby
171
+ class PostResolver < GraphQL::Schema::Resolver
172
+ include SearchObject.module(:graphql)
173
+
174
+ type PostType.connection_type, null: false
175
+
176
+ # ...
177
+ end
178
+ ```
178
179
 
179
180
  ```ruby
180
- connection :posts, Types::PostType.connection_type, function: Resolvers::PostSearch
181
+ field :posts, resolver: PostResolver
181
182
  ```
182
183
 
183
184
  ## Contributing
data/Rakefile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'bundler/gem_tasks'
2
4
  require 'rspec/core/rake_task'
3
5
  require 'rubocop/rake_task'
@@ -5,4 +7,4 @@ require 'rubocop/rake_task'
5
7
  RSpec::Core::RakeTask.new(:spec)
6
8
  RuboCop::RakeTask.new(:rubocop)
7
9
 
8
- task default: [:rubocop, :spec]
10
+ task default: %i[rubocop spec]
@@ -1 +1 @@
1
- 2.3.1
1
+ 2.5.1
data/example/Gemfile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source 'https://rubygems.org'
2
4
 
3
5
  git_source(:github) do |repo_name|
@@ -5,7 +7,7 @@ git_source(:github) do |repo_name|
5
7
  "https://github.com/#{repo_name}.git"
6
8
  end
7
9
 
8
- gem 'rails', '~> 5.1.0'
10
+ gem 'rails', '~> 5.2.0'
9
11
 
10
12
  gem 'graphql'
11
13
  gem 'puma', '~> 3.7'
data/example/README.md CHANGED
@@ -16,9 +16,9 @@ This is example application showing, one of the possible usages of ```SearchObje
16
16
  ```
17
17
  gem install bundler
18
18
  bundle install
19
- rake db:create
20
- rake db:migrate
21
- rake db:seed
19
+ rails db:create
20
+ rails db:migrate
21
+ rails db:seed
22
22
 
23
23
  rails server
24
24
  ```
data/example/Rakefile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Add your own tasks in files placed in lib/tasks ending in .rake,
2
4
  # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3
5
 
@@ -1,2 +1,4 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class ApplicationController < ActionController::API
2
4
  end
@@ -1,29 +1,33 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class GraphqlController < ApplicationController
2
4
  def execute
3
- render json: Schema.execute(query, variables: variables, context: context)
5
+ result = Schema.execute(params[:query],
6
+ variables: ensure_hash(params[:variables]),
7
+ context: {},
8
+ operation_name: params[:operationName])
9
+ render json: result
10
+ rescue StandardError => e
11
+ raise e unless Rails.env.development?
12
+
13
+ handle_error_in_development e
4
14
  end
5
15
 
6
16
  private
7
17
 
8
- def query
9
- params[:query]
10
- end
11
-
12
- def variables
13
- ensure_hash(params[:variables])
18
+ def ensure_hash(ambiguous_param)
19
+ case ambiguous_param
20
+ when String then ambiguous_param.present? ? ensure_hash(JSON.parse(ambiguous_param)) : {}
21
+ when Hash, ActionController::Parameters then ambiguous_param
22
+ when nil then {}
23
+ else raise ArgumentError, "Unexpected parameter: #{ambiguous_param}"
24
+ end
14
25
  end
15
26
 
16
- def context
17
- {}
18
- end
27
+ def handle_error_in_development(error)
28
+ logger.error error.message
29
+ logger.error error.backtrace.join("\n")
19
30
 
20
- # Handle form data, JSON body, or a blank value
21
- def ensure_hash(params)
22
- case params
23
- when String then params.present? ? ensure_hash(JSON.parse(params)) : {}
24
- when Hash, ActionController::Parameters then params
25
- when nil then {}
26
- else raise ArgumentError, "Unexpected parameter: #{params}"
27
- end
31
+ render json: { error: { message: error.message, backtrace: error.backtrace }, data: {} }, status: 500
28
32
  end
29
33
  end
File without changes
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Resolvers
4
+ class BaseResolver < GraphQL::Schema::Resolver
5
+ end
6
+ end
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Resolvers
2
- class BaseSearchResolver
4
+ class BaseSearchResolver < BaseResolver
3
5
  include SearchObject.module(:graphql)
4
6
 
5
7
  def escape_search_term(term)
@@ -1,10 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Resolvers
2
4
  class CategorySearch < Resolvers::BaseSearchResolver
3
- type Types::CategoryType
5
+ type Types::CategoryType.connection_type, null: false
4
6
  description 'Lists categories'
5
7
 
6
- OrderEnum = GraphQL::EnumType.define do
7
- name 'CategoryOrder'
8
+ class OrderEnum < Types::BaseEnum
9
+ graphql_name 'CategoryOrder'
8
10
 
9
11
  value 'RECENT'
10
12
  value 'NAME'
@@ -1,10 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Resolvers
2
4
  class PostSearch < Resolvers::BaseSearchResolver
3
- type Types::PostType
5
+ type Types::PostType.connection_type, null: false
4
6
  description 'Lists posts'
5
7
 
6
- OrderEnum = GraphQL::EnumType.define do
7
- name 'PostOrder'
8
+ class OrderEnum < Types::BaseEnum
9
+ graphql_name 'PostOrder'
8
10
 
9
11
  value 'RECENT'
10
12
  value 'VIEWS'
@@ -51,7 +53,7 @@ module Resolvers
51
53
  end
52
54
 
53
55
  def apply_order_with_recent(scope)
54
- scope.order 'published_at IS NOT NULL, published_at DESC'
56
+ scope.order Arel.sql('published_at IS NOT NULL'), published_at: :desc
55
57
  end
56
58
 
57
59
  def apply_order_with_views(scope)
@@ -1,3 +1,5 @@
1
- Schema = GraphQL::Schema.define do
1
+ # frozen_string_literal: true
2
+
3
+ class Schema < GraphQL::Schema
2
4
  query Types::QueryType
3
5
  end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Types
4
+ class BaseEnum < GraphQL::Schema::Enum
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Types
4
+ class BaseInputObject < GraphQL::Schema::InputObject
5
+ end
6
+ end