graphql_rails 1.2.6 → 2.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/Gemfile.lock +2 -2
- data/docs/components/model.md +39 -5
- data/docs/other_tools/schema_dump.md +8 -8
- data/lib/graphql_rails/attributes/attributable.rb +6 -14
- data/lib/graphql_rails/attributes/attribute.rb +8 -33
- data/lib/graphql_rails/attributes/attribute_configurable.rb +33 -0
- data/lib/graphql_rails/attributes/attribute_name_parser.rb +7 -7
- data/lib/graphql_rails/attributes/input_attribute.rb +19 -13
- data/lib/graphql_rails/attributes/input_type_parser.rb +5 -7
- data/lib/graphql_rails/attributes/type_parseable.rb +32 -11
- data/lib/graphql_rails/attributes/type_parser.rb +4 -9
- data/lib/graphql_rails/concerns/chainable_options.rb +49 -0
- data/lib/graphql_rails/input_configurable.rb +2 -5
- data/lib/graphql_rails/model/configurable.rb +24 -10
- data/lib/graphql_rails/model/configuration.rb +8 -11
- data/lib/graphql_rails/model/find_or_build_graphql_type.rb +19 -18
- data/lib/graphql_rails/model/input.rb +10 -21
- data/lib/graphql_rails/router/route.rb +2 -2
- data/lib/graphql_rails/tasks/dump_graphql_schema.rb +12 -26
- data/lib/graphql_rails/tasks/dump_graphql_schemas.rb +57 -0
- data/lib/graphql_rails/tasks/schema.rake +8 -5
- data/lib/graphql_rails/version.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1d635269612ec07a541e7adebb01a9da7420f74511d8bbc4a30c60cea2eadc3f
|
4
|
+
data.tar.gz: 5d8e87e2d4c22bcf679645fa0de355b5c2a1765d357e28ba00560e83279462a0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4bdbac43bd69d1ace6bc7b29d6cfba07225950ff9a583f269310eed608fc5554afa934e2e34d4f2001349bdc8385fe4d94b6dc1b8844cb20f5d850276b5c9576
|
7
|
+
data.tar.gz: 9bdf1be49c697610f584def6bb016b5bd60455eb813c5b4884b491c39cb7df7c29d277efe56e45e79bc24089c3cf1befa9c178471396fe6eb6ca52c2ec49bffc
|
data/CHANGELOG.md
CHANGED
@@ -9,6 +9,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
9
9
|
|
10
10
|
* Added/Changed/Deprecated/Removed/Fixed/Security: YOUR CHANGE HERE
|
11
11
|
|
12
|
+
## [2.0.0](2021-12-03)
|
13
|
+
|
14
|
+
* Added: support for generating multiple schema dumps with `rake graphql_rails:schema:dump`.
|
15
|
+
* Added: support for using chainable syntax for input attributes.
|
16
|
+
* Changed: changed default `predicate method type from `Boolean` to `Boolean!`
|
17
|
+
* Changed: changed error message when trying to paginate not supported types
|
18
|
+
* Added: support defining graphql-ruby types as strings.
|
19
|
+
|
12
20
|
## [1.2.4](2021-05-05)
|
13
21
|
|
14
22
|
* Fixed: Dynamic types definition where type A references type B referencing type A.
|
data/Gemfile.lock
CHANGED
data/docs/components/model.md
CHANGED
@@ -27,8 +27,8 @@ Most commonly you will use `attribute` to make your model methods and attributes
|
|
27
27
|
|
28
28
|
Some types can be determined by attribute name, so you can skip this attribute:
|
29
29
|
|
30
|
-
* attributes which ends with name `*_id` has `ID
|
31
|
-
* attributes which ends with `?` has `Boolean
|
30
|
+
* attributes which ends with name `*_id` has `ID!` type
|
31
|
+
* attributes which ends with `?` has `Boolean!` type
|
32
32
|
* all other attributes without type are considered to be `String`
|
33
33
|
|
34
34
|
available types are:
|
@@ -45,9 +45,9 @@ class User
|
|
45
45
|
include GraphqlRails::Model
|
46
46
|
|
47
47
|
graphql do |c|
|
48
|
-
c.attribute :shop_id # ID type
|
48
|
+
c.attribute :shop_id # ID! type
|
49
49
|
c.attribute :full_name # String type
|
50
|
-
c.attribute :admin? # Boolean type
|
50
|
+
c.attribute :admin? # Boolean! type
|
51
51
|
c.attribute :level, type: 'integer'
|
52
52
|
c.attribute :money, type: 'float'
|
53
53
|
end
|
@@ -72,7 +72,7 @@ end
|
|
72
72
|
class User
|
73
73
|
include GraphqlRails::Model
|
74
74
|
|
75
|
-
graphql.attribute :address, type: AddressType, required: true
|
75
|
+
graphql.attribute :address, type: 'AddressType!', required: true
|
76
76
|
end
|
77
77
|
```
|
78
78
|
|
@@ -243,6 +243,24 @@ class User
|
|
243
243
|
end
|
244
244
|
```
|
245
245
|
|
246
|
+
### attribute.with
|
247
|
+
|
248
|
+
When you want to define some options dynamically, it's quite handy to use "Attribute#with" method:
|
249
|
+
|
250
|
+
```ruby
|
251
|
+
class User
|
252
|
+
include GraphqlRails::Model
|
253
|
+
|
254
|
+
graphql do |c|
|
255
|
+
c.attribute(:shop_id).with(type: 'ID', description: 'references to shop')
|
256
|
+
# same as:
|
257
|
+
# c.attribute(:shop_id, type: 'ID', description: 'references to shop')
|
258
|
+
# also same as:
|
259
|
+
# c.attribute(:shop_id).type('ID').description('references to shop')
|
260
|
+
end
|
261
|
+
end
|
262
|
+
```
|
263
|
+
|
246
264
|
### "attribute" configuration with chainable methods
|
247
265
|
|
248
266
|
If your attribute definition is complex, you can define attribute in more eye-friendly chainable way with:
|
@@ -361,6 +379,22 @@ class User
|
|
361
379
|
end
|
362
380
|
```
|
363
381
|
|
382
|
+
### "input.attribute" configuration with chainable methods
|
383
|
+
|
384
|
+
If your input attribute definition is complex, you can define attribute in more eye-friendly chainable way with:
|
385
|
+
|
386
|
+
```ruby
|
387
|
+
class User
|
388
|
+
include GraphqlRails::Model
|
389
|
+
|
390
|
+
graphql.input do |c|
|
391
|
+
c.attribute(:friends_count)
|
392
|
+
.type(:integer!)
|
393
|
+
.description('Can not be zero or less')
|
394
|
+
end
|
395
|
+
end
|
396
|
+
```
|
397
|
+
|
364
398
|
#### required type
|
365
399
|
|
366
400
|
There are few ways how to mark field as required.
|
@@ -6,24 +6,24 @@ GraphqlRails includes rake task to allow creating schema snapshots easier:
|
|
6
6
|
rake graphql_rails:schema:dump
|
7
7
|
```
|
8
8
|
|
9
|
-
## Dumping
|
9
|
+
## Dumping only selected schema groups
|
10
10
|
|
11
|
-
You can
|
11
|
+
You can specify which schema groups you want to dump. In order to do so, provide groups list as rake task argument and separate group names by comma:
|
12
12
|
|
13
13
|
```bash
|
14
|
-
rake graphql_rails:schema:dump['your_group_name']
|
14
|
+
rake graphql_rails:schema:dump['your_group_name, your_group_name2']
|
15
15
|
```
|
16
16
|
|
17
|
-
|
17
|
+
You can do this also by using ENV variable `SCHEMA_GROUP_NAME`:
|
18
18
|
|
19
19
|
```bash
|
20
|
-
SCHEMA_GROUP_NAME=your_group_name rake graphql_rails:schema:dump
|
20
|
+
SCHEMA_GROUP_NAME="your_group_name, your_group_name2" rake graphql_rails:schema:dump
|
21
21
|
```
|
22
22
|
|
23
|
-
## Dumping schema in to non default
|
23
|
+
## Dumping schema in to non default folder
|
24
24
|
|
25
|
-
By default schema will be dumped to `spec/fixtures
|
25
|
+
By default schema will be dumped to `spec/fixtures` directory. If you want different schema path, add `GRAPHQL_SCHEMA_DUMP_DIR` env variable, like this:
|
26
26
|
|
27
27
|
```bash
|
28
|
-
|
28
|
+
GRAPHQL_SCHEMA_DUMP_DIR='path/to/graphql/dumps' rake graphql_rails:schema:dump
|
29
29
|
```
|
@@ -6,14 +6,14 @@ require 'graphql_rails/attributes/attribute_name_parser'
|
|
6
6
|
module GraphqlRails
|
7
7
|
module Attributes
|
8
8
|
# contains methods which are shared between various attribute-like classes
|
9
|
-
# expects `initial_name` and `
|
9
|
+
# expects `initial_name` and `type` to be defined
|
10
10
|
module Attributable
|
11
11
|
def field_name
|
12
12
|
attribute_name_parser.field_name
|
13
13
|
end
|
14
14
|
|
15
15
|
def type_name
|
16
|
-
|
16
|
+
type.to_s
|
17
17
|
end
|
18
18
|
|
19
19
|
def name
|
@@ -23,17 +23,9 @@ module GraphqlRails
|
|
23
23
|
def required?
|
24
24
|
return @required unless @required.nil?
|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
def required
|
30
|
-
@required = true
|
31
|
-
self
|
32
|
-
end
|
33
|
-
|
34
|
-
def optional
|
35
|
-
@required = false
|
36
|
-
self
|
26
|
+
(type.nil? && attribute_name_parser.required?) ||
|
27
|
+
type.to_s[/!$/].present? ||
|
28
|
+
type.is_a?(GraphQL::Schema::NonNull)
|
37
29
|
end
|
38
30
|
|
39
31
|
def graphql_model
|
@@ -52,7 +44,7 @@ module GraphqlRails
|
|
52
44
|
|
53
45
|
def type_parser
|
54
46
|
@type_parser ||= begin
|
55
|
-
type_for_parser =
|
47
|
+
type_for_parser = type || attribute_name_parser.graphql_type
|
56
48
|
TypeParser.new(type_for_parser, paginated: paginated?)
|
57
49
|
end
|
58
50
|
end
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'graphql'
|
4
4
|
require 'graphql_rails/attributes/attributable'
|
5
|
+
require 'graphql_rails/attributes/attribute_configurable'
|
5
6
|
require 'graphql_rails/input_configurable'
|
6
7
|
|
7
8
|
module GraphqlRails
|
@@ -9,47 +10,21 @@ module GraphqlRails
|
|
9
10
|
# contains info about single graphql attribute
|
10
11
|
class Attribute
|
11
12
|
include Attributable
|
13
|
+
include AttributeConfigurable
|
12
14
|
include InputConfigurable
|
13
15
|
|
14
16
|
attr_reader :attributes
|
15
17
|
|
16
|
-
|
17
|
-
def initialize(name, type = nil, description: nil, property: name, required: nil, options: {})
|
18
|
-
@initial_type = type
|
18
|
+
def initialize(name)
|
19
19
|
@initial_name = name
|
20
|
-
@
|
21
|
-
@description = description
|
22
|
-
@property = property.to_s
|
23
|
-
@required = required
|
20
|
+
@property = name.to_s
|
24
21
|
@attributes ||= {}
|
25
22
|
end
|
26
|
-
# rubocop:enable Metrics/ParameterLists
|
27
23
|
|
28
|
-
def
|
29
|
-
return @
|
24
|
+
def property(new_value = NOT_SET)
|
25
|
+
return @property if new_value == NOT_SET
|
30
26
|
|
31
|
-
@
|
32
|
-
self
|
33
|
-
end
|
34
|
-
|
35
|
-
def description(new_description = nil)
|
36
|
-
return @description if new_description.nil?
|
37
|
-
|
38
|
-
@description = new_description
|
39
|
-
self
|
40
|
-
end
|
41
|
-
|
42
|
-
def property(new_property = nil)
|
43
|
-
return @property if new_property.nil?
|
44
|
-
|
45
|
-
@property = new_property.to_s
|
46
|
-
self
|
47
|
-
end
|
48
|
-
|
49
|
-
def options(new_options = {})
|
50
|
-
return @options if new_options.blank?
|
51
|
-
|
52
|
-
@options = new_options
|
27
|
+
@property = new_value.to_s
|
53
28
|
self
|
54
29
|
end
|
55
30
|
|
@@ -82,7 +57,7 @@ module GraphqlRails
|
|
82
57
|
|
83
58
|
protected
|
84
59
|
|
85
|
-
attr_reader :
|
60
|
+
attr_reader :initial_name
|
86
61
|
|
87
62
|
private
|
88
63
|
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'graphql_rails/attributes/type_parser'
|
4
|
+
require 'graphql_rails/attributes/attribute_name_parser'
|
5
|
+
require 'graphql_rails/model/build_enum_type'
|
6
|
+
require 'graphql_rails/concerns/chainable_options'
|
7
|
+
require 'active_support/concern'
|
8
|
+
|
9
|
+
module GraphqlRails
|
10
|
+
module Attributes
|
11
|
+
# Allows to set or get various attribute parameters
|
12
|
+
module AttributeConfigurable
|
13
|
+
extend ActiveSupport::Concern
|
14
|
+
|
15
|
+
included do
|
16
|
+
include GraphqlRails::ChainableOptions
|
17
|
+
|
18
|
+
chainable_option :description
|
19
|
+
chainable_option :options, default: {}
|
20
|
+
chainable_option :type
|
21
|
+
end
|
22
|
+
|
23
|
+
def required(new_value = true) # rubocop:disable Style/OptionalBooleanParameter
|
24
|
+
@required = new_value
|
25
|
+
self
|
26
|
+
end
|
27
|
+
|
28
|
+
def optional(new_value = true) # rubocop:disable Style/OptionalBooleanParameter
|
29
|
+
required(!new_value)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -5,12 +5,8 @@ module GraphqlRails
|
|
5
5
|
# Parses attribute name and can generates graphql scalar type,
|
6
6
|
# grapqhl name and etc. based on that
|
7
7
|
class AttributeNameParser
|
8
|
-
attr_reader :name
|
9
|
-
|
10
8
|
def initialize(original_name, options: {})
|
11
|
-
|
12
|
-
@required = !name['!'].nil?
|
13
|
-
@name = name.tr('!', '')
|
9
|
+
@original_name = original_name.to_s
|
14
10
|
@options = options
|
15
11
|
end
|
16
12
|
|
@@ -36,12 +32,16 @@ module GraphqlRails
|
|
36
32
|
end
|
37
33
|
|
38
34
|
def required?
|
39
|
-
|
35
|
+
original_name['!'].present? || original_name.end_with?('?')
|
36
|
+
end
|
37
|
+
|
38
|
+
def name
|
39
|
+
@name ||= original_name.tr('!', '')
|
40
40
|
end
|
41
41
|
|
42
42
|
private
|
43
43
|
|
44
|
-
attr_reader :options
|
44
|
+
attr_reader :options, :original_name
|
45
45
|
|
46
46
|
def original_format?
|
47
47
|
options[:input_format] == :original || options[:attribute_name_format] == :original
|
@@ -4,22 +4,19 @@ module GraphqlRails
|
|
4
4
|
module Attributes
|
5
5
|
# contains info about single graphql input attribute
|
6
6
|
class InputAttribute
|
7
|
+
require 'graphql_rails/model/build_enum_type'
|
7
8
|
require_relative './input_type_parser'
|
8
9
|
require_relative './attribute_name_parser'
|
9
10
|
include Attributable
|
11
|
+
include AttributeConfigurable
|
10
12
|
|
11
|
-
|
13
|
+
chainable_option :subtype
|
14
|
+
chainable_option :enum
|
12
15
|
|
13
|
-
|
14
|
-
|
16
|
+
def initialize(name, config:)
|
17
|
+
@config = config
|
15
18
|
@initial_name = name
|
16
|
-
@initial_type = type
|
17
|
-
@description = description
|
18
|
-
@options = options
|
19
|
-
@subtype = subtype
|
20
|
-
@required = required
|
21
19
|
end
|
22
|
-
# rubocop:enable Metrics/ParameterLists
|
23
20
|
|
24
21
|
def input_argument_args
|
25
22
|
type = raw_input_type || input_type_parser.input_type_arg
|
@@ -37,7 +34,7 @@ module GraphqlRails
|
|
37
34
|
|
38
35
|
private
|
39
36
|
|
40
|
-
attr_reader :initial_name, :
|
37
|
+
attr_reader :initial_name, :config
|
41
38
|
|
42
39
|
def attribute_name_parser
|
43
40
|
@attribute_name_parser ||= AttributeNameParser.new(
|
@@ -51,14 +48,23 @@ module GraphqlRails
|
|
51
48
|
|
52
49
|
def input_type_parser
|
53
50
|
@input_type_parser ||= begin
|
54
|
-
initial_parseable_type =
|
51
|
+
initial_parseable_type = type || enum_type || attribute_name_parser.graphql_type
|
55
52
|
InputTypeParser.new(initial_parseable_type, subtype: subtype)
|
56
53
|
end
|
57
54
|
end
|
58
55
|
|
56
|
+
def enum_type
|
57
|
+
return if enum.blank?
|
58
|
+
|
59
|
+
::GraphqlRails::Model::BuildEnumType.call(
|
60
|
+
"#{config.name}_#{initial_name}_enum",
|
61
|
+
allowed_values: enum
|
62
|
+
)
|
63
|
+
end
|
64
|
+
|
59
65
|
def raw_input_type
|
60
|
-
return
|
61
|
-
return
|
66
|
+
return type if type.is_a?(GraphQL::InputObjectType)
|
67
|
+
return type.graphql_input_type if type.is_a?(Model::Input)
|
62
68
|
end
|
63
69
|
end
|
64
70
|
end
|
@@ -15,12 +15,6 @@ module GraphqlRails
|
|
15
15
|
@subtype = subtype
|
16
16
|
end
|
17
17
|
|
18
|
-
def graphql_type
|
19
|
-
return nil if unparsed_type.nil?
|
20
|
-
|
21
|
-
partly_parsed_type || parsed_type
|
22
|
-
end
|
23
|
-
|
24
18
|
def input_type_arg
|
25
19
|
if list?
|
26
20
|
list_type_arg
|
@@ -34,7 +28,11 @@ module GraphqlRails
|
|
34
28
|
attr_reader :unparsed_type, :subtype
|
35
29
|
|
36
30
|
def unwrapped_type
|
37
|
-
raw_unwrapped_type ||
|
31
|
+
raw_unwrapped_type ||
|
32
|
+
unwrapped_scalar_type ||
|
33
|
+
unwrapped_model_input_type ||
|
34
|
+
graphql_type_object ||
|
35
|
+
raise_not_supported_type_error
|
38
36
|
end
|
39
37
|
|
40
38
|
def raw_unwrapped_type
|
@@ -58,25 +58,46 @@ module GraphqlRails
|
|
58
58
|
end
|
59
59
|
|
60
60
|
def core_scalar_type?
|
61
|
-
unwrapped_scalar_type.
|
61
|
+
unwrapped_scalar_type.present?
|
62
62
|
end
|
63
63
|
|
64
64
|
def graphql_model
|
65
|
-
|
66
|
-
|
67
|
-
unparsed_type
|
68
|
-
else
|
69
|
-
nullable_inner_name.safe_constantize
|
70
|
-
end
|
71
|
-
|
72
|
-
return if type_class.nil?
|
73
|
-
return unless type_class < GraphqlRails::Model
|
65
|
+
extract_type_class_if { |type| graphql_model?(type) }
|
66
|
+
end
|
74
67
|
|
75
|
-
|
68
|
+
def graphql_type_object
|
69
|
+
type_object = extract_type_class_if { |type| graphql_type_object?(type) }
|
70
|
+
type_object || graphql_model&.graphql&.graphql_type
|
76
71
|
end
|
77
72
|
|
78
73
|
protected
|
79
74
|
|
75
|
+
def extract_type_class_if
|
76
|
+
return unparsed_type if yield(unparsed_type)
|
77
|
+
|
78
|
+
type_class = nullable_inner_name.safe_constantize
|
79
|
+
return type_class if yield(type_class)
|
80
|
+
|
81
|
+
nil
|
82
|
+
end
|
83
|
+
|
84
|
+
def graphql_model?(type_class)
|
85
|
+
type_class.is_a?(Class) && type_class < GraphqlRails::Model
|
86
|
+
end
|
87
|
+
|
88
|
+
def graphql_type_object?(type_class)
|
89
|
+
return false unless type_class.is_a?(Class)
|
90
|
+
|
91
|
+
type_class < GraphQL::Schema::Object || type_class < GraphQL::Schema::Scalar
|
92
|
+
end
|
93
|
+
|
94
|
+
def applicable_graphql_type?(type)
|
95
|
+
return false unless type.is_a?(Class)
|
96
|
+
return true if type < GraphqlRails::Model
|
97
|
+
|
98
|
+
false
|
99
|
+
end
|
100
|
+
|
80
101
|
def unwrap_type(type)
|
81
102
|
unwrappable = type
|
82
103
|
unwrappable = unwrappable.of_type while wrapped_type?(unwrappable)
|
@@ -51,7 +51,9 @@ module GraphqlRails
|
|
51
51
|
def paginated_type_arg
|
52
52
|
return graphql_model.graphql.connection_type if graphql_model
|
53
53
|
|
54
|
-
|
54
|
+
error_message = "Unable to paginate #{unparsed_type.inspect}. " \
|
55
|
+
'Pagination is only supported for models which include GraphqlRails::Model'
|
56
|
+
raise NotSupportedFeature, error_message
|
55
57
|
end
|
56
58
|
|
57
59
|
def list_type_arg
|
@@ -107,14 +109,7 @@ module GraphqlRails
|
|
107
109
|
end
|
108
110
|
|
109
111
|
def type_by_name
|
110
|
-
unwrapped_scalar_type ||
|
111
|
-
end
|
112
|
-
|
113
|
-
def unwrapped_model_type
|
114
|
-
type_class = graphql_model
|
115
|
-
return unless type_class
|
116
|
-
|
117
|
-
type_class.graphql.graphql_type
|
112
|
+
unwrapped_scalar_type || graphql_type_object || raise_not_supported_type_error
|
118
113
|
end
|
119
114
|
end
|
120
115
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphqlRails
|
4
|
+
# Allows defining methods chained way
|
5
|
+
module ChainableOptions
|
6
|
+
NOT_SET = Object.new
|
7
|
+
|
8
|
+
# nodoc
|
9
|
+
module ClassMethods
|
10
|
+
def chainable_option(option_name, default: nil)
|
11
|
+
define_method(option_name) do |value = NOT_SET|
|
12
|
+
get_or_set_chainable_option(option_name, value, default: default)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.included(base)
|
18
|
+
base.extend(ClassMethods)
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize_copy(other)
|
22
|
+
super
|
23
|
+
@chainable_option = other.instance_variable_get(:@chainable_option).dup
|
24
|
+
end
|
25
|
+
|
26
|
+
def with(**options)
|
27
|
+
options.each do |method_name, args|
|
28
|
+
send_args = [method_name]
|
29
|
+
send_args << args if method(method_name).parameters.present?
|
30
|
+
public_send(*send_args)
|
31
|
+
end
|
32
|
+
self
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def fetch_chainable_option(option_name, *default, &block)
|
38
|
+
@chainable_option.fetch(option_name.to_sym, *default, &block)
|
39
|
+
end
|
40
|
+
|
41
|
+
def get_or_set_chainable_option(option_name, value = NOT_SET, default: nil)
|
42
|
+
@chainable_option ||= {}
|
43
|
+
return fetch_chainable_option(option_name, default) if value == NOT_SET
|
44
|
+
|
45
|
+
@chainable_option[option_name.to_sym] = value
|
46
|
+
self
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -42,11 +42,8 @@ module GraphqlRails
|
|
42
42
|
end
|
43
43
|
|
44
44
|
def build_input_attribute(name, options: {}, **other_options)
|
45
|
-
|
46
|
-
|
47
|
-
options: input_attribute_options.merge(options),
|
48
|
-
**other_options
|
49
|
-
)
|
45
|
+
input_options = input_attribute_options.merge(options)
|
46
|
+
Attributes::InputAttribute.new(name.to_s, config: self).with(options: input_options, **other_options)
|
50
47
|
end
|
51
48
|
end
|
52
49
|
end
|
@@ -2,14 +2,25 @@
|
|
2
2
|
|
3
3
|
module GraphqlRails
|
4
4
|
module Model
|
5
|
-
#
|
6
|
-
#
|
5
|
+
# Contains methods which are shared between various configurations.
|
6
|
+
#
|
7
|
+
# Expects `default_name` to be defined.
|
8
|
+
# Expects `build_attribute(attr_name)` method to be defined.
|
7
9
|
module Configurable
|
10
|
+
require 'active_support/concern'
|
11
|
+
require 'graphql_rails/concerns/chainable_options'
|
12
|
+
|
13
|
+
extend ActiveSupport::Concern
|
14
|
+
|
15
|
+
included do
|
16
|
+
include GraphqlRails::ChainableOptions
|
17
|
+
|
18
|
+
chainable_option :description
|
19
|
+
end
|
20
|
+
|
8
21
|
def initialize_copy(other)
|
9
22
|
super
|
10
|
-
@name = nil
|
11
23
|
@type_name = nil
|
12
|
-
@description = nil
|
13
24
|
@attributes = other.attributes.transform_values(&:dup)
|
14
25
|
end
|
15
26
|
|
@@ -17,18 +28,21 @@ module GraphqlRails
|
|
17
28
|
@attributes ||= {}
|
18
29
|
end
|
19
30
|
|
20
|
-
def name(
|
21
|
-
|
22
|
-
@name || default_name
|
31
|
+
def name(*args)
|
32
|
+
get_or_set_chainable_option(:name, *args) || default_name
|
23
33
|
end
|
24
34
|
|
25
35
|
def type_name
|
26
36
|
@type_name ||= "#{name.camelize}Type#{SecureRandom.hex}"
|
27
37
|
end
|
28
38
|
|
29
|
-
def
|
30
|
-
|
31
|
-
|
39
|
+
def attribute(attribute_name, **attribute_options)
|
40
|
+
key = attribute_name.to_s
|
41
|
+
|
42
|
+
attributes[key] ||= build_attribute(attribute_name).tap do |new_attribute|
|
43
|
+
new_attribute.with(**attribute_options) unless attribute_options.empty?
|
44
|
+
yield(new_attribute) if block_given?
|
45
|
+
end
|
32
46
|
end
|
33
47
|
end
|
34
48
|
end
|
@@ -2,7 +2,6 @@
|
|
2
2
|
|
3
3
|
require 'graphql_rails/attributes'
|
4
4
|
require 'graphql_rails/model/find_or_build_graphql_type'
|
5
|
-
require 'graphql_rails/model/build_enum_type'
|
6
5
|
require 'graphql_rails/model/input'
|
7
6
|
require 'graphql_rails/model/configurable'
|
8
7
|
require 'graphql_rails/model/build_connection_type'
|
@@ -11,6 +10,7 @@ module GraphqlRails
|
|
11
10
|
module Model
|
12
11
|
# stores information about model specific config, like attributes and types
|
13
12
|
class Configuration
|
13
|
+
include ChainableOptions
|
14
14
|
include Configurable
|
15
15
|
|
16
16
|
def initialize(model_class)
|
@@ -27,16 +27,9 @@ module GraphqlRails
|
|
27
27
|
def attribute(attribute_name, **attribute_options)
|
28
28
|
key = attribute_name.to_s
|
29
29
|
|
30
|
-
attributes[key] ||=
|
31
|
-
|
32
|
-
|
33
|
-
attribute_options.each do |method_name, args|
|
34
|
-
send_args = [method_name]
|
35
|
-
send_args << args if attribute.method(method_name).parameters.present?
|
36
|
-
attribute.public_send(*send_args)
|
37
|
-
end
|
38
|
-
|
39
|
-
yield(attribute) if block_given?
|
30
|
+
attributes[key] ||= build_attribute(attribute_name).tap do |new_attribute|
|
31
|
+
new_attribute.with(**attribute_options)
|
32
|
+
yield(new_attribute) if block_given?
|
40
33
|
end
|
41
34
|
end
|
42
35
|
|
@@ -79,6 +72,10 @@ module GraphqlRails
|
|
79
72
|
|
80
73
|
attr_reader :model_class
|
81
74
|
|
75
|
+
def build_attribute(attribute_name)
|
76
|
+
Attributes::Attribute.new(attribute_name)
|
77
|
+
end
|
78
|
+
|
82
79
|
def default_name
|
83
80
|
@default_name ||= model_class.name.split('::').last
|
84
81
|
end
|
@@ -37,29 +37,30 @@ module GraphqlRails
|
|
37
37
|
end
|
38
38
|
|
39
39
|
def add_fields_to_graphql_type
|
40
|
-
|
40
|
+
scalar_attributes, dynamic_attributes = attributes.values.partition(&:scalar_type?)
|
41
41
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
name: name, description: description,
|
46
|
-
attributes: attributes, type_name: type_name
|
47
|
-
)
|
48
|
-
end
|
49
|
-
AddFieldsToGraphqlType.call(klass: klass, attributes: dynamic_attributes)
|
50
|
-
end
|
42
|
+
AddFieldsToGraphqlType.call(klass: klass, attributes: scalar_attributes)
|
43
|
+
dynamic_attributes.each { |attribute| find_or_build_dynamic_type(attribute) }
|
44
|
+
AddFieldsToGraphqlType.call(klass: klass, attributes: dynamic_attributes)
|
51
45
|
end
|
52
46
|
|
53
|
-
def
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
attribute.graphql_model.graphql.type_name
|
60
|
-
)
|
47
|
+
def find_or_build_dynamic_type(attribute)
|
48
|
+
graphql_model = attribute.graphql_model
|
49
|
+
if graphql_model
|
50
|
+
find_or_build_graphql_model_type(graphql_model)
|
51
|
+
else
|
52
|
+
AddFieldsToGraphqlType.call(klass: klass, attributes: [attribute])
|
61
53
|
end
|
62
54
|
end
|
55
|
+
|
56
|
+
def find_or_build_graphql_model_type(graphql_model)
|
57
|
+
self.class.call(
|
58
|
+
name: graphql_model.graphql.name,
|
59
|
+
description: graphql_model.graphql.description,
|
60
|
+
attributes: graphql_model.graphql.attributes,
|
61
|
+
type_name: graphql_model.graphql.type_name
|
62
|
+
)
|
63
|
+
end
|
63
64
|
end
|
64
65
|
end
|
65
66
|
end
|
@@ -1,14 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'graphql_rails/model/build_graphql_input_type'
|
4
|
-
require 'graphql_rails/model/configurable'
|
5
|
-
|
6
3
|
module GraphqlRails
|
7
4
|
module Model
|
8
5
|
# stores information about model input specific config, like attributes and types
|
9
6
|
class Input
|
7
|
+
require 'graphql_rails/concerns/chainable_options'
|
8
|
+
require 'graphql_rails/model/configurable'
|
9
|
+
require 'graphql_rails/model/build_graphql_input_type'
|
10
|
+
|
10
11
|
include Configurable
|
11
12
|
|
13
|
+
chainable_option :enum
|
14
|
+
|
12
15
|
def initialize(model_class, input_name_suffix)
|
13
16
|
@model_class = model_class
|
14
17
|
@input_name_suffix = input_name_suffix
|
@@ -20,34 +23,20 @@ module GraphqlRails
|
|
20
23
|
)
|
21
24
|
end
|
22
25
|
|
23
|
-
def attribute(attribute_name, type: nil, enum: nil, **attribute_options)
|
24
|
-
input_type = attribute_type(attribute_name, type: type, enum: enum, **attribute_options)
|
25
|
-
|
26
|
-
attributes[attribute_name.to_s] = Attributes::InputAttribute.new(
|
27
|
-
attribute_name, type: input_type, **attribute_options
|
28
|
-
)
|
29
|
-
end
|
30
|
-
|
31
26
|
private
|
32
27
|
|
33
28
|
attr_reader :input_name_suffix, :model_class
|
34
29
|
|
30
|
+
def build_attribute(attribute_name)
|
31
|
+
Attributes::InputAttribute.new(attribute_name, config: self)
|
32
|
+
end
|
33
|
+
|
35
34
|
def default_name
|
36
35
|
@default_name ||= begin
|
37
36
|
suffix = input_name_suffix ? input_name_suffix.to_s.camelize : ''
|
38
37
|
"#{model_class.name.split('::').last}#{suffix}Input"
|
39
38
|
end
|
40
39
|
end
|
41
|
-
|
42
|
-
def attribute_type(attribute_name, type:, enum:, description: nil, **_other)
|
43
|
-
return type unless enum
|
44
|
-
|
45
|
-
BuildEnumType.call(
|
46
|
-
"#{name}_#{attribute_name}_enum",
|
47
|
-
allowed_values: enum,
|
48
|
-
description: description
|
49
|
-
)
|
50
|
-
end
|
51
40
|
end
|
52
41
|
end
|
53
42
|
end
|
@@ -6,7 +6,7 @@ module GraphqlRails
|
|
6
6
|
class Router
|
7
7
|
# Generic class for any type graphql action. Should not be used directly
|
8
8
|
class Route
|
9
|
-
attr_reader :name, :module_name, :on, :relative_path
|
9
|
+
attr_reader :name, :module_name, :on, :relative_path, :groups
|
10
10
|
|
11
11
|
def initialize(name, to: '', on:, groups: nil, **options)
|
12
12
|
@name = name.to_s.camelize(:lower)
|
@@ -43,7 +43,7 @@ module GraphqlRails
|
|
43
43
|
|
44
44
|
private
|
45
45
|
|
46
|
-
attr_reader :function
|
46
|
+
attr_reader :function
|
47
47
|
|
48
48
|
def resolver
|
49
49
|
@resolver ||= Controller::BuildControllerActionResolver.call(route: self)
|
@@ -7,51 +7,37 @@ module GraphqlRails
|
|
7
7
|
|
8
8
|
class MissingGraphqlRouterError < GraphqlRails::Error; end
|
9
9
|
|
10
|
-
attr_reader :name
|
11
|
-
|
12
10
|
def self.call(**args)
|
13
11
|
new(**args).call
|
14
12
|
end
|
15
13
|
|
16
|
-
def initialize(
|
17
|
-
@
|
14
|
+
def initialize(group:, router:, dump_dir: nil)
|
15
|
+
@group = group
|
16
|
+
@router = router
|
17
|
+
@dump_dir = dump_dir
|
18
18
|
end
|
19
19
|
|
20
20
|
def call
|
21
|
-
validate
|
22
21
|
File.write(schema_path, schema.to_definition)
|
23
22
|
end
|
24
23
|
|
25
24
|
private
|
26
25
|
|
27
|
-
|
28
|
-
return if router
|
29
|
-
|
30
|
-
error_message = \
|
31
|
-
'GraphqlRouter is missing. ' \
|
32
|
-
'Run `rails g graphql_rails:install` to build it'
|
33
|
-
raise MissingGraphqlRouterError, error_message
|
34
|
-
end
|
35
|
-
|
36
|
-
def router
|
37
|
-
@router ||= '::GraphqlRouter'.safe_constantize
|
38
|
-
end
|
26
|
+
attr_reader :router, :group
|
39
27
|
|
40
28
|
def schema
|
41
|
-
@schema ||=
|
29
|
+
@schema ||= router.graphql_schema(group.presence)
|
42
30
|
end
|
43
31
|
|
44
32
|
def schema_path
|
45
|
-
|
46
|
-
|
33
|
+
FileUtils.mkdir_p(dump_dir)
|
34
|
+
file_name = group.present? ? "graphql_#{group}_schema.graphql" : 'graphql_schema.graphql'
|
47
35
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
FileUtils.mkdir_p(schema_folder_path)
|
52
|
-
file_name = name.present? ? "graphql_#{name}_schema.graphql" : 'graphql_schema.graphql'
|
36
|
+
"#{dump_dir}/#{file_name}"
|
37
|
+
end
|
53
38
|
|
54
|
-
|
39
|
+
def dump_dir
|
40
|
+
@dump_dir ||= Rails.root.join('spec/fixtures').to_s
|
55
41
|
end
|
56
42
|
end
|
57
43
|
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'graphql_rails/tasks/dump_graphql_schema'
|
4
|
+
|
5
|
+
module GraphqlRails
|
6
|
+
# Generates graphql schema dump files
|
7
|
+
class DumpGraphqlSchemas
|
8
|
+
require 'graphql_rails/errors/error'
|
9
|
+
|
10
|
+
class MissingGraphqlRouterError < GraphqlRails::Error; end
|
11
|
+
|
12
|
+
def self.call(**args)
|
13
|
+
new(**args).call
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(dump_dir:, groups: nil)
|
17
|
+
@groups = groups.presence
|
18
|
+
@dump_dir = dump_dir
|
19
|
+
end
|
20
|
+
|
21
|
+
def call
|
22
|
+
validate
|
23
|
+
return dump_default_schema if groups.empty?
|
24
|
+
|
25
|
+
groups.each { |group| dump_graphql_schema(group) }
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
attr_reader :dump_dir
|
31
|
+
|
32
|
+
def dump_default_schema
|
33
|
+
dump_graphql_schema('')
|
34
|
+
end
|
35
|
+
|
36
|
+
def dump_graphql_schema(group)
|
37
|
+
DumpGraphqlSchema.call(group: group, router: router, dump_dir: dump_dir)
|
38
|
+
end
|
39
|
+
|
40
|
+
def validate
|
41
|
+
return if router
|
42
|
+
|
43
|
+
error_message = \
|
44
|
+
'GraphqlRouter is missing. ' \
|
45
|
+
'Run `rails g graphql_rails:install` to build it'
|
46
|
+
raise MissingGraphqlRouterError, error_message
|
47
|
+
end
|
48
|
+
|
49
|
+
def router
|
50
|
+
@router ||= '::GraphqlRouter'.safe_constantize
|
51
|
+
end
|
52
|
+
|
53
|
+
def groups
|
54
|
+
@groups ||= router.routes.flat_map(&:groups).uniq
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -1,14 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'graphql_rails/tasks/
|
3
|
+
require 'graphql_rails/tasks/dump_graphql_schemas'
|
4
4
|
|
5
5
|
namespace :graphql_rails do
|
6
6
|
namespace :schema do
|
7
7
|
desc 'Dump GraphQL schema'
|
8
|
-
task(:
|
9
|
-
|
10
|
-
|
11
|
-
|
8
|
+
task(dump: :environment) do |_, args|
|
9
|
+
groups_from_args = args.extras
|
10
|
+
groups_from_env = ENV['SCHEMA_GROUP_NAME'].to_s.split(',').map(&:strip)
|
11
|
+
groups = groups_from_args + groups_from_env
|
12
|
+
dump_dir = ENV.fetch('GRAPHQL_SCHEMA_DUMP_DIR') { Rails.root.join('spec/fixtures').to_s }
|
13
|
+
|
14
|
+
GraphqlRails::DumpGraphqlSchemas.call(groups: groups, dump_dir: dump_dir)
|
12
15
|
end
|
13
16
|
end
|
14
17
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: graphql_rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Povilas Jurčys
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-12-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: graphql
|
@@ -174,12 +174,14 @@ files:
|
|
174
174
|
- lib/graphql_rails/attributes.rb
|
175
175
|
- lib/graphql_rails/attributes/attributable.rb
|
176
176
|
- lib/graphql_rails/attributes/attribute.rb
|
177
|
+
- lib/graphql_rails/attributes/attribute_configurable.rb
|
177
178
|
- lib/graphql_rails/attributes/attribute_name_parser.rb
|
178
179
|
- lib/graphql_rails/attributes/input_attribute.rb
|
179
180
|
- lib/graphql_rails/attributes/input_type_parser.rb
|
180
181
|
- lib/graphql_rails/attributes/type_name_info.rb
|
181
182
|
- lib/graphql_rails/attributes/type_parseable.rb
|
182
183
|
- lib/graphql_rails/attributes/type_parser.rb
|
184
|
+
- lib/graphql_rails/concerns/chainable_options.rb
|
183
185
|
- lib/graphql_rails/concerns/service.rb
|
184
186
|
- lib/graphql_rails/controller.rb
|
185
187
|
- lib/graphql_rails/controller/action.rb
|
@@ -226,6 +228,7 @@ files:
|
|
226
228
|
- lib/graphql_rails/router/schema_builder.rb
|
227
229
|
- lib/graphql_rails/rspec_controller_helpers.rb
|
228
230
|
- lib/graphql_rails/tasks/dump_graphql_schema.rb
|
231
|
+
- lib/graphql_rails/tasks/dump_graphql_schemas.rb
|
229
232
|
- lib/graphql_rails/tasks/schema.rake
|
230
233
|
- lib/graphql_rails/version.rb
|
231
234
|
homepage: https://github.com/samesystem/graphql_rails
|