graphql-filters 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/.rubocop.yml +1635 -0
  4. data/CHANGELOG.md +13 -0
  5. data/Gemfile +10 -0
  6. data/Gemfile.lock +77 -0
  7. data/LICENSE +21 -0
  8. data/README.md +265 -0
  9. data/Rakefile +10 -0
  10. data/lib/graphql/filters/activerecord_patch/arel/nodes/contained.rb +9 -0
  11. data/lib/graphql/filters/activerecord_patch/arel/predications.rb +9 -0
  12. data/lib/graphql/filters/activerecord_patch.rb +3 -0
  13. data/lib/graphql/filters/dsl/graphql/schema/enum.rb +16 -0
  14. data/lib/graphql/filters/dsl/graphql/schema/field.rb +64 -0
  15. data/lib/graphql/filters/dsl/graphql/schema/list.rb +28 -0
  16. data/lib/graphql/filters/dsl/graphql/schema/member.rb +25 -0
  17. data/lib/graphql/filters/dsl/graphql/schema/non_null.rb +15 -0
  18. data/lib/graphql/filters/dsl/graphql/schema/object.rb +16 -0
  19. data/lib/graphql/filters/dsl/graphql/schema/scalar.rb +16 -0
  20. data/lib/graphql/filters/dsl/graphql/types/numeric.rb +20 -0
  21. data/lib/graphql/filters/dsl/graphql/types/string.rb +16 -0
  22. data/lib/graphql/filters/dsl.rb +3 -0
  23. data/lib/graphql/filters/filterable.rb +42 -0
  24. data/lib/graphql/filters/input_types/base_comparison_input_type.rb +12 -0
  25. data/lib/graphql/filters/input_types/base_list_comparison_input_type.rb +23 -0
  26. data/lib/graphql/filters/input_types/base_scalar_comparison_input_type.rb +63 -0
  27. data/lib/graphql/filters/input_types/fields_comparison_input_type.rb +58 -0
  28. data/lib/graphql/filters/input_types/list_object_comparison_input_type.rb +97 -0
  29. data/lib/graphql/filters/input_types/list_scalar_comparison_input_type.rb +134 -0
  30. data/lib/graphql/filters/input_types/numeric_comparison_input_type.rb +45 -0
  31. data/lib/graphql/filters/input_types/object_comparison_input_type.rb +71 -0
  32. data/lib/graphql/filters/input_types/string_comparison_input_type.rb +64 -0
  33. data/lib/graphql/filters/utility/cached_class.rb +74 -0
  34. data/lib/graphql/filters/version.rb +5 -0
  35. data/lib/graphql/filters.rb +26 -0
  36. data/lib/graphql/models_connect/dsl/graphql/schema/object.rb +27 -0
  37. data/lib/graphql/models_connect/dsl.rb +3 -0
  38. data/lib/graphql/models_connect.rb +15 -0
  39. metadata +126 -0
