graphql 1.4.5 → 1.5.3

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 (139) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/enum_generator.rb +33 -0
  3. data/lib/generators/graphql/function_generator.rb +15 -0
  4. data/lib/generators/graphql/install_generator.rb +118 -0
  5. data/lib/generators/graphql/interface_generator.rb +27 -0
  6. data/lib/generators/graphql/loader_generator.rb +17 -0
  7. data/lib/generators/graphql/mutation_generator.rb +19 -0
  8. data/lib/generators/graphql/object_generator.rb +34 -0
  9. data/lib/generators/graphql/templates/enum.erb +4 -0
  10. data/lib/generators/graphql/templates/function.erb +17 -0
  11. data/lib/generators/graphql/templates/graphql_controller.erb +32 -0
  12. data/lib/generators/graphql/templates/interface.erb +4 -0
  13. data/lib/generators/graphql/templates/loader.erb +15 -0
  14. data/lib/generators/graphql/templates/mutation.erb +12 -0
  15. data/lib/generators/graphql/templates/object.erb +5 -0
  16. data/lib/generators/graphql/templates/query_type.erb +15 -0
  17. data/lib/generators/graphql/templates/schema.erb +34 -0
  18. data/lib/generators/graphql/templates/union.erb +4 -0
  19. data/lib/generators/graphql/type_generator.rb +78 -0
  20. data/lib/generators/graphql/union_generator.rb +33 -0
  21. data/lib/graphql.rb +10 -0
  22. data/lib/graphql/analysis/analyze_query.rb +1 -1
  23. data/lib/graphql/analysis/query_complexity.rb +6 -50
  24. data/lib/graphql/analysis/query_depth.rb +1 -1
  25. data/lib/graphql/argument.rb +21 -0
  26. data/lib/graphql/compatibility/execution_specification/counter_schema.rb +3 -3
  27. data/lib/graphql/define.rb +1 -0
  28. data/lib/graphql/define/assign_argument.rb +3 -19
  29. data/lib/graphql/define/assign_mutation_function.rb +34 -0
  30. data/lib/graphql/define/assign_object_field.rb +26 -14
  31. data/lib/graphql/define/defined_object_proxy.rb +21 -0
  32. data/lib/graphql/define/instance_definable.rb +61 -11
  33. data/lib/graphql/directive.rb +6 -1
  34. data/lib/graphql/execution/directive_checks.rb +1 -0
  35. data/lib/graphql/execution/execute.rb +14 -9
  36. data/lib/graphql/execution/field_result.rb +1 -0
  37. data/lib/graphql/execution/lazy.rb +8 -17
  38. data/lib/graphql/execution/lazy/lazy_method_map.rb +2 -0
  39. data/lib/graphql/execution/lazy/resolve.rb +1 -0
  40. data/lib/graphql/execution/selection_result.rb +1 -0
  41. data/lib/graphql/execution/typecast.rb +39 -26
  42. data/lib/graphql/field.rb +15 -3
  43. data/lib/graphql/field/resolve.rb +3 -3
  44. data/lib/graphql/function.rb +134 -0
  45. data/lib/graphql/id_type.rb +1 -1
  46. data/lib/graphql/input_object_type.rb +1 -1
  47. data/lib/graphql/internal_representation.rb +1 -1
  48. data/lib/graphql/internal_representation/node.rb +35 -107
  49. data/lib/graphql/internal_representation/rewrite.rb +189 -183
  50. data/lib/graphql/internal_representation/visit.rb +38 -0
  51. data/lib/graphql/introspection/input_value_type.rb +10 -1
  52. data/lib/graphql/introspection/schema_type.rb +1 -1
  53. data/lib/graphql/language/lexer.rb +6 -3
  54. data/lib/graphql/language/lexer.rl +6 -3
  55. data/lib/graphql/object_type.rb +53 -13
  56. data/lib/graphql/query.rb +30 -14
  57. data/lib/graphql/query/arguments.rb +2 -0
  58. data/lib/graphql/query/context.rb +2 -2
  59. data/lib/graphql/query/literal_input.rb +9 -0
  60. data/lib/graphql/query/serial_execution/field_resolution.rb +2 -2
  61. data/lib/graphql/query/serial_execution/selection_resolution.rb +1 -1
  62. data/lib/graphql/relay.rb +1 -0
  63. data/lib/graphql/relay/array_connection.rb +1 -1
  64. data/lib/graphql/relay/base_connection.rb +34 -15
  65. data/lib/graphql/relay/connection_resolve.rb +7 -2
  66. data/lib/graphql/relay/mutation.rb +45 -4
  67. data/lib/graphql/relay/node.rb +18 -6
  68. data/lib/graphql/relay/range_add.rb +45 -0
  69. data/lib/graphql/relay/relation_connection.rb +17 -2
  70. data/lib/graphql/runtime_type_error.rb +1 -0
  71. data/lib/graphql/schema.rb +40 -5
  72. data/lib/graphql/schema/base_64_encoder.rb +1 -0
  73. data/lib/graphql/schema/build_from_definition.rb +56 -21
  74. data/lib/graphql/schema/default_parse_error.rb +10 -0
  75. data/lib/graphql/schema/loader.rb +8 -1
  76. data/lib/graphql/schema/null_mask.rb +1 -0
  77. data/lib/graphql/schema/validation.rb +35 -0
  78. data/lib/graphql/static_validation.rb +1 -0
  79. data/lib/graphql/static_validation/all_rules.rb +1 -0
  80. data/lib/graphql/static_validation/arguments_validator.rb +7 -4
  81. data/lib/graphql/static_validation/definition_dependencies.rb +183 -0
  82. data/lib/graphql/static_validation/rules/fields_will_merge.rb +28 -96
  83. data/lib/graphql/static_validation/rules/fragment_names_are_unique.rb +23 -0
  84. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +8 -5
  85. data/lib/graphql/static_validation/rules/fragments_are_finite.rb +6 -31
  86. data/lib/graphql/static_validation/rules/fragments_are_used.rb +11 -41
  87. data/lib/graphql/static_validation/rules/operation_names_are_valid.rb +2 -2
  88. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +19 -7
  89. data/lib/graphql/static_validation/validation_context.rb +22 -1
  90. data/lib/graphql/static_validation/validator.rb +4 -1
  91. data/lib/graphql/string_type.rb +5 -1
  92. data/lib/graphql/version.rb +1 -1
  93. data/readme.md +12 -3
  94. data/spec/generators/graphql/enum_generator_spec.rb +29 -0
  95. data/spec/generators/graphql/function_generator_spec.rb +33 -0
  96. data/spec/generators/graphql/install_generator_spec.rb +185 -0
  97. data/spec/generators/graphql/interface_generator_spec.rb +32 -0
  98. data/spec/generators/graphql/loader_generator_spec.rb +31 -0
  99. data/spec/generators/graphql/mutation_generator_spec.rb +28 -0
  100. data/spec/generators/graphql/object_generator_spec.rb +42 -0
  101. data/spec/generators/graphql/union_generator_spec.rb +50 -0
  102. data/spec/graphql/analysis/query_complexity_spec.rb +2 -1
  103. data/spec/graphql/define/instance_definable_spec.rb +38 -0
  104. data/spec/graphql/directive/skip_directive_spec.rb +1 -0
  105. data/spec/graphql/directive_spec.rb +18 -0
  106. data/spec/graphql/execution/typecast_spec.rb +41 -46
  107. data/spec/graphql/field_spec.rb +1 -1
  108. data/spec/graphql/function_spec.rb +128 -0
  109. data/spec/graphql/internal_representation/rewrite_spec.rb +166 -129
  110. data/spec/graphql/introspection/type_type_spec.rb +1 -1
  111. data/spec/graphql/language/lexer_spec.rb +6 -0
  112. data/spec/graphql/object_type_spec.rb +73 -2
  113. data/spec/graphql/query/arguments_spec.rb +28 -0
  114. data/spec/graphql/query/variables_spec.rb +7 -1
  115. data/spec/graphql/query_spec.rb +30 -0
  116. data/spec/graphql/relay/base_connection_spec.rb +26 -8
  117. data/spec/graphql/relay/connection_resolve_spec.rb +45 -0
  118. data/spec/graphql/relay/connection_type_spec.rb +21 -0
  119. data/spec/graphql/relay/node_spec.rb +30 -2
  120. data/spec/graphql/relay/range_add_spec.rb +113 -0
  121. data/spec/graphql/schema/build_from_definition_spec.rb +114 -0
  122. data/spec/graphql/schema/loader_spec.rb +1 -0
  123. data/spec/graphql/schema/printer_spec.rb +2 -2
  124. data/spec/graphql/schema/validation_spec.rb +80 -11
  125. data/spec/graphql/schema/warden_spec.rb +10 -10
  126. data/spec/graphql/schema_spec.rb +18 -1
  127. data/spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb +16 -0
  128. data/spec/graphql/static_validation/rules/fields_will_merge_spec.rb +50 -3
  129. data/spec/graphql/static_validation/rules/fragment_names_are_unique_spec.rb +27 -0
  130. data/spec/graphql/static_validation/rules/fragments_are_finite_spec.rb +57 -0
  131. data/spec/graphql/static_validation/rules/fragments_are_used_spec.rb +1 -1
  132. data/spec/graphql/static_validation/rules/variables_are_input_types_spec.rb +14 -0
  133. data/spec/graphql/string_type_spec.rb +7 -0
  134. data/spec/spec_helper.rb +3 -3
  135. data/spec/support/base_generator_test.rb +7 -0
  136. data/spec/support/dummy/schema.rb +32 -30
  137. data/spec/support/star_wars/schema.rb +81 -23
  138. metadata +98 -20
  139. data/lib/graphql/internal_representation/selection.rb +0 -85
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: dbc1c5f1e53ac27a08d6ffa5956514b54d1fb547
4
- data.tar.gz: 4614d534b6cf6b55140909b0b04af5ce9560b3cd
3
+ metadata.gz: f8a07faba9f807e0d1a1cb2d658dbb03aebd5aff
4
+ data.tar.gz: 7cc789d4ff25519e433770bab5fbdff0421338c4
5
5
  SHA512:
