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,191 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rails
|
4
|
+
module GraphQL
|
5
|
+
class Request
|
6
|
+
# = GraphQL Request Backtrace
|
7
|
+
#
|
8
|
+
# Display any request errors in a nice way. By default, it won't display
|
9
|
+
# anything that is internal of this gem, but
|
10
|
+
module Backtrace
|
11
|
+
COL_MAX_WIDTH = 100
|
12
|
+
|
13
|
+
mattr_accessor :skip_base_class, instance_accessor: false,
|
14
|
+
default: Rails::GraphQL::StandardError
|
15
|
+
|
16
|
+
extend self
|
17
|
+
|
18
|
+
# Check if the given +error+ should be skipped
|
19
|
+
# TODO: Maybe check +cause+ to proper evaluate the skip
|
20
|
+
def skip?(error)
|
21
|
+
error.class <= skip_base_class
|
22
|
+
end
|
23
|
+
|
24
|
+
# Display the provided +error+ from the provided +request+
|
25
|
+
def print(error, component, request)
|
26
|
+
return if skip?(error)
|
27
|
+
|
28
|
+
table = print_table(error, component, request)
|
29
|
+
info = print_backtrace(error, request)
|
30
|
+
|
31
|
+
request.schema.logger.error(+"#{table}\n\n#{info}")
|
32
|
+
end
|
33
|
+
|
34
|
+
protected
|
35
|
+
|
36
|
+
# Organize and print a table of the place where the error occurred
|
37
|
+
def print_table(error, component, request)
|
38
|
+
table = begin_table
|
39
|
+
stack = [component] + request.stack
|
40
|
+
counter = stack.count { |item| !item.is_a?(Numeric) }
|
41
|
+
objects = request.strategy.context
|
42
|
+
oidx = -1
|
43
|
+
|
44
|
+
last_object = suffix = nil
|
45
|
+
while (item = stack.shift)
|
46
|
+
next suffix = +"[#{item}]" if item.is_a?(Numeric)
|
47
|
+
location = request.location_of(item)
|
48
|
+
location = location[0].values.join(':') if location
|
49
|
+
|
50
|
+
data = [counter, location]
|
51
|
+
add = send("row_for_#{item.kind}", data, item, suffix)
|
52
|
+
|
53
|
+
if item.kind == :field
|
54
|
+
oidx += 1
|
55
|
+
data[5] ||= oidx == 0 ? '↓' : print_object(objects&.at(oidx - 1))
|
56
|
+
data[3] ||= print_object(objects&.at(oidx))
|
57
|
+
end
|
58
|
+
|
59
|
+
suffix = nil
|
60
|
+
counter -= 1
|
61
|
+
add_to_table(table, data) if add != false
|
62
|
+
end
|
63
|
+
|
64
|
+
stringify_table(table)
|
65
|
+
end
|
66
|
+
|
67
|
+
# Print the backtrace steps of the error
|
68
|
+
def print_backtrace(error, request)
|
69
|
+
steps = error.backtrace
|
70
|
+
steps = cleaner.clean(steps) unless cleaner.nil?
|
71
|
+
|
72
|
+
klass = +"(\e[4m#{error.class}\e[24m)"
|
73
|
+
stage = +" [#{request.strategy.stage}]" if skip_base_class != StandardError
|
74
|
+
|
75
|
+
+"\e[1m#{error.message} #{klass}#{stage}\e[0m\n#{steps.join("\n")}"
|
76
|
+
end
|
77
|
+
|
78
|
+
# Add new information to the table and update headers sizes
|
79
|
+
def add_to_table(table, data)
|
80
|
+
data = data.map(&:to_s)
|
81
|
+
table[:header].each.with_index do |(header, size), idx|
|
82
|
+
length = data[idx].length
|
83
|
+
if length > COL_MAX_WIDTH
|
84
|
+
table[:header][header] = COL_MAX_WIDTH
|
85
|
+
data[idx] = data[idx][0..COL_MAX_WIDTH][0..-5] + '...'
|
86
|
+
elsif length > size
|
87
|
+
table[:header][header] = length
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
table[:body] << data
|
92
|
+
end
|
93
|
+
|
94
|
+
# Build the string of the given table
|
95
|
+
def stringify_table(table)
|
96
|
+
sizes = table[:header].values
|
97
|
+
headers = table[:header].keys
|
98
|
+
|
99
|
+
# Add a little banner
|
100
|
+
table[:body][-1][1] = "\e[1m\e[35m#{'GQL'.ljust(sizes[1])}\e[0m"
|
101
|
+
|
102
|
+
# Build all the lines
|
103
|
+
lines = table[:body].reverse.prepend(headers).map do |row|
|
104
|
+
+' ' << row.map.with_index do |col, idx|
|
105
|
+
col.ljust(sizes[idx])
|
106
|
+
end.join(' | ') << ' '
|
107
|
+
end
|
108
|
+
|
109
|
+
# Add a divider between headers and values
|
110
|
+
divider = sizes.map { |val| '-' * val }.join('-+-')
|
111
|
+
divider = +'-' << divider << '-'
|
112
|
+
lines.insert(1, divider)
|
113
|
+
|
114
|
+
# Bold the header and join the lines
|
115
|
+
lines[0] = +"\e[1m#{lines[0]}\e[0m"
|
116
|
+
lines.join("\n")
|
117
|
+
end
|
118
|
+
|
119
|
+
# Better display records and other objects that might be to big to
|
120
|
+
# show in here
|
121
|
+
def print_object(object)
|
122
|
+
object.respond_to?(:to_gql_backtrace) ? object.to_gql_backtrace : object.inspect
|
123
|
+
end
|
124
|
+
|
125
|
+
# Visitors
|
126
|
+
def row_for_field(data, item, suffix)
|
127
|
+
field = item.field
|
128
|
+
name = +"#{field.owner.gql_name}.#{field.gql_name}#{suffix}" unless field.nil?
|
129
|
+
|
130
|
+
data.push(name || +"*.#{item.name}")
|
131
|
+
data.push(nil, (item.arguments ? item.arguments.to_json : 'nil'), nil)
|
132
|
+
end
|
133
|
+
|
134
|
+
def row_for_fragment(data, item, *)
|
135
|
+
type = item.instance_variable_get(:@node)[1]
|
136
|
+
object = item.current_object || item.type_klass
|
137
|
+
data.push(+"fragment #{item.name}", type, '')
|
138
|
+
data.push(print_object(object))
|
139
|
+
end
|
140
|
+
|
141
|
+
def row_for_operation(data, item, *)
|
142
|
+
data.push(+"#{item.type} #{item.name}".squish)
|
143
|
+
data.push('nil')
|
144
|
+
data.push(item.arguments.to_json)
|
145
|
+
data.push(item.typename)
|
146
|
+
end
|
147
|
+
|
148
|
+
def row_for_spread(data, item, *)
|
149
|
+
return false unless item.inline?
|
150
|
+
|
151
|
+
type = item.instance_variable_get(:@node)[1]
|
152
|
+
object = item.current_object || item.type_klass
|
153
|
+
data.push('...', type, '')
|
154
|
+
data.push(print_object(object))
|
155
|
+
end
|
156
|
+
|
157
|
+
def row_for_schema(data, item, *)
|
158
|
+
data.push('schema', item.namespace.inspect, nil, item.name)
|
159
|
+
end
|
160
|
+
|
161
|
+
private
|
162
|
+
|
163
|
+
# The headers and sizes plus the rows for the table structure
|
164
|
+
def begin_table
|
165
|
+
{
|
166
|
+
header: {
|
167
|
+
' ' => 1,
|
168
|
+
'Loc' => 3,
|
169
|
+
'Field' => 5,
|
170
|
+
'Object' => 6,
|
171
|
+
'Arguments' => 9,
|
172
|
+
'Result' => 6,
|
173
|
+
},
|
174
|
+
body: [],
|
175
|
+
}
|
176
|
+
end
|
177
|
+
|
178
|
+
# Find the class that will be responsible for cleaning the backtrace
|
179
|
+
def cleaner
|
180
|
+
LogSubscriber.backtrace_cleaner
|
181
|
+
end
|
182
|
+
|
183
|
+
# Rewrite the cleaner method so that it returns nil and do not clean
|
184
|
+
# any of the items of the backtrace
|
185
|
+
def show_everything!
|
186
|
+
redefine_singleton_method(:cleaner) { nil }
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
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 Component Field
|
7
7
|
#
|
8
8
|
# This class holds information about a given field that should be
|
@@ -14,61 +14,73 @@ module Rails # :nodoc:
|
|
14
14
|
include Directives
|
15
15
|
|
16
16
|
delegate :decorate, to: :type_klass
|
17
|
-
delegate :operation, :variables, to: :parent
|
18
|
-
delegate :method_name, :resolver, :performer, :type_klass
|
19
|
-
:dynamic_resolver?, to: :field
|
20
|
-
|
21
|
-
parent_memoize :request
|
17
|
+
delegate :operation, :variables, :request, to: :parent
|
18
|
+
delegate :method_name, :resolver, :performer, :type_klass,:leaf_type?,
|
19
|
+
:dynamic_resolver?, :mutation?, to: :field
|
22
20
|
|
23
21
|
attr_reader :name, :alias_name, :parent, :field, :arguments, :current_object
|
24
22
|
|
25
23
|
alias args arguments
|
26
24
|
|
27
|
-
def initialize(parent, node
|
25
|
+
def initialize(parent, node)
|
28
26
|
@parent = parent
|
29
27
|
|
30
|
-
@name =
|
31
|
-
@alias_name =
|
32
|
-
|
33
|
-
super(node, data)
|
34
|
-
end
|
28
|
+
@name = node[0]
|
29
|
+
@alias_name = node[1]
|
35
30
|
|
36
|
-
|
37
|
-
def all_directives
|
38
|
-
field.all_directives + super
|
31
|
+
super(node)
|
39
32
|
end
|
40
33
|
|
41
34
|
# Override that considers the requested field directives and also the
|
42
35
|
# definition field events, both from itself and its directives events
|
43
36
|
def all_listeners
|
44
|
-
|
37
|
+
request.nested_cache(:listeners, field) do
|
38
|
+
if !field.listeners?
|
39
|
+
directive_listeners
|
40
|
+
elsif !directives?
|
41
|
+
field.all_listeners
|
42
|
+
else
|
43
|
+
local = directive_listeners
|
44
|
+
local.empty? ? field.all_listeners : field.all_listeners + local
|
45
|
+
end
|
46
|
+
end
|
45
47
|
end
|
46
48
|
|
47
49
|
# Override that considers the requested field directives and also the
|
48
50
|
# definition field events, both from itself and its directives events
|
49
51
|
def all_events
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
52
|
+
request.nested_cache(:events, field) do
|
53
|
+
if !field.events?
|
54
|
+
directive_events
|
55
|
+
elsif !directives?
|
56
|
+
field.all_events
|
57
|
+
else
|
58
|
+
Helpers.merge_hash_array(field.all_events, directive_events)
|
59
|
+
end
|
60
|
+
end
|
54
61
|
end
|
55
62
|
|
56
63
|
# Get and cache all the arguments for the field
|
57
64
|
def all_arguments
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
65
|
+
return unless field.arguments?
|
66
|
+
|
67
|
+
request.nested_cache(:arguments, field) do
|
68
|
+
field.all_arguments.each_value.with_object({}) do |argument, hash|
|
69
|
+
hash[argument.gql_name] = argument
|
63
70
|
end
|
64
71
|
end
|
65
72
|
end
|
66
73
|
|
74
|
+
# Check if the field is using a directive
|
75
|
+
def using?(item_or_symbol)
|
76
|
+
super || field.using?(item_or_symbol)
|
77
|
+
end
|
78
|
+
|
67
79
|
# Assign a given +field+ to this class. The field must be an output
|
68
80
|
# field, which means that +output_type?+ must be true. It also must be
|
69
81
|
# called exactly once per field.
|
70
|
-
def
|
71
|
-
raise ArgumentError,
|
82
|
+
def assign_to(field)
|
83
|
+
raise ArgumentError, (+<<~MSG).squish if defined?(@assigned)
|
72
84
|
The "#{gql_name}" field is already assigned to #{@field.inspect}.
|
73
85
|
MSG
|
74
86
|
|
@@ -97,6 +109,14 @@ module Rails # :nodoc:
|
|
97
109
|
true
|
98
110
|
end
|
99
111
|
|
112
|
+
# Check if all the sub fields are broadcastable
|
113
|
+
# TODO: Maybe check for interfaces and if all types allow broadcast
|
114
|
+
def broadcastable?
|
115
|
+
value = field.broadcastable?
|
116
|
+
value = schema.config.default_subscription_broadcastable if value.nil?
|
117
|
+
value != false
|
118
|
+
end
|
119
|
+
|
100
120
|
# A little extension of the +is_a?+ method that allows checking it using
|
101
121
|
# the underlying +field+
|
102
122
|
def of_type?(klass)
|
@@ -106,7 +126,7 @@ module Rails # :nodoc:
|
|
106
126
|
# When the field is invalid, there's no much to do
|
107
127
|
# TODO: Maybe add a invalid event trigger here
|
108
128
|
def resolve_invalid(error = nil)
|
109
|
-
request.exception_to_error(error,
|
129
|
+
request.exception_to_error(error, self) if error.present?
|
110
130
|
|
111
131
|
validate_output!(nil)
|
112
132
|
response.safe_add(gql_name, nil)
|
@@ -118,26 +138,44 @@ module Rails # :nodoc:
|
|
118
138
|
# field needs to be redirected to the one from the actual resolved
|
119
139
|
# +object+ type
|
120
140
|
def resolve_with!(object)
|
141
|
+
return if skipped?
|
121
142
|
return resolve! if invalid?
|
122
143
|
|
123
144
|
old_field, @field = @field, object[@field.name]
|
145
|
+
request.nested_cache(:listeners, field) { strategy.add_listeners_from(self) }
|
124
146
|
@current_object = object
|
125
147
|
resolve!
|
126
148
|
ensure
|
127
149
|
@field, @current_object = old_field, nil
|
128
150
|
end
|
129
151
|
|
152
|
+
# Build the cache object
|
153
|
+
def cache_dump
|
154
|
+
super.merge(field: (field && all_to_gid(field)))
|
155
|
+
end
|
156
|
+
|
157
|
+
# Organize from cache data
|
158
|
+
def cache_load(data)
|
159
|
+
@name = data[:node][0]
|
160
|
+
@alias_name = data[:node][1]
|
161
|
+
@field = all_from_gid(data[:field])
|
162
|
+
super
|
163
|
+
|
164
|
+
check_authorization! unless unresolvable?
|
165
|
+
end
|
166
|
+
|
130
167
|
protected
|
131
168
|
|
132
169
|
# Perform the organization step
|
133
170
|
def organize_then(&block)
|
134
171
|
super(block) do
|
135
172
|
check_assignment!
|
173
|
+
|
174
|
+
parse_directives(@node[3])
|
136
175
|
check_authorization!
|
137
176
|
|
138
|
-
parse_arguments
|
139
|
-
|
140
|
-
parse_selection
|
177
|
+
parse_arguments(@node[2])
|
178
|
+
parse_selection(@node[4])
|
141
179
|
end
|
142
180
|
end
|
143
181
|
|
@@ -149,8 +187,7 @@ module Rails # :nodoc:
|
|
149
187
|
# Perform the resolve step
|
150
188
|
def resolve_then(&block)
|
151
189
|
stacked do
|
152
|
-
|
153
|
-
send(field.array? ? 'resolve_many' : 'resolve_one', &block)
|
190
|
+
send((field.array? ? :resolve_many : :resolve_one), &block)
|
154
191
|
rescue StandardError => error
|
155
192
|
resolve_invalid(error)
|
156
193
|
end
|
@@ -181,46 +218,30 @@ module Rails # :nodoc:
|
|
181
218
|
end
|
182
219
|
end
|
183
220
|
|
184
|
-
# This override allows reasigned fields to perform events. This
|
185
|
-
# happens when fields are originally organized from interfaces. If
|
186
|
-
# the event is stopped for the object, then it doesn't proceed to the
|
187
|
-
# strategy implementation, ensuring compatibility
|
188
|
-
def trigger_event(event_name, **xargs)
|
189
|
-
return super if !defined?(@current_object) || @current_object.nil?
|
190
|
-
|
191
|
-
listeners = request.cache(:listeners)[field] ||= field.all_listeners
|
192
|
-
return super unless listeners.include?(event_name)
|
193
|
-
|
194
|
-
callbacks = request.cache(:events)[field] ||= field.all_events
|
195
|
-
old_events, @all_events = @all_events, callbacks
|
196
|
-
super
|
197
|
-
ensure
|
198
|
-
@all_events = old_events
|
199
|
-
end
|
200
|
-
|
201
221
|
# Check if the field was assigned correctly to an output field
|
202
222
|
def check_assignment!
|
203
|
-
raise MissingFieldError,
|
223
|
+
raise MissingFieldError, (+<<~MSG).squish if field.nil?
|
204
224
|
Unable to find a field named "#{gql_name}" on
|
205
225
|
#{entry_point? ? operation.kind : parent.type_klass.name}.
|
206
226
|
MSG
|
207
227
|
|
208
|
-
raise FieldError,
|
228
|
+
raise FieldError, (+<<~MSG).squish unless field.output_type?
|
209
229
|
The "#{gql_name}" was assigned to a non-output type of field: #{field.inspect}.
|
210
230
|
MSG
|
211
231
|
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
232
|
+
if @node[4].nil?
|
233
|
+
raise FieldError, (+<<~MSG).squish if !field.leaf_type?
|
234
|
+
The "#{gql_name}" was assigned to the #{type_klass.gql_name} which
|
235
|
+
is not a leaf type and requires a selection of fields.
|
236
|
+
MSG
|
237
|
+
else
|
238
|
+
raise FieldError, (+<<~MSG).squish if field.leaf_type?
|
239
|
+
The "#{gql_name}" was assigned to the #{type_klass.gql_name} which
|
240
|
+
is a leaf type and does not have nested fields.
|
241
|
+
MSG
|
242
|
+
end
|
222
243
|
|
223
|
-
raise DisabledFieldError,
|
244
|
+
raise DisabledFieldError, (+<<~MSG).squish if field.disabled?
|
224
245
|
The "#{gql_name}" was found but it is marked as disabled.
|
225
246
|
MSG
|
226
247
|
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 Component Fragment
|
7
7
|
#
|
8
8
|
# This class holds information about a given fragment defined using the
|
@@ -12,19 +12,18 @@ module Rails # :nodoc:
|
|
12
12
|
include SelectionSet
|
13
13
|
include Directives
|
14
14
|
|
15
|
-
attr_reader :name, :type_klass, :request
|
15
|
+
attr_reader :name, :type_klass, :request, :current_object
|
16
16
|
|
17
|
-
def initialize(request, node
|
18
|
-
@name =
|
17
|
+
def initialize(request, node)
|
18
|
+
@name = node[0]
|
19
19
|
@request = request
|
20
20
|
|
21
|
-
super(node
|
21
|
+
super(node)
|
22
22
|
|
23
23
|
check_duplicated_fragment!
|
24
24
|
end
|
25
25
|
|
26
26
|
# Return a lazy loaded variable proc
|
27
|
-
# TODO: Mark all the dependent variables
|
28
27
|
def variables
|
29
28
|
Request::Arguments.lazy
|
30
29
|
end
|
@@ -34,6 +33,16 @@ module Rails # :nodoc:
|
|
34
33
|
Request::Arguments.operation
|
35
34
|
end
|
36
35
|
|
36
|
+
# Stores all the used variables
|
37
|
+
def used_variables
|
38
|
+
return @used_variables if defined?(@used_variables)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Stores all the used nested fragments
|
42
|
+
def used_fragments
|
43
|
+
return @used_fragments if defined?(@used_fragments)
|
44
|
+
end
|
45
|
+
|
37
46
|
# Spread should always be performed with a current object, thus the
|
38
47
|
# typename comes from it
|
39
48
|
def typename
|
@@ -42,7 +51,7 @@ module Rails # :nodoc:
|
|
42
51
|
|
43
52
|
# Only resolve if the +type_klass+ is equivalent to the given +object+
|
44
53
|
def resolve_with!(object)
|
45
|
-
return if
|
54
|
+
return if unresolvable?
|
46
55
|
|
47
56
|
@current_object = object
|
48
57
|
resolve!
|
@@ -50,6 +59,24 @@ module Rails # :nodoc:
|
|
50
59
|
@current_object = nil
|
51
60
|
end
|
52
61
|
|
62
|
+
# Check if all the sub fields are broadcastable
|
63
|
+
def broadcastable?
|
64
|
+
selection.each_value.all?(&:broadcastable?)
|
65
|
+
end
|
66
|
+
|
67
|
+
# Build the cache object
|
68
|
+
def cache_dump
|
69
|
+
super.merge(type_klass: all_to_gid(type_klass))
|
70
|
+
end
|
71
|
+
|
72
|
+
# Organize from cache data
|
73
|
+
def cache_load(data)
|
74
|
+
@name = data[:node][0]
|
75
|
+
@type_klass = all_from_gid(data[:type_klass])
|
76
|
+
|
77
|
+
super
|
78
|
+
end
|
79
|
+
|
53
80
|
protected
|
54
81
|
|
55
82
|
# Fragments always resolve selection unstacked on response, meaning
|
@@ -58,20 +85,25 @@ module Rails # :nodoc:
|
|
58
85
|
false
|
59
86
|
end
|
60
87
|
|
88
|
+
# Wrap the field organization with the collection of variables
|
89
|
+
def organize
|
90
|
+
organize_then { collect_usages { organize_fields } }
|
91
|
+
end
|
92
|
+
|
61
93
|
# Perform the organization step
|
62
94
|
def organize_then(&block)
|
63
95
|
super(block) do
|
64
|
-
@type_klass = find_type!(
|
65
|
-
parse_directives(:fragment_definition)
|
96
|
+
@type_klass = find_type!(@node[1])
|
97
|
+
parse_directives(@node[2], :fragment_definition)
|
66
98
|
|
67
99
|
check_assignment!
|
68
|
-
parse_selection
|
100
|
+
parse_selection(@node[3])
|
69
101
|
end
|
70
102
|
end
|
71
103
|
|
72
104
|
# Resolve the spread operation
|
73
105
|
def resolve
|
74
|
-
return if
|
106
|
+
return if unresolvable?
|
75
107
|
|
76
108
|
object = @current_object || type_klass
|
77
109
|
resolve_then if type_klass =~ object
|
@@ -86,32 +118,48 @@ module Rails # :nodoc:
|
|
86
118
|
|
87
119
|
# Check if the field was assigned correctly to an output field
|
88
120
|
def check_assignment!
|
89
|
-
raise ExecutionError,
|
90
|
-
Unable to
|
121
|
+
raise ExecutionError, (+<<~MSG).squish unless type_klass.output_type?
|
122
|
+
Unable to assign #{type_klass.gql_name} to "#{name}" fragment because
|
91
123
|
it is not a output type.
|
92
124
|
MSG
|
93
125
|
|
94
|
-
raise ExecutionError,
|
95
|
-
Unable to
|
96
|
-
a "#{type_klass.kind}" type can not be the source of a
|
126
|
+
raise ExecutionError, (+<<~MSG).squish if type_klass.leaf_type?
|
127
|
+
Unable to assign #{type_klass.gql_name} to "#{name}" fragment because
|
128
|
+
a "#{type_klass.kind}" type can not be the source of a fragment.
|
97
129
|
MSG
|
98
130
|
end
|
99
131
|
|
100
132
|
# If there is another fragment with the same name already defined,
|
101
133
|
# raise an error
|
102
134
|
def check_duplicated_fragment!
|
103
|
-
|
135
|
+
other = request.document[1].find do |other|
|
136
|
+
other != @node && name == other[0]
|
137
|
+
end
|
104
138
|
|
139
|
+
return if other.nil?
|
105
140
|
invalidate!
|
106
141
|
|
107
|
-
|
108
|
-
location = GraphQL::Native.get_location(other_node)
|
109
|
-
|
110
|
-
request.report_node_error(<<~MSG.squish, @node)
|
142
|
+
request.report_node_error((+<<~MSG).squish, self)
|
111
143
|
Duplicated fragment named "#{name}" defined on
|
112
|
-
line #{
|
144
|
+
line #{other.begin_line}:#{other.begin_column}
|
113
145
|
MSG
|
114
146
|
end
|
147
|
+
|
148
|
+
# Use the information on the operation to collect all the variables
|
149
|
+
# and nested fragments that were used inside a fragment
|
150
|
+
def collect_usages
|
151
|
+
vars_total = operation.used_variables.size
|
152
|
+
frag_total = operation.used_fragments.size
|
153
|
+
yield
|
154
|
+
ensure
|
155
|
+
if operation.used_variables.size > vars_total
|
156
|
+
@used_variables = Set.new(operation.used_variables.to_enum.drop(vars_total))
|
157
|
+
end
|
158
|
+
|
159
|
+
if operation.used_fragments.size > frag_total
|
160
|
+
@used_fragments = Set.new(operation.used_fragments.to_enum.drop(frag_total))
|
161
|
+
end
|
162
|
+
end
|
115
163
|
end
|
116
164
|
end
|
117
165
|
end
|