data/CHANGELOG.md ADDED
@@ -0,0 +1,13 @@
1
+ # Changelog
2
+
3
+ [//]: # (
4
+ ## <Release number> <Date YYYY-MM-DD>
5
+ ### Breaking changes
6
+ ### Deprecations
7
+ ### New features
8
+ ### Bug fixes
9
+ )
10
+
11
+ ## 1.0.0 2023-03-06
12
+
13
+ First release. Refer to [README.md](README.md) for the full documentation.
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in graphql-filters.gemspec
4
+ gemspec
5
+
6
+ gem 'rake', '~> 13.0'
7
+
8
+ gem 'rspec', '~> 3.0'
9
+
10
+ gem 'rubocop', '~> 1.21'
data/Gemfile.lock ADDED
@@ -0,0 +1,77 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ graphql-filters (1.0.0)
5
+ activerecord (~> 7.0.0)
6
+ activesupport (~> 7.0.0)
7
+ graphql (~> 2.0.0)
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ activemodel (7.0.4.2)
13
+ activesupport (= 7.0.4.2)
14
+ activerecord (7.0.4.2)
15
+ activemodel (= 7.0.4.2)
16
+ activesupport (= 7.0.4.2)
17
+ activesupport (7.0.4.2)
18
+ concurrent-ruby (~> 1.0, >= 1.0.2)
19
+ i18n (>= 1.6, < 2)
20
+ minitest (>= 5.1)
21
+ tzinfo (~> 2.0)
22
+ ast (2.4.2)
23
+ concurrent-ruby (1.2.2)
24
+ diff-lcs (1.5.0)
25
+ graphql (2.0.17)
26
+ i18n (1.12.0)
27
+ concurrent-ruby (~> 1.0)
28
+ json (2.6.3)
29
+ minitest (5.18.0)
30
+ parallel (1.22.1)
31
+ parser (3.2.0.0)
32
+ ast (~> 2.4.1)
33
+ rainbow (3.1.1)
34
+ rake (13.0.6)
35
+ regexp_parser (2.6.2)
36
+ rexml (3.2.5)
37
+ rspec (3.12.0)
38
+ rspec-core (~> 3.12.0)
39
+ rspec-expectations (~> 3.12.0)
40
+ rspec-mocks (~> 3.12.0)
41
+ rspec-core (3.12.0)
42
+ rspec-support (~> 3.12.0)
43
+ rspec-expectations (3.12.2)
44
+ diff-lcs (>= 1.2.0, < 2.0)
45
+ rspec-support (~> 3.12.0)
46
+ rspec-mocks (3.12.3)
47
+ diff-lcs (>= 1.2.0, < 2.0)
48
+ rspec-support (~> 3.12.0)
49
+ rspec-support (3.12.0)
50
+ rubocop (1.44.1)
51
+ json (~> 2.3)
52
+ parallel (~> 1.10)
53
+ parser (>= 3.2.0.0)
54
+ rainbow (>= 2.2.2, < 4.0)
55
+ regexp_parser (>= 1.8, < 3.0)
56
+ rexml (>= 3.2.5, < 4.0)
57
+ rubocop-ast (>= 1.24.1, < 2.0)
58
+ ruby-progressbar (~> 1.7)
59
+ unicode-display_width (>= 2.4.0, < 3.0)
60
+ rubocop-ast (1.24.1)
61
+ parser (>= 3.1.1.0)
62
+ ruby-progressbar (1.11.0)
63
+ tzinfo (2.0.6)
64
+ concurrent-ruby (~> 1.0)
65
+ unicode-display_width (2.4.2)
66
+
67
+ PLATFORMS
68
+ arm64-darwin-22
69
+
70
+ DEPENDENCIES
71
+ graphql-filters!
72
+ rake (~> 13.0)
73
+ rspec (~> 3.0)
74
+ rubocop (~> 1.21)
75
+
76
+ BUNDLED WITH
77
+ 2.3.9
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Moku S.r.l., Riccardo Agatea
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,265 @@
1
+ # GraphQL Filters
2
+
3
+ A way to define automated filters on GraphQL fields.
4
+
5
+ This gem provides a module to include (or prepend, see below) in your resolvers that will automatically generate a tree of input types that your clients can use to filter the result of their queries. The filters are completely typed in the GraphQL schema, and are transpiled into an Active Record relation. The relation uses subqueries instead of joins to apply filters on associations, which might be less efficient. This, however, makes it possible for the client to make a query like "I need all the Kanto routes where I can catch Oddish, but for each route I also need all the other Pokémon".
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'graphql-filters', '~> 0.1.0'
13
+ ```
14
+
15
+ And then execute:
16
+ ```bash
17
+ $ bundle
18
+ ```
19
+
20
+ ## Usage
21
+
22
+ The easiest way to use GraphQL Filters is on top of [SearchObject](https://github.com/RStankov/SearchObject) and its [GraphQL plugin](https://github.com/RStankov/SearchObjectGraphQL). Just include `GraphQL::Filters::Filterable` in your resolvers, and it will add an option to automatically filter the underlying collection. For example:
23
+
24
+ ```ruby
25
+ class RoutesResolver < BaseResolver
26
+ include SearchObject.module(:graphql)
27
+
28
+ scope { Route.all }
29
+
30
+ type [RouteType], null: false
31
+
32
+ include GraphQL::Filters::Filterable
33
+ end
34
+ ```
35
+
36
+ Otherwise, you have to explicitly define a `resolve` method and have it return an `ActiveRecord::Relation`; in this case youy need to prepend `GraphQL::Filters::Filterable` in the resolver, otherwise it won't have access to the starting scope:
37
+
38
+ ```ruby
39
+ class RoutesResolver < BaseResolver
40
+ type [RouteType], null: false
41
+
42
+ def resolve
43
+ Route.all
44
+ end
45
+
46
+ prepend GraphQL::Filters::Filterable
47
+ end
48
+ ```
49
+
50
+ Using either of these resolvers for a `routes` field will generate all the necessary input types to make a query like this:
51
+
52
+ ```graphql
53
+ query {
54
+ routes(
55
+ filter: {
56
+ fields: {
57
+ region: {
58
+ fields: {
59
+ name: { equals: "Kanto" }
60
+ }
61
+ },
62
+ catchablePokemon: {
63
+ any: {
64
+ fields: {
65
+ pokemon: {
66
+ types: {
67
+ any: {
68
+ fields: {
69
+ name: { equals: "Water"}
70
+ }
71
+ }
72
+ }
73
+ }
74
+ }
75
+ }
76
+ }
77
+ }
78
+ }
79
+ ){
80
+ name
81
+ trainers{
82
+ name
83
+ isDouble
84
+ }
85
+ catchablePokemon{
86
+ levelRange
87
+ rate
88
+ pokemon{
89
+ name
90
+ types{
91
+ name
92
+ }
93
+ }
94
+ }
95
+ }
96
+ ```
97
+
98
+ Notice that eager loading is outside the scope of this gem, so if without anything else the above query will fall victim to the N+1 problem.
99
+
100
+ Each input type is generated based on the respective type: scalar and enum types allow for basic comparisons like equality and inclusion, while object types let you build complex queries that mix and match comparisons on their fields. List types let you make `any`, `all`, and `none` queries based on a nested filter. Support for null-checked filters is planned for future development.
101
+
102
+ ### Underlying models
103
+
104
+ GraphQL Filters relies on the assumption that every object type exists on top of an Active Record model. A field of type `PokemonType` will always be resolved to an instance of `Pokemon`, and its fields will match (at least loosely) the attributes of the model. This assumption allows the gem to generate appropriate subqueries for nested filters.
105
+
106
+ By default, the gem assumes that if an object type is `<Name>Type`, then its underlying model is `<Name>` and it is in the same module. This isn't always the case, especially if you follow the convention suggested by the GraphQL Ruby documentation, so all your object types are in a `Types` module. For a single exception you can explicitly declare the model inside your object type:
107
+
108
+ ```ruby
109
+ module Types
110
+ class PokemonType < BaseObject
111
+ model_class Pokemon
112
+ ...
113
+ end
114
+ end
115
+ ```
116
+
117
+ To change the default behavior of the gem, override the `default_model_class` class method in your base object class:
118
+
119
+ ```ruby
120
+ module Types
121
+ class BaseObject < GraphQL::Schema::Object
122
+ def self.default_model_class
123
+ model_name = name
124
+ .delete_prefix('Types::')
125
+ .delete_suffix('Type')
126
+
127
+ const_get model_name
128
+ end
129
+ end
130
+ end
131
+ ```
132
+
133
+ ### Comparators
134
+
135
+ The best way to know what comparators you can use with each field is to open the GraphQL schema in your favorite client. What follows is a description of what each comparator does; unless explicitly indicated, `not<Comparison>` will match if and only if `<comparison>` will not.
136
+
137
+ #### Constant
138
+
139
+ `constant` is available for all types, and either always or never matches, depending on the passed boolean value. It can be useful to build complex filters.
140
+
141
+ #### Equality
142
+
143
+ `equals` is available for all scalar and enum types, and their respective list types, and matches if the field has the provided value.
144
+
145
+ #### Inclusion
146
+
147
+ `in` is available for all scalar and enum types, and their respective list types, and matches if the field has one of the provided values.
148
+
149
+ #### Numerical comparisons
150
+
151
+ `greaterThan`, `greaterThanOrEqualsTo`, `lessThan` and `lessThanOrEqualsTo` are available for numerical types (including `ISO8601Date` and `ISO8601DateTime`) and behave as expected.
152
+
153
+ #### Pattern matching
154
+
155
+ `matches` is available for the `String` type. Its value is a string in the format `<version>/<pattern>/<options>`.
156
+
157
+ - At the moment, `<version>` can only be `v1`, but extensions are planned for future development.
158
+ - For version `v1`, `<pattern>` will match a `.` with any one character and a `*` with zero or more characters. To match any literal character you can prefix it with `\​`.
159
+ - For version `v1`, `<options>` can be empty, or be `i`, which will make the match case insensitive.
160
+
161
+ #### List comparisons
162
+
163
+ `any`, `all`, and `none` are available for any list, take a comparator for the type of the elements of the list, and match, respectively, if at least one, all, or none, of the elements of the list match the nested comparator.
164
+
165
+ #### Object comparisons
166
+
167
+ For each object type `<Type>`, two comparison input types are generated. `<Type>ComplexFilterInput` has `and`, `or`, and `not` fields to build complex comparators, plus a `fields` field of type `<Type>ComparisonInput`. For each field of `<Type>`, `<Type>ComparisonInput` has a field with the same name and the respective comparison input type. For example , if `Pokemon` has a `name` field of type `String`, then `PokemonComparisonInput` has a `name` field of type `StringComparisonInput`.
168
+
169
+ ### Input Types
170
+
171
+ The autogenerated input types are ready to go as is, but you might need to access them, for example to provide some documentation (the autogeneration of extensive documentation is planned for future development). For each type, you can access its corresponding input type through the `comparison_input_type` method. For object types, this method returns the class corresponding to the `<Type>ComplexFilterInput` input type; in turn, it has a `fields_comparison_input_type` that returns the class corresponding to the `<Type>ComparisonInput` input type.
172
+
173
+ ### Configuration
174
+
175
+ To configure the behavior of GraphQL Filters, create an initializer in `config/initializers`, and call the `configure` method:
176
+
177
+ ```ruby
178
+ GraphQL::Filters.configure do |config|
179
+ ...
180
+ end
181
+ ```
182
+
183
+ #### `config.base_input_object_class`
184
+
185
+ By default, GraphQL Filters uses `GraphQL::Schema::InputObject` as base class for comparison input types. To use another class, assign it to `config.base_input_object_class`.
186
+
187
+ ### Options
188
+
189
+ The `field` method accepts some options that can tweak the generated input types and the transpilation of the arguments into a query. You can pass these options in three ways, in order of priority:
190
+
191
+ - as a keyword argument to the `field` method:
192
+
193
+ ```ruby
194
+ field :name, String, null: false, filter: {...}
195
+ ```
196
+
197
+ - as a single positional argument to the `filter` method inside the block you pass to the `field` method:
198
+
199
+ ```ruby
200
+ field :name, String, null: false do
201
+ filter({...})
202
+ end
203
+ ```
204
+
205
+ - as keyword arguments to the `filter` method inside the block you pass to the `field` method:
206
+
207
+ ```ruby
208
+ field :name, String, null: false do
209
+ filter ...
210
+ end
211
+ ```
212
+
213
+ #### Valid options
214
+
215
+ - `enabled`
216
+
217
+ Can be `true` or `false` (default: `true`). Controls whether or not the client can use this field in the filters. Passing `true` or `false` directly to `filter` is a shortcut:
218
+
219
+ ```ruby
220
+ field :name, String, null: false, filter: false
221
+
222
+ # is equivalent to
223
+
224
+ field :name, String, null: false, filter: {enabled: false}
225
+ ```
226
+
227
+ - `attribute_name`
228
+
229
+ The name of the attribute that the field is tied to in the model. Defaults to the name of the resolver method for the field (which by default is the same as the name of the field itself).
230
+
231
+ - `association_name`
232
+
233
+ The name of the Active Record association that the field is tied to in the model. Equivalent to `attribute_name`, has the same default.
234
+
235
+ ## Plans for future development
236
+
237
+ - A finer grain support for non-nullable fields.
238
+ - A pattern format for the string match comparator that uses real regular expressions.
239
+ - Autogenerated documentation.
240
+ - More options, both for the gem as a whole and for the single fields.
241
+ - The ability to (easily) specify custom comparator input types and provide custom logic for specific comparators.
242
+
243
+ ## Version numbers
244
+
245
+ GraphQL Filters loosely follows [Semantic Versioning](https://semver.org/), with a hard guarantee that breaking changes to the public API will always coincide with an increase to the `MAJOR` number.
246
+
247
+ Version numbers are in three parts: `MAJOR.MINOR.PATCH`.
248
+
249
+ - Breaking changes to the public API increment the `MAJOR`. There may also be changes that would otherwise increase the `MINOR` or the `PATCH`.
250
+ - Additions, deprecations, and "big" non breaking changes to the public API increment the `MINOR`. There may also be changes that would otherwise increase the `PATCH`.
251
+ - Bug fixes and "small" non breaking changes to the public API increment the `PATCH`.
252
+
253
+ Notice that any feature deprecated by a minor release can be expected to be removed by the next major release.
254
+
255
+ ## Changelog
256
+
257
+ Full list of changes in [CHANGELOG.md](CHANGELOG.md)
258
+
259
+ ## Contributing
260
+
261
+ Bug reports and pull requests are welcome on GitHub at https://github.com/moku-io/graphql-filters.
262
+
263
+ ## License
264
+
265
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new :spec
5
+
6
+ require 'rubocop/rake_task'
7
+
8
+ RuboCop::RakeTask.new
9
+
10
+ task default: [:spec, :rubocop]
@@ -0,0 +1,9 @@
1
+ module Arel
2
+ module Nodes
3
+ class Contained < InfixOperation
4
+ def initialize left, right
5
+ super :'<@', left, right
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ require_relative 'nodes/contained'
2
+
3
+ monkey_patch = Module.new do
4
+ def contained other
5
+ Nodes::Contained.new self, Nodes.build_quoted(other, self)
6
+ end
7
+ end
8
+
9
+ Arel::Predications.prepend monkey_patch
@@ -0,0 +1,3 @@
1
+ Dir['activerecord_patch/**/*.rb', base: __dir__].each do |filename|
2
+ require_relative filename
3
+ end
@@ -0,0 +1,16 @@
1
+ require 'active_support/concern'
2
+ require_relative '../../../input_types/base_scalar_comparison_input_type'
3
+
4
+ monkey_patch = Module.new do
5
+ extend ActiveSupport::Concern
6
+
7
+ class_methods do
8
+ protected
9
+
10
+ def get_comparison_input_type(*)
11
+ GraphQL::Filters::InputTypes::BaseScalarComparisonInputType[self]
12
+ end
13
+ end
14
+ end
15
+
16
+ GraphQL::Schema::Enum.prepend monkey_patch
@@ -0,0 +1,64 @@
1
+ require 'active_support/concern'
2
+ require 'active_support/core_ext/class/attribute'
3
+ require 'ostruct'
4
+
5
+ monkey_patch = Module.new do
6
+ extend ActiveSupport::Concern
7
+
8
+ prepended do
9
+ class_attribute :filter_options_defaults,
10
+ instance_predicate: false,
11
+ instance_writer: false,
12
+ instance_reader: true,
13
+ default: {
14
+ enabled: true,
15
+ attribute_name: :method_sym.to_proc,
16
+ association_name: :method_sym.to_proc
17
+ }
18
+ end
19
+
20
+ def initialize *args, filter: true, **kwargs, &block
21
+ super(*args, **kwargs) do
22
+ filter filter
23
+
24
+ next if block.nil?
25
+
26
+ if block.arity == 1
27
+ block.call self
28
+ else
29
+ instance_exec &block
30
+ end
31
+ end
32
+ end
33
+
34
+ def filter options={}, **kwargs
35
+ # options can be either true, false, or an hash, so `if options` or `if options.present?` aren't enough
36
+
37
+ options = case options
38
+ when false
39
+ {enabled: false}
40
+ when true
41
+ {enabled: true}
42
+ else
43
+ options
44
+ end
45
+
46
+ applied_filter_options_defaults = filter_options_defaults.transform_values do |value|
47
+ if value.is_a? Proc
48
+ value.call self
49
+ else
50
+ value
51
+ end
52
+ end
53
+
54
+ filter_options.reverse_merge! applied_filter_options_defaults
55
+ filter_options.reverse_merge! options
56
+ filter_options.reverse_merge! kwargs
57
+ end
58
+
59
+ def filter_options
60
+ @filter_options ||= {}
61
+ end
62
+ end
63
+
64
+ GraphQL::Schema::Field.prepend monkey_patch
@@ -0,0 +1,28 @@
1
+ require 'active_support/concern'
2
+ require_relative '../../../input_types/base_list_comparison_input_type'
3
+ require_relative '../../../input_types/list_scalar_comparison_input_type'
4
+ require_relative '../../../input_types/list_object_comparison_input_type'
5
+
6
+ monkey_patch = Module.new do
7
+ extend ActiveSupport::Concern
8
+
9
+ def comparison_input_type new_comparison_input_type=nil
10
+ if new_comparison_input_type.present?
11
+ @comparison_input_type = new_comparison_input_type
12
+ else
13
+ @comparison_input_type ||= build_comparison_input_type
14
+ end
15
+ end
16
+
17
+ protected
18
+
19
+ def build_comparison_input_type
20
+ if [GraphQL::TypeKinds::SCALAR, GraphQL::TypeKinds::ENUM].include? unwrap.kind
21
+ GraphQL::Filters::InputTypes::ListScalarComparisonInputType[self]
22
+ else
23
+ GraphQL::Filters::InputTypes::ListObjectComparisonInputType[self]
24
+ end
25
+ end
26
+ end
27
+
28
+ GraphQL::Schema::List.prepend monkey_patch
@@ -0,0 +1,25 @@
1
+ require 'active_support/concern'
2
+ require 'active_support/core_ext/class/attribute'
3
+ require_relative '../../../input_types/base_comparison_input_type'
4
+
5
+ monkey_patch = Module.new do
6
+ extend ActiveSupport::Concern
7
+
8
+ class_methods do
9
+ def comparison_input_type new_comparison_input_type=nil
10
+ if new_comparison_input_type.present?
11
+ @comparison_input_type = new_comparison_input_type
12
+ else
13
+ @comparison_input_type ||= get_comparison_input_type
14
+ end
15
+ end
16
+
17
+ protected
18
+
19
+ def get_comparison_input_type
20
+ GraphQL::Filters::InputTypes::BaseComparisonInputType
21
+ end
22
+ end
23
+ end
24
+
25
+ GraphQL::Schema::Member.prepend monkey_patch
@@ -0,0 +1,15 @@
1
+ require 'active_support/concern'
2
+
3
+ monkey_patch = Module.new do
4
+ extend ActiveSupport::Concern
5
+
6
+ def comparison_input_type new_comparison_input_type=nil
7
+ if new_comparison_input_type.present?
8
+ @comparison_input_type = new_comparison_input_type
9
+ else
10
+ @comparison_input_type ||= of_type.comparison_input_type
11
+ end
12
+ end
13
+ end
14
+
15
+ GraphQL::Schema::NonNull.prepend monkey_patch
@@ -0,0 +1,16 @@
1
+ require 'active_support/concern'
2
+ require_relative '../../../input_types/object_comparison_input_type'
3
+
4
+ monkey_patch = Module.new do
5
+ extend ActiveSupport::Concern
6
+
7
+ class_methods do
8
+ protected
9
+
10
+ def get_comparison_input_type(*)
11
+ GraphQL::Filters::InputTypes::ObjectComparisonInputType[self]
12
+ end
13
+ end
14
+ end
15
+
16
+ GraphQL::Schema::Object.prepend monkey_patch
@@ -0,0 +1,16 @@
1
+ require 'active_support/concern'
2
+ require_relative '../../../input_types/base_scalar_comparison_input_type'
3
+
4
+ monkey_patch = Module.new do
5
+ extend ActiveSupport::Concern
6
+
7
+ class_methods do
8
+ protected
9
+
10
+ def get_comparison_input_type(*)
11
+ GraphQL::Filters::InputTypes::BaseScalarComparisonInputType[self]
12
+ end
13
+ end
14
+ end
15
+
16
+ GraphQL::Schema::Scalar.prepend monkey_patch
@@ -0,0 +1,20 @@
1
+ require 'active_support/concern'
2
+ require_relative '../../../input_types/numeric_comparison_input_type'
3
+
4
+ monkey_patch = Module.new do
5
+ extend ActiveSupport::Concern
6
+
7
+ class_methods do
8
+ protected
9
+
10
+ def get_comparison_input_type(*)
11
+ GraphQL::Filters::InputTypes::NumericComparisonInputType[self]
12
+ end
13
+ end
14
+ end
15
+
16
+ GraphQL::Types::Int.prepend monkey_patch
17
+ GraphQL::Types::BigInt.prepend monkey_patch
18
+ GraphQL::Types::Float.prepend monkey_patch
19
+ GraphQL::Types::ISO8601Date.prepend monkey_patch
20
+ GraphQL::Types::ISO8601DateTime.prepend monkey_patch
@@ -0,0 +1,16 @@
1
+ require 'active_support/concern'
2
+ require_relative '../../../input_types/string_comparison_input_type'
3
+
4
+ monkey_patch = Module.new do
5
+ extend ActiveSupport::Concern
6
+
7
+ class_methods do
8
+ protected
9
+
10
+ def get_comparison_input_type(*)
11
+ GraphQL::Filters::InputTypes::StringComparisonInputType
12
+ end
13
+ end
14
+ end
15
+
16
+ GraphQL::Types::String.prepend monkey_patch
@@ -0,0 +1,3 @@
1
+ Dir['dsl/**/*.rb', base: __dir__].each do |filename|
2
+ require_relative filename
3
+ end