graphql-dsl 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 (45) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/main.yml +23 -0
  3. data/.gitignore +12 -0
  4. data/.rspec +2 -0
  5. data/.rubocop.yml +44 -0
  6. data/.ruby-version +1 -0
  7. data/.yardopts +1 -0
  8. data/CODE_OF_CONDUCT.md +84 -0
  9. data/Gemfile +6 -0
  10. data/Gemfile.lock +64 -0
  11. data/LICENSE.txt +21 -0
  12. data/README.md +899 -0
  13. data/Rakefile +6 -0
  14. data/bin/console +15 -0
  15. data/bin/setup +7 -0
  16. data/graphql-dsl.gemspec +38 -0
  17. data/lib/graphql/dsl/constants.rb +9 -0
  18. data/lib/graphql/dsl/error.rb +32 -0
  19. data/lib/graphql/dsl/formatter/arguments.rb +26 -0
  20. data/lib/graphql/dsl/formatter/directives.rb +52 -0
  21. data/lib/graphql/dsl/formatter/executable_document.rb +22 -0
  22. data/lib/graphql/dsl/formatter/field.rb +49 -0
  23. data/lib/graphql/dsl/formatter/formatter.rb +41 -0
  24. data/lib/graphql/dsl/formatter/fragment_operation.rb +41 -0
  25. data/lib/graphql/dsl/formatter/fragment_spread.rb +25 -0
  26. data/lib/graphql/dsl/formatter/inline_fragment.rb +43 -0
  27. data/lib/graphql/dsl/formatter/operation.rb +60 -0
  28. data/lib/graphql/dsl/formatter/values.rb +146 -0
  29. data/lib/graphql/dsl/formatter/variable_definitions.rb +43 -0
  30. data/lib/graphql/dsl/nodes/containers/directive.rb +46 -0
  31. data/lib/graphql/dsl/nodes/containers/variable_definition.rb +52 -0
  32. data/lib/graphql/dsl/nodes/executable_document.rb +69 -0
  33. data/lib/graphql/dsl/nodes/field.rb +39 -0
  34. data/lib/graphql/dsl/nodes/fragment_operation.rb +36 -0
  35. data/lib/graphql/dsl/nodes/fragment_spread.rb +24 -0
  36. data/lib/graphql/dsl/nodes/inline_fragment.rb +34 -0
  37. data/lib/graphql/dsl/nodes/mixins/selection_set.rb +106 -0
  38. data/lib/graphql/dsl/nodes/node.rb +39 -0
  39. data/lib/graphql/dsl/nodes/operation.rb +61 -0
  40. data/lib/graphql/dsl/version.rb +9 -0
  41. data/lib/graphql/dsl.rb +230 -0
  42. data/lib/graphql-dsl.rb +3 -0
  43. data/lib/graphql_dsl.rb +36 -0
  44. data/tasks/readme/update.rake +143 -0
  45. 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
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ module DSL
5
+ ##
6
+ # Gem version
7
+ VERSION = '1.0.0'
8
+ end
9
+ end