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
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rails
|
4
|
+
module GraphQL
|
5
|
+
class Request
|
6
|
+
# = GraphQl Cached Strategy
|
7
|
+
#
|
8
|
+
# This strategy will process hard cached operations. Soft cached
|
9
|
+
# operations are those that only the document is cached in the server and
|
10
|
+
# processed via its unique identifier (UUID). Whereas, hard cached
|
11
|
+
# operations pretty muchy skips the organize step since that is what is
|
12
|
+
# cached.
|
13
|
+
#
|
14
|
+
# Beware, if the version in the cache is different from the version in the
|
15
|
+
# type map, it won't be able to process it.
|
16
|
+
class Strategy::CachedStrategy < Strategy
|
17
|
+
self.priority = 100
|
18
|
+
|
19
|
+
class << self
|
20
|
+
|
21
|
+
# Resolve whenever it has a cache directive on any of the operations
|
22
|
+
def can_resolve?(request)
|
23
|
+
false
|
24
|
+
# request.operations.each_value.any? do |op|
|
25
|
+
# op.data&.directives&.any? { |dir| directive_name(dir) == 'cached' }
|
26
|
+
# end
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def directive_name(obj)
|
32
|
+
Native.node_name(Native.directive_name(obj))
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Executes the strategy in the normal mode
|
37
|
+
def resolve!
|
38
|
+
response.with_stack('data') do
|
39
|
+
for_each_operation { |op| collect_listeners { op.organize! } }
|
40
|
+
for_each_operation { |op| collect_data { op.prepare! } }
|
41
|
+
for_each_operation { |op| collect_response { op.resolve! } }
|
42
|
+
|
43
|
+
# collect_data(true) { op.prepare! }
|
44
|
+
# collect_response { op.resolve! }
|
45
|
+
|
46
|
+
# operations.each_value do |op|
|
47
|
+
# collect_listeners { op.organize! }
|
48
|
+
# collect_data(true) { op.prepare! }
|
49
|
+
# collect_response { op.resolve! }
|
50
|
+
# end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
# Execute a given block for each defined operation
|
57
|
+
def for_each_operation(&block)
|
58
|
+
operations.each_value(&block)
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module Rails
|
4
|
-
module GraphQL
|
5
|
-
class Request
|
3
|
+
module Rails
|
4
|
+
module GraphQL
|
5
|
+
class Request
|
6
6
|
# = GraphQl Strategy Dynamic Instance
|
7
7
|
#
|
8
8
|
# When an event is call on non-object types, this class allows both
|
@@ -16,18 +16,18 @@ module Rails # :nodoc:
|
|
16
16
|
|
17
17
|
private
|
18
18
|
|
19
|
-
def respond_to_missing?(method_name, include_private = false)
|
19
|
+
def respond_to_missing?(method_name, include_private = false)
|
20
20
|
__current_object__&.respond_to?(method_name, include_private) || super
|
21
21
|
end
|
22
22
|
|
23
|
-
def method_missing(method_name, *args, **xargs, &block)
|
23
|
+
def method_missing(method_name, *args, **xargs, &block)
|
24
24
|
object = __current_object__
|
25
25
|
|
26
26
|
return super unless object&.respond_to?(method_name)
|
27
27
|
object.public_send(method_name, *args, **xargs, &block)
|
28
28
|
end
|
29
29
|
|
30
|
-
def __current_object__
|
30
|
+
def __current_object__
|
31
31
|
return unless __getobj__.instance_variable_defined?(:@event)
|
32
32
|
|
33
33
|
event = __getobj__.instance_variable_get(:@event)
|
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module Rails
|
4
|
-
module GraphQL
|
5
|
-
class Request
|
3
|
+
module Rails
|
4
|
+
module GraphQL
|
5
|
+
class Request
|
6
6
|
# = GraphQl Multi Query Strategy
|
7
7
|
#
|
8
8
|
# This is a resolution strategy to solve requests that only contain
|
@@ -11,25 +11,18 @@ module Rails # :nodoc:
|
|
11
11
|
class Strategy::MultiQueryStrategy < Strategy
|
12
12
|
self.priority = 10
|
13
13
|
|
14
|
-
def self.can_resolve?(request)
|
15
|
-
request.operations.
|
14
|
+
def self.can_resolve?(request)
|
15
|
+
request.operations.each_value.all? { |op| op.of_type?(:query) }
|
16
16
|
end
|
17
17
|
|
18
18
|
# Executes the strategy in the normal mode
|
19
19
|
def resolve!
|
20
|
-
response.with_stack(
|
20
|
+
response.with_stack('data') do
|
21
21
|
for_each_operation { |op| collect_listeners { op.organize! } }
|
22
22
|
for_each_operation { |op| collect_data { op.prepare! } }
|
23
23
|
for_each_operation { |op| collect_response { op.resolve! } }
|
24
24
|
end
|
25
25
|
end
|
26
|
-
|
27
|
-
private
|
28
|
-
|
29
|
-
# Execute a given block for each defined operation
|
30
|
-
def for_each_operation
|
31
|
-
operations.each_value { |op| yield op }
|
32
|
-
end
|
33
26
|
end
|
34
27
|
end
|
35
28
|
end
|
@@ -1,24 +1,24 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module Rails
|
4
|
-
module GraphQL
|
5
|
-
class Request
|
3
|
+
module Rails
|
4
|
+
module GraphQL
|
5
|
+
class Request
|
6
6
|
# = GraphQl Sequenced Strategy
|
7
7
|
#
|
8
8
|
# This is the default resolution strategy, where each operation is
|
9
9
|
# performed in sequece, and they don't relate to each other in any way.
|
10
10
|
class Strategy::SequencedStrategy < Strategy
|
11
|
-
def self.can_resolve?(_)
|
11
|
+
def self.can_resolve?(_)
|
12
12
|
true
|
13
13
|
end
|
14
14
|
|
15
15
|
# Executes the strategy in the normal mode
|
16
16
|
def resolve!
|
17
|
-
response.with_stack(
|
18
|
-
|
19
|
-
collect_listeners
|
20
|
-
collect_data
|
21
|
-
collect_response
|
17
|
+
response.with_stack('data') do
|
18
|
+
for_each_operation do |op|
|
19
|
+
collect_listeners { op.organize! }
|
20
|
+
collect_data(true) { op.prepare! }
|
21
|
+
collect_response { op.resolve! }
|
22
22
|
end
|
23
23
|
end
|
24
24
|
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module Rails
|
4
|
-
module GraphQL
|
5
|
-
class Request
|
3
|
+
module Rails
|
4
|
+
module GraphQL
|
5
|
+
class Request
|
6
6
|
# = GraphQL Request Strategy
|
7
7
|
#
|
8
8
|
# This is the base class for the strategies of resolving a request.
|
@@ -11,10 +11,9 @@ module Rails # :nodoc:
|
|
11
11
|
|
12
12
|
autoload :DynamicInstance
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
end
|
14
|
+
autoload :SequencedStrategy
|
15
|
+
autoload :MultiQueryStrategy
|
16
|
+
autoload :CachedStrategy
|
18
17
|
|
19
18
|
# Configurations for the prepare step
|
20
19
|
PREPARE_XARGS = { object?: true, reverse?: true }.freeze
|
@@ -24,7 +23,7 @@ module Rails # :nodoc:
|
|
24
23
|
|
25
24
|
delegate :operations, :errors, :response, :schema, to: :request
|
26
25
|
|
27
|
-
attr_reader :listeners, :request, :context
|
26
|
+
attr_reader :listeners, :request, :context, :stage
|
28
27
|
|
29
28
|
class << self
|
30
29
|
# Check if the strategy can resolve the given +request+. By default,
|
@@ -38,7 +37,15 @@ module Rails # :nodoc:
|
|
38
37
|
def initialize(request)
|
39
38
|
@request = request
|
40
39
|
@objects_pool = {}
|
41
|
-
|
40
|
+
@listeners = Hash.new { |h, k| h[k] = Set.new }
|
41
|
+
add_listeners_from(request)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Clear all strategy information
|
45
|
+
def clear
|
46
|
+
@listeners.clear
|
47
|
+
@objects_pool.clear
|
48
|
+
@stage = @context = @objects_pool = @data_pool = @listeners = nil
|
42
49
|
end
|
43
50
|
|
44
51
|
# Executes the strategy in the normal mode
|
@@ -48,17 +55,12 @@ module Rails # :nodoc:
|
|
48
55
|
|
49
56
|
# Find a given +type+ and store it on request cache
|
50
57
|
def find_type!(type)
|
51
|
-
request.
|
58
|
+
request.nested_cache(:types, type) { schema.find_type!(type) }
|
52
59
|
end
|
53
60
|
|
54
61
|
# Find a given +directive+ and store it on request cache
|
55
62
|
def find_directive!(directive)
|
56
|
-
request.
|
57
|
-
end
|
58
|
-
|
59
|
-
# Check if it's enabled to collect listeners
|
60
|
-
def add_listeners?
|
61
|
-
!listeners.frozen?
|
63
|
+
request.nested_cache(:directives, directive) { schema.find_directive!(directive) }
|
62
64
|
end
|
63
65
|
|
64
66
|
# Check if any listener were actually added
|
@@ -79,8 +81,8 @@ module Rails # :nodoc:
|
|
79
81
|
|
80
82
|
# When a +field+ has a perform step, run it under the context of the
|
81
83
|
# prepared value from the data pool
|
82
|
-
def perform(field)
|
83
|
-
context.stacked(@data_pool[field]) do
|
84
|
+
def perform(field, data = nil)
|
85
|
+
context.stacked(data || @data_pool[field]) do
|
84
86
|
safe_store_data(field) do
|
85
87
|
Event.trigger(:perform, field, self, &field.performer)
|
86
88
|
end
|
@@ -91,27 +93,26 @@ module Rails # :nodoc:
|
|
91
93
|
# block using context stack
|
92
94
|
def prepare(field, &block)
|
93
95
|
value = safe_store_data(field) do
|
94
|
-
|
96
|
+
prepared = request.prepared_data_for(field)
|
97
|
+
if prepared.is_a?(PreparedData)
|
98
|
+
field.prepared_data!
|
99
|
+
prepared.all
|
100
|
+
else
|
101
|
+
Event.trigger(:prepare, field, self, **PREPARE_XARGS)
|
102
|
+
end
|
95
103
|
end
|
96
104
|
|
97
|
-
|
105
|
+
perform(field, value) if field.mutation?
|
98
106
|
|
99
|
-
|
100
|
-
|
101
|
-
It is expected to get a result from prepare events
|
102
|
-
MSG
|
107
|
+
value = @data_pool[field]
|
108
|
+
context.stacked(value, &block) unless value.nil?
|
103
109
|
end
|
104
110
|
|
105
111
|
# Resolve a value for a given object, It uses the +args+ to prevent
|
106
112
|
# problems with nil values.
|
107
113
|
def resolve(field, *args, array: false, decorate: false, &block)
|
108
|
-
|
109
|
-
prepared = data_for(args, field)&.last
|
110
|
-
args << Event.trigger(:resolve, field, self, prepared: prepared,
|
111
|
-
&field.resolver) if field.try(:dynamic_resolver?)
|
112
|
-
end if args.size.zero?
|
114
|
+
resolve_data_for(field, args)
|
113
115
|
|
114
|
-
# Now we have a value to set on the context
|
115
116
|
value = args.last
|
116
117
|
value = field.decorate(value) if decorate
|
117
118
|
context.stacked(value) do |current|
|
@@ -124,12 +125,18 @@ module Rails # :nodoc:
|
|
124
125
|
end
|
125
126
|
end
|
126
127
|
|
127
|
-
#
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
128
|
+
# Get the resolved data for a given field
|
129
|
+
def resolve_data_for(field, args)
|
130
|
+
return unless args.size.zero?
|
131
|
+
|
132
|
+
if field.try(:dynamic_resolver?)
|
133
|
+
prepared = prepared_data_for(field)
|
134
|
+
args << Event.trigger(:resolve, field, self, prepared: prepared, &field.resolver)
|
135
|
+
elsif field.prepared_data?
|
136
|
+
args << prepared_data_for(field)
|
137
|
+
else
|
138
|
+
data_for(args, field)
|
139
|
+
end
|
133
140
|
end
|
134
141
|
|
135
142
|
# Check if the given class is in the pool, or add a new instance to the
|
@@ -154,20 +161,35 @@ module Rails # :nodoc:
|
|
154
161
|
def trigger_event(event_name, **xargs)
|
155
162
|
return unless listening_to?(event_name)
|
156
163
|
|
157
|
-
objects
|
158
|
-
|
164
|
+
# A simpler attempt to remove select less objects (or even none) by
|
165
|
+
# assuming that the first item will work as exclusive and
|
166
|
+
# non-exclusive, and the others, only non-exclusive or anything
|
167
|
+
# different than a +Callback+
|
168
|
+
event_name = event_name.to_sym
|
169
|
+
list = listeners[event_name]
|
170
|
+
objects = request.stack.select.with_index do |obj, idx|
|
171
|
+
next unless list.include?(obj)
|
172
|
+
next true if idx == 0
|
173
|
+
|
174
|
+
obj.all_events.try(:[], event_name)&.any? do |ev|
|
175
|
+
!(ev.is_a?(Callback) && ev.exclusive?)
|
176
|
+
end
|
177
|
+
end
|
159
178
|
|
160
|
-
|
179
|
+
# Now trigger with more for all the selected objects
|
180
|
+
Event.trigger(event_name, objects, self, **xargs) if objects.present?
|
161
181
|
end
|
162
182
|
|
163
183
|
# Check what kind of event listeners the object have, in order to speed
|
164
|
-
# up processing by avoiding
|
165
|
-
def
|
166
|
-
|
167
|
-
|
168
|
-
object.all_listeners.each do |event_name|
|
184
|
+
# up processing by avoiding unnecessary event instances
|
185
|
+
def add_listeners_from(object)
|
186
|
+
object.all_listeners&.each do |event_name|
|
169
187
|
listeners[event_name] << object
|
170
188
|
end
|
189
|
+
|
190
|
+
if request.prepared_data_for?(object)
|
191
|
+
listeners[:prepare] << object
|
192
|
+
end
|
171
193
|
end
|
172
194
|
|
173
195
|
# Store a given resolve +value+ for a given +field+
|
@@ -177,48 +199,93 @@ module Rails # :nodoc:
|
|
177
199
|
|
178
200
|
# Only store a given +value+ for a given +field+ if it is not set yet
|
179
201
|
def safe_store_data(field, value = nil)
|
180
|
-
|
181
|
-
|
182
|
-
|
202
|
+
value ||= yield if block_given?
|
203
|
+
@data_pool[field] ||= value unless value.nil?
|
204
|
+
end
|
205
|
+
|
206
|
+
# Get the prepared data for the given +field+, getting ready for
|
207
|
+
# resolve, while ensuring to check prepared data on request
|
208
|
+
def prepared_data_for(field)
|
209
|
+
return @data_pool[field] unless field.prepared_data?
|
210
|
+
|
211
|
+
prepared = request.prepared_data_for(field).next
|
212
|
+
prepared unless prepared === PreparedData::NULL
|
213
|
+
end
|
214
|
+
|
215
|
+
# Simply run the organize step for compilation
|
216
|
+
def compile
|
217
|
+
for_each_operation { |op| collect_listeners { op.organize! } }
|
218
|
+
end
|
219
|
+
|
220
|
+
# Build the cache object
|
221
|
+
def cache_dump
|
222
|
+
{ class: self.class }
|
223
|
+
end
|
224
|
+
|
225
|
+
# Organize from cache data
|
226
|
+
def cache_load(data)
|
227
|
+
data, operations, fragments = data.values_at(:strategy, :operations, :fragments)
|
228
|
+
|
229
|
+
collect_listeners do
|
230
|
+
# Load all operations
|
231
|
+
operations = operations.transform_values do |operation|
|
232
|
+
request.build_from_cache(operation.delete(:type)).tap do |instance|
|
233
|
+
instance.instance_variable_set(:@request, request)
|
234
|
+
instance.cache_load(operation)
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
# Load all fragments
|
239
|
+
fragments = fragments&.transform_values do |fragment|
|
240
|
+
request.build_from_cache(Component::Fragment).tap do |instance|
|
241
|
+
instance.instance_variable_set(:@request, request)
|
242
|
+
instance.cache_load(fragment)
|
243
|
+
end
|
244
|
+
end
|
183
245
|
end
|
246
|
+
|
247
|
+
# Mark itself as already organized
|
248
|
+
@organized = true
|
249
|
+
|
250
|
+
# Save operations and fragments into the request
|
251
|
+
request.instance_variable_set(:@operations, operations)
|
252
|
+
request.instance_variable_set(:@fragments, fragments)
|
184
253
|
end
|
185
254
|
|
186
255
|
protected
|
187
256
|
|
188
|
-
#
|
189
|
-
def
|
190
|
-
|
191
|
-
|
257
|
+
# Execute a given block for each defined operation
|
258
|
+
def for_each_operation
|
259
|
+
operations.each do |key, value|
|
260
|
+
operations[key] = Component::Operation.build(request, value) \
|
261
|
+
if value.is_a?(::GQLParser::Token)
|
192
262
|
|
193
|
-
|
194
|
-
|
195
|
-
listeners.freeze
|
263
|
+
yield(operations[key])
|
264
|
+
end
|
196
265
|
end
|
197
266
|
|
198
|
-
# A
|
267
|
+
# A start of the organize step
|
199
268
|
def collect_listeners
|
200
|
-
|
269
|
+
return if defined?(@organized)
|
270
|
+
@stage = :organize
|
201
271
|
yield
|
202
|
-
lock_listeners!
|
203
272
|
end
|
204
273
|
|
205
274
|
# This is where the strategy is most effective. By preparing the tree,
|
206
275
|
# it can load data in a pretty smart way
|
207
|
-
def collect_data
|
276
|
+
def collect_data(force = false)
|
277
|
+
@stage = :prepare
|
208
278
|
@data_pool = {}
|
209
279
|
@context = request.build(Request::Context)
|
210
280
|
|
211
281
|
# TODO: Create an orchestrator to allow cross query loading
|
212
|
-
yield if listening_to?(:prepare)
|
282
|
+
yield if force || listening_to?(:prepare)
|
213
283
|
end
|
214
284
|
|
215
|
-
#
|
216
|
-
# ({Request::Context}[rdoc-ref:Rails::GraphQL::Request::Context])
|
217
|
-
# and start collecting results
|
285
|
+
# Start collecting results
|
218
286
|
def collect_response
|
287
|
+
@stage = :resolve
|
219
288
|
yield
|
220
|
-
ensure
|
221
|
-
@context = @objects_pool = @data_pool = @listeners = nil
|
222
289
|
end
|
223
290
|
|
224
291
|
# Fetch the data for a given field and set as the first element
|
@@ -232,17 +299,6 @@ module Rails # :nodoc:
|
|
232
299
|
|
233
300
|
result << current[key] if current.respond_to?(:key?) && current.key?(key)
|
234
301
|
end
|
235
|
-
|
236
|
-
private
|
237
|
-
|
238
|
-
# Collect the base listeners from the request
|
239
|
-
def collect_request_listeners
|
240
|
-
@listeners = Hash.new { |h, k| h[k] = [] }
|
241
|
-
add_listener(request)
|
242
|
-
|
243
|
-
lock_listeners!
|
244
|
-
@base_listeners = @listeners
|
245
|
-
end
|
246
302
|
end
|
247
303
|
end
|
248
304
|
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rails
|
4
|
+
module GraphQL
|
5
|
+
class Request
|
6
|
+
# = GraphQL Request Subscription
|
7
|
+
#
|
8
|
+
# A simple object to store information about a generated subscription
|
9
|
+
# TODO: Add a callback for the schema allowing it to prepare the context
|
10
|
+
# before saving it into a subscription
|
11
|
+
class Subscription
|
12
|
+
NULL_SCOPE = Object.new.freeze
|
13
|
+
|
14
|
+
attr_reader :sid, :schema, :args, :field, :scope, :context, :broadcastable,
|
15
|
+
:origin, :last_updated_at, :operation_id
|
16
|
+
|
17
|
+
alias broadcastable? broadcastable
|
18
|
+
|
19
|
+
def initialize(request, operation)
|
20
|
+
entrypoint = operation.selection.each_value.first
|
21
|
+
|
22
|
+
@schema = request.schema.namespace
|
23
|
+
@origin = request.origin
|
24
|
+
@operation_id = operation.hash
|
25
|
+
@args = entrypoint.arguments.to_h
|
26
|
+
@field = entrypoint.field
|
27
|
+
@context = request.context.to_h
|
28
|
+
@broadcastable = operation.broadcastable?
|
29
|
+
updated!
|
30
|
+
|
31
|
+
@scope = parse_scope(field.full_scope, request, operation)
|
32
|
+
@sid = request.schema.subscription_id_for(self)
|
33
|
+
end
|
34
|
+
|
35
|
+
def updated!
|
36
|
+
@last_updated_at = Time.current
|
37
|
+
end
|
38
|
+
|
39
|
+
def marshal_dump
|
40
|
+
raise ::TypeError, +"Request subscriptions must not be used as payload."
|
41
|
+
end
|
42
|
+
|
43
|
+
def inspect
|
44
|
+
(+<<~INFO).squish << '>'
|
45
|
+
#<#{self.class.name}
|
46
|
+
#{schema}@#{sid}
|
47
|
+
[#{scope.nil? ? scope.inspect : scope.hash}, #{args.hash}]
|
48
|
+
#{field.inspect}
|
49
|
+
INFO
|
50
|
+
end
|
51
|
+
|
52
|
+
protected
|
53
|
+
|
54
|
+
def parse_scope(list, request, operation)
|
55
|
+
enum = GraphQL.enumerate(list)
|
56
|
+
return NULL_SCOPE if enum.empty?
|
57
|
+
|
58
|
+
ext_self = nil
|
59
|
+
enum.map do |item|
|
60
|
+
case item
|
61
|
+
when Symbol
|
62
|
+
context[item]
|
63
|
+
when Proc
|
64
|
+
next item.call if item.arity == 0
|
65
|
+
|
66
|
+
ext_self ||= SimpleDelegator.new(self).tap do |object|
|
67
|
+
object.define_singleton_method(:request) { request }
|
68
|
+
object.define_singleton_method(:operation) { operation }
|
69
|
+
end
|
70
|
+
|
71
|
+
item.call(ext_self)
|
72
|
+
else
|
73
|
+
item
|
74
|
+
end
|
75
|
+
end.compact
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|