rails-graphql 0.1.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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +19 -0
- data/Rakefile +31 -0
- data/ext/depend +3 -0
- data/ext/extconf.rb +57 -0
- data/ext/graphqlparser/Ast.cpp +346 -0
- data/ext/graphqlparser/Ast.h +1214 -0
- data/ext/graphqlparser/AstNode.h +36 -0
- data/ext/graphqlparser/AstVisitor.h +137 -0
- data/ext/graphqlparser/GraphQLParser.cpp +76 -0
- data/ext/graphqlparser/GraphQLParser.h +55 -0
- data/ext/graphqlparser/JsonVisitor.cpp +161 -0
- data/ext/graphqlparser/JsonVisitor.cpp.inc +456 -0
- data/ext/graphqlparser/JsonVisitor.h +121 -0
- data/ext/graphqlparser/JsonVisitor.h.inc +110 -0
- data/ext/graphqlparser/VERSION +1 -0
- data/ext/graphqlparser/c/GraphQLAst.cpp +324 -0
- data/ext/graphqlparser/c/GraphQLAst.h +180 -0
- data/ext/graphqlparser/c/GraphQLAstForEachConcreteType.h +44 -0
- data/ext/graphqlparser/c/GraphQLAstNode.cpp +25 -0
- data/ext/graphqlparser/c/GraphQLAstNode.h +33 -0
- data/ext/graphqlparser/c/GraphQLAstToJSON.cpp +21 -0
- data/ext/graphqlparser/c/GraphQLAstToJSON.h +24 -0
- data/ext/graphqlparser/c/GraphQLAstVisitor.cpp +55 -0
- data/ext/graphqlparser/c/GraphQLAstVisitor.h +53 -0
- data/ext/graphqlparser/c/GraphQLParser.cpp +35 -0
- data/ext/graphqlparser/c/GraphQLParser.h +54 -0
- data/ext/graphqlparser/dump_json_ast.cpp +48 -0
- data/ext/graphqlparser/lexer.lpp +324 -0
- data/ext/graphqlparser/parser.ypp +693 -0
- data/ext/graphqlparser/parsergen/lexer.cpp +2633 -0
- data/ext/graphqlparser/parsergen/lexer.h +528 -0
- data/ext/graphqlparser/parsergen/location.hh +189 -0
- data/ext/graphqlparser/parsergen/parser.tab.cpp +3300 -0
- data/ext/graphqlparser/parsergen/parser.tab.hpp +646 -0
- data/ext/graphqlparser/parsergen/position.hh +179 -0
- data/ext/graphqlparser/parsergen/stack.hh +156 -0
- data/ext/graphqlparser/syntaxdefs.h +19 -0
- data/ext/libgraphqlparser/AstNode.h +36 -0
- data/ext/libgraphqlparser/CMakeLists.txt +148 -0
- data/ext/libgraphqlparser/CONTRIBUTING.md +23 -0
- data/ext/libgraphqlparser/GraphQLParser.cpp +76 -0
- data/ext/libgraphqlparser/GraphQLParser.h +55 -0
- data/ext/libgraphqlparser/JsonVisitor.cpp +161 -0
- data/ext/libgraphqlparser/JsonVisitor.h +121 -0
- data/ext/libgraphqlparser/LICENSE +22 -0
- data/ext/libgraphqlparser/README.clang-tidy +7 -0
- data/ext/libgraphqlparser/README.md +84 -0
- data/ext/libgraphqlparser/ast/ast.ast +203 -0
- data/ext/libgraphqlparser/ast/ast.py +61 -0
- data/ext/libgraphqlparser/ast/c.py +100 -0
- data/ext/libgraphqlparser/ast/c.pyc +0 -0
- data/ext/libgraphqlparser/ast/c_impl.py +61 -0
- data/ext/libgraphqlparser/ast/c_impl.pyc +0 -0
- data/ext/libgraphqlparser/ast/c_visitor_impl.py +39 -0
- data/ext/libgraphqlparser/ast/c_visitor_impl.pyc +0 -0
- data/ext/libgraphqlparser/ast/casing.py +26 -0
- data/ext/libgraphqlparser/ast/casing.pyc +0 -0
- data/ext/libgraphqlparser/ast/cxx.py +197 -0
- data/ext/libgraphqlparser/ast/cxx.pyc +0 -0
- data/ext/libgraphqlparser/ast/cxx_impl.py +61 -0
- data/ext/libgraphqlparser/ast/cxx_impl.pyc +0 -0
- data/ext/libgraphqlparser/ast/cxx_json_visitor_header.py +42 -0
- data/ext/libgraphqlparser/ast/cxx_json_visitor_header.pyc +0 -0
- data/ext/libgraphqlparser/ast/cxx_json_visitor_impl.py +80 -0
- data/ext/libgraphqlparser/ast/cxx_json_visitor_impl.pyc +0 -0
- data/ext/libgraphqlparser/ast/cxx_visitor.py +64 -0
- data/ext/libgraphqlparser/ast/cxx_visitor.pyc +0 -0
- data/ext/libgraphqlparser/ast/js.py +65 -0
- data/ext/libgraphqlparser/ast/license.py +10 -0
- data/ext/libgraphqlparser/ast/license.pyc +0 -0
- data/ext/libgraphqlparser/c/GraphQLAstNode.cpp +25 -0
- data/ext/libgraphqlparser/c/GraphQLAstNode.h +33 -0
- data/ext/libgraphqlparser/c/GraphQLAstToJSON.cpp +21 -0
- data/ext/libgraphqlparser/c/GraphQLAstToJSON.h +24 -0
- data/ext/libgraphqlparser/c/GraphQLAstVisitor.cpp +55 -0
- data/ext/libgraphqlparser/c/GraphQLAstVisitor.h +53 -0
- data/ext/libgraphqlparser/c/GraphQLParser.cpp +35 -0
- data/ext/libgraphqlparser/c/GraphQLParser.h +54 -0
- data/ext/libgraphqlparser/clang-tidy-all.sh +3 -0
- data/ext/libgraphqlparser/cmake/version.cmake +16 -0
- data/ext/libgraphqlparser/dump_json_ast.cpp +48 -0
- data/ext/libgraphqlparser/go/README.md +20 -0
- data/ext/libgraphqlparser/go/callbacks.go +18 -0
- data/ext/libgraphqlparser/go/gotest.go +64 -0
- data/ext/libgraphqlparser/lexer.lpp +324 -0
- data/ext/libgraphqlparser/libgraphqlparser.pc.in +11 -0
- data/ext/libgraphqlparser/parser.ypp +693 -0
- data/ext/libgraphqlparser/parsergen/lexer.cpp +2633 -0
- data/ext/libgraphqlparser/parsergen/lexer.h +528 -0
- data/ext/libgraphqlparser/parsergen/location.hh +189 -0
- data/ext/libgraphqlparser/parsergen/parser.tab.cpp +3300 -0
- data/ext/libgraphqlparser/parsergen/parser.tab.hpp +646 -0
- data/ext/libgraphqlparser/parsergen/position.hh +179 -0
- data/ext/libgraphqlparser/parsergen/stack.hh +156 -0
- data/ext/libgraphqlparser/python/CMakeLists.txt +14 -0
- data/ext/libgraphqlparser/python/README.md +5 -0
- data/ext/libgraphqlparser/python/example.py +31 -0
- data/ext/libgraphqlparser/syntaxdefs.h +19 -0
- data/ext/libgraphqlparser/test/BuildCAPI.c +5 -0
- data/ext/libgraphqlparser/test/CMakeLists.txt +25 -0
- data/ext/libgraphqlparser/test/JsonVisitorTests.cpp +28 -0
- data/ext/libgraphqlparser/test/ParserTests.cpp +352 -0
- data/ext/libgraphqlparser/test/kitchen-sink.graphql +59 -0
- data/ext/libgraphqlparser/test/kitchen-sink.json +1 -0
- data/ext/libgraphqlparser/test/schema-kitchen-sink.graphql +78 -0
- data/ext/libgraphqlparser/test/schema-kitchen-sink.json +1 -0
- data/ext/libgraphqlparser/test/valgrind.supp +33 -0
- data/ext/version.cpp +21 -0
- data/lib/generators/graphql/controller_generator.rb +22 -0
- data/lib/generators/graphql/schema_generator.rb +22 -0
- data/lib/generators/graphql/templates/controller.erb +5 -0
- data/lib/generators/graphql/templates/schema.erb +6 -0
- data/lib/graphqlparser.so +0 -0
- data/lib/rails-graphql.rb +2 -0
- data/lib/rails/graphql.rake +1 -0
- data/lib/rails/graphql.rb +185 -0
- data/lib/rails/graphql/adapters/mysql_adapter.rb +0 -0
- data/lib/rails/graphql/adapters/pg_adapter.rb +50 -0
- data/lib/rails/graphql/adapters/sqlite_adapter.rb +39 -0
- data/lib/rails/graphql/argument.rb +220 -0
- data/lib/rails/graphql/callback.rb +124 -0
- data/lib/rails/graphql/collectors.rb +14 -0
- data/lib/rails/graphql/collectors/hash_collector.rb +83 -0
- data/lib/rails/graphql/collectors/idented_collector.rb +73 -0
- data/lib/rails/graphql/collectors/json_collector.rb +114 -0
- data/lib/rails/graphql/config.rb +61 -0
- data/lib/rails/graphql/directive.rb +203 -0
- data/lib/rails/graphql/directive/deprecated_directive.rb +59 -0
- data/lib/rails/graphql/directive/include_directive.rb +24 -0
- data/lib/rails/graphql/directive/skip_directive.rb +24 -0
- data/lib/rails/graphql/errors.rb +42 -0
- data/lib/rails/graphql/event.rb +141 -0
- data/lib/rails/graphql/field.rb +318 -0
- data/lib/rails/graphql/field/input_field.rb +92 -0
- data/lib/rails/graphql/field/mutation_field.rb +52 -0
- data/lib/rails/graphql/field/output_field.rb +96 -0
- data/lib/rails/graphql/field/proxied_field.rb +131 -0
- data/lib/rails/graphql/field/resolved_field.rb +96 -0
- data/lib/rails/graphql/field/scoped_config.rb +22 -0
- data/lib/rails/graphql/field/typed_field.rb +104 -0
- data/lib/rails/graphql/helpers.rb +40 -0
- data/lib/rails/graphql/helpers/attribute_delegator.rb +39 -0
- data/lib/rails/graphql/helpers/inherited_collection.rb +152 -0
- data/lib/rails/graphql/helpers/leaf_from_ar.rb +141 -0
- data/lib/rails/graphql/helpers/registerable.rb +103 -0
- data/lib/rails/graphql/helpers/with_arguments.rb +125 -0
- data/lib/rails/graphql/helpers/with_assignment.rb +113 -0
- data/lib/rails/graphql/helpers/with_callbacks.rb +55 -0
- data/lib/rails/graphql/helpers/with_directives.rb +126 -0
- data/lib/rails/graphql/helpers/with_events.rb +81 -0
- data/lib/rails/graphql/helpers/with_fields.rb +141 -0
- data/lib/rails/graphql/helpers/with_namespace.rb +40 -0
- data/lib/rails/graphql/helpers/with_owner.rb +35 -0
- data/lib/rails/graphql/helpers/with_schema_fields.rb +230 -0
- data/lib/rails/graphql/helpers/with_validator.rb +52 -0
- data/lib/rails/graphql/introspection.rb +53 -0
- data/lib/rails/graphql/native.rb +56 -0
- data/lib/rails/graphql/native/functions.rb +38 -0
- data/lib/rails/graphql/native/location.rb +41 -0
- data/lib/rails/graphql/native/pointers.rb +23 -0
- data/lib/rails/graphql/native/visitor.rb +349 -0
- data/lib/rails/graphql/railtie.rb +85 -0
- data/lib/rails/graphql/railties/base_generator.rb +35 -0
- data/lib/rails/graphql/railties/controller.rb +101 -0
- data/lib/rails/graphql/railties/controller_runtime.rb +40 -0
- data/lib/rails/graphql/railties/log_subscriber.rb +62 -0
- data/lib/rails/graphql/request.rb +343 -0
- data/lib/rails/graphql/request/arguments.rb +93 -0
- data/lib/rails/graphql/request/component.rb +100 -0
- data/lib/rails/graphql/request/component/field.rb +225 -0
- data/lib/rails/graphql/request/component/fragment.rb +118 -0
- data/lib/rails/graphql/request/component/operation.rb +178 -0
- data/lib/rails/graphql/request/component/operation/subscription.rb +16 -0
- data/lib/rails/graphql/request/component/spread.rb +119 -0
- data/lib/rails/graphql/request/component/typename.rb +82 -0
- data/lib/rails/graphql/request/context.rb +51 -0
- data/lib/rails/graphql/request/errors.rb +54 -0
- data/lib/rails/graphql/request/event.rb +112 -0
- data/lib/rails/graphql/request/helpers/directives.rb +64 -0
- data/lib/rails/graphql/request/helpers/selection_set.rb +87 -0
- data/lib/rails/graphql/request/helpers/value_writers.rb +115 -0
- data/lib/rails/graphql/request/steps/organizable.rb +146 -0
- data/lib/rails/graphql/request/steps/prepareable.rb +33 -0
- data/lib/rails/graphql/request/steps/resolveable.rb +32 -0
- data/lib/rails/graphql/request/strategy.rb +249 -0
- data/lib/rails/graphql/request/strategy/dynamic_instance.rb +41 -0
- data/lib/rails/graphql/request/strategy/multi_query_strategy.rb +36 -0
- data/lib/rails/graphql/request/strategy/sequenced_strategy.rb +28 -0
- data/lib/rails/graphql/schema.rb +272 -0
- data/lib/rails/graphql/shortcuts.rb +77 -0
- data/lib/rails/graphql/source.rb +371 -0
- data/lib/rails/graphql/source/active_record/builders.rb +154 -0
- data/lib/rails/graphql/source/active_record_source.rb +231 -0
- data/lib/rails/graphql/source/scoped_arguments.rb +87 -0
- data/lib/rails/graphql/to_gql.rb +368 -0
- data/lib/rails/graphql/type.rb +138 -0
- data/lib/rails/graphql/type/enum.rb +206 -0
- data/lib/rails/graphql/type/enum/directive_location_enum.rb +30 -0
- data/lib/rails/graphql/type/enum/type_kind_enum.rb +57 -0
- data/lib/rails/graphql/type/input.rb +134 -0
- data/lib/rails/graphql/type/interface.rb +82 -0
- data/lib/rails/graphql/type/object.rb +111 -0
- data/lib/rails/graphql/type/object/directive_object.rb +34 -0
- data/lib/rails/graphql/type/object/enum_value_object.rb +25 -0
- data/lib/rails/graphql/type/object/field_object.rb +54 -0
- data/lib/rails/graphql/type/object/input_value_object.rb +49 -0
- data/lib/rails/graphql/type/object/schema_object.rb +40 -0
- data/lib/rails/graphql/type/object/type_object.rb +136 -0
- data/lib/rails/graphql/type/scalar.rb +71 -0
- data/lib/rails/graphql/type/scalar/bigint_scalar.rb +34 -0
- data/lib/rails/graphql/type/scalar/binary_scalar.rb +30 -0
- data/lib/rails/graphql/type/scalar/boolean_scalar.rb +37 -0
- data/lib/rails/graphql/type/scalar/date_scalar.rb +34 -0
- data/lib/rails/graphql/type/scalar/date_time_scalar.rb +32 -0
- data/lib/rails/graphql/type/scalar/decimal_scalar.rb +35 -0
- data/lib/rails/graphql/type/scalar/float_scalar.rb +32 -0
- data/lib/rails/graphql/type/scalar/id_scalar.rb +39 -0
- data/lib/rails/graphql/type/scalar/int_scalar.rb +36 -0
- data/lib/rails/graphql/type/scalar/string_scalar.rb +28 -0
- data/lib/rails/graphql/type/scalar/time_scalar.rb +40 -0
- data/lib/rails/graphql/type/union.rb +87 -0
- data/lib/rails/graphql/type_map.rb +347 -0
- data/lib/rails/graphql/version.rb +7 -0
- data/test/assets/introspection-db.json +0 -0
- data/test/assets/introspection-mem.txt +1 -0
- data/test/assets/introspection.gql +91 -0
- data/test/assets/luke.jpg +0 -0
- data/test/assets/mem.gql +428 -0
- data/test/assets/sqlite.gql +423 -0
- data/test/config.rb +80 -0
- data/test/graphql/request/context_test.rb +70 -0
- data/test/graphql/schema_test.rb +190 -0
- data/test/graphql/source_test.rb +237 -0
- data/test/graphql/type/enum_test.rb +203 -0
- data/test/graphql/type/input_test.rb +138 -0
- data/test/graphql/type/interface_test.rb +72 -0
- data/test/graphql/type/object_test.rb +104 -0
- data/test/graphql/type/scalar/bigint_scalar_test.rb +42 -0
- data/test/graphql/type/scalar/binary_scalar_test.rb +17 -0
- data/test/graphql/type/scalar/boolean_scalar_test.rb +40 -0
- data/test/graphql/type/scalar/date_scalar_test.rb +29 -0
- data/test/graphql/type/scalar/date_time_scalar_test.rb +29 -0
- data/test/graphql/type/scalar/decimal_scalar_test.rb +28 -0
- data/test/graphql/type/scalar/float_scalar_test.rb +22 -0
- data/test/graphql/type/scalar/id_scalar_test.rb +26 -0
- data/test/graphql/type/scalar/int_scalar_test.rb +26 -0
- data/test/graphql/type/scalar/string_scalar_test.rb +17 -0
- data/test/graphql/type/scalar/time_scalar_test.rb +36 -0
- data/test/graphql/type/scalar_test.rb +45 -0
- data/test/graphql/type/union_test.rb +82 -0
- data/test/graphql/type_map_test.rb +362 -0
- data/test/graphql/type_test.rb +68 -0
- data/test/graphql_test.rb +55 -0
- data/test/integration/config.rb +56 -0
- data/test/integration/memory/star_wars_introspection_test.rb +144 -0
- data/test/integration/memory/star_wars_query_test.rb +184 -0
- data/test/integration/memory/star_wars_validation_test.rb +99 -0
- data/test/integration/schemas/memory.rb +232 -0
- data/test/integration/schemas/sqlite.rb +82 -0
- data/test/integration/sqlite/star_wars_introspection_test.rb +15 -0
- data/test/integration/sqlite/star_wars_mutation_test.rb +82 -0
- data/test/integration/sqlite/star_wars_query_test.rb +71 -0
- data/test/test_ext.rb +48 -0
- metadata +509 -0
@@ -0,0 +1,138 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rails # :nodoc:
|
4
|
+
module GraphQL # :nodoc:
|
5
|
+
# = GraphQL Type
|
6
|
+
#
|
7
|
+
# This is the most pure object from GraphQL. Anything that a schema can
|
8
|
+
# define will be an extension of this class
|
9
|
+
# See: http://spec.graphql.org/June2018/#sec-Types
|
10
|
+
class Type
|
11
|
+
extend ActiveSupport::Autoload
|
12
|
+
extend Helpers::WithDirectives
|
13
|
+
extend Helpers::Registerable
|
14
|
+
|
15
|
+
# A direct representation of the spec types
|
16
|
+
KINDS = %w[Scalar Object Interface Union Enum Input].freeze
|
17
|
+
eager_autoload { KINDS.each { |kind| autoload kind.to_sym } }
|
18
|
+
|
19
|
+
delegate :base_type, :kind, :kind_enum, :input_type?, :output_type?,
|
20
|
+
:leaf_type?, to: :class, prefix: :gql
|
21
|
+
|
22
|
+
# A +base_object+ helps to identify what methods are actually available
|
23
|
+
# to work as resolvers
|
24
|
+
class_attribute :base_object, instance_writer: false, default: false
|
25
|
+
|
26
|
+
self.spec_object = true
|
27
|
+
self.base_object = true
|
28
|
+
self.abstract = true
|
29
|
+
|
30
|
+
class << self
|
31
|
+
alias internal? spec_object?
|
32
|
+
|
33
|
+
# Returns the base type of the class. It will be one of the classes
|
34
|
+
# defined on +Type::KINDS+
|
35
|
+
def base_type
|
36
|
+
nil
|
37
|
+
end
|
38
|
+
|
39
|
+
# Check if the other type is equivalent
|
40
|
+
def =~(other)
|
41
|
+
(other.is_a?(Module) ? other : other.class) <= self
|
42
|
+
end
|
43
|
+
|
44
|
+
alias of_type? =~
|
45
|
+
|
46
|
+
# Return the base type in a symbolized way
|
47
|
+
def kind
|
48
|
+
base_type.name.demodulize.underscore.to_sym
|
49
|
+
end
|
50
|
+
|
51
|
+
# Return the specific value for the __TypeKind of this class
|
52
|
+
def kind_enum
|
53
|
+
kind.to_s.upcase
|
54
|
+
end
|
55
|
+
|
56
|
+
# Defines if the current type is a valid input type
|
57
|
+
def input_type?
|
58
|
+
false
|
59
|
+
end
|
60
|
+
|
61
|
+
# Defines if the current type is a valid output type
|
62
|
+
def output_type?
|
63
|
+
false
|
64
|
+
end
|
65
|
+
|
66
|
+
# Defines if the current type is a leaf output type
|
67
|
+
def leaf_type?
|
68
|
+
false
|
69
|
+
end
|
70
|
+
|
71
|
+
# A little helper to instanteate the type if necessary
|
72
|
+
def decorate(value)
|
73
|
+
value
|
74
|
+
end
|
75
|
+
|
76
|
+
# Checks if a given method can act as resolver
|
77
|
+
def gql_resolver?(method_name)
|
78
|
+
ref_object = self
|
79
|
+
ref_object = ref_object.superclass until ref_object.base_object?
|
80
|
+
(instance_methods - ref_object.instance_methods).include?(method_name)
|
81
|
+
end
|
82
|
+
|
83
|
+
# Defines a series of question methods based on the kind
|
84
|
+
KINDS.each { |kind| define_method("#{kind.downcase}?") { false } }
|
85
|
+
|
86
|
+
def eager_load! # :nodoc:
|
87
|
+
super
|
88
|
+
|
89
|
+
# Due to inheritance
|
90
|
+
return unless eql?(GraphQL::Type)
|
91
|
+
|
92
|
+
Type::Enum.eager_load!
|
93
|
+
Type::Object.eager_load!
|
94
|
+
Type::Scalar.eager_load!
|
95
|
+
|
96
|
+
Source.eager_load!
|
97
|
+
TypeMap.loaded! :Type
|
98
|
+
end
|
99
|
+
|
100
|
+
protected
|
101
|
+
|
102
|
+
# Provide a list of settings to setup the current child class
|
103
|
+
def setup!(**options)
|
104
|
+
return unless superclass.eql?(GraphQL::Type)
|
105
|
+
|
106
|
+
redefine_singleton_method(:kind) { options[:kind] } if options.key?(:kind)
|
107
|
+
self.directive_location = kind
|
108
|
+
|
109
|
+
redefine_singleton_method(:leaf_type?) { true } if options[:leaf]
|
110
|
+
redefine_singleton_method(:input_type?) { true } if options[:input]
|
111
|
+
redefine_singleton_method(:output_type?) { true } if options[:output]
|
112
|
+
end
|
113
|
+
|
114
|
+
private
|
115
|
+
|
116
|
+
# Reset some class attributes, meaning that they are not cascade
|
117
|
+
def inherited(subclass)
|
118
|
+
if subclass.superclass.eql?(GraphQL::Type)
|
119
|
+
subclass.redefine_singleton_method(:base_type) { subclass }
|
120
|
+
|
121
|
+
question_method = "#{subclass.name.demodulize.underscore}?"
|
122
|
+
subclass.redefine_singleton_method(question_method) { true }
|
123
|
+
|
124
|
+
subclass.spec_object = true
|
125
|
+
subclass.base_object = true
|
126
|
+
subclass.abstract = true
|
127
|
+
else
|
128
|
+
subclass.spec_object = false
|
129
|
+
subclass.base_object = false
|
130
|
+
subclass.abstract = false
|
131
|
+
end
|
132
|
+
|
133
|
+
super if defined? super
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
@@ -0,0 +1,206 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rails # :nodoc:
|
4
|
+
module GraphQL # :nodoc:
|
5
|
+
class Type # :nodoc:
|
6
|
+
# = GraphQL EnumType
|
7
|
+
#
|
8
|
+
# Enum types, like scalar types, also represent leaf values in a GraphQL
|
9
|
+
# type system. However Enum types describe the set of possible values.
|
10
|
+
# See http://spec.graphql.org/June2018/#EnumTypeDefinition
|
11
|
+
class Enum < Type
|
12
|
+
extend ActiveSupport::Autoload
|
13
|
+
|
14
|
+
setup! leaf: true, input: true, output: true
|
15
|
+
|
16
|
+
eager_autoload do
|
17
|
+
autoload :DirectiveLocationEnum
|
18
|
+
autoload :TypeKindEnum
|
19
|
+
end
|
20
|
+
|
21
|
+
# Define the methods for accessing the values attribute
|
22
|
+
inherited_collection :values
|
23
|
+
|
24
|
+
# Define the methods for accessing the description of each enum value
|
25
|
+
inherited_collection :value_description, type: :hash
|
26
|
+
|
27
|
+
# Define the methods for accessing the directives of each enum value
|
28
|
+
inherited_collection :value_directives, type: :hash
|
29
|
+
|
30
|
+
class << self
|
31
|
+
# Mark the enum as indexed, allowing values being set by number
|
32
|
+
def indexed!
|
33
|
+
@indexed = true
|
34
|
+
end
|
35
|
+
|
36
|
+
# Checks if the enum was marked as indexed
|
37
|
+
def indexed?
|
38
|
+
defined?(@indexed) && @indexed.present?
|
39
|
+
end
|
40
|
+
|
41
|
+
# Check if a given value is a valid non-deserialized input
|
42
|
+
def valid_input?(value)
|
43
|
+
value.is_a?(String) && all_values.include?(value)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Check if a given value is a valid non-serialized output
|
47
|
+
def valid_output?(value)
|
48
|
+
all_values.include?(as_json(value))
|
49
|
+
end
|
50
|
+
|
51
|
+
# Transforms the given value to its representation in a JSON string
|
52
|
+
def to_json(value)
|
53
|
+
as_json(value)&.inspect
|
54
|
+
end
|
55
|
+
|
56
|
+
# Transforms the given value to its representation in a Hash object
|
57
|
+
def as_json(value)
|
58
|
+
return if value.nil?
|
59
|
+
return value.to_s if value.is_a?(self)
|
60
|
+
return all_values.drop(value).first if indexed? && value.is_a?(Numeric)
|
61
|
+
value.to_s.underscore.upcase
|
62
|
+
end
|
63
|
+
|
64
|
+
# Turn a user input of this given type into an ruby object
|
65
|
+
def deserialize(value)
|
66
|
+
new(value) if valid_input?(value)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Use the instance as decorator
|
70
|
+
def decorate(value)
|
71
|
+
deserialize(as_json(value))
|
72
|
+
end
|
73
|
+
|
74
|
+
# Use this method to add values to the enum type
|
75
|
+
#
|
76
|
+
# ==== Options
|
77
|
+
#
|
78
|
+
# * <tt>:desc</tt> - The description of the enum value (defaults to nil).
|
79
|
+
# * <tt>:directives</tt> - The list of directives associated with the value
|
80
|
+
# (defaults to nil).
|
81
|
+
# * <tt>:deprecated</tt> - A shortcut that auto-attach a @deprecated
|
82
|
+
# directive to the value. A +true+ value simple attaches the directive,
|
83
|
+
# but provide a string so it can be used as the reason of the deprecation.
|
84
|
+
# See {DeprecatedDirective}[rdoc-ref:Rails::GraphQL::Directive::DeprecatedDirective]
|
85
|
+
# (defaults to false).
|
86
|
+
def add(value, desc: nil, directives: nil, deprecated: false)
|
87
|
+
raise ArgumentError, <<~MSG.squish unless value.is_a?(String) && value.present?
|
88
|
+
The "#{value}" is invalid.
|
89
|
+
MSG
|
90
|
+
|
91
|
+
value = value.upcase
|
92
|
+
raise ArgumentError, <<~MSG.squish if all_values.include?(value)
|
93
|
+
The "#{value}" is already defined for #{gql_name} enum.
|
94
|
+
MSG
|
95
|
+
|
96
|
+
directives = Array.wrap(directives)
|
97
|
+
directives << deprecated_klass.new(
|
98
|
+
reason: (deprecated.is_a?(String) ? deprecated : nil),
|
99
|
+
) if deprecated.present?
|
100
|
+
|
101
|
+
directives = GraphQL.directives_to_set(directives,
|
102
|
+
location: :enum_value,
|
103
|
+
source: self,
|
104
|
+
)
|
105
|
+
|
106
|
+
values << value
|
107
|
+
value_description[value] = desc unless desc.nil?
|
108
|
+
value_directives[value] = directives
|
109
|
+
end
|
110
|
+
|
111
|
+
# Check if a given +value+ is using a +directive+
|
112
|
+
def value_using?(value, directive)
|
113
|
+
raise ArgumentError, <<~MSG.squish unless directive < GraphQL::Directive
|
114
|
+
The provided #{item_or_symbol.inspect} is not a valid directive.
|
115
|
+
MSG
|
116
|
+
|
117
|
+
!!value_directives[as_json(value)]&.any? { |item| item.is_a?(directive) }
|
118
|
+
end
|
119
|
+
|
120
|
+
# Build a hash with deprecated values and their respective reason for
|
121
|
+
# logging and introspection purposes
|
122
|
+
def all_deprecated_values
|
123
|
+
@all_deprecated_values ||= begin
|
124
|
+
all_value_directives.to_a.inject({}) do |list, (value, dirs)|
|
125
|
+
obj = dirs.find { |dir| dir.is_a?(deprecated_klass) }
|
126
|
+
obj ? list.merge(value => obj.args.reason) : list
|
127
|
+
end
|
128
|
+
end.freeze
|
129
|
+
end
|
130
|
+
|
131
|
+
# This returns the field directives and all value directives
|
132
|
+
def all_directives
|
133
|
+
all_value_directives.each_value.reduce(:+)
|
134
|
+
end
|
135
|
+
|
136
|
+
def inspect # :nodoc:
|
137
|
+
<<~INFO.squish + '>'
|
138
|
+
#<GraphQL::Enum #{gql_name}
|
139
|
+
(#{all_values.size})
|
140
|
+
{#{all_values.to_a.join(' | ')}}
|
141
|
+
INFO
|
142
|
+
end
|
143
|
+
|
144
|
+
private
|
145
|
+
|
146
|
+
def deprecated_klass
|
147
|
+
Directive::DeprecatedDirective
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
attr_reader :value
|
152
|
+
|
153
|
+
delegate :to_s, :inspect, to: :@value
|
154
|
+
|
155
|
+
def initialize(value)
|
156
|
+
@value = value
|
157
|
+
end
|
158
|
+
|
159
|
+
# Use lower case for symbolized value
|
160
|
+
def to_sym
|
161
|
+
@value.downcase.to_sym
|
162
|
+
end
|
163
|
+
|
164
|
+
# Allow finding the indexed position of the value
|
165
|
+
def to_i
|
166
|
+
self.class.all_values.find_index(@value)
|
167
|
+
end
|
168
|
+
|
169
|
+
# Checks if the current value is valid
|
170
|
+
def valid?
|
171
|
+
self.class.valid_output?(@value)
|
172
|
+
end
|
173
|
+
|
174
|
+
# Gets all the description of the current value
|
175
|
+
def description
|
176
|
+
@description ||= @value && self.class.all_value_description[@value]
|
177
|
+
end
|
178
|
+
|
179
|
+
# Gets all the directives associated with the current value
|
180
|
+
def directives
|
181
|
+
@directives ||= @value && self.class.all_value_directives[@value]
|
182
|
+
end
|
183
|
+
|
184
|
+
# Checks if the current value is marked as deprecated
|
185
|
+
def deprecated?
|
186
|
+
self.class.all_deprecated_values.include?(@value)
|
187
|
+
end
|
188
|
+
|
189
|
+
# Return the deprecated reason
|
190
|
+
def deprecated_reason
|
191
|
+
deprecated_directive&.args&.reason
|
192
|
+
end
|
193
|
+
|
194
|
+
private
|
195
|
+
|
196
|
+
# Find and store the directive that marked the current value as
|
197
|
+
# deprecated
|
198
|
+
def deprecated_directive
|
199
|
+
@deprecated_directive ||= directives.find do |dir|
|
200
|
+
dir.is_a?(Directive::DeprecatedDirective)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rails # :nodoc:
|
4
|
+
module GraphQL # :nodoc:
|
5
|
+
class Type # :nodoc:
|
6
|
+
# Bigint basically removes the limit of the value, but it serializes as
|
7
|
+
# a string so it won't go against the spec
|
8
|
+
class Enum::DirectiveLocationEnum < Enum
|
9
|
+
self.spec_object = true
|
10
|
+
|
11
|
+
rename! '__DirectiveLocation'
|
12
|
+
|
13
|
+
desc 'The valid locations that a directive may be placed.'
|
14
|
+
|
15
|
+
%w[QUERY MUTATION SUBSCRIPTION FIELD FRAGMENT_DEFINITION
|
16
|
+
FRAGMENT_SPREAD INLINE_FRAGMENT].each do |value|
|
17
|
+
desc = value.downcase.tr('_', ' ')
|
18
|
+
add(value, desc: "Mark as a executable directive usable on #{desc} objects.")
|
19
|
+
end
|
20
|
+
|
21
|
+
%w[SCHEMA SCALAR OBJECT FIELD_DEFINITION ARGUMENT_DEFINITION INTERFACE UNION
|
22
|
+
ENUM ENUM_VALUE INPUT_OBJECT INPUT_FIELD_DEFINITION].each do |value|
|
23
|
+
desc = value.downcase.tr('_', ' ')
|
24
|
+
desc = "Mark as a type system directive usable on #{desc} definitions."
|
25
|
+
add(value, desc: desc.gsub(/definition definitions\.$/, 'definitions.'))
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rails # :nodoc:
|
4
|
+
module GraphQL # :nodoc:
|
5
|
+
class Type # :nodoc:
|
6
|
+
# Bigint basically removes the limit of the value, but it serializes as
|
7
|
+
# a string so it won't go against the spec
|
8
|
+
class Enum::TypeKindEnum < Enum
|
9
|
+
self.spec_object = true
|
10
|
+
|
11
|
+
rename! '__TypeKind'
|
12
|
+
|
13
|
+
desc <<~DESC
|
14
|
+
The fundamental unit of any GraphQL Schema is the type.
|
15
|
+
This enum enlist all the valid base types.
|
16
|
+
DESC
|
17
|
+
|
18
|
+
add 'SCALAR', desc: <<~DESC
|
19
|
+
Scalar types represent primitive leaf values in a GraphQL type system.
|
20
|
+
DESC
|
21
|
+
|
22
|
+
add 'OBJECT', desc: <<~DESC
|
23
|
+
Objects represent a list of named fields, each of which yield a value of a
|
24
|
+
specific type.
|
25
|
+
DESC
|
26
|
+
|
27
|
+
add 'INTERFACE', desc: <<~DESC
|
28
|
+
Interfaces represent a list of named fields and their types.
|
29
|
+
DESC
|
30
|
+
|
31
|
+
add 'UNION', desc: <<~DESC
|
32
|
+
Unions represent an object that could be one of a list of GraphQL Object types.
|
33
|
+
DESC
|
34
|
+
|
35
|
+
add 'ENUM', desc: <<~DESC
|
36
|
+
Enum types, like scalar types, also represent leaf values in a GraphQL
|
37
|
+
type system. However Enum types describe the set of possible values.
|
38
|
+
DESC
|
39
|
+
|
40
|
+
add 'INPUT_OBJECT', desc: <<~DESC
|
41
|
+
Objects represent a list of named fields, each of which yield a value of
|
42
|
+
a specific type.
|
43
|
+
DESC
|
44
|
+
|
45
|
+
add 'LIST', desc: <<~DESC
|
46
|
+
A GraphQL list is a special collection type which declares the type of
|
47
|
+
each item in the List (referred to as the item type of the list).
|
48
|
+
DESC
|
49
|
+
|
50
|
+
add 'NON_NULL', desc: <<~DESC
|
51
|
+
This type wraps an underlying type, and this type acts identically to that wrapped
|
52
|
+
type, with the exception that null is not a valid response for the wrapping type.
|
53
|
+
DESC
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rails # :nodoc:
|
4
|
+
module GraphQL # :nodoc:
|
5
|
+
class Type # :nodoc:
|
6
|
+
# = GraphQL InputType
|
7
|
+
#
|
8
|
+
# Input defines a set of input fields; the input fields are either
|
9
|
+
# scalars, enums, or other input objects.
|
10
|
+
# See http://spec.graphql.org/June2018/#InputObjectTypeDefinition
|
11
|
+
class Input < Type
|
12
|
+
extend Helpers::WithAssignment
|
13
|
+
extend Helpers::WithFields
|
14
|
+
|
15
|
+
setup! kind: :input_object, input: true
|
16
|
+
|
17
|
+
self.field_type = Field::InputField
|
18
|
+
self.valid_field_types = [
|
19
|
+
Type::Enum,
|
20
|
+
Type::Input,
|
21
|
+
Type::Scalar,
|
22
|
+
].freeze
|
23
|
+
|
24
|
+
class << self
|
25
|
+
# A little override on the name of the object due to the suffix config
|
26
|
+
def gql_name
|
27
|
+
return @gql_name if defined?(@gql_name)
|
28
|
+
|
29
|
+
suffix = GraphQL.config.auto_suffix_input_objects
|
30
|
+
return super if suffix.blank?
|
31
|
+
|
32
|
+
result = super
|
33
|
+
result += suffix if result && !result.end_with?(suffix)
|
34
|
+
@gql_name = result
|
35
|
+
end
|
36
|
+
|
37
|
+
# Check if a given value is a valid non-deserialized input
|
38
|
+
def valid_input?(value)
|
39
|
+
value = value.to_h if value.respond_to?(:to_h)
|
40
|
+
return false unless value.is_a?(Hash)
|
41
|
+
|
42
|
+
fields = enabled_fields
|
43
|
+
value = value.transform_keys { |key| key.to_s.camelize(:lower) }
|
44
|
+
value = build_defaults.merge(value)
|
45
|
+
|
46
|
+
return false unless value.size.eql?(fields.size)
|
47
|
+
|
48
|
+
fields.all? { |item| item.valid_input?(value[item.gql_name]) }
|
49
|
+
end
|
50
|
+
|
51
|
+
# Turn the given value into an isntance of the input object
|
52
|
+
def deserialize(value)
|
53
|
+
value = value.to_h if value.respond_to?(:to_h)
|
54
|
+
value = {} unless value.is_a?(Hash)
|
55
|
+
value = enabled_fields.map do |field|
|
56
|
+
next unless value.key?(field.gql_name) || value.key?(field.name)
|
57
|
+
[field.name, field.deserialize(value[field.gql_name] || value[field.name])]
|
58
|
+
end.compact.to_h
|
59
|
+
|
60
|
+
new(OpenStruct.new(value))
|
61
|
+
end
|
62
|
+
|
63
|
+
# Build a hash with the default values for each of the given fields
|
64
|
+
def build_defaults
|
65
|
+
enabled_fields.map { |field| [field.gql_name, field.default] }.to_h
|
66
|
+
end
|
67
|
+
|
68
|
+
def inspect # :nodoc:
|
69
|
+
args = fields.each_value.map(&:inspect)
|
70
|
+
args = args.presence && "(#{args.join(', ')})"
|
71
|
+
"#<GraphQL::Input #{gql_name}#{args}>"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
attr_reader :args
|
76
|
+
attr_writer :resource
|
77
|
+
|
78
|
+
delegate :fields, to: :class
|
79
|
+
delegate :[], to: :args
|
80
|
+
|
81
|
+
delegate_missing_to :resource
|
82
|
+
|
83
|
+
def initialize(args = nil, **xargs)
|
84
|
+
@args = args || OpenStruct.new(xargs.transform_keys { |key| key.to_s.underscore })
|
85
|
+
@args.freeze
|
86
|
+
|
87
|
+
validate! if args.nil?
|
88
|
+
end
|
89
|
+
|
90
|
+
# If the input is assigned to a class, then initialize it with the
|
91
|
+
# received arguments. It also accepts extra arguments for inheritance
|
92
|
+
# purposes
|
93
|
+
def resource(*args, **xargs, &block)
|
94
|
+
@resource ||= (klass = safe_assigned_class).nil? ? nil : begin
|
95
|
+
xargs = xargs.reverse_merge(params)
|
96
|
+
klass.new(*args, **xargs, &block)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# Just return the arguments as an hash
|
101
|
+
def params
|
102
|
+
parametrize(self)
|
103
|
+
end
|
104
|
+
|
105
|
+
# Checks if all the values provided to the input instance are valid
|
106
|
+
def validate!(*)
|
107
|
+
errors = []
|
108
|
+
fields.each do |name, field|
|
109
|
+
field.validate_output!(@args[name.to_s])
|
110
|
+
rescue InvalidValueError => error
|
111
|
+
errors << error.message
|
112
|
+
end
|
113
|
+
|
114
|
+
return if errors.empty?
|
115
|
+
raise InvalidValueError, <<~MSG.squish
|
116
|
+
Invalid value provided to #{gql_name} field: #{errors.to_sentence}.
|
117
|
+
MSG
|
118
|
+
end
|
119
|
+
|
120
|
+
private
|
121
|
+
|
122
|
+
# Make sure to turn inputs into params
|
123
|
+
def parametrize(input)
|
124
|
+
case input
|
125
|
+
when Type::Input then parametrize(input.args.to_h)
|
126
|
+
when Array then input.map(&method(:parametrize))
|
127
|
+
when Hash then input.transform_values(&method(:parametrize))
|
128
|
+
else input
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|