rails-graphql 0.2.1 → 1.0.0.beta
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 +4 -4
- data/ext/console.rb +18 -0
- data/ext/extconf.h +3 -0
- data/ext/extconf.rb +1 -54
- data/ext/gql_parser.c +646 -0
- data/ext/shared.c +482 -0
- data/ext/shared.h +177 -0
- data/lib/gql_parser.so +0 -0
- data/lib/rails/graphql/adapters/mysql_adapter.rb +59 -0
- data/lib/rails/graphql/adapters/pg_adapter.rb +25 -22
- data/lib/rails/graphql/adapters/sqlite_adapter.rb +17 -14
- data/lib/rails/graphql/alternative/field_set.rb +36 -0
- data/lib/rails/graphql/alternative/mutation.rb +17 -0
- data/lib/rails/graphql/alternative/query.rb +93 -0
- data/lib/rails/graphql/alternative/subscription.rb +17 -0
- data/lib/rails/graphql/alternative.rb +20 -0
- data/lib/rails/graphql/argument.rb +21 -24
- data/lib/rails/graphql/callback.rb +24 -9
- data/lib/rails/graphql/collectors/hash_collector.rb +14 -6
- data/lib/rails/graphql/collectors/idented_collector.rb +10 -7
- data/lib/rails/graphql/collectors/json_collector.rb +22 -17
- data/lib/rails/graphql/collectors.rb +4 -4
- data/lib/rails/graphql/config.rb +130 -15
- data/lib/rails/graphql/directive/cached_directive.rb +33 -0
- data/lib/rails/graphql/directive/deprecated_directive.rb +10 -10
- data/lib/rails/graphql/directive/include_directive.rb +5 -4
- data/lib/rails/graphql/directive/skip_directive.rb +5 -4
- data/lib/rails/graphql/directive.rb +118 -63
- data/lib/rails/graphql/errors.rb +33 -4
- data/lib/rails/graphql/event.rb +16 -5
- data/lib/rails/graphql/field/authorized_field.rb +19 -3
- data/lib/rails/graphql/field/input_field.rb +11 -10
- data/lib/rails/graphql/field/mutation_field.rb +42 -7
- data/lib/rails/graphql/field/output_field.rb +102 -13
- data/lib/rails/graphql/field/proxied_field.rb +31 -22
- data/lib/rails/graphql/field/resolved_field.rb +26 -24
- data/lib/rails/graphql/field/scoped_config.rb +10 -4
- data/lib/rails/graphql/field/subscription_field.rb +140 -0
- data/lib/rails/graphql/field/typed_field.rb +43 -22
- data/lib/rails/graphql/field.rb +70 -56
- data/lib/rails/graphql/global_id.rb +85 -0
- data/lib/rails/graphql/helpers/attribute_delegator.rb +5 -5
- data/lib/rails/graphql/helpers/inherited_collection/array.rb +50 -0
- data/lib/rails/graphql/helpers/inherited_collection/base.rb +43 -0
- data/lib/rails/graphql/helpers/inherited_collection/hash.rb +87 -0
- data/lib/rails/graphql/helpers/inherited_collection.rb +25 -76
- data/lib/rails/graphql/helpers/instantiable.rb +15 -0
- data/lib/rails/graphql/helpers/leaf_from_ar.rb +7 -7
- data/lib/rails/graphql/helpers/registerable.rb +44 -62
- data/lib/rails/graphql/helpers/unregisterable.rb +16 -0
- data/lib/rails/graphql/helpers/with_arguments.rb +31 -27
- data/lib/rails/graphql/helpers/with_assignment.rb +6 -6
- data/lib/rails/graphql/helpers/with_callbacks.rb +25 -8
- data/lib/rails/graphql/helpers/with_description.rb +71 -0
- data/lib/rails/graphql/helpers/with_directives.rb +54 -30
- data/lib/rails/graphql/helpers/with_events.rb +21 -23
- data/lib/rails/graphql/helpers/with_fields.rb +76 -22
- data/lib/rails/graphql/helpers/with_global_id.rb +22 -0
- data/lib/rails/graphql/helpers/with_name.rb +43 -0
- data/lib/rails/graphql/helpers/with_namespace.rb +7 -4
- data/lib/rails/graphql/helpers/with_owner.rb +8 -7
- data/lib/rails/graphql/helpers/with_schema_fields.rb +137 -55
- data/lib/rails/graphql/helpers/with_validator.rb +9 -9
- data/lib/rails/graphql/helpers.rb +10 -3
- data/lib/rails/graphql/introspection.rb +43 -36
- data/lib/rails/graphql/railtie.rb +88 -33
- data/lib/rails/graphql/railties/base_generator.rb +3 -9
- data/lib/rails/graphql/railties/channel.rb +157 -0
- data/lib/rails/graphql/railties/controller.rb +62 -17
- data/lib/rails/graphql/railties/controller_runtime.rb +5 -5
- data/lib/rails/graphql/railties/log_subscriber.rb +81 -14
- data/lib/rails/graphql/request/arguments.rb +24 -49
- data/lib/rails/graphql/request/backtrace.rb +191 -0
- data/lib/rails/graphql/request/component/field.rb +86 -65
- data/lib/rails/graphql/request/component/fragment.rb +72 -24
- data/lib/rails/graphql/request/component/operation/subscription.rb +164 -4
- data/lib/rails/graphql/request/component/operation.rb +63 -31
- data/lib/rails/graphql/request/component/spread.rb +68 -25
- data/lib/rails/graphql/request/component/typename.rb +27 -12
- data/lib/rails/graphql/request/component.rb +75 -36
- data/lib/rails/graphql/request/context.rb +18 -8
- data/lib/rails/graphql/request/errors.rb +16 -6
- data/lib/rails/graphql/request/event.rb +19 -8
- data/lib/rails/graphql/request/helpers/directives.rb +68 -27
- data/lib/rails/graphql/request/helpers/selection_set.rb +51 -25
- data/lib/rails/graphql/request/helpers/value_writers.rb +18 -16
- data/lib/rails/graphql/request/prepared_data.rb +98 -0
- data/lib/rails/graphql/request/steps/authorizable.rb +24 -14
- data/lib/rails/graphql/request/steps/organizable.rb +110 -48
- data/lib/rails/graphql/request/steps/{prepareable.rb → preparable.rb} +20 -7
- data/lib/rails/graphql/request/steps/{resolveable.rb → resolvable.rb} +15 -6
- data/lib/rails/graphql/request/strategy/cached_strategy.rb +64 -0
- data/lib/rails/graphql/request/strategy/dynamic_instance.rb +6 -6
- data/lib/rails/graphql/request/strategy/multi_query_strategy.rb +6 -13
- data/lib/rails/graphql/request/strategy/sequenced_strategy.rb +9 -9
- data/lib/rails/graphql/request/strategy.rb +131 -75
- data/lib/rails/graphql/request/subscription.rb +80 -0
- data/lib/rails/graphql/request.rb +305 -86
- data/lib/rails/graphql/schema.rb +240 -48
- data/lib/rails/graphql/shortcuts.rb +22 -3
- data/lib/rails/graphql/source/active_record/builders.rb +49 -35
- data/lib/rails/graphql/source/active_record_source.rb +70 -54
- data/lib/rails/graphql/source/base.rb +111 -0
- data/lib/rails/graphql/source/builder.rb +128 -0
- data/lib/rails/graphql/source/scoped_arguments.rb +31 -19
- data/lib/rails/graphql/source.rb +89 -213
- data/lib/rails/graphql/subscription/provider/action_cable.rb +112 -0
- data/lib/rails/graphql/subscription/provider/base.rb +191 -0
- data/lib/rails/graphql/subscription/provider.rb +18 -0
- data/lib/rails/graphql/subscription/store/base.rb +145 -0
- data/lib/rails/graphql/subscription/store/memory.rb +127 -0
- data/lib/rails/graphql/subscription/store.rb +19 -0
- data/lib/rails/graphql/subscription.rb +17 -0
- data/lib/rails/graphql/to_gql.rb +29 -32
- data/lib/rails/graphql/type/enum/directive_location_enum.rb +11 -11
- data/lib/rails/graphql/type/enum/type_kind_enum.rb +3 -3
- data/lib/rails/graphql/type/enum.rb +34 -48
- data/lib/rails/graphql/type/input.rb +74 -23
- data/lib/rails/graphql/type/interface.rb +16 -26
- data/lib/rails/graphql/type/object/directive_object.rb +4 -4
- data/lib/rails/graphql/type/object/enum_value_object.rb +3 -3
- data/lib/rails/graphql/type/object/field_object.rb +24 -6
- data/lib/rails/graphql/type/object/input_value_object.rb +3 -3
- data/lib/rails/graphql/type/object/schema_object.rb +5 -8
- data/lib/rails/graphql/type/object/type_object.rb +29 -19
- data/lib/rails/graphql/type/object.rb +26 -23
- data/lib/rails/graphql/type/scalar/any_scalar.rb +30 -0
- data/lib/rails/graphql/type/scalar/bigint_scalar.rb +5 -5
- data/lib/rails/graphql/type/scalar/binary_scalar.rb +3 -3
- data/lib/rails/graphql/type/scalar/boolean_scalar.rb +8 -8
- data/lib/rails/graphql/type/scalar/date_scalar.rb +3 -3
- data/lib/rails/graphql/type/scalar/date_time_scalar.rb +3 -3
- data/lib/rails/graphql/type/scalar/decimal_scalar.rb +3 -3
- data/lib/rails/graphql/type/scalar/float_scalar.rb +5 -5
- data/lib/rails/graphql/type/scalar/id_scalar.rb +6 -5
- data/lib/rails/graphql/type/scalar/int_scalar.rb +6 -5
- data/lib/rails/graphql/type/scalar/json_scalar.rb +39 -0
- data/lib/rails/graphql/type/scalar/string_scalar.rb +18 -4
- data/lib/rails/graphql/type/scalar/time_scalar.rb +5 -5
- data/lib/rails/graphql/type/scalar.rb +25 -22
- data/lib/rails/graphql/type/union.rb +14 -16
- data/lib/rails/graphql/type.rb +34 -25
- data/lib/rails/graphql/type_map.rb +256 -164
- data/lib/rails/graphql/uri.rb +166 -0
- data/lib/rails/graphql/version.rb +15 -3
- data/lib/rails/graphql.rake +3 -0
- data/lib/rails/graphql.rb +85 -52
- data/lib/rails-graphql.rb +1 -1
- data/test/assets/en.yml +29 -0
- data/test/assets/introspection-mem.txt +1 -1
- data/test/assets/mem.gql +18 -45
- data/test/assets/mysql.gql +392 -0
- data/test/assets/sqlite.gql +21 -12
- data/test/assets/translate.gql +335 -0
- data/test/config.rb +18 -8
- data/test/graphql/schema_test.rb +12 -19
- data/test/graphql/source_test.rb +8 -75
- data/test/graphql/type/enum_test.rb +207 -203
- data/test/graphql/type/input_test.rb +14 -9
- data/test/graphql/type/interface_test.rb +4 -4
- data/test/graphql/type/scalar/any_scalar_test.rb +38 -0
- data/test/graphql/type/scalar/boolean_scalar_test.rb +6 -3
- data/test/graphql/type/scalar/json_scalar_test.rb +23 -0
- data/test/graphql/type_map_test.rb +51 -66
- data/test/graphql/type_test.rb +0 -19
- data/test/graphql_test.rb +1 -1
- data/test/integration/{authorization/authorization_test.rb → authorization_test.rb} +40 -14
- data/test/integration/config.rb +36 -3
- data/test/integration/customization_test.rb +39 -0
- data/test/integration/global_id_test.rb +99 -0
- data/test/integration/memory/star_wars_introspection_test.rb +24 -16
- data/test/integration/memory/star_wars_query_test.rb +54 -3
- data/test/integration/memory/star_wars_validation_test.rb +1 -1
- data/test/integration/mysql/star_wars_introspection_test.rb +25 -0
- data/test/integration/persisted_query_test.rb +87 -0
- data/test/integration/resolver_precedence_test.rb +154 -0
- data/test/integration/schemas/memory.rb +22 -7
- data/test/integration/schemas/mysql.rb +62 -0
- data/test/integration/schemas/sqlite.rb +21 -12
- data/test/integration/sqlite/star_wars_global_id_test.rb +83 -0
- data/test/integration/sqlite/star_wars_introspection_test.rb +10 -0
- data/test/integration/sqlite/star_wars_query_test.rb +14 -1
- data/test/integration/translate_test.rb +61 -0
- data/test/test_ext.rb +16 -13
- metadata +108 -157
- data/ext/depend +0 -3
- data/ext/graphqlparser/Ast.cpp +0 -346
- data/ext/graphqlparser/Ast.h +0 -1214
- data/ext/graphqlparser/AstNode.h +0 -36
- data/ext/graphqlparser/AstVisitor.h +0 -137
- data/ext/graphqlparser/GraphQLParser.cpp +0 -76
- data/ext/graphqlparser/GraphQLParser.h +0 -55
- data/ext/graphqlparser/JsonVisitor.cpp +0 -161
- data/ext/graphqlparser/JsonVisitor.cpp.inc +0 -456
- data/ext/graphqlparser/JsonVisitor.h +0 -121
- data/ext/graphqlparser/JsonVisitor.h.inc +0 -110
- data/ext/graphqlparser/VERSION +0 -1
- data/ext/graphqlparser/c/GraphQLAst.cpp +0 -324
- data/ext/graphqlparser/c/GraphQLAst.h +0 -180
- data/ext/graphqlparser/c/GraphQLAstForEachConcreteType.h +0 -44
- data/ext/graphqlparser/c/GraphQLAstNode.cpp +0 -25
- data/ext/graphqlparser/c/GraphQLAstNode.h +0 -33
- data/ext/graphqlparser/c/GraphQLAstToJSON.cpp +0 -21
- data/ext/graphqlparser/c/GraphQLAstToJSON.h +0 -24
- data/ext/graphqlparser/c/GraphQLAstVisitor.cpp +0 -55
- data/ext/graphqlparser/c/GraphQLAstVisitor.h +0 -53
- data/ext/graphqlparser/c/GraphQLParser.cpp +0 -35
- data/ext/graphqlparser/c/GraphQLParser.h +0 -54
- data/ext/graphqlparser/dump_json_ast.cpp +0 -48
- data/ext/graphqlparser/lexer.lpp +0 -324
- data/ext/graphqlparser/parser.ypp +0 -693
- data/ext/graphqlparser/parsergen/lexer.cpp +0 -2633
- data/ext/graphqlparser/parsergen/lexer.h +0 -528
- data/ext/graphqlparser/parsergen/location.hh +0 -189
- data/ext/graphqlparser/parsergen/parser.tab.cpp +0 -3300
- data/ext/graphqlparser/parsergen/parser.tab.hpp +0 -646
- data/ext/graphqlparser/parsergen/position.hh +0 -179
- data/ext/graphqlparser/parsergen/stack.hh +0 -156
- data/ext/graphqlparser/syntaxdefs.h +0 -19
- data/ext/libgraphqlparser/AstNode.h +0 -36
- data/ext/libgraphqlparser/CMakeLists.txt +0 -148
- data/ext/libgraphqlparser/CONTRIBUTING.md +0 -23
- data/ext/libgraphqlparser/GraphQLParser.cpp +0 -76
- data/ext/libgraphqlparser/GraphQLParser.h +0 -55
- data/ext/libgraphqlparser/JsonVisitor.cpp +0 -161
- data/ext/libgraphqlparser/JsonVisitor.h +0 -121
- data/ext/libgraphqlparser/LICENSE +0 -22
- data/ext/libgraphqlparser/README.clang-tidy +0 -7
- data/ext/libgraphqlparser/README.md +0 -84
- data/ext/libgraphqlparser/ast/ast.ast +0 -203
- data/ext/libgraphqlparser/ast/ast.py +0 -61
- data/ext/libgraphqlparser/ast/c.py +0 -100
- data/ext/libgraphqlparser/ast/c.pyc +0 -0
- data/ext/libgraphqlparser/ast/c_impl.py +0 -61
- data/ext/libgraphqlparser/ast/c_impl.pyc +0 -0
- data/ext/libgraphqlparser/ast/c_visitor_impl.py +0 -39
- data/ext/libgraphqlparser/ast/c_visitor_impl.pyc +0 -0
- data/ext/libgraphqlparser/ast/casing.py +0 -26
- data/ext/libgraphqlparser/ast/casing.pyc +0 -0
- data/ext/libgraphqlparser/ast/cxx.py +0 -197
- data/ext/libgraphqlparser/ast/cxx.pyc +0 -0
- data/ext/libgraphqlparser/ast/cxx_impl.py +0 -61
- data/ext/libgraphqlparser/ast/cxx_impl.pyc +0 -0
- data/ext/libgraphqlparser/ast/cxx_json_visitor_header.py +0 -42
- data/ext/libgraphqlparser/ast/cxx_json_visitor_header.pyc +0 -0
- data/ext/libgraphqlparser/ast/cxx_json_visitor_impl.py +0 -80
- data/ext/libgraphqlparser/ast/cxx_json_visitor_impl.pyc +0 -0
- data/ext/libgraphqlparser/ast/cxx_visitor.py +0 -64
- data/ext/libgraphqlparser/ast/cxx_visitor.pyc +0 -0
- data/ext/libgraphqlparser/ast/js.py +0 -65
- data/ext/libgraphqlparser/ast/license.py +0 -10
- data/ext/libgraphqlparser/ast/license.pyc +0 -0
- data/ext/libgraphqlparser/c/GraphQLAstNode.cpp +0 -25
- data/ext/libgraphqlparser/c/GraphQLAstNode.h +0 -33
- data/ext/libgraphqlparser/c/GraphQLAstToJSON.cpp +0 -21
- data/ext/libgraphqlparser/c/GraphQLAstToJSON.h +0 -24
- data/ext/libgraphqlparser/c/GraphQLAstVisitor.cpp +0 -55
- data/ext/libgraphqlparser/c/GraphQLAstVisitor.h +0 -53
- data/ext/libgraphqlparser/c/GraphQLParser.cpp +0 -35
- data/ext/libgraphqlparser/c/GraphQLParser.h +0 -54
- data/ext/libgraphqlparser/clang-tidy-all.sh +0 -3
- data/ext/libgraphqlparser/cmake/version.cmake +0 -16
- data/ext/libgraphqlparser/dump_json_ast.cpp +0 -48
- data/ext/libgraphqlparser/go/README.md +0 -20
- data/ext/libgraphqlparser/go/callbacks.go +0 -18
- data/ext/libgraphqlparser/go/gotest.go +0 -64
- data/ext/libgraphqlparser/lexer.lpp +0 -324
- data/ext/libgraphqlparser/libgraphqlparser.pc.in +0 -11
- data/ext/libgraphqlparser/parser.ypp +0 -693
- data/ext/libgraphqlparser/parsergen/lexer.cpp +0 -2633
- data/ext/libgraphqlparser/parsergen/lexer.h +0 -528
- data/ext/libgraphqlparser/parsergen/location.hh +0 -189
- data/ext/libgraphqlparser/parsergen/parser.tab.cpp +0 -3300
- data/ext/libgraphqlparser/parsergen/parser.tab.hpp +0 -646
- data/ext/libgraphqlparser/parsergen/position.hh +0 -179
- data/ext/libgraphqlparser/parsergen/stack.hh +0 -156
- data/ext/libgraphqlparser/python/CMakeLists.txt +0 -14
- data/ext/libgraphqlparser/python/README.md +0 -5
- data/ext/libgraphqlparser/python/example.py +0 -31
- data/ext/libgraphqlparser/syntaxdefs.h +0 -19
- data/ext/libgraphqlparser/test/BuildCAPI.c +0 -5
- data/ext/libgraphqlparser/test/CMakeLists.txt +0 -25
- data/ext/libgraphqlparser/test/JsonVisitorTests.cpp +0 -28
- data/ext/libgraphqlparser/test/ParserTests.cpp +0 -352
- data/ext/libgraphqlparser/test/kitchen-sink.graphql +0 -59
- data/ext/libgraphqlparser/test/kitchen-sink.json +0 -1
- data/ext/libgraphqlparser/test/schema-kitchen-sink.graphql +0 -78
- data/ext/libgraphqlparser/test/schema-kitchen-sink.json +0 -1
- data/ext/libgraphqlparser/test/valgrind.supp +0 -33
- data/ext/version.cpp +0 -21
- data/lib/graphqlparser.so +0 -0
- data/lib/rails/graphql/native/functions.rb +0 -38
- data/lib/rails/graphql/native/location.rb +0 -41
- data/lib/rails/graphql/native/pointers.rb +0 -23
- data/lib/rails/graphql/native/visitor.rb +0 -349
- data/lib/rails/graphql/native.rb +0 -56
- data/test/integration/schemas/authorization.rb +0 -12
data/lib/rails/graphql/source.rb
CHANGED
@@ -1,29 +1,45 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module Rails
|
4
|
-
module GraphQL
|
3
|
+
module Rails
|
4
|
+
module GraphQL
|
5
5
|
# = GraphQL Source
|
6
6
|
#
|
7
7
|
# Source is an abstract object that can contains fields, objects, and
|
8
|
-
#
|
9
|
-
# proxies, ensuring that it still
|
8
|
+
# information that them are delivered to the relative schemas throughout
|
9
|
+
# proxies, ensuring that it still keeps the main ownership of the objects
|
10
10
|
class Source
|
11
11
|
extend ActiveSupport::Autoload
|
12
12
|
|
13
13
|
extend Helpers::InheritedCollection
|
14
|
-
extend Helpers::WithSchemaFields
|
15
|
-
extend Helpers::WithAssignment
|
16
14
|
extend Helpers::WithNamespace
|
15
|
+
extend Helpers::WithEvents
|
16
|
+
extend Helpers::WithCallbacks
|
17
17
|
|
18
|
-
|
18
|
+
include Helpers::Instantiable
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
20
|
+
ATTACH_FIELDS_STEP = -> do
|
21
|
+
if fields?
|
22
|
+
attach_fields!(type, fields)
|
23
|
+
attach_scoped_arguments_to(fields.values)
|
24
|
+
end
|
24
25
|
end
|
25
26
|
|
26
|
-
|
27
|
+
autoload :Base
|
28
|
+
autoload :Builder
|
29
|
+
|
30
|
+
autoload :ScopedArguments
|
31
|
+
autoload :ActiveRecordSource
|
32
|
+
|
33
|
+
extend Source::Builder
|
34
|
+
|
35
|
+
# Helper class to be used as the +self+ in configuration blocks
|
36
|
+
ScopedConfig = Struct.new(:receiver, :self_object, :type) do
|
37
|
+
def safe_field(name, *args, **xargs, &block)
|
38
|
+
return if receiver.send(:skip_field?, name, on: type)
|
39
|
+
self_object.safe_field(name, *args, **xargs, &block)
|
40
|
+
end
|
41
|
+
|
42
|
+
# skip_field?(item.name, on: holder.kind)
|
27
43
|
def respond_to_missing?(method_name, include_private = false)
|
28
44
|
self_object.respond_to?(method_name, include_private) ||
|
29
45
|
receiver.respond_to?(method_name, include_private)
|
@@ -39,53 +55,34 @@ module Rails # :nodoc:
|
|
39
55
|
# If a source is marked as abstract, it means that it generates a new
|
40
56
|
# source describer and any non-abstract class inherited from it will be
|
41
57
|
# described by this new abstraction
|
42
|
-
class_attribute :abstract,
|
58
|
+
class_attribute :abstract, instance_accessor: false, default: false
|
43
59
|
|
44
60
|
# List of hook names used while describing a new source. This basically
|
45
61
|
# set the order of the execution of the hooks while validating the hooks
|
46
|
-
# callbacks using the +on+ method
|
47
|
-
|
48
|
-
|
49
|
-
default: %i[start object input query mutation finish].to_set
|
62
|
+
# callbacks using the +on+ method
|
63
|
+
class_attribute :hook_names, instance_accessor: false,
|
64
|
+
default: %i[start object input query mutation subscription].to_set
|
50
65
|
|
51
66
|
# The list of hooks defined in order to describe a source
|
52
67
|
inherited_collection :hooks, instance_reader: false, type: :hash_array
|
53
68
|
|
54
|
-
# The name of the class (or the class itself) to be used as superclass for
|
55
|
-
# the generate GraphQL object type of this source
|
56
|
-
class_attribute :object_class, instance_writer: false,
|
57
|
-
default: '::Rails::GraphQL::Type::Object'
|
58
|
-
|
59
|
-
# The name of the class (or the class itself) to be used as superclass for
|
60
|
-
# the generate GraphQL input type of this source
|
61
|
-
class_attribute :input_class, instance_writer: false,
|
62
|
-
default: '::Rails::GraphQL::Type::Input'
|
63
|
-
|
64
|
-
# Mark if the objects created from this source will build fields for
|
65
|
-
# associations associated to the object
|
66
|
-
class_attribute :with_associations, instance_writer: false, default: true
|
67
|
-
|
68
69
|
# A list of fields to skip when performing shared methods
|
69
|
-
inherited_collection :skip_fields, instance_reader: false
|
70
|
+
inherited_collection :skip_fields, instance_reader: false, type: :set
|
70
71
|
|
71
72
|
# A list of fields to skip but segmented by holder source
|
72
73
|
inherited_collection :segmented_skip_fields, instance_reader: false, type: :hash_set
|
73
74
|
|
74
|
-
#
|
75
|
-
#
|
76
|
-
|
77
|
-
delegate_missing_to :event
|
78
|
-
attr_reader :event
|
75
|
+
# A list of fields that should only be included. Available only when using
|
76
|
+
# individual builders
|
77
|
+
inherited_collection :segmented_only_fields, instance_reader: false, type: :hash_set
|
79
78
|
|
80
79
|
self.abstract = true
|
81
80
|
|
82
81
|
class << self
|
83
|
-
|
82
|
+
delegate :field, :proxy_field, :overwrite_field, :field?, :field_names,
|
83
|
+
:gql_name, to: :object
|
84
84
|
|
85
|
-
|
86
|
-
:field_names, :gql_name, to: :object
|
87
|
-
|
88
|
-
def kind # :nodoc:
|
85
|
+
def kind
|
89
86
|
:source
|
90
87
|
end
|
91
88
|
|
@@ -96,27 +93,19 @@ module Rails # :nodoc:
|
|
96
93
|
|
97
94
|
# Get the main name of the source
|
98
95
|
def base_name
|
99
|
-
name.demodulize[0..-7]
|
100
|
-
end
|
101
|
-
|
102
|
-
# Wait the end of the class in order to create the objects
|
103
|
-
def inherited(subclass)
|
104
|
-
subclass.abstract = false
|
105
|
-
super if defined? super
|
106
|
-
|
107
|
-
pending[subclass] ||= caller(1).find do |item|
|
108
|
-
!item.end_with?("`inherited'")
|
109
|
-
end
|
96
|
+
name.demodulize[0..-7]
|
110
97
|
end
|
111
98
|
|
99
|
+
# :singleton-method:
|
112
100
|
# Find a source for a given object. If none is found, then raise an
|
113
101
|
# exception
|
114
102
|
def find_for!(object)
|
115
|
-
find_for(object) || raise(::ArgumentError,
|
103
|
+
find_for(object) || raise(::ArgumentError, (+<<~MSG).squish)
|
116
104
|
Unable to find a source for "#{object.name}".
|
117
105
|
MSG
|
118
106
|
end
|
119
107
|
|
108
|
+
# :singleton-method:
|
120
109
|
# Using the list of +base_sources+, find the first one that can handle
|
121
110
|
# the given +object+
|
122
111
|
def find_for(object)
|
@@ -124,60 +113,17 @@ module Rails # :nodoc:
|
|
124
113
|
base_sources.reverse_each.find { |source| object <= source.assigned_class }
|
125
114
|
end
|
126
115
|
|
127
|
-
# Return the GraphQL object type associated with the source. It will
|
128
|
-
# create one if it's not defined yet. The created class will be added
|
129
|
-
# to the +::GraphQL+ namespace with the addition of any namespace of the
|
130
|
-
# currect class
|
131
|
-
def object
|
132
|
-
@object ||= create_type(superclass: object_class)
|
133
|
-
end
|
134
|
-
|
135
|
-
# Return the GraphQL input type associated with the source. It will
|
136
|
-
# create one if it's not defined yet. The created class will be added
|
137
|
-
# to the +::GraphQL+ namespace with the addition of any namespace of the
|
138
|
-
# currect class
|
139
|
-
def input
|
140
|
-
@input ||= create_type(superclass: input_class)
|
141
|
-
end
|
142
|
-
|
143
|
-
# Check if the object was already built
|
144
|
-
def built?
|
145
|
-
defined?(@built) && !!@built
|
146
|
-
end
|
147
|
-
|
148
|
-
# Checks if a given method can act as resolver
|
149
|
-
def gql_resolver?(method_name)
|
150
|
-
(instance_methods - GraphQL::Source.instance_methods).include?(method_name)
|
151
|
-
end
|
152
|
-
|
153
116
|
# Attach all defined schema fields into the schemas using the namespaces
|
154
117
|
# configured for the source
|
155
|
-
def attach_fields!
|
156
|
-
|
157
|
-
schemas.each_value do |schema|
|
158
|
-
Helpers::WithSchemaFields::SCHEMA_FIELD_TYPES.keys.each do |type|
|
159
|
-
list = public_send("#{type}_fields")
|
160
|
-
next if list.empty?
|
161
|
-
|
162
|
-
list.each_value do |field|
|
163
|
-
next if schema.has_field?(type, field)
|
164
|
-
schema.add_proxy_field(type, field)
|
165
|
-
end
|
166
|
-
end
|
167
|
-
end
|
118
|
+
def attach_fields!(type = :all, from = self)
|
119
|
+
schemas.each { |schema| schema.import_into(type, from) }
|
168
120
|
end
|
169
121
|
|
170
122
|
# Find all the schemas associated with the configured namespaces
|
171
|
-
def
|
172
|
-
|
173
|
-
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
177
|
-
def eager_load! # :nodoc:
|
178
|
-
super
|
179
|
-
|
180
|
-
build_pending!
|
123
|
+
def schemas
|
124
|
+
GraphQL.enumerate(namespaces.presence || :base).lazy.filter_map do |ns|
|
125
|
+
Schema.find(ns)
|
126
|
+
end
|
181
127
|
end
|
182
128
|
|
183
129
|
protected
|
@@ -191,54 +137,15 @@ module Rails # :nodoc:
|
|
191
137
|
end
|
192
138
|
|
193
139
|
# A little bypass to the actual type map after register method which
|
194
|
-
# just add the
|
140
|
+
# just add the namespace by default
|
195
141
|
# See {TypeMap#after_register}[rdoc-ref:Rails::GraphQL::TypeMap#after_register]
|
196
142
|
def type_map_after_register(*args, **xargs, &block)
|
197
143
|
xargs[:namespaces] ||= namespaces
|
198
144
|
GraphQL.type_map.after_register(*args, **xargs, &block)
|
199
145
|
end
|
200
146
|
|
201
|
-
# A helper method to create an enum type
|
202
|
-
def create_enum(enum_name, values, **xargs, &block)
|
203
|
-
enumerator = values.each_pair if values.respond_to?(:each_pair)
|
204
|
-
enumerator ||= values.each.with_index
|
205
|
-
|
206
|
-
xargs = xargs.reverse_merge(once: true)
|
207
|
-
create_type(:enum, as: enum_name.classify, **xargs) do
|
208
|
-
indexed! if enumerator.first.last.is_a?(Numeric)
|
209
|
-
enumerator.sort_by(&:last).map(&:first).each(&method(:add))
|
210
|
-
instance_exec(&block) if block.present?
|
211
|
-
end
|
212
|
-
end
|
213
|
-
|
214
|
-
# Helper method to create a class based on the given type and allows
|
215
|
-
# several other settings to be executed on it
|
216
|
-
def create_type(type = nil, **xargs, &block)
|
217
|
-
name = "#{gql_module.name}::#{xargs.delete(:as) || base_name}"
|
218
|
-
superclass = xargs.delete(:superclass)
|
219
|
-
with_owner = xargs.delete(:with_owner)
|
220
|
-
|
221
|
-
if superclass.nil?
|
222
|
-
superclass = type.to_s.classify
|
223
|
-
elsif superclass.is_a?(String)
|
224
|
-
superclass = superclass.constantize
|
225
|
-
end
|
226
|
-
|
227
|
-
source = self
|
228
|
-
Schema.send(:create_type, name, superclass, **xargs) do
|
229
|
-
include Helpers::WithOwner if with_owner
|
230
|
-
set_namespaces(*source.namespaces)
|
231
|
-
|
232
|
-
self.owner = source if respond_to?(:owner=)
|
233
|
-
self.assigned_to = source.safe_assigned_class \
|
234
|
-
if source.assigned? && is_a?(Helpers::WithAssignment)
|
235
|
-
|
236
|
-
instance_exec(&block) if block.present?
|
237
|
-
end
|
238
|
-
end
|
239
|
-
|
240
147
|
# Add fields to be skipped on the given +source+ as the segment
|
241
|
-
def
|
148
|
+
def skip_from(source, *fields)
|
242
149
|
segmented_skip_fields[source] += fields.flatten.compact.map(&:to_sym).to_set
|
243
150
|
end
|
244
151
|
|
@@ -246,13 +153,13 @@ module Rails # :nodoc:
|
|
246
153
|
# parent hooks. If the class is already built, then execute the hook.
|
247
154
|
# Use the +unshift: true+ to add the hook at the beginning of the
|
248
155
|
# list, which will then be the last to run
|
249
|
-
def
|
250
|
-
raise ArgumentError,
|
156
|
+
def step(hook_name, unshift: false, &block)
|
157
|
+
raise ArgumentError, (+<<~MSG).squish unless hook_names.include?(hook_name.to_sym)
|
251
158
|
The #{hook_name.inspect} is not a valid hook method.
|
252
159
|
MSG
|
253
160
|
|
254
|
-
if built?
|
255
|
-
|
161
|
+
if built?(hook_name)
|
162
|
+
hook_scope_for(hook_name).instance_exec(&block)
|
256
163
|
else
|
257
164
|
hooks[hook_name.to_sym].public_send(unshift ? :unshift : :push, block)
|
258
165
|
end
|
@@ -262,7 +169,7 @@ module Rails # :nodoc:
|
|
262
169
|
def skip(*names)
|
263
170
|
names.each do |hook_name|
|
264
171
|
hook_name = hook_name.to_s.singularize.to_sym
|
265
|
-
|
172
|
+
step(hook_name) { throw :skip }
|
266
173
|
end
|
267
174
|
end
|
268
175
|
|
@@ -270,7 +177,7 @@ module Rails # :nodoc:
|
|
270
177
|
# +on hook_name do; end+
|
271
178
|
def override(hook_name, &block)
|
272
179
|
skip(hook_name)
|
273
|
-
|
180
|
+
step(hook_name, &block)
|
274
181
|
end
|
275
182
|
|
276
183
|
# It's an alternative to +self.hook_names -= %i[*names]+ which
|
@@ -291,86 +198,55 @@ module Rails # :nodoc:
|
|
291
198
|
|
292
199
|
# Return the module where the GraphQL types should be created at
|
293
200
|
def gql_module
|
294
|
-
name.
|
201
|
+
name.start_with?('GraphQL::') ? module_parent : ::GraphQL
|
295
202
|
end
|
296
203
|
|
297
|
-
#
|
298
|
-
#
|
299
|
-
def
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
204
|
+
# Add one or more fields to the list of fields that needs to be
|
205
|
+
# ignored in all places. It converts strings to underscore
|
206
|
+
def skip_fields!(*list)
|
207
|
+
list = list.flatten.map do |value|
|
208
|
+
value.is_a?(Symbol) ? value.to_s : value.to_s.underscore
|
209
|
+
end
|
210
|
+
|
211
|
+
self.skip_fields.merge(list)
|
304
212
|
end
|
305
213
|
|
306
|
-
|
214
|
+
# Check if a given field +name+ should be skipped on the give type
|
215
|
+
def skip_field?(name, on:)
|
216
|
+
on = :input if on == :input_object
|
217
|
+
name = name.to_s.underscore
|
307
218
|
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
@@pending ||= {}
|
219
|
+
all_skip_fields&.include?(name) ||
|
220
|
+
all_segmented_skip_fields.try(:[], on)&.include?(name) ||
|
221
|
+
all_segmented_only_fields.try(:[], on)&.exclude?(name)
|
312
222
|
end
|
313
223
|
|
314
|
-
#
|
315
|
-
def
|
316
|
-
|
224
|
+
# Run a list of hooks using the +source+ as the instance of the block
|
225
|
+
def run_hooks(hook_name, source = self)
|
226
|
+
all_hooks.try(:[], hook_name.to_sym)&.reverse_each do |block|
|
227
|
+
source.instance_exec(&block)
|
228
|
+
end
|
317
229
|
end
|
318
230
|
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
231
|
+
private
|
232
|
+
|
233
|
+
# Make sure to reset the value of +abstract+
|
234
|
+
def inherited(subclass)
|
235
|
+
subclass.abstract = false
|
236
|
+
super if defined? super
|
324
237
|
end
|
325
238
|
|
326
239
|
# Find all classes that inherits from source that are abstract,
|
327
240
|
# meaning that they are a base sources
|
328
241
|
def base_sources
|
329
|
-
@@base_sources ||=
|
330
|
-
eager_load!
|
331
|
-
descendants.select(&:abstract?).to_set
|
332
|
-
end
|
333
|
-
end
|
334
|
-
|
335
|
-
# Build all the objects associated with this source
|
336
|
-
def build!
|
337
|
-
return if built?
|
338
|
-
|
339
|
-
raise DefinitionError, <<~MSG.squish if abstract
|
340
|
-
Abstract source #{name} cannot be built.
|
341
|
-
MSG
|
342
|
-
|
343
|
-
@built = true
|
344
|
-
|
345
|
-
catch(:done) do
|
346
|
-
hook_names.each do |hook_name|
|
347
|
-
break if hook_name === :finish
|
348
|
-
catch(:skip) { send("run_#{hook_name}_hooks") }
|
349
|
-
end
|
350
|
-
end
|
351
|
-
|
352
|
-
catch(:skip) { send(:run_finish_hooks) } if respond_to?(:run_finish_hooks, true)
|
242
|
+
@@base_sources ||= GraphQL.config.sources.map(&:constantize).to_set
|
353
243
|
end
|
354
244
|
|
355
|
-
{
|
356
|
-
start: 'self',
|
357
|
-
finish: 'self',
|
358
|
-
object: 'Helpers::AttributeDelegator.new(self, :object)',
|
359
|
-
input: 'Helpers::AttributeDelegator.new(self, :input)',
|
360
|
-
query: format('schema_scoped_config(self, %s)', ':query'),
|
361
|
-
mutation: format('schema_scoped_config(self, %s)', ':mutation'),
|
362
|
-
subscription: format('schema_scoped_config(self, %s)', ':subscription'),
|
363
|
-
}.each do |key, object|
|
364
|
-
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
365
|
-
def run_#{key}_hooks(list = nil)
|
366
|
-
source_config = Source::ScopedConfig.new(self, #{object})
|
367
|
-
Array.wrap(list.presence || all_hooks[:#{key}]).reverse_each do |block|
|
368
|
-
source_config.instance_exec(&block)
|
369
|
-
end
|
370
|
-
end
|
371
|
-
RUBY
|
372
|
-
end
|
373
245
|
end
|
246
|
+
|
247
|
+
step(:query, &ATTACH_FIELDS_STEP)
|
248
|
+
step(:mutation, &ATTACH_FIELDS_STEP)
|
249
|
+
step(:subscription, &ATTACH_FIELDS_STEP)
|
374
250
|
end
|
375
251
|
end
|
376
252
|
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'action_cable'
|
4
|
+
|
5
|
+
module Rails
|
6
|
+
module GraphQL
|
7
|
+
module Subscription
|
8
|
+
module Provider
|
9
|
+
# = GraphQL Action Cable Subscription Provider
|
10
|
+
#
|
11
|
+
# The subscription provider associated with Rails Action Cable, that
|
12
|
+
# delivers subscription notifications through an Action Cable Channel
|
13
|
+
class ActionCable < Base
|
14
|
+
INTERNAL_CHANNEL = 'rails-graphql:events'
|
15
|
+
|
16
|
+
attr_reader :cable, :prefix
|
17
|
+
|
18
|
+
def initialize(*args, **options)
|
19
|
+
@cable = options.fetch(:cable, ::ActionCable)
|
20
|
+
@prefix = options.fetch(:prefix, 'graphql')
|
21
|
+
|
22
|
+
@event_callback = ->(message) do
|
23
|
+
method_name, args, xargs = Marshal.load(message)
|
24
|
+
@mutex.synchronize { send(method_name, *args, **xargs) }
|
25
|
+
end
|
26
|
+
|
27
|
+
super
|
28
|
+
end
|
29
|
+
|
30
|
+
def shutdown
|
31
|
+
@pubsub = nil
|
32
|
+
end
|
33
|
+
|
34
|
+
def accepts?(operation)
|
35
|
+
operation.request.origin.is_a?(::ActionCable::Channel::Base)
|
36
|
+
end
|
37
|
+
|
38
|
+
def add(*subscriptions)
|
39
|
+
with_pubsub do
|
40
|
+
subscriptions.each do |item|
|
41
|
+
log(:added, item)
|
42
|
+
store.add(item)
|
43
|
+
stream_from(item)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def async_remove(item)
|
49
|
+
return unless instance?(item) || !(item = store.fetch(item)).nil?
|
50
|
+
cable.server.broadcast(stream_name(item), unsubscribed_payload)
|
51
|
+
store.remove(item)
|
52
|
+
|
53
|
+
log(:removed, item)
|
54
|
+
end
|
55
|
+
|
56
|
+
def async_update(item, data = nil)
|
57
|
+
return unless instance?(item) || !(item = store.fetch(item)).nil?
|
58
|
+
removing = false
|
59
|
+
|
60
|
+
log(:updated, item) do
|
61
|
+
data = execute(item) if data.nil?
|
62
|
+
item.updated!
|
63
|
+
|
64
|
+
unless (removing = unsubscribing?(data))
|
65
|
+
data = { 'result' => data, 'more' => true }
|
66
|
+
cable.server.broadcast(stream_name(item), data)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
async_remove(item) if removing
|
71
|
+
end
|
72
|
+
|
73
|
+
def stream_name(item)
|
74
|
+
"#{prefix}:#{instance?(item) ? item.sid : item}"
|
75
|
+
end
|
76
|
+
|
77
|
+
protected
|
78
|
+
|
79
|
+
def stream_from(item)
|
80
|
+
item.origin.stream_from(stream_name(item))
|
81
|
+
end
|
82
|
+
|
83
|
+
def execute(subscription, **xargs)
|
84
|
+
super(subscription, origin: subscription.origin, **xargs, as: :hash)
|
85
|
+
end
|
86
|
+
|
87
|
+
def async_exec(method_name, *args, **xargs)
|
88
|
+
payload = [method_name, args, store.serialize(**xargs)]
|
89
|
+
with_pubsub { @pubsub.broadcast(INTERNAL_CHANNEL, Marshal.dump(payload)) }
|
90
|
+
nil
|
91
|
+
end
|
92
|
+
|
93
|
+
def with_pubsub(&callback)
|
94
|
+
success = -> { cable.server.event_loop.post(&callback) }
|
95
|
+
return success.call if defined?(@pubsub) && !@pubsub.nil?
|
96
|
+
|
97
|
+
cable.server.pubsub.subscribe(INTERNAL_CHANNEL, @event_callback, success)
|
98
|
+
@pubsub = cable.server.pubsub
|
99
|
+
end
|
100
|
+
|
101
|
+
def validate!
|
102
|
+
super
|
103
|
+
|
104
|
+
raise ValidationError, (+<<~MSG).squish if @prefix.blank?
|
105
|
+
Unable to setup #{self.class.name} because a proper prefix was not provided.
|
106
|
+
MSG
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|