6
- metadata.gz: 39b333cf8e34be84ab666461a8609c11468783a906f927998b31f5a1ff96c4ca40f114769871bb421b9d7f51b21fa4c0aa6ab018ef543713da431ff0983fca75
7
- data.tar.gz: 2d0a5d0e3aaf5d53735ae687a6486ed3c1387bd325c51eb482cc6bb7dbb275ba880e7d5680229118309b2e2056ad23422473f43a4167ae580947e0120ea89d0d
6
+ metadata.gz: c4699ee8d911f2a26824b08f938bec2d3b564f28864491d355d242e91dd79b17de8b301d91f8016409cf76da93e811364620bb24637a81a616093df5a16a2035
7
+ data.tar.gz: f805fd9332370ceb6876dc9e68178a5f1753edb6993e14881eba5b36bb7935502a7419c7a0d03fd0b405533be943f4cc4db50f430b7f61cafd331a3ab97a7858
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+ require 'generators/graphql/type_generator'
3
+
4
+ module Graphql
5
+ module Generators
6
+ # Generate an interface type by name,
7
+ # with the specified fields.
8
+ #
9
+ # ```
10
+ # rails g graphql:interface NamedEntityType name:String!
11
+ # ```
12
+ class EnumGenerator < TypeGeneratorBase
13
+ desc "Create a GraphQL::EnumType with the given name and values"
14
+ source_root File.expand_path('../templates', __FILE__)
15
+
16
+ argument :values,
17
+ type: :array,
18
+ default: [],
19
+ banner: "value{:ruby_value} value{:ruby_value} ...",
20
+ desc: "Values for this enum (if present, ruby_value will be inserted verbatim)"
21
+
22
+ def create_type_file
23
+ template "enum.erb", "app/graphql/types/#{type_file_name}.rb"
24
+ end
25
+
26
+ private
27
+
28
+ def prepared_values
29
+ values.map { |v| v.split(":", 2) }
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+ require "rails/generators/named_base"
3
+
4
+ module Graphql
5
+ module Generators
6
+ class FunctionGenerator < Rails::Generators::NamedBase
7
+ desc "Create a GraphQL::Function by name"
8
+ source_root File.expand_path('../templates', __FILE__)
9
+
10
+ def create_function_file
11
+ template "function.erb", "app/graphql/functions/#{file_name}.rb"
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,118 @@
1
+ # frozen_string_literal: true
2
+ require 'rails/generators/base'
3
+
4
+ module Graphql
5
+ module Generators
6
+ # Add GraphQL to a Rails app with `rails g graphql:install`.
7
+ #
8
+ # Setup a folder structure for GraphQL:
9
+ #
10
+ # ```
11
+ # - app/
12
+ # - graphql/
13
+ # - resolvers/
14
+ # - types/
15
+ # - query_type.rb
16
+ # - loaders/
17
+ # - mutations/
18
+ # - {app_name}_schema.rb
19
+ # ```
20
+ #
21
+ # (Add `.gitkeep`s by default, support `--skip-keeps`)
22
+ #
23
+ # Add a controller for serving GraphQL queries:
24
+ #
25
+ # ```
26
+ # app/controllers/graphql_controller.rb
27
+ # ```
28
+ #
29
+ # Add a route for that controller:
30
+ #
31
+ # ```ruby
32
+ # # config/routes.rb
33
+ # post "/graphql", to: "graphql#execute"
34
+ # ```
35
+ #
36
+ # Accept a `--relay` option which adds
37
+ # The root `node(id: ID!)` field.
38
+ #
39
+ # Accept a `--batch` option which adds `GraphQL::Batch` setup.
40
+ #
41
+ # Use `--no-graphiql` to skip `graphiql-rails` installation.
42
+ class InstallGenerator < Rails::Generators::Base
43
+ desc "Install GraphQL folder structure and boilerplate code"
44
+ source_root File.expand_path('../templates', __FILE__)
45
+
46
+ class_option :schema,
47
+ type: :string,
48
+ default: nil,
49
+ desc: "Name for the schema constant (default: {app_name}Schema)"
50
+
51
+ class_option :skip_keeps,
52
+ type: :boolean,
53
+ default: false,
54
+ desc: "Skip .keep files for source control"
55
+
56
+ class_option :skip_graphiql,
57
+ type: :boolean,
58
+ default: false,
59
+ desc: "Skip graphiql-rails installation"
60
+
61
+ class_option :relay,
62
+ type: :boolean,
63
+ default: false,
64
+ desc: "Include GraphQL::Relay installation"
65
+
66
+ class_option :batch,
67
+ type: :boolean,
68
+ default: false,
69
+ desc: "Include GraphQL::Batch installation"
70
+
71
+
72
+ GRAPHIQL_ROUTE = <<-RUBY
73
+ if Rails.env.development?
74
+ mount GraphiQL::Rails::Engine, at: "/graphiql", graphql_path: "/graphql"
75
+ end
76
+ RUBY
77
+
78
+ def create_folder_structure
79
+ create_dir("app/graphql/mutations")
80
+ create_dir("app/graphql/types")
81
+ template("query_type.erb", "app/graphql/types/query_type.rb")
82
+ template("schema.erb", "app/graphql/#{schema_name.underscore}.rb")
83
+ template("graphql_controller.erb", "app/controllers/graphql_controller.rb")
84
+ route('post "/graphql", to: "graphql#execute"')
85
+
86
+ if !options[:skip_graphiql]
87
+ gem("graphiql-rails", group: :development)
88
+ route(GRAPHIQL_ROUTE)
89
+ end
90
+
91
+ if options[:batch]
92
+ gem("graphql-batch")
93
+ create_dir("app/graphql/loaders")
94
+ end
95
+ end
96
+
97
+ private
98
+
99
+ def create_dir(dir)
100
+ empty_directory(dir)
101
+ if !options[:skip_keeps]
102
+ create_file("#{dir}/.keep")
103
+ end
104
+ end
105
+
106
+ def schema_name
107
+ @schema_name ||= begin
108
+ if options[:schema]
109
+ options[:schema]
110
+ else
111
+ require File.expand_path("config/application", destination_root)
112
+ "#{Rails.application.class.parent_name}Schema"
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+ require 'generators/graphql/type_generator'
3
+
4
+ module Graphql
5
+ module Generators
6
+ # Generate an interface type by name,
7
+ # with the specified fields.
8
+ #
9
+ # ```
10
+ # rails g graphql:interface NamedEntityType name:String!
11
+ # ```
12
+ class InterfaceGenerator < TypeGeneratorBase
13
+ desc "Create a GraphQL::InterfaceType with the given name and fields"
14
+ source_root File.expand_path('../templates', __FILE__)
15
+
16
+ argument :fields,
17
+ type: :array,
18
+ default: [],
19
+ banner: "name:type name:type ...",
20
+ desc: "Fields for this interface (type may be expressed as Ruby or GraphQL)"
21
+
22
+ def create_type_file
23
+ template "interface.erb", "app/graphql/types/#{type_file_name}.rb"
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+ require "rails/generators/named_base"
3
+
4
+ module Graphql
5
+ module Generators
6
+ # @example Generate a `GraphQL::Batch` loader by name.
7
+ # rails g graphql:loader RecordLoader
8
+ class LoaderGenerator < Rails::Generators::NamedBase
9
+ desc "Create a GraphQL::Batch::Loader by name"
10
+ source_root File.expand_path('../templates', __FILE__)
11
+
12
+ def create_loader_file
13
+ template "loader.erb", "app/graphql/loaders/#{file_name}.rb"
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+ require 'rails/generators/named_base'
3
+
4
+ module Graphql
5
+ module Generators
6
+ # TODO: What other options should be supported?
7
+ #
8
+ # @example Generate a `Relay::Mutation` by name
9
+ # rails g graphql:mutation CreatePostMutation
10
+ class MutationGenerator < Rails::Generators::NamedBase
11
+ desc "Create a Relay mutation by name"
12
+ source_root File.expand_path('../templates', __FILE__)
13
+
14
+ def create_mutation_file
15
+ template "mutation.erb", "app/graphql/mutations/#{file_name}.rb"
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+ require 'generators/graphql/type_generator'
3
+
4
+ module Graphql
5
+ module Generators
6
+ # Generate an object type by name,
7
+ # with the specified fields.
8
+ #
9
+ # ```
10
+ # rails g graphql:object PostType name:String!
11
+ # ```
12
+ #
13
+ # Add the Node interface with `--node`.
14
+ class ObjectGenerator < TypeGeneratorBase
15
+ desc "Create a GraphQL::ObjectType with the given name and fields"
16
+ source_root File.expand_path('../templates', __FILE__)
17
+
18
+ argument :fields,
19
+ type: :array,
20
+ default: [],
21
+ banner: "name:type name:type ...",
22
+ desc: "Fields for this object (type may be expressed as Ruby or GraphQL)"
23
+
24
+ class_option :node,
25
+ type: :boolean,
26
+ default: false,
27
+ desc: "Include the Relay Node interface"
28
+
29
+ def create_type_file
30
+ template "object.erb", "app/graphql/types/#{type_file_name}.rb"
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,4 @@
1
+ <%= type_ruby_name %> = GraphQL::EnumType.define do
2
+ name "<%= type_graphql_name %>"
3
+ <% prepared_values.each do |v| %> value "<%= v[0] %>"<%= v.length > 1 ? ", value: #{v[1]}" : "" %>
4
+ <% end %>end
@@ -0,0 +1,17 @@
1
+ class Functions::<%= name %> < GraphQL::Function
2
+ # Define `initialize` to store field-level options, eg
3
+ #
4
+ # field :myField, function: Functions::<%= name %>.new(type: MyType)
5
+ #
6
+ # attr_reader :type
7
+ # def initialize(type:)
8
+ # @type = type
9
+ # end
10
+
11
+ # add arguments by type:
12
+ # argument :id, !GraphQL::ID_TYPE
13
+
14
+ # Resolve function:
15
+ def call(obj, args, ctx)
16
+ end
17
+ end
@@ -0,0 +1,32 @@
1
+ class GraphqlController < ApplicationController
2
+ def execute
3
+ variables = ensure_hash(params[:variables])
4
+ query = params[:query]
5
+ context = {
6
+ # Query context goes here, for example:
7
+ # current_user: current_user,
8
+ }
9
+ result = <%= schema_name %>.execute(query, variables: variables, context: context)
10
+ render json: result
11
+ end
12
+
13
+ private
14
+
15
+ # Handle form data, JSON body, or a blank value
16
+ def ensure_hash(ambiguous_param)
17
+ case ambiguous_param
18
+ when String
19
+ if ambiguous_param.present?
20
+ ensure_hash(JSON.parse(ambiguous_param))
21
+ else
22
+ {}
23
+ end
24
+ when Hash, ActionController::Parameters
25
+ ambiguous_param
26
+ when nil
27
+ {}
28
+ else
29
+ raise ArgumentError, "Unexpected parameter: #{ambiguous_param}"
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,4 @@
1
+ <%= type_ruby_name %> = GraphQL::InterfaceType.define do
2
+ name "<%= type_graphql_name %>"
3
+ <% normalized_fields.each do |f| %> field :<%= f[0] %>, <%= f[1] %>
4
+ <% end %>end
@@ -0,0 +1,15 @@
1
+ class Loaders::<%= name %> < GraphQL::Batch::Loader
2
+ # Define `initialize` to store grouping arguments, eg
3
+ #
4
+ # Loaders::<%= name %>.for(group).load(value)
5
+ #
6
+ # def initialize()
7
+ # end
8
+
9
+ # `keys` contains each key from `.load(key)`.
10
+ # Find the corresponding values, then
11
+ # call `fulfill(key, value)` or `fulfill(key, nil)`
12
+ # for each key.
13
+ def perform(keys)
14
+ end
15
+ end
@@ -0,0 +1,12 @@
1
+ Mutations::<%= name %> = GraphQL::Relay::Mutation.define do
2
+ name "<%= name %>"
3
+ # TODO: define return fields
4
+ # return_field :post, Types::PostType
5
+
6
+ # TODO: define arguments
7
+ # input_field :name, !types.String
8
+
9
+ resolve ->(obj, args, ctx) {
10
+ # TODO: define resolve function
11
+ }
12
+ end
@@ -0,0 +1,5 @@
1
+ <%= type_ruby_name %> = GraphQL::ObjectType.define do
2
+ name "<%= type_graphql_name %>"
3
+ <% if options.node %> implements GraphQL::Relay::Node.interface
4
+ <% end %><% normalized_fields.each do |f| %> field :<%= f[0] %>, <%= f[1] %>
5
+ <% end %>end
@@ -0,0 +1,15 @@
1
+ Types::QueryType = GraphQL::ObjectType.define do
2
+ name "Query"
3
+ # Add root-level fields here.
4
+ # They will be entry points for queries on your schema.
5
+
6
+ # TODO: remove me
7
+ field :testField, types.String do
8
+ description "An example field added by the generator"
9
+ resolve ->(obj, args, ctx) {
10
+ "Hello World!"
11
+ }
12
+ end
13
+ <% if options[:relay] %>
14
+ field :node, GraphQL::Relay::Node.field
15
+ <% end %>end
@@ -0,0 +1,34 @@
1
+ <%= schema_name %> = GraphQL::Schema.define do
2
+ query(Types::QueryType)
3
+ <% if options[:relay] %>
4
+ # Relay Object Identification:
5
+
6
+ # Return a string UUID for `object`
7
+ id_from_object ->(object, type_definition, query_ctx) {
8
+ # Here's a simple implementation which:
9
+ # - joins the type name & object.id
10
+ # - encodes it with base64:
11
+ # GraphQL::Schema::UniqueWithinType.encode(type_definition.name, object.id)
12
+ }
13
+
14
+ # Given a string UUID, find the object
15
+ object_from_id ->(id, query_ctx) {
16
+ # For example, to decode the UUIDs generated above:
17
+ # type_name, item_id = GraphQL::Schema::UniqueWithinType.decode(id)
18
+ #
19
+ # Then, based on `type_name` and `id`
20
+ # find an object in your application
21
+ # ...
22
+ }
23
+
24
+ # Object Resolution
25
+ resolve_type -> (obj, ctx) {
26
+ # TODO: Implement this function
27
+ # to return the correct type for `obj`
28
+ raise(NotImplementedError)
29
+ }
30
+ <% end %><% if options[:batch] %>
31
+ # GraphQL::Batch setup:
32
+ lazy_resolve(Promise, :sync)
33
+ instrument(:query, GraphQL::Batch::Setup)
34
+ <% end %>end
@@ -0,0 +1,4 @@
1
+ <%= type_ruby_name %> = GraphQL::UnionType.define do
2
+ name "<%= type_graphql_name %>"
3
+ <% if possible_types.any? %> possible_types [<%= normalized_possible_types.join(", ") %>]
4
+ <% end %>end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+ require 'rails/generators/base'
3
+ require 'graphql'
4
+
5
+ module Graphql
6
+ module Generators
7
+ class TypeGeneratorBase < Rails::Generators::Base
8
+ argument :type_name,
9
+ type: :string,
10
+ required: true,
11
+ banner: "TypeName",
12
+ desc: "Name of this object type (expressed as Ruby or GraphQL)"
13
+
14
+ # Take a type expression in any combination of GraphQL or Ruby styles
15
+ # and return it in a specified output style
16
+ # TODO: nullability / list with `mode: :graphql` doesn't work
17
+ # @param type_expresson [String]
18
+ # @param mode [Symbol]
19
+ # @return [String]
20
+ def self.normalize_type_expression(type_expression, mode:)
21
+ if type_expression.start_with?("!")
22
+ "!#{normalize_type_expression(type_expression[1..-1], mode: mode)}"
23
+ elsif type_expression.end_with?("!")
24
+ "!#{normalize_type_expression(type_expression[0..-2], mode: mode)}"
25
+ elsif type_expression.start_with?("[") && type_expression.end_with?("]")
26
+ "types[#{normalize_type_expression(type_expression[1..-2], mode: mode)}]"
27
+ elsif type_expression.start_with?("types[") && type_expression.end_with?("]")
28
+ "types[#{normalize_type_expression(type_expression[6..-2], mode: mode)}]"
29
+ elsif type_expression.end_with?("Type")
30
+ normalize_type_expression(type_expression[0..-5], mode: mode)
31
+ elsif type_expression.start_with?("Types::")
32
+ normalize_type_expression(type_expression[7..-1], mode: mode)
33
+ elsif type_expression.start_with?("types.")
34
+ normalize_type_expression(type_expression[6..-1], mode: mode)
35
+ else
36
+ case mode
37
+ when :ruby
38
+ case type_expression
39
+ when "Int", "Float", "Boolean", "String", "ID"
40
+ "types.#{type_expression}"
41
+ else
42
+ "Types::#{type_expression}Type"
43
+ end
44
+ when :graphql
45
+ type_expression
46
+ else
47
+ raise "Unexpected normalize mode: #{mode}"
48
+ end
49
+ end
50
+ end
51
+
52
+ private
53
+
54
+ # @return [String] The user-provided type name, normalized to Ruby code
55
+ def type_ruby_name
56
+ @type_ruby_name ||= self.class.normalize_type_expression(type_name, mode: :ruby)
57
+ end
58
+
59
+ # @return [String] The user-provided type name, as a GraphQL name
60
+ def type_graphql_name
61
+ @type_graphql_name ||= self.class.normalize_type_expression(type_name, mode: :graphql)
62
+ end
63
+
64
+ # @return [String] The user-provided type name, as a file name (without extension)
65
+ def type_file_name
66
+ @type_file_name ||= "#{type_graphql_name}Type".underscore
67
+ end
68
+
69
+ # @return [Array<Array(String, String)>>] User-provided fields, in `(name, Ruby type name)` pairs
70
+ def normalized_fields
71
+ @normalized_fields ||= fields.map { |f|
72
+ name, raw_type = f.split(":", 2)
73
+ [name, self.class.normalize_type_expression(raw_type, mode: :ruby)]
74
+ }
75
+ end
76
+ end
77
+ end
78
+ end