graphql 1.9.0.pre1 → 1.9.0.pre2
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/lib/graphql.rb +5 -1
- data/lib/graphql/analysis/ast/analyzer.rb +1 -1
- data/lib/graphql/analysis/ast/visitor.rb +6 -1
- data/lib/graphql/backwards_compatibility.rb +1 -1
- data/lib/graphql/dig.rb +19 -0
- data/lib/graphql/directive.rb +13 -1
- data/lib/graphql/directive/include_directive.rb +1 -7
- data/lib/graphql/directive/skip_directive.rb +1 -8
- data/lib/graphql/execution/interpreter.rb +23 -13
- data/lib/graphql/execution/interpreter/resolve.rb +56 -0
- data/lib/graphql/execution/interpreter/runtime.rb +174 -74
- data/lib/graphql/execution/lazy.rb +7 -1
- data/lib/graphql/execution/lookahead.rb +71 -6
- data/lib/graphql/execution_error.rb +1 -1
- data/lib/graphql/introspection/entry_points.rb +5 -1
- data/lib/graphql/introspection/type_type.rb +4 -4
- data/lib/graphql/language.rb +0 -1
- data/lib/graphql/language/block_string.rb +37 -0
- data/lib/graphql/language/document_from_schema_definition.rb +1 -1
- data/lib/graphql/language/lexer.rb +55 -36
- data/lib/graphql/language/lexer.rl +8 -3
- data/lib/graphql/language/nodes.rb +27 -4
- data/lib/graphql/language/parser.rb +55 -55
- data/lib/graphql/language/parser.y +11 -11
- data/lib/graphql/language/printer.rb +1 -1
- data/lib/graphql/language/visitor.rb +22 -13
- data/lib/graphql/literal_validation_error.rb +6 -0
- data/lib/graphql/query.rb +13 -0
- data/lib/graphql/query/arguments.rb +2 -1
- data/lib/graphql/query/context.rb +3 -10
- data/lib/graphql/query/executor.rb +1 -1
- data/lib/graphql/query/validation_pipeline.rb +1 -1
- data/lib/graphql/relay/connection_resolve.rb +1 -1
- data/lib/graphql/relay/relation_connection.rb +1 -1
- data/lib/graphql/schema.rb +81 -11
- data/lib/graphql/schema/argument.rb +1 -1
- data/lib/graphql/schema/build_from_definition.rb +2 -4
- data/lib/graphql/schema/directive.rb +103 -0
- data/lib/graphql/schema/directive/feature.rb +66 -0
- data/lib/graphql/schema/directive/include.rb +25 -0
- data/lib/graphql/schema/directive/skip.rb +25 -0
- data/lib/graphql/schema/directive/transform.rb +48 -0
- data/lib/graphql/schema/enum_value.rb +2 -2
- data/lib/graphql/schema/field.rb +63 -17
- data/lib/graphql/schema/input_object.rb +1 -0
- data/lib/graphql/schema/member/base_dsl_methods.rb +4 -2
- data/lib/graphql/schema/member/build_type.rb +33 -1
- data/lib/graphql/schema/member/has_fields.rb +8 -73
- data/lib/graphql/schema/relay_classic_mutation.rb +6 -1
- data/lib/graphql/schema/resolver.rb +1 -1
- data/lib/graphql/static_validation.rb +2 -1
- data/lib/graphql/static_validation/all_rules.rb +1 -0
- data/lib/graphql/static_validation/base_visitor.rb +25 -10
- data/lib/graphql/static_validation/definition_dependencies.rb +3 -3
- data/lib/graphql/static_validation/{message.rb → error.rb} +11 -11
- data/lib/graphql/static_validation/interpreter_visitor.rb +14 -0
- data/lib/graphql/static_validation/literal_validator.rb +54 -11
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +34 -5
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible_error.rb +31 -0
- data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +2 -2
- data/lib/graphql/static_validation/rules/argument_names_are_unique_error.rb +30 -0
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +7 -1
- data/lib/graphql/static_validation/rules/arguments_are_defined_error.rb +35 -0
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +5 -1
- data/lib/graphql/static_validation/rules/directives_are_defined_error.rb +29 -0
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +11 -2
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations_error.rb +31 -0
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +11 -2
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type_error.rb +32 -0
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +14 -2
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections_error.rb +31 -0
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +24 -6
- data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +32 -0
- data/lib/graphql/static_validation/rules/fragment_names_are_unique.rb +5 -1
- data/lib/graphql/static_validation/rules/fragment_names_are_unique_error.rb +29 -0
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +8 -1
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible_error.rb +35 -0
- data/lib/graphql/static_validation/rules/fragment_types_exist.rb +5 -1
- data/lib/graphql/static_validation/rules/fragment_types_exist_error.rb +29 -0
- data/lib/graphql/static_validation/rules/fragments_are_finite.rb +6 -1
- data/lib/graphql/static_validation/rules/fragments_are_finite_error.rb +29 -0
- data/lib/graphql/static_validation/rules/fragments_are_named.rb +4 -1
- data/lib/graphql/static_validation/rules/fragments_are_named_error.rb +26 -0
- data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +5 -1
- data/lib/graphql/static_validation/rules/fragments_are_on_composite_types_error.rb +30 -0
- data/lib/graphql/static_validation/rules/fragments_are_used.rb +13 -3
- data/lib/graphql/static_validation/rules/fragments_are_used_error.rb +29 -0
- data/lib/graphql/static_validation/rules/mutation_root_exists.rb +4 -1
- data/lib/graphql/static_validation/rules/mutation_root_exists_error.rb +26 -0
- data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +2 -2
- data/lib/graphql/static_validation/rules/no_definitions_are_present_error.rb +25 -0
- data/lib/graphql/static_validation/rules/operation_names_are_valid.rb +9 -2
- data/lib/graphql/static_validation/rules/operation_names_are_valid_error.rb +28 -0
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +7 -1
- data/lib/graphql/static_validation/rules/required_arguments_are_present_error.rb +35 -0
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +47 -0
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present_error.rb +35 -0
- data/lib/graphql/static_validation/rules/subscription_root_exists.rb +4 -1
- data/lib/graphql/static_validation/rules/subscription_root_exists_error.rb +26 -0
- data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +4 -3
- data/lib/graphql/static_validation/rules/unique_directives_per_location_error.rb +29 -0
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +20 -6
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed_error.rb +39 -0
- data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +5 -1
- data/lib/graphql/static_validation/rules/variable_names_are_unique_error.rb +29 -0
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +8 -1
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed_error.rb +38 -0
- data/lib/graphql/static_validation/rules/variables_are_input_types.rb +12 -2
- data/lib/graphql/static_validation/rules/variables_are_input_types_error.rb +32 -0
- data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +18 -2
- data/lib/graphql/static_validation/rules/variables_are_used_and_defined_error.rb +37 -0
- data/lib/graphql/static_validation/validator.rb +24 -14
- data/lib/graphql/tracing/new_relic_tracing.rb +2 -2
- data/lib/graphql/tracing/skylight_tracing.rb +2 -2
- data/lib/graphql/unauthorized_field_error.rb +23 -0
- data/lib/graphql/version.rb +1 -1
- data/spec/graphql/analysis/ast_spec.rb +40 -0
- data/spec/graphql/authorization_spec.rb +93 -20
- data/spec/graphql/base_type_spec.rb +3 -1
- data/spec/graphql/execution/interpreter_spec.rb +127 -4
- data/spec/graphql/execution/lazy_spec.rb +49 -0
- data/spec/graphql/execution/lookahead_spec.rb +113 -21
- data/spec/graphql/execution/multiplex_spec.rb +2 -1
- data/spec/graphql/introspection/type_type_spec.rb +1 -1
- data/spec/graphql/language/lexer_spec.rb +72 -3
- data/spec/graphql/language/printer_spec.rb +18 -6
- data/spec/graphql/query/arguments_spec.rb +21 -0
- data/spec/graphql/query/context_spec.rb +10 -0
- data/spec/graphql/schema/build_from_definition_spec.rb +144 -29
- data/spec/graphql/schema/directive/feature_spec.rb +81 -0
- data/spec/graphql/schema/directive/transform_spec.rb +39 -0
- data/spec/graphql/schema/enum_spec.rb +5 -3
- data/spec/graphql/schema/field_extension_spec.rb +3 -3
- data/spec/graphql/schema/field_spec.rb +19 -0
- data/spec/graphql/schema/input_object_spec.rb +81 -0
- data/spec/graphql/schema/member/build_type_spec.rb +46 -0
- data/spec/graphql/schema/member/scoped_spec.rb +3 -3
- data/spec/graphql/schema/printer_spec.rb +244 -96
- data/spec/graphql/schema/relay_classic_mutation_spec.rb +26 -0
- data/spec/graphql/schema/resolver_spec.rb +1 -1
- data/spec/graphql/schema/warden_spec.rb +35 -11
- data/spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb +212 -72
- data/spec/graphql/static_validation/rules/argument_names_are_unique_spec.rb +2 -2
- data/spec/graphql/static_validation/rules/arguments_are_defined_spec.rb +72 -29
- data/spec/graphql/static_validation/rules/directives_are_defined_spec.rb +4 -2
- data/spec/graphql/static_validation/rules/directives_are_in_valid_locations_spec.rb +4 -2
- data/spec/graphql/static_validation/rules/fields_are_defined_on_type_spec.rb +10 -5
- data/spec/graphql/static_validation/rules/fields_have_appropriate_selections_spec.rb +10 -5
- data/spec/graphql/static_validation/rules/fields_will_merge_spec.rb +2 -1
- data/spec/graphql/static_validation/rules/fragment_names_are_unique_spec.rb +2 -1
- data/spec/graphql/static_validation/rules/fragment_spreads_are_possible_spec.rb +6 -3
- data/spec/graphql/static_validation/rules/fragment_types_exist_spec.rb +4 -2
- data/spec/graphql/static_validation/rules/fragments_are_finite_spec.rb +4 -2
- data/spec/graphql/static_validation/rules/fragments_are_named_spec.rb +2 -1
- data/spec/graphql/static_validation/rules/fragments_are_on_composite_types_spec.rb +6 -3
- data/spec/graphql/static_validation/rules/fragments_are_used_spec.rb +22 -2
- data/spec/graphql/static_validation/rules/mutation_root_exists_spec.rb +2 -1
- data/spec/graphql/static_validation/rules/operation_names_are_valid_spec.rb +6 -3
- data/spec/graphql/static_validation/rules/required_arguments_are_present_spec.rb +13 -4
- data/spec/graphql/static_validation/rules/required_input_object_attributes_are_present_spec.rb +58 -0
- data/spec/graphql/static_validation/rules/subscription_root_exists_spec.rb +2 -1
- data/spec/graphql/static_validation/rules/unique_directives_per_location_spec.rb +14 -7
- data/spec/graphql/static_validation/rules/variable_default_values_are_correctly_typed_spec.rb +14 -7
- data/spec/graphql/static_validation/rules/variable_usages_are_allowed_spec.rb +8 -4
- data/spec/graphql/static_validation/rules/variables_are_input_types_spec.rb +8 -4
- data/spec/graphql/static_validation/rules/variables_are_used_and_defined_spec.rb +6 -3
- data/spec/graphql/static_validation/validator_spec.rb +6 -4
- data/spec/graphql/tracing/new_relic_tracing_spec.rb +10 -0
- data/spec/graphql/tracing/skylight_tracing_spec.rb +10 -0
- data/spec/graphql/types/iso_8601_date_time_spec.rb +1 -2
- data/spec/integration/mongoid/star_trek/schema.rb +5 -5
- data/spec/integration/rails/graphql/relay/relation_connection_spec.rb +37 -8
- data/spec/integration/rails/graphql/schema_spec.rb +2 -2
- data/spec/integration/rails/spec_helper.rb +10 -0
- data/spec/integration/tmp/app/graphql/types/bird_type.rb +7 -0
- data/spec/integration/tmp/dummy/Gemfile +45 -0
- data/spec/integration/tmp/dummy/README.rdoc +28 -0
- data/spec/integration/tmp/dummy/Rakefile +6 -0
- data/spec/integration/tmp/dummy/app/assets/javascripts/application.js +16 -0
- data/spec/integration/tmp/dummy/app/assets/stylesheets/application.css +15 -0
- data/spec/integration/tmp/dummy/app/controllers/application_controller.rb +5 -0
- data/spec/integration/tmp/dummy/app/controllers/graphql_controller.rb +43 -0
- data/spec/integration/tmp/dummy/app/graphql/dummy_schema.rb +34 -0
- data/spec/integration/tmp/dummy/app/graphql/types/base_enum.rb +4 -0
- data/spec/integration/tmp/dummy/app/graphql/types/base_input_object.rb +4 -0
- data/spec/integration/tmp/dummy/app/graphql/types/base_interface.rb +5 -0
- data/spec/integration/tmp/dummy/app/graphql/types/base_object.rb +4 -0
- data/spec/integration/tmp/dummy/app/graphql/types/base_scalar.rb +4 -0
- data/spec/integration/tmp/dummy/app/graphql/types/base_union.rb +4 -0
- data/spec/integration/tmp/dummy/app/graphql/types/mutation_type.rb +10 -0
- data/spec/integration/tmp/dummy/app/graphql/types/query_type.rb +15 -0
- data/spec/integration/tmp/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/integration/tmp/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/integration/tmp/dummy/bin/bundle +3 -0
- data/spec/integration/tmp/dummy/bin/rails +4 -0
- data/spec/integration/tmp/dummy/bin/rake +4 -0
- data/spec/integration/tmp/dummy/bin/setup +29 -0
- data/spec/integration/tmp/dummy/config.ru +4 -0
- data/spec/integration/tmp/dummy/config/application.rb +32 -0
- data/spec/integration/tmp/dummy/config/boot.rb +3 -0
- data/spec/integration/tmp/dummy/config/environment.rb +5 -0
- data/spec/integration/tmp/dummy/config/environments/development.rb +38 -0
- data/spec/integration/tmp/dummy/config/environments/production.rb +76 -0
- data/spec/integration/tmp/dummy/config/environments/test.rb +42 -0
- data/spec/integration/tmp/dummy/config/initializers/assets.rb +11 -0
- data/spec/integration/tmp/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/integration/tmp/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/spec/integration/tmp/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/integration/tmp/dummy/config/initializers/inflections.rb +16 -0
- data/spec/integration/tmp/dummy/config/initializers/mime_types.rb +4 -0
- data/spec/integration/tmp/dummy/config/initializers/session_store.rb +3 -0
- data/spec/integration/tmp/dummy/config/initializers/to_time_preserves_timezone.rb +10 -0
- data/spec/integration/tmp/dummy/config/initializers/wrap_parameters.rb +9 -0
- data/spec/integration/tmp/dummy/config/locales/en.yml +23 -0
- data/spec/integration/tmp/dummy/config/routes.rb +61 -0
- data/spec/integration/tmp/dummy/config/secrets.yml +22 -0
- data/spec/integration/tmp/dummy/db/seeds.rb +7 -0
- data/spec/integration/tmp/dummy/public/404.html +67 -0
- data/spec/integration/tmp/dummy/public/422.html +67 -0
- data/spec/integration/tmp/dummy/public/500.html +66 -0
- data/spec/integration/tmp/dummy/public/favicon.ico +0 -0
- data/spec/integration/tmp/dummy/public/robots.txt +5 -0
- data/spec/support/dummy/schema.rb +2 -2
- data/spec/support/error_bubbling_helpers.rb +23 -0
- data/spec/support/jazz.rb +53 -6
- data/spec/support/lazy_helpers.rb +26 -8
- data/spec/support/new_relic.rb +3 -0
- data/spec/support/skylight.rb +3 -0
- data/spec/support/star_wars/schema.rb +13 -9
- data/spec/support/static_validation_helpers.rb +3 -1
- metadata +145 -22
- data/lib/graphql/language/comments.rb +0 -45
- data/spec/graphql/schema/member/has_fields_spec.rb +0 -132
- data/spec/integration/tmp/app/graphql/types/family_type.rb +0 -9
@@ -70,6 +70,55 @@ describe GraphQL::Execution::Lazy do
|
|
70
70
|
assert_equal expected_data, res["data"]
|
71
71
|
end
|
72
72
|
|
73
|
+
# This only works with the interpreter
|
74
|
+
if TESTING_INTERPRETER
|
75
|
+
[
|
76
|
+
[1, 2, LazyHelpers::MAGIC_NUMBER_WITH_LAZY_AUTHORIZED_HOOK],
|
77
|
+
[2, LazyHelpers::MAGIC_NUMBER_WITH_LAZY_AUTHORIZED_HOOK, 1],
|
78
|
+
[LazyHelpers::MAGIC_NUMBER_WITH_LAZY_AUTHORIZED_HOOK, 1, 2],
|
79
|
+
].each do |ordered_values|
|
80
|
+
it "resolves each field at one depth before proceeding to the next depth (using #{ordered_values})" do
|
81
|
+
res = run_query <<-GRAPHQL, variables: { values: ordered_values }
|
82
|
+
query($values: [Int!]!) {
|
83
|
+
listSum(values: $values) {
|
84
|
+
nestedSum(value: 3) {
|
85
|
+
value
|
86
|
+
}
|
87
|
+
}
|
88
|
+
}
|
89
|
+
GRAPHQL
|
90
|
+
|
91
|
+
# Even though magic number `44`'s `.authorized?` hook returns a lazy value,
|
92
|
+
# these fields should be resolved together and return the same value.
|
93
|
+
assert_equal 56, res["data"]["listSum"][0]["nestedSum"]["value"]
|
94
|
+
assert_equal 56, res["data"]["listSum"][1]["nestedSum"]["value"]
|
95
|
+
assert_equal 56, res["data"]["listSum"][2]["nestedSum"]["value"]
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
it "Handles fields that return nil" do
|
100
|
+
values = [
|
101
|
+
LazyHelpers::MAGIC_NUMBER_THAT_RETURNS_NIL,
|
102
|
+
LazyHelpers::MAGIC_NUMBER_WITH_LAZY_AUTHORIZED_HOOK,
|
103
|
+
1,
|
104
|
+
2,
|
105
|
+
]
|
106
|
+
|
107
|
+
res = run_query <<-GRAPHQL, variables: { values: values }
|
108
|
+
query($values: [Int!]!) {
|
109
|
+
listSum(values: $values) {
|
110
|
+
nullableNestedSum(value: 3) {
|
111
|
+
value
|
112
|
+
}
|
113
|
+
}
|
114
|
+
}
|
115
|
+
GRAPHQL
|
116
|
+
|
117
|
+
values = res["data"]["listSum"].map { |s| s && s["nullableNestedSum"]["value"] }
|
118
|
+
assert_equal [nil, 56, 56, 56], values
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
73
122
|
it "propagates nulls to the root" do
|
74
123
|
res = run_query %|
|
75
124
|
{
|
@@ -48,12 +48,22 @@ describe GraphQL::Execution::Lookahead do
|
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
51
|
+
class LookaheadInstrumenter
|
52
|
+
def self.before_query(query)
|
53
|
+
query.context[:root_lookahead_names] = query.lookahead.selections.map(&:name)
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.after_query(q)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
51
60
|
class Schema < GraphQL::Schema
|
52
61
|
query(Query)
|
62
|
+
instrument :query, LookaheadInstrumenter
|
63
|
+
if TESTING_INTERPRETER
|
64
|
+
use GraphQL::Execution::Interpreter
|
65
|
+
end
|
53
66
|
end
|
54
|
-
# Cause everything to be loaded
|
55
|
-
# TODO remove this
|
56
|
-
Schema.graphql_definition
|
57
67
|
end
|
58
68
|
|
59
69
|
describe "looking ahead" do
|
@@ -80,9 +90,7 @@ describe GraphQL::Execution::Lookahead do
|
|
80
90
|
end
|
81
91
|
|
82
92
|
it "can detect fields on objects with symbol or string" do
|
83
|
-
|
84
|
-
field = LookaheadTest::Query.fields["findBirdSpecies"]
|
85
|
-
lookahead = GraphQL::Execution::Lookahead.new(query: query, ast_nodes: [ast_node], field: field)
|
93
|
+
lookahead = query.lookahead.selection("findBirdSpecies")
|
86
94
|
assert_equal true, lookahead.selects?("similarSpecies")
|
87
95
|
assert_equal true, lookahead.selects?(:similar_species)
|
88
96
|
assert_equal false, lookahead.selects?("isWaterfowl")
|
@@ -90,15 +98,12 @@ describe GraphQL::Execution::Lookahead do
|
|
90
98
|
end
|
91
99
|
|
92
100
|
it "detects by name, not by alias" do
|
93
|
-
|
94
|
-
lookahead = GraphQL::Execution::Lookahead.new(query: query, ast_nodes: [ast_node], root_type: LookaheadTest::Query)
|
95
|
-
assert_equal true, lookahead.selects?("__typename")
|
101
|
+
assert_equal true, query.lookahead.selects?("__typename")
|
96
102
|
end
|
97
103
|
|
98
104
|
describe "constraints by arguments" do
|
99
105
|
let(:lookahead) do
|
100
|
-
|
101
|
-
GraphQL::Execution::Lookahead.new(query: query, ast_nodes: [ast_node], root_type: LookaheadTest::Query)
|
106
|
+
query.lookahead
|
102
107
|
end
|
103
108
|
|
104
109
|
it "is true without constraints" do
|
@@ -138,9 +143,7 @@ describe GraphQL::Execution::Lookahead do
|
|
138
143
|
end
|
139
144
|
|
140
145
|
it "can do a chained lookahead" do
|
141
|
-
|
142
|
-
lookahead = GraphQL::Execution::Lookahead.new(query: query, ast_nodes: [ast_node], root_type: LookaheadTest::Query)
|
143
|
-
next_lookahead = lookahead.selection(:find_bird_species, arguments: { by_name: "Cardinal" })
|
146
|
+
next_lookahead = query.lookahead.selection(:find_bird_species, arguments: { by_name: "Cardinal" })
|
144
147
|
assert_equal true, next_lookahead.selected?
|
145
148
|
nested_selection = next_lookahead.selection(:similar_species).selection(:is_waterfowl, arguments: {})
|
146
149
|
assert_equal true, nested_selection.selected?
|
@@ -148,10 +151,8 @@ describe GraphQL::Execution::Lookahead do
|
|
148
151
|
end
|
149
152
|
|
150
153
|
it "can detect fields on lists with symbol or string" do
|
151
|
-
|
152
|
-
|
153
|
-
assert_equal true, lookahead.selection(:find_bird_species).selection(:similar_species).selection(:is_waterfowl).selected?
|
154
|
-
assert_equal true, lookahead.selection("findBirdSpecies").selection("similarSpecies").selection("isWaterfowl").selected?
|
154
|
+
assert_equal true, query.lookahead.selection(:find_bird_species).selection(:similar_species).selection(:is_waterfowl).selected?
|
155
|
+
assert_equal true, query.lookahead.selection("findBirdSpecies").selection("similarSpecies").selection("isWaterfowl").selected?
|
155
156
|
end
|
156
157
|
|
157
158
|
describe "merging branches and fragments" do
|
@@ -184,9 +185,7 @@ describe GraphQL::Execution::Lookahead do
|
|
184
185
|
}
|
185
186
|
|
186
187
|
it "finds selections using merging" do
|
187
|
-
|
188
|
-
lookahead = GraphQL::Execution::Lookahead.new(query: query, ast_nodes: [ast_node], root_type: LookaheadTest::Query)
|
189
|
-
merged_lookahead = lookahead.selection(:find_bird_species).selection(:similar_species)
|
188
|
+
merged_lookahead = query.lookahead.selection(:find_bird_species).selection(:similar_species)
|
190
189
|
assert merged_lookahead.selects?(:__typename)
|
191
190
|
assert merged_lookahead.selects?(:is_waterfowl)
|
192
191
|
assert merged_lookahead.selects?(:name)
|
@@ -213,6 +212,99 @@ describe GraphQL::Execution::Lookahead do
|
|
213
212
|
res = LookaheadTest::Schema.execute(query_str, context: context)
|
214
213
|
refute res.key?("errors")
|
215
214
|
assert_equal 2, context[:lookahead_latin_name]
|
215
|
+
assert_equal [:find_bird_species], context[:root_lookahead_names]
|
216
|
+
end
|
217
|
+
|
218
|
+
it "works for invalid queries" do
|
219
|
+
context = {lookahead_latin_name: 0}
|
220
|
+
res = LookaheadTest::Schema.execute("{ doesNotExist }", context: context)
|
221
|
+
assert res.key?("errors")
|
222
|
+
assert_equal 0, context[:lookahead_latin_name]
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
describe '#selections' do
|
227
|
+
let(:document) {
|
228
|
+
GraphQL.parse <<-GRAPHQL
|
229
|
+
query {
|
230
|
+
findBirdSpecies(byName: "Laughing Gull") {
|
231
|
+
name
|
232
|
+
similarSpecies {
|
233
|
+
likesWater: isWaterfowl
|
234
|
+
}
|
235
|
+
}
|
236
|
+
}
|
237
|
+
GRAPHQL
|
238
|
+
}
|
239
|
+
|
240
|
+
def query(doc = document)
|
241
|
+
GraphQL::Query.new(LookaheadTest::Schema, document: doc)
|
242
|
+
end
|
243
|
+
|
244
|
+
it "provides a list of all selections" do
|
245
|
+
ast_node = document.definitions.first.selections.first
|
246
|
+
field = LookaheadTest::Query.fields["findBirdSpecies"]
|
247
|
+
lookahead = GraphQL::Execution::Lookahead.new(query: query, ast_nodes: [ast_node], field: field)
|
248
|
+
assert_equal lookahead.selections.map(&:name), [:name, :similar_species]
|
249
|
+
end
|
250
|
+
|
251
|
+
it "filters outs selections which do not match arguments" do
|
252
|
+
ast_node = document.definitions.first
|
253
|
+
lookahead = GraphQL::Execution::Lookahead.new(query: query, ast_nodes: [ast_node], root_type: LookaheadTest::Query)
|
254
|
+
arguments = { by_name: "Cardinal" }
|
255
|
+
|
256
|
+
assert_equal lookahead.selections(arguments: arguments).map(&:name), []
|
257
|
+
end
|
258
|
+
|
259
|
+
it "includes selections which match arguments" do
|
260
|
+
ast_node = document.definitions.first
|
261
|
+
lookahead = GraphQL::Execution::Lookahead.new(query: query, ast_nodes: [ast_node], root_type: LookaheadTest::Query)
|
262
|
+
arguments = { by_name: "Laughing Gull" }
|
263
|
+
|
264
|
+
assert_equal lookahead.selections(arguments: arguments).map(&:name), [:find_bird_species]
|
265
|
+
end
|
266
|
+
|
267
|
+
it 'handles duplicate selections across fragments' do
|
268
|
+
doc = GraphQL.parse <<-GRAPHQL
|
269
|
+
query {
|
270
|
+
... on Query {
|
271
|
+
...MoreFields
|
272
|
+
}
|
273
|
+
}
|
274
|
+
|
275
|
+
fragment MoreFields on Query {
|
276
|
+
findBirdSpecies(byName: "Laughing Gull") {
|
277
|
+
name
|
278
|
+
}
|
279
|
+
findBirdSpecies(byName: "Laughing Gull") {
|
280
|
+
...EvenMoreFields
|
281
|
+
}
|
282
|
+
}
|
283
|
+
|
284
|
+
fragment EvenMoreFields on BirdSpecies {
|
285
|
+
similarSpecies {
|
286
|
+
likesWater: isWaterfowl
|
287
|
+
}
|
288
|
+
}
|
289
|
+
GRAPHQL
|
290
|
+
|
291
|
+
lookahead = query(doc).lookahead
|
292
|
+
|
293
|
+
root_selections = lookahead.selections
|
294
|
+
assert_equal [:find_bird_species], root_selections.map(&:name), "Selections are merged"
|
295
|
+
assert_equal 2, root_selections.first.ast_nodes.size, "It represents both nodes"
|
296
|
+
|
297
|
+
assert_equal [:name, :similar_species], root_selections.first.selections.map(&:name), "Subselections are merged"
|
298
|
+
end
|
299
|
+
|
300
|
+
it "works for missing selections" do
|
301
|
+
ast_node = document.definitions.first.selections.first
|
302
|
+
field = LookaheadTest::Query.fields["findBirdSpecies"]
|
303
|
+
lookahead = GraphQL::Execution::Lookahead.new(query: query, ast_nodes: [ast_node], field: field)
|
304
|
+
null_lookahead = lookahead.selection(:genus)
|
305
|
+
# This is an implementation detail, but I want to make sure the test is set up right
|
306
|
+
assert_instance_of GraphQL::Execution::Lookahead::NullLookahead, null_lookahead
|
307
|
+
assert_equal [], null_lookahead.selections
|
216
308
|
end
|
217
309
|
end
|
218
310
|
end
|
@@ -94,7 +94,8 @@ describe GraphQL::Execution::Multiplex do
|
|
94
94
|
"errors" => [{
|
95
95
|
"message"=>"Field must have selections (field 'nullableNestedSum' returns LazySum but has no selections. Did you mean 'nullableNestedSum { ... }'?)",
|
96
96
|
"locations"=>[{"line"=>1, "column"=>4}],
|
97
|
-
"
|
97
|
+
"path"=>["query", "validationError"],
|
98
|
+
"extensions"=>{"code"=>"selectionMismatch", "nodeName"=>"field 'nullableNestedSum'", "typeName"=>"LazySum"}
|
98
99
|
}]
|
99
100
|
},
|
100
101
|
]
|
@@ -146,7 +146,7 @@ describe GraphQL::Introspection::TypeType do
|
|
146
146
|
GRAPHQL
|
147
147
|
type_result = res["data"]["__schema"]["types"].find { |t| t["name"] == "Faction" }
|
148
148
|
field_result = type_result["fields"].find { |f| f["name"] == "bases" }
|
149
|
-
all_arg_names = ["after", "before", "first", "last", "nameIncludes"]
|
149
|
+
all_arg_names = ["after", "before", "first", "last", "nameIncludes", "complexOrder"]
|
150
150
|
returned_arg_names = field_result["args"].map { |a| a["name"] }
|
151
151
|
assert_equal all_arg_names, returned_arg_names
|
152
152
|
end
|
@@ -26,12 +26,32 @@ describe GraphQL::Language::Lexer do
|
|
26
26
|
assert_equal tokens[0], tokens[1].prev_token
|
27
27
|
end
|
28
28
|
|
29
|
+
it "allows escaped quotes in strings" do
|
30
|
+
tokens = subject.tokenize('"a\\"b""c"')
|
31
|
+
assert_equal 'a"b', tokens[0].value
|
32
|
+
assert_equal 'c', tokens[1].value
|
33
|
+
end
|
34
|
+
|
29
35
|
describe "block strings" do
|
30
|
-
let(:query_string) { %|{ a(b: """\nc\n
|
36
|
+
let(:query_string) { %|{ a(b: """\nc\n \\""" d\n""" """""e""""")}|}
|
31
37
|
|
32
38
|
it "tokenizes them" do
|
33
|
-
|
34
|
-
assert_equal "
|
39
|
+
assert_equal "c\n \"\"\" d", tokens[5].value
|
40
|
+
assert_equal "\"\"e\"\"", tokens[6].value
|
41
|
+
end
|
42
|
+
|
43
|
+
it "tokenizes 10 quote edge case correctly" do
|
44
|
+
tokens = subject.tokenize('""""""""""')
|
45
|
+
assert_equal '""', tokens[0].value # first 8 quotes are a valid block string """"""""
|
46
|
+
assert_equal '', tokens[1].value # last 2 quotes are a valid string ""
|
47
|
+
end
|
48
|
+
|
49
|
+
it "tokenizes with nested single quote strings correctly" do
|
50
|
+
tokens = subject.tokenize('"""{"x"}"""')
|
51
|
+
assert_equal '{"x"}', tokens[0].value
|
52
|
+
|
53
|
+
tokens = subject.tokenize('"""{"foo":"bar"}"""')
|
54
|
+
assert_equal '{"foo":"bar"}', tokens[0].value
|
35
55
|
end
|
36
56
|
end
|
37
57
|
|
@@ -62,5 +82,54 @@ describe GraphQL::Language::Lexer do
|
|
62
82
|
rparen_token = tokens[6]
|
63
83
|
assert_equal '(RPAREN ")" [1:10])', rparen_token.inspect
|
64
84
|
end
|
85
|
+
|
86
|
+
it "counts block string line properly" do
|
87
|
+
str = <<-GRAPHQL
|
88
|
+
"""
|
89
|
+
Here is a
|
90
|
+
multiline description
|
91
|
+
"""
|
92
|
+
type Query {
|
93
|
+
a: B
|
94
|
+
}
|
95
|
+
|
96
|
+
"Here's another description"
|
97
|
+
|
98
|
+
type B {
|
99
|
+
a: B
|
100
|
+
}
|
101
|
+
|
102
|
+
"""
|
103
|
+
And another
|
104
|
+
multiline description
|
105
|
+
"""
|
106
|
+
|
107
|
+
|
108
|
+
type C {
|
109
|
+
a: B
|
110
|
+
}
|
111
|
+
GRAPHQL
|
112
|
+
|
113
|
+
tokens = subject.tokenize(str)
|
114
|
+
|
115
|
+
string_tok, type_keyword_tok, query_name_tok,
|
116
|
+
_curly, _ident, _colon, _ident, _curly,
|
117
|
+
string_tok_2, type_keyword_tok_2, b_name_tok,
|
118
|
+
_curly, _ident, _colon, _ident, _curly,
|
119
|
+
string_tok_3, type_keyword_tok_3, c_name_tok = tokens
|
120
|
+
|
121
|
+
assert_equal 1, string_tok.line
|
122
|
+
assert_equal 5, type_keyword_tok.line
|
123
|
+
assert_equal 5, query_name_tok.line
|
124
|
+
|
125
|
+
# Make sure it handles the empty spaces, too
|
126
|
+
assert_equal 9, string_tok_2.line
|
127
|
+
assert_equal 11, type_keyword_tok_2.line
|
128
|
+
assert_equal 11, b_name_tok.line
|
129
|
+
|
130
|
+
assert_equal 15, string_tok_3.line
|
131
|
+
assert_equal 21, type_keyword_tok_3.line
|
132
|
+
assert_equal 21, c_name_tok.line
|
133
|
+
end
|
65
134
|
end
|
66
135
|
end
|
@@ -112,7 +112,9 @@ describe GraphQL::Language::Printer do
|
|
112
112
|
mutation: MutationType
|
113
113
|
}
|
114
114
|
|
115
|
-
|
115
|
+
"""
|
116
|
+
Union description
|
117
|
+
"""
|
116
118
|
union AnnotatedUnion @onUnion = A | B
|
117
119
|
|
118
120
|
type Foo implements Bar & AnnotatedInterface {
|
@@ -125,7 +127,9 @@ describe GraphQL::Language::Printer do
|
|
125
127
|
seven(argument: String = null): Type
|
126
128
|
}
|
127
129
|
|
128
|
-
|
130
|
+
"""
|
131
|
+
Scalar description
|
132
|
+
"""
|
129
133
|
scalar CustomScalar
|
130
134
|
|
131
135
|
type AnnotatedObject implements Bar @onObject(arg: "value") {
|
@@ -137,9 +141,13 @@ describe GraphQL::Language::Printer do
|
|
137
141
|
four(argument: String = "string"): String
|
138
142
|
}
|
139
143
|
|
140
|
-
|
144
|
+
"""
|
145
|
+
Enum description
|
146
|
+
"""
|
141
147
|
enum Site {
|
142
|
-
|
148
|
+
"""
|
149
|
+
Enum value description
|
150
|
+
"""
|
143
151
|
DESKTOP
|
144
152
|
MOBILE
|
145
153
|
}
|
@@ -150,7 +158,9 @@ describe GraphQL::Language::Printer do
|
|
150
158
|
|
151
159
|
union Feed = Story | Article | Advert
|
152
160
|
|
153
|
-
|
161
|
+
"""
|
162
|
+
Input description
|
163
|
+
"""
|
154
164
|
input InputType {
|
155
165
|
key: String!
|
156
166
|
answer: Int = 42
|
@@ -160,7 +170,9 @@ describe GraphQL::Language::Printer do
|
|
160
170
|
|
161
171
|
scalar CustomScalar
|
162
172
|
|
163
|
-
|
173
|
+
"""
|
174
|
+
Directive description
|
175
|
+
"""
|
164
176
|
directive @skip(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
|
165
177
|
|
166
178
|
scalar AnnotatedScalar @onScalar
|
@@ -121,6 +121,27 @@ describe GraphQL::Query::Arguments do
|
|
121
121
|
end
|
122
122
|
end
|
123
123
|
|
124
|
+
describe "#dig" do
|
125
|
+
it "returns the value at that key" do
|
126
|
+
assert_equal 1, arguments.dig("a")
|
127
|
+
assert_equal 1, arguments.dig(:a)
|
128
|
+
assert arguments.dig("inputObject").is_a?(GraphQL::Query::Arguments)
|
129
|
+
end
|
130
|
+
|
131
|
+
it "works with nested keys" do
|
132
|
+
assert_equal 3, arguments.dig("inputObject", "d")
|
133
|
+
assert_equal 3, arguments.dig(:inputObject, :d)
|
134
|
+
assert_equal 3, arguments.dig("inputObject", :d)
|
135
|
+
assert_equal 3, arguments.dig(:inputObject, "d")
|
136
|
+
end
|
137
|
+
|
138
|
+
it "returns nil for missing keys" do
|
139
|
+
assert_nil arguments.dig("z")
|
140
|
+
assert_nil arguments.dig(7)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
|
124
145
|
describe "#key?" do
|
125
146
|
let(:arg_values) { [] }
|
126
147
|
let(:schema) {
|
@@ -235,6 +235,16 @@ TABLE
|
|
235
235
|
end
|
236
236
|
end
|
237
237
|
|
238
|
+
describe "splatting" do
|
239
|
+
let(:context) { GraphQL::Query::Context.new(query: OpenStruct.new(schema: schema), values: {a: {b: 1}}, object: nil) }
|
240
|
+
|
241
|
+
let(:splat) { ->(**context) { context } }
|
242
|
+
|
243
|
+
it "runs successfully" do
|
244
|
+
assert_equal({a: { b: 1 }}, splat.call(context))
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
238
248
|
describe "accessing context after the fact" do
|
239
249
|
let(:query_string) { %|
|
240
250
|
{ pushContext }
|