graphql-dsl 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/workflows/main.yml +23 -0
- data/.gitignore +12 -0
- data/.rspec +2 -0
- data/.rubocop.yml +44 -0
- data/.ruby-version +1 -0
- data/.yardopts +1 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +64 -0
- data/LICENSE.txt +21 -0
- data/README.md +899 -0
- data/Rakefile +6 -0
- data/bin/console +15 -0
- data/bin/setup +7 -0
- data/graphql-dsl.gemspec +38 -0
- data/lib/graphql/dsl/constants.rb +9 -0
- data/lib/graphql/dsl/error.rb +32 -0
- data/lib/graphql/dsl/formatter/arguments.rb +26 -0
- data/lib/graphql/dsl/formatter/directives.rb +52 -0
- data/lib/graphql/dsl/formatter/executable_document.rb +22 -0
- data/lib/graphql/dsl/formatter/field.rb +49 -0
- data/lib/graphql/dsl/formatter/formatter.rb +41 -0
- data/lib/graphql/dsl/formatter/fragment_operation.rb +41 -0
- data/lib/graphql/dsl/formatter/fragment_spread.rb +25 -0
- data/lib/graphql/dsl/formatter/inline_fragment.rb +43 -0
- data/lib/graphql/dsl/formatter/operation.rb +60 -0
- data/lib/graphql/dsl/formatter/values.rb +146 -0
- data/lib/graphql/dsl/formatter/variable_definitions.rb +43 -0
- data/lib/graphql/dsl/nodes/containers/directive.rb +46 -0
- data/lib/graphql/dsl/nodes/containers/variable_definition.rb +52 -0
- data/lib/graphql/dsl/nodes/executable_document.rb +69 -0
- data/lib/graphql/dsl/nodes/field.rb +39 -0
- data/lib/graphql/dsl/nodes/fragment_operation.rb +36 -0
- data/lib/graphql/dsl/nodes/fragment_spread.rb +24 -0
- data/lib/graphql/dsl/nodes/inline_fragment.rb +34 -0
- data/lib/graphql/dsl/nodes/mixins/selection_set.rb +106 -0
- data/lib/graphql/dsl/nodes/node.rb +39 -0
- data/lib/graphql/dsl/nodes/operation.rb +61 -0
- data/lib/graphql/dsl/version.rb +9 -0
- data/lib/graphql/dsl.rb +230 -0
- data/lib/graphql-dsl.rb +3 -0
- data/lib/graphql_dsl.rb +36 -0
- data/tasks/readme/update.rake +143 -0
- metadata +173 -0
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphQL
|
4
|
+
module DSL
|
5
|
+
##
|
6
|
+
# Container for directive
|
7
|
+
class Directive
|
8
|
+
##
|
9
|
+
# @return [String, Symbol, nil] directive name
|
10
|
+
attr_reader :name
|
11
|
+
|
12
|
+
##
|
13
|
+
# @return [Hash] arguments
|
14
|
+
attr_reader :arguments
|
15
|
+
|
16
|
+
##
|
17
|
+
# Create directive container
|
18
|
+
#
|
19
|
+
# @param name [String, Symbol] directive name
|
20
|
+
# @param arguments [Hash] arguments
|
21
|
+
def initialize(name, arguments = {})
|
22
|
+
raise Error, 'Variable name must be specified' if name.nil? || name.empty?
|
23
|
+
|
24
|
+
@name = name
|
25
|
+
@arguments = arguments
|
26
|
+
end
|
27
|
+
|
28
|
+
class << self
|
29
|
+
##
|
30
|
+
# Create directive container from argument value
|
31
|
+
#
|
32
|
+
# @param value [] argument value
|
33
|
+
#
|
34
|
+
# @return [Directive] directive container
|
35
|
+
def from(value)
|
36
|
+
case value
|
37
|
+
when Directive then value
|
38
|
+
when Symbol, String then new(value)
|
39
|
+
else
|
40
|
+
raise Error.new('Unsupported format of directive', class: value.class.name, value: value)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphQL
|
4
|
+
module DSL
|
5
|
+
##
|
6
|
+
# Container for variable definition
|
7
|
+
class VariableDefinition
|
8
|
+
##
|
9
|
+
# @return [String, Symbol, nil] variable type
|
10
|
+
attr_reader :type
|
11
|
+
|
12
|
+
##
|
13
|
+
# @return [Object, nil] default value of variable
|
14
|
+
attr_reader :default
|
15
|
+
|
16
|
+
##
|
17
|
+
# @return [Array<Directive>] list of directives
|
18
|
+
attr_reader :directives
|
19
|
+
|
20
|
+
##
|
21
|
+
# Create variable definition container
|
22
|
+
#
|
23
|
+
# @param type [String, Symbol] variable type
|
24
|
+
# @param default [Object, nil] default value
|
25
|
+
# @param directives [Array<Directive, Hash, Array>] list of directives
|
26
|
+
def initialize(type, default = UNDEFINED, directives = [])
|
27
|
+
raise Error, 'Variable type must be specified' if type.nil? || type.empty?
|
28
|
+
|
29
|
+
@type = type
|
30
|
+
@default = default
|
31
|
+
@directives = directives.map { |directive| Directive.from(directive) }
|
32
|
+
end
|
33
|
+
|
34
|
+
class << self
|
35
|
+
##
|
36
|
+
# Create variable definition container from argument value
|
37
|
+
#
|
38
|
+
# @param value [] argument value
|
39
|
+
#
|
40
|
+
# @return [VariableDefinition] variable definition container
|
41
|
+
def from(value)
|
42
|
+
case value
|
43
|
+
when VariableDefinition then value
|
44
|
+
when Symbol, String then new(value)
|
45
|
+
else
|
46
|
+
raise Error.new('Unsupported format of variable definition', class: value.class.name, value: value)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphQL
|
4
|
+
module DSL
|
5
|
+
##
|
6
|
+
# Executable document GraphQL node
|
7
|
+
class ExecutableDocument < Node
|
8
|
+
##
|
9
|
+
# Create executable document
|
10
|
+
#
|
11
|
+
# @param block [Proc] declare DSL for operations
|
12
|
+
def initialize(&block)
|
13
|
+
super(nil, &block)
|
14
|
+
end
|
15
|
+
|
16
|
+
##
|
17
|
+
# Create GraphQL query operation
|
18
|
+
#
|
19
|
+
# @param name [String, Symbol, nil] query name
|
20
|
+
# @param variable_definitions [Hash] variable definitions
|
21
|
+
# @param directives [Array<Directive, Hash, Array>] list of directives
|
22
|
+
# @param block [Proc] declare DSL for sub-fields
|
23
|
+
#
|
24
|
+
# @return [void]
|
25
|
+
def query(name = nil, variable_definitions = {}, directives = [], &block)
|
26
|
+
@__nodes << Operation.new(:query, name, variable_definitions, directives, &block)
|
27
|
+
end
|
28
|
+
|
29
|
+
##
|
30
|
+
# Create GraphQL mutation operation
|
31
|
+
#
|
32
|
+
# @param name [String, Symbol, nil] mutation name
|
33
|
+
# @param variable_definitions [Hash] variable definitions
|
34
|
+
# @param directives [Array<Directive, Hash, Array>] list of directives
|
35
|
+
# @param block [Proc] declare DSL for sub-fields
|
36
|
+
#
|
37
|
+
# @return [void]
|
38
|
+
def mutation(name = nil, variable_definitions = {}, directives = [], &block)
|
39
|
+
@__nodes << Operation.new(:mutation, name, variable_definitions, directives, &block)
|
40
|
+
end
|
41
|
+
|
42
|
+
##
|
43
|
+
# Create GraphQL subscription operation
|
44
|
+
#
|
45
|
+
# @param name [String, Symbol, nil] subscription name
|
46
|
+
# @param variable_definitions [Hash] variable definitions
|
47
|
+
# @param directives [Array<Directive, Hash, Array>] list of directives
|
48
|
+
# @param block [Proc] declare DSL for sub-fields
|
49
|
+
#
|
50
|
+
# @return [void]
|
51
|
+
def subscription(name = nil, variable_definitions = {}, directives = [], &block)
|
52
|
+
@__nodes << Operation.new(:subscription, name, variable_definitions, directives, &block)
|
53
|
+
end
|
54
|
+
|
55
|
+
##
|
56
|
+
# Create GraphQL fragment operation
|
57
|
+
#
|
58
|
+
# @param name [String, Symbol] fragment name
|
59
|
+
# @param type [String, Symbol] fragment type or interface
|
60
|
+
# @param directives [Array<Directive, Hash, Array>] list of directives
|
61
|
+
# @param block [Proc] declare DSL for sub-fields
|
62
|
+
#
|
63
|
+
# @return [void]
|
64
|
+
def fragment(name, type, directives = [], &block)
|
65
|
+
@__nodes << FragmentOperation.new(name, type, directives, &block)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphQL
|
4
|
+
module DSL
|
5
|
+
##
|
6
|
+
# Field GraphQL node
|
7
|
+
class Field < Node
|
8
|
+
include SelectionSet
|
9
|
+
|
10
|
+
##
|
11
|
+
# @return [String, Symbol, nil] field alias
|
12
|
+
attr_reader :__alias
|
13
|
+
|
14
|
+
##
|
15
|
+
# @return [Hash] list of filed arguments
|
16
|
+
attr_reader :__arguments
|
17
|
+
|
18
|
+
##
|
19
|
+
# @return [Array<Directive>] list of directives
|
20
|
+
attr_reader :__directives
|
21
|
+
|
22
|
+
##
|
23
|
+
# Create field
|
24
|
+
#
|
25
|
+
# @param field_name [String, Symbol] field name
|
26
|
+
# @param field_alias [String, Symbol, nil] field alias
|
27
|
+
# @param arguments [Hash] field arguments
|
28
|
+
# @param directives [Array<Directive, Hash, Array>] list of directives
|
29
|
+
# @param block [Proc] declare DSL for sub-fields
|
30
|
+
def initialize(field_name, field_alias = nil, arguments = {}, directives = [], &block)
|
31
|
+
@__alias = field_alias
|
32
|
+
@__arguments = arguments
|
33
|
+
@__directives = directives.map { |directive| Directive.from(directive) }
|
34
|
+
|
35
|
+
super(field_name, &block)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphQL
|
4
|
+
module DSL
|
5
|
+
##
|
6
|
+
# Fragment operation GraphQL node
|
7
|
+
class FragmentOperation < Node
|
8
|
+
include SelectionSet
|
9
|
+
|
10
|
+
##
|
11
|
+
# @return [String, Symbol] fragment type or interface
|
12
|
+
attr_reader :__type
|
13
|
+
|
14
|
+
##
|
15
|
+
# @return [Array<Directive>] list of directives
|
16
|
+
attr_reader :__directives
|
17
|
+
|
18
|
+
##
|
19
|
+
# Create fragment operation
|
20
|
+
#
|
21
|
+
# @param name [String, Symbol] fragment name
|
22
|
+
# @param type [String, Symbol] fragment type or interface
|
23
|
+
# @param directives [Array<Directive, Hash, Array>] list of directives
|
24
|
+
# @param block [Proc] declare DSL for sub-fields
|
25
|
+
def initialize(name, type, directives = [], &block)
|
26
|
+
raise Error, '`name` must be specified' if name.nil? || name.empty?
|
27
|
+
raise Error, '`type` must be specified' if type.nil? || type.empty?
|
28
|
+
|
29
|
+
@__type = type
|
30
|
+
@__directives = directives.map { |directive| Directive.from(directive) }
|
31
|
+
|
32
|
+
super(name, &block)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphQL
|
4
|
+
module DSL
|
5
|
+
##
|
6
|
+
# Fragment spread GraphQL node
|
7
|
+
class FragmentSpread < Node
|
8
|
+
##
|
9
|
+
# @return [Array<Directive>] list of directives
|
10
|
+
attr_reader :__directives
|
11
|
+
|
12
|
+
##
|
13
|
+
# Create fragment spread
|
14
|
+
#
|
15
|
+
# @param name [String, Symbol] fragment name
|
16
|
+
# @param directives [Array<Hash, Array, Directive>] list of directives
|
17
|
+
def initialize(name, directives = [])
|
18
|
+
@__directives = directives.map { |directive| Directive.from(directive) }
|
19
|
+
|
20
|
+
super(name)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphQL
|
4
|
+
module DSL
|
5
|
+
##
|
6
|
+
# Inline fragment GraphQL node
|
7
|
+
class InlineFragment < Node
|
8
|
+
include SelectionSet
|
9
|
+
|
10
|
+
##
|
11
|
+
# @return [String, Symbol, nil] inline fragment type or interface
|
12
|
+
attr_reader :__type
|
13
|
+
|
14
|
+
##
|
15
|
+
# @return [Array<Directive>] list of directives
|
16
|
+
attr_reader :__directives
|
17
|
+
|
18
|
+
##
|
19
|
+
# Create inline fragment
|
20
|
+
#
|
21
|
+
# @param type [String, Symbol, nil] fragment type
|
22
|
+
# @param directives [Array<Directive, Hash, Array>] list of directives
|
23
|
+
# @param block [Proc] declare DSL for sub-fields
|
24
|
+
def initialize(type = nil, directives = [], &block)
|
25
|
+
raise Error, 'Sub-fields must be specified for inline fragment' if block.nil?
|
26
|
+
|
27
|
+
@__type = type
|
28
|
+
@__directives = directives.map { |directive| Directive.from(directive) }
|
29
|
+
|
30
|
+
super(nil, &block)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphQL
|
4
|
+
module DSL
|
5
|
+
##
|
6
|
+
# This mixin help to reuse selections sets
|
7
|
+
module SelectionSet
|
8
|
+
##
|
9
|
+
# Declare new GraphQL field
|
10
|
+
#
|
11
|
+
# This method can help to avoid name collisions i.e. +__field(:object_id)+
|
12
|
+
#
|
13
|
+
# @param name [String, Symbol] field name
|
14
|
+
# @param __alias [String, Symbol, nil] field alias
|
15
|
+
# @param __directives [Array] list of directives
|
16
|
+
# @param arguments [Hash] field arguments
|
17
|
+
# @param block [Proc] declare sub-fields
|
18
|
+
#
|
19
|
+
# @return [void]
|
20
|
+
#
|
21
|
+
# @example Declare fields use __field method (i.e. use GraphQL query)
|
22
|
+
# query = GraphQL::DSL.query {
|
23
|
+
# __field(:field1, id: 1) {
|
24
|
+
# __field(:subfield1, id: 1)
|
25
|
+
# __field(:subfield2, id: 2)
|
26
|
+
# }
|
27
|
+
# }
|
28
|
+
#
|
29
|
+
# @example Declare fields use DSL (i.e. use GraphQL query)
|
30
|
+
# query = GraphQL::DSL.query {
|
31
|
+
# field1 id: 1 {
|
32
|
+
# subfield1 id: 1
|
33
|
+
# subfield2 id: 2
|
34
|
+
# }
|
35
|
+
# }
|
36
|
+
def __field(name, __alias: nil, __directives: [], **arguments, &block) # rubocop:disable Lint/UnderscorePrefixedVariableName
|
37
|
+
@__nodes << Field.new(name, __alias, arguments, __directives, &block)
|
38
|
+
end
|
39
|
+
|
40
|
+
###
|
41
|
+
# Insert GraphQL fragment
|
42
|
+
#
|
43
|
+
# @param name [String, Symbol] fragment name
|
44
|
+
# @param __directives [Array] list of directives
|
45
|
+
#
|
46
|
+
# @return [void]
|
47
|
+
#
|
48
|
+
# @example Insert fragment with +fragment1+ name
|
49
|
+
# query = GraphQL::DSL.query {
|
50
|
+
# field1 id: 1 {
|
51
|
+
# __fragment :fragment1
|
52
|
+
# }
|
53
|
+
# }
|
54
|
+
def __fragment(name, __directives: []) # rubocop:disable Lint/UnderscorePrefixedVariableName
|
55
|
+
@__nodes << FragmentSpread.new(name, __directives)
|
56
|
+
end
|
57
|
+
|
58
|
+
###
|
59
|
+
# Insert GraphQL inline fragment
|
60
|
+
#
|
61
|
+
# @param type [String, Symbol, nil] fragment type
|
62
|
+
# @param __directives [Array] list of directives
|
63
|
+
# @param block [Proc] declare DSL for sub-fields
|
64
|
+
#
|
65
|
+
# @return [void]
|
66
|
+
def __inline_fragment(type, __directives: [], &block) # rubocop:disable Lint/UnderscorePrefixedVariableName
|
67
|
+
@__nodes << InlineFragment.new(type, __directives, &block)
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
##
|
73
|
+
# Allow to respond to method missing at any case.
|
74
|
+
def respond_to_missing?(_method_name, _include_private = false)
|
75
|
+
true
|
76
|
+
end
|
77
|
+
|
78
|
+
##
|
79
|
+
# Declare new GraphQL field
|
80
|
+
#
|
81
|
+
# @example Declare fields (i.e. use GraphQL query)
|
82
|
+
# query = GraphQL::DSL.query {
|
83
|
+
# items {
|
84
|
+
# id
|
85
|
+
# title
|
86
|
+
# }
|
87
|
+
# }
|
88
|
+
#
|
89
|
+
# puts query.to_gql
|
90
|
+
# # {
|
91
|
+
# # items
|
92
|
+
# # {
|
93
|
+
# # id
|
94
|
+
# # title
|
95
|
+
# # }
|
96
|
+
# # }
|
97
|
+
#
|
98
|
+
# @see #__field
|
99
|
+
def method_missing(name, *args, &block)
|
100
|
+
arguments = args.empty? ? {} : args[0]
|
101
|
+
|
102
|
+
__field(name, **arguments, &block)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphQL
|
4
|
+
module DSL
|
5
|
+
##
|
6
|
+
# @abstract Base class for all GraphQL DSL nodes
|
7
|
+
class Node
|
8
|
+
##
|
9
|
+
# @return [String, Symbol, nil] node name
|
10
|
+
attr_reader :__name
|
11
|
+
|
12
|
+
# @return [Array<Node>] list of sub-nodes
|
13
|
+
attr_reader :__nodes
|
14
|
+
|
15
|
+
##
|
16
|
+
# Create node
|
17
|
+
#
|
18
|
+
# @param name [String, Symbol, nil] node name
|
19
|
+
# @param block [Proc] declare DSL for sub-nodes
|
20
|
+
def initialize(name = nil, &block)
|
21
|
+
@__name = name
|
22
|
+
@__nodes = []
|
23
|
+
|
24
|
+
instance_eval(&block) if block
|
25
|
+
end
|
26
|
+
|
27
|
+
##
|
28
|
+
# Generate GraphQL query
|
29
|
+
#
|
30
|
+
# @param level [Integer] indent level
|
31
|
+
# @param formatter [Formatter] GraphQL query formatter
|
32
|
+
#
|
33
|
+
# @return [String] GraphQL query string
|
34
|
+
def to_gql(level = 0, formatter = Formatter.new)
|
35
|
+
formatter.format_node(self, level)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphQL
|
4
|
+
module DSL
|
5
|
+
##
|
6
|
+
# Operation GraphQL node
|
7
|
+
class Operation < Node
|
8
|
+
include SelectionSet
|
9
|
+
|
10
|
+
##
|
11
|
+
# @return [Symbol] operation type (see {#initialize})
|
12
|
+
attr_reader :__operation_type
|
13
|
+
|
14
|
+
##
|
15
|
+
# @return [Hash<Symbol, VariableDefinition>] variable definitions
|
16
|
+
attr_reader :__variable_definitions
|
17
|
+
|
18
|
+
##
|
19
|
+
# @return [Array<Directive>] list of directives
|
20
|
+
attr_reader :__directives
|
21
|
+
|
22
|
+
##
|
23
|
+
# Create operation (query, mutation, subscription)
|
24
|
+
#
|
25
|
+
# @param operation_type [Symbol] operation type
|
26
|
+
# @option operation_type [Symbol] :query query operation
|
27
|
+
# @option operation_type [Symbol] :mutation mutation operation
|
28
|
+
# @option operation_type [Symbol] :subscription subscription operation
|
29
|
+
# @param name [String, Symbol, nil] operation name
|
30
|
+
# @param variable_definitions [Hash] variable definitions
|
31
|
+
# @param directives [Array<Directive, Hash, Array>] list of directives
|
32
|
+
# @param block [Proc] declare DSL for sub-fields
|
33
|
+
def initialize(operation_type, name = nil, variable_definitions = {}, directives = [], &block)
|
34
|
+
variable_definitions.each do |variable_name, _|
|
35
|
+
raise Error, 'Variable name must be specified' if variable_name.nil? || variable_name.empty?
|
36
|
+
end
|
37
|
+
|
38
|
+
@__operation_type = operation_type
|
39
|
+
@__variable_definitions = variable_definitions.transform_values do |variable_definition|
|
40
|
+
VariableDefinition.from(variable_definition)
|
41
|
+
end
|
42
|
+
@__directives = directives.map { |directive| Directive.from(directive) }
|
43
|
+
|
44
|
+
super(name, &block)
|
45
|
+
end
|
46
|
+
|
47
|
+
##
|
48
|
+
# Declare operation variable
|
49
|
+
#
|
50
|
+
# @param name [Symbol, String] variable name
|
51
|
+
# @param type [Symbol, String] variable type
|
52
|
+
# @param directives [Array<Directive, Hash, Array>] variable directives
|
53
|
+
# @param default [Object] variable default value
|
54
|
+
#
|
55
|
+
# @return [void]
|
56
|
+
def __var(name, type, default: UNDEFINED, directives: [])
|
57
|
+
@__variable_definitions[name] = VariableDefinition.new(type, default, directives)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|