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,318 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rails # :nodoc:
|
4
|
+
module GraphQL # :nodoc:
|
5
|
+
# = GraphQL Field
|
6
|
+
#
|
7
|
+
# A field has multiple purposes, which is defined by the specific subclass
|
8
|
+
# used. They are also, in various ways, similar to arguments, since they
|
9
|
+
# tend to have the same structure.
|
10
|
+
# array as input.
|
11
|
+
#
|
12
|
+
# ==== Options
|
13
|
+
#
|
14
|
+
# * <tt>:owner</tt> - The main object that this field belongs to.
|
15
|
+
# * <tt>:null</tt> - Marks if the overall type can be null
|
16
|
+
# (defaults to true).
|
17
|
+
# * <tt>:array</tt> - Marks if the type should be wrapped as an array
|
18
|
+
# (defaults to false).
|
19
|
+
# * <tt>:nullable</tt> - Marks if the internal values of an array can be null
|
20
|
+
# (defaults to true).
|
21
|
+
# * <tt>:full</tt> - Shortcut for +null: false, nullable: false, array: true+
|
22
|
+
# (defaults to false).
|
23
|
+
# * <tt>:method_name</tt> - The name of the method used to fetch the field data
|
24
|
+
# (defaults to nil).
|
25
|
+
# * <tt>:enabled</tt> - Mark the field as enabled
|
26
|
+
# (defaults to true).
|
27
|
+
# * <tt>:disabled</tt> - Works as the oposite of the enabled option
|
28
|
+
# (defaults to false).
|
29
|
+
# * <tt>:directives</tt> - The list of directives associated with the value
|
30
|
+
# (defaults to nil).
|
31
|
+
# * <tt>:desc</tt> - The description of the argument
|
32
|
+
# (defaults to nil).
|
33
|
+
#
|
34
|
+
# It also accepts a block for further configurations
|
35
|
+
class Field
|
36
|
+
extend ActiveSupport::Autoload
|
37
|
+
include Helpers::WithDirectives
|
38
|
+
|
39
|
+
autoload :ScopedConfig
|
40
|
+
|
41
|
+
autoload :ResolvedField
|
42
|
+
autoload :TypedField
|
43
|
+
autoload :ProxiedField
|
44
|
+
|
45
|
+
autoload :InputField
|
46
|
+
autoload :OutputField
|
47
|
+
autoload :MutationField
|
48
|
+
|
49
|
+
delegate :input_type?, :output_type?, :leaf_type?, :proxy?, :mutation?, to: :class
|
50
|
+
|
51
|
+
delegate :namespaces, to: :owner
|
52
|
+
|
53
|
+
attr_reader :name, :gql_name, :owner
|
54
|
+
|
55
|
+
class << self
|
56
|
+
# A small shared helper method that allows field information to be
|
57
|
+
# proxied
|
58
|
+
def proxyable_methods(*list, klass:, allow_nil: false)
|
59
|
+
list = list.flatten.compact.map do |method_name|
|
60
|
+
ivar = '@' + method_name.delete_suffix('?')
|
61
|
+
accessor = 'field' + (allow_nil ? '&.' : '.') + method_name
|
62
|
+
"def #{method_name}; defined?(#{ivar}) ? #{ivar} : #{accessor}; end"
|
63
|
+
end
|
64
|
+
|
65
|
+
klass.class_eval(list.join("\n"), __FILE__, __LINE__ + 1)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Defines if the current field is valid as an input type
|
69
|
+
def input_type?
|
70
|
+
false
|
71
|
+
end
|
72
|
+
|
73
|
+
# Defines if the current field is valid as an output type
|
74
|
+
def output_type?
|
75
|
+
false
|
76
|
+
end
|
77
|
+
|
78
|
+
# Defines if the current field is considered a leaf output
|
79
|
+
def leaf_type?
|
80
|
+
false
|
81
|
+
end
|
82
|
+
|
83
|
+
# Checks if the the field is a proxy kind of field
|
84
|
+
def proxy?
|
85
|
+
false
|
86
|
+
end
|
87
|
+
|
88
|
+
# Checks if the field is associated with a mutation
|
89
|
+
def mutation?
|
90
|
+
false
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def initialize(name, owner:, **xargs, &block)
|
95
|
+
@owner = owner
|
96
|
+
normalize_name(name)
|
97
|
+
|
98
|
+
@directives = GraphQL.directives_to_set(xargs[:directives], source: self)
|
99
|
+
@method_name = xargs[:method_name].to_s.underscore.to_sym \
|
100
|
+
unless xargs[:method_name].nil?
|
101
|
+
|
102
|
+
full = xargs.fetch(:full, false)
|
103
|
+
@null = full ? false : xargs.fetch(:null, true)
|
104
|
+
@array = full ? true : xargs.fetch(:array, false)
|
105
|
+
@nullable = full ? false : xargs.fetch(:nullable, true)
|
106
|
+
|
107
|
+
@desc = xargs[:desc]&.strip_heredoc&.chomp
|
108
|
+
@enabled = xargs.fetch(:enabled, !xargs.fetch(:disabled, false))
|
109
|
+
|
110
|
+
configure(&block) if block.present?
|
111
|
+
end
|
112
|
+
|
113
|
+
def initialize_copy(*) # :nodoc:
|
114
|
+
super
|
115
|
+
|
116
|
+
@owner = nil
|
117
|
+
end
|
118
|
+
|
119
|
+
# Apply a controlled set of changes to the field
|
120
|
+
def apply_changes(**xargs, &block)
|
121
|
+
required_items! unless xargs.fetch(:nullable, true)
|
122
|
+
required! unless xargs.fetch(:null, true)
|
123
|
+
disable! if xargs.fetch(:disabled, false)
|
124
|
+
enable! if xargs.fetch(:enabled, false)
|
125
|
+
|
126
|
+
@desc = xargs[:desc].strip_heredoc.chomp if xargs.key?(:desc)
|
127
|
+
configure(&block) if block.present?
|
128
|
+
end
|
129
|
+
|
130
|
+
# Allow extra configurations to be performed using a block
|
131
|
+
def configure(&block)
|
132
|
+
Field::ScopedConfig.new(self, block.binding.receiver).instance_exec(&block)
|
133
|
+
end
|
134
|
+
|
135
|
+
# Returns the name of the method used to retrieve the information
|
136
|
+
def method_name
|
137
|
+
defined?(@method_name) ? @method_name : @name
|
138
|
+
end
|
139
|
+
|
140
|
+
# Check if the other field is equivalent
|
141
|
+
def =~(other)
|
142
|
+
other.is_a?(GraphQL::Field) &&
|
143
|
+
other.array? == array? &&
|
144
|
+
(other.null? == null? || other.null? && !null?) &&
|
145
|
+
(other.nullable? == nullable? || other.nullable? && !nullable?)
|
146
|
+
end
|
147
|
+
|
148
|
+
# Checks if the argument can be null
|
149
|
+
def null?
|
150
|
+
!!@null
|
151
|
+
end
|
152
|
+
|
153
|
+
# Checks if the argument can be an array
|
154
|
+
def array?
|
155
|
+
!!@array
|
156
|
+
end
|
157
|
+
|
158
|
+
# Checks if the argument can have null elements in the array
|
159
|
+
def nullable?
|
160
|
+
!!@nullable
|
161
|
+
end
|
162
|
+
|
163
|
+
# Check if tre field is enabled
|
164
|
+
def enabled?
|
165
|
+
!!@enabled
|
166
|
+
end
|
167
|
+
|
168
|
+
# Check if tre field is disabled
|
169
|
+
def disabled?
|
170
|
+
!enabled?
|
171
|
+
end
|
172
|
+
|
173
|
+
# Mark the field as globally enabled
|
174
|
+
def enable!
|
175
|
+
@enabled = true
|
176
|
+
end
|
177
|
+
|
178
|
+
# Mark the field as globally disabled
|
179
|
+
def disable!
|
180
|
+
@enabled = false
|
181
|
+
end
|
182
|
+
|
183
|
+
# Return the description of the argument
|
184
|
+
def description
|
185
|
+
@desc
|
186
|
+
end
|
187
|
+
|
188
|
+
# Checks if a description was provided
|
189
|
+
def description?
|
190
|
+
defined?(@desc) && !!@desc
|
191
|
+
end
|
192
|
+
|
193
|
+
# Check if the field is an internal one
|
194
|
+
def internal?
|
195
|
+
name.start_with?('__')
|
196
|
+
end
|
197
|
+
|
198
|
+
# This method must be overridden by children classes
|
199
|
+
def valid_input?(*)
|
200
|
+
enabled?
|
201
|
+
end
|
202
|
+
|
203
|
+
# This method must be overridden by children classes
|
204
|
+
def valid_output?(*)
|
205
|
+
enabled?
|
206
|
+
end
|
207
|
+
|
208
|
+
# Transforms the given value to its representation in a JSON string
|
209
|
+
def to_json(value)
|
210
|
+
return 'null' if value.nil?
|
211
|
+
return type_klass.to_json(value) unless array?
|
212
|
+
value.map { |part| type_klass.to_json(part) }
|
213
|
+
end
|
214
|
+
|
215
|
+
# Turn the given value into a JSON string representation
|
216
|
+
def as_json(value)
|
217
|
+
return if value.nil?
|
218
|
+
return type_klass.as_json(value) unless array?
|
219
|
+
value.map { |part| type_klass.as_json(part) }
|
220
|
+
end
|
221
|
+
|
222
|
+
# Turn a user input of this given type into an ruby object
|
223
|
+
def deserialize(value)
|
224
|
+
return if value.nil?
|
225
|
+
return type_klass.deserialize(value) unless array?
|
226
|
+
value.map { |val| type_klass.deserialize(val) unless val.nil? }
|
227
|
+
end
|
228
|
+
|
229
|
+
# Check if the given value is valid using +valid_input?+ or
|
230
|
+
# +valid_output?+ depending of the type of the field
|
231
|
+
def valid?(value)
|
232
|
+
input_type? ? valid_input?(value) : valid_output?(value)
|
233
|
+
end
|
234
|
+
|
235
|
+
# Checks if the definition of the field is valid.
|
236
|
+
def validate!(*)
|
237
|
+
super if defined? super
|
238
|
+
|
239
|
+
raise NameError, <<~MSG.squish if gql_name.start_with?('__') && !internal?
|
240
|
+
The name "#{gql_name}" is invalid. Only internal fields from the
|
241
|
+
spec can have a name starting with "__".
|
242
|
+
MSG
|
243
|
+
end
|
244
|
+
|
245
|
+
# Update the null value
|
246
|
+
def required!
|
247
|
+
@null = false
|
248
|
+
end
|
249
|
+
|
250
|
+
# Update the nullable value
|
251
|
+
def required_items!
|
252
|
+
@nullable = false
|
253
|
+
end
|
254
|
+
|
255
|
+
# Create a proxy of the current field
|
256
|
+
def to_proxy(*args, **xargs, &block)
|
257
|
+
proxy = self.class.allocate
|
258
|
+
proxy.extend Field::ProxiedField
|
259
|
+
proxy.send(:proxied)
|
260
|
+
proxy.send(:initialize, self, *args, **xargs, &block)
|
261
|
+
proxy
|
262
|
+
end
|
263
|
+
|
264
|
+
def inspect # :nodoc:
|
265
|
+
<<~INSPECT.squish + '>'
|
266
|
+
#<#{self.class.name}
|
267
|
+
#{inspect_owner}
|
268
|
+
#{inspect_source}
|
269
|
+
#{inspect_enabled}
|
270
|
+
#{gql_name}#{inspect_arguments}#{inspect_type}
|
271
|
+
#{inspect_default_value}
|
272
|
+
#{inspect_directives}
|
273
|
+
INSPECT
|
274
|
+
end
|
275
|
+
|
276
|
+
protected
|
277
|
+
|
278
|
+
# Allow the subclasses to define the extra inspection methods
|
279
|
+
def respond_to_missing?(method_name, *)
|
280
|
+
method_name.start_with?('inspect_') || super
|
281
|
+
end
|
282
|
+
|
283
|
+
# Allow the subclasses to define the extra inspection methods
|
284
|
+
def method_missing(method_name, *)
|
285
|
+
method_name.start_with?('inspect_') ? '' : super
|
286
|
+
end
|
287
|
+
|
288
|
+
# Ensures the consistency of the name of the field
|
289
|
+
def normalize_name(value)
|
290
|
+
return if value.blank?
|
291
|
+
|
292
|
+
@name = value.to_s.underscore.to_sym
|
293
|
+
@gql_name = @name.to_s.gsub(/^_+/, '').camelize(:lower)
|
294
|
+
|
295
|
+
if internal?
|
296
|
+
@gql_name.prepend('__')
|
297
|
+
elsif @name.start_with?('_')
|
298
|
+
@gql_name.prepend('_')
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
# Helper method to inspect the directives
|
303
|
+
def inspect_directives
|
304
|
+
all_directives.map(&:inspect)
|
305
|
+
end
|
306
|
+
|
307
|
+
# Show the name of the owner of the object for inspection
|
308
|
+
def inspect_owner
|
309
|
+
owner.is_a?(Module) ? owner.name : owner.class.name
|
310
|
+
end
|
311
|
+
|
312
|
+
# Add a disable tag to the inspection if the field is disabled
|
313
|
+
def inspect_enabled
|
314
|
+
'[disabled]' if disabled?
|
315
|
+
end
|
316
|
+
end
|
317
|
+
end
|
318
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rails # :nodoc:
|
4
|
+
module GraphQL # :nodoc:
|
5
|
+
# = GraphQL Input Field
|
6
|
+
#
|
7
|
+
# An input field works the same way as an argument and they are pretty much
|
8
|
+
# equivalent. The main difference between an argument and a input field is
|
9
|
+
# that input fields holds object-like values and they can be inherited.
|
10
|
+
# Arguments can hold object-like values only when their type is associated
|
11
|
+
# with an InputField.
|
12
|
+
#
|
13
|
+
# ==== Options
|
14
|
+
#
|
15
|
+
# * <tt>:default</tt> - Sets a default value for the argument (defaults to nil).
|
16
|
+
# * <tt>:directives</tt> - The list of directives associated with the value
|
17
|
+
# (defaults to nil).
|
18
|
+
class Field::InputField < Field
|
19
|
+
include Field::TypedField
|
20
|
+
|
21
|
+
attr_reader :default
|
22
|
+
|
23
|
+
redefine_singleton_method(:input_type?) { true }
|
24
|
+
self.directive_location = :input_field_definition
|
25
|
+
|
26
|
+
def initialize(*args, default: nil, **xargs, &block)
|
27
|
+
super(*args, **xargs, &block)
|
28
|
+
@default = default
|
29
|
+
end
|
30
|
+
|
31
|
+
def configure # :nodoc:
|
32
|
+
raise ArgumentError, 'Input fields can\'t be further configured using blocks'
|
33
|
+
end
|
34
|
+
|
35
|
+
# Allow change the default value for the input
|
36
|
+
def apply_changes(**xargs, &block)
|
37
|
+
@default = xargs[:default] if xargs.key?(:default)
|
38
|
+
super
|
39
|
+
end
|
40
|
+
|
41
|
+
# Checks if a default value was provided
|
42
|
+
def default_value?
|
43
|
+
!default.nil?
|
44
|
+
end
|
45
|
+
|
46
|
+
# This checks if a given serialized value is valid for this field
|
47
|
+
def valid_input?(value, deep: true)
|
48
|
+
return false unless super
|
49
|
+
return null? if value.nil?
|
50
|
+
return valid_input_array?(value, deep) if array?
|
51
|
+
|
52
|
+
return true unless leaf_type? || deep
|
53
|
+
type_klass.valid_input?(value)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Return the default value if the given +value+ is nil
|
57
|
+
def deserialize(value = nil)
|
58
|
+
value.nil? ? @default : super
|
59
|
+
end
|
60
|
+
|
61
|
+
# Checks if the default value of the field is valid
|
62
|
+
def validate!(*)
|
63
|
+
super if defined? super
|
64
|
+
|
65
|
+
raise ArgumentError, <<~MSG.squish unless type_klass.input_type?
|
66
|
+
The "#{type_klass.gql_name}" is not a valid input type.
|
67
|
+
MSG
|
68
|
+
|
69
|
+
raise ArgumentError, <<~MSG.squish unless default.nil? || valid_input?(default)
|
70
|
+
The given default value "#{default.inspect}" is not valid for this field.
|
71
|
+
MSG
|
72
|
+
end
|
73
|
+
|
74
|
+
protected
|
75
|
+
|
76
|
+
# Check if the given +value+ is a valid array as input
|
77
|
+
def valid_input_array?(value, deep)
|
78
|
+
return false unless value.is_a?(Array)
|
79
|
+
|
80
|
+
value.all? do |val|
|
81
|
+
(val.nil? && nullable?) || (leaf_type? || !deep) ||
|
82
|
+
type_klass.valid_input?(val)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# Display the default value when it is present for inspection
|
87
|
+
def inspect_default_value
|
88
|
+
" = #{to_hash.inspect}" if default?
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rails # :nodoc:
|
4
|
+
module GraphQL # :nodoc:
|
5
|
+
# = GraphQL Output Field
|
6
|
+
#
|
7
|
+
# This is an extension of a normal output field, which just add extra
|
8
|
+
# validation and ensurance that the +perform+ step can be executed
|
9
|
+
class Field::MutationField < Field::OutputField
|
10
|
+
redefine_singleton_method(:mutation?) { true }
|
11
|
+
|
12
|
+
module Proxied # :nodoc: all
|
13
|
+
def performer
|
14
|
+
super || field.performer
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# Add a block or a callable method that is executed before the resolver
|
19
|
+
# but after all the before resolve
|
20
|
+
def perform(*args, **xargs, &block)
|
21
|
+
@performer = Callback.new(self, :perform, *args, **xargs, &block)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Get the performer that can be already defined or used through the
|
25
|
+
# +method_name+ if that is callable
|
26
|
+
def performer
|
27
|
+
@performer ||= callable?(method_name) \
|
28
|
+
? Callback.new(self, :perform, method_name) \
|
29
|
+
: false
|
30
|
+
end
|
31
|
+
|
32
|
+
# Ensures that the performer is defined
|
33
|
+
def validate!(*)
|
34
|
+
super if defined? super
|
35
|
+
|
36
|
+
raise ValidationError, <<~MSG.squish unless performer.present?
|
37
|
+
The "#{gql_name}" mutation field must have a perform action through a given
|
38
|
+
block or a method named #{method_name} on #{owner.class.name}.
|
39
|
+
MSG
|
40
|
+
end
|
41
|
+
|
42
|
+
protected
|
43
|
+
|
44
|
+
def proxied # :nodoc:
|
45
|
+
super if defined? super
|
46
|
+
extend Field::MutationField::Proxied
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
Field::ScopedConfig.delegate :perform, to: :field
|
51
|
+
end
|
52
|
+
end
|