graphql 0.17.2 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/graphql.rb +1 -0
- data/lib/graphql/analysis/query_depth.rb +1 -1
- data/lib/graphql/base_type.rb +25 -1
- data/lib/graphql/define.rb +2 -0
- data/lib/graphql/define/assign_connection.rb +11 -0
- data/lib/graphql/define/assign_global_id_field.rb +11 -0
- data/lib/graphql/define/assign_object_field.rb +21 -20
- data/lib/graphql/define/defined_object_proxy.rb +2 -2
- data/lib/graphql/define/instance_definable.rb +13 -3
- data/lib/graphql/field.rb +1 -1
- data/lib/graphql/language/generation.rb +57 -6
- data/lib/graphql/language/lexer.rb +434 -212
- data/lib/graphql/language/lexer.rl +18 -0
- data/lib/graphql/language/nodes.rb +75 -0
- data/lib/graphql/language/parser.rb +853 -341
- data/lib/graphql/language/parser.y +114 -17
- data/lib/graphql/query.rb +15 -1
- data/lib/graphql/relay.rb +13 -0
- data/lib/graphql/relay/array_connection.rb +80 -0
- data/lib/graphql/relay/base_connection.rb +138 -0
- data/lib/graphql/relay/connection_field.rb +54 -0
- data/lib/graphql/relay/connection_type.rb +25 -0
- data/lib/graphql/relay/edge.rb +22 -0
- data/lib/graphql/relay/edge_type.rb +14 -0
- data/lib/graphql/relay/global_id_resolve.rb +15 -0
- data/lib/graphql/relay/global_node_identification.rb +124 -0
- data/lib/graphql/relay/mutation.rb +146 -0
- data/lib/graphql/relay/page_info.rb +13 -0
- data/lib/graphql/relay/relation_connection.rb +98 -0
- data/lib/graphql/schema.rb +3 -0
- data/lib/graphql/schema/printer.rb +12 -2
- data/lib/graphql/static_validation/message.rb +9 -5
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +1 -1
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +3 -3
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +7 -7
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +4 -4
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +5 -5
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +6 -6
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +17 -9
- data/lib/graphql/static_validation/rules/fragment_types_exist.rb +1 -1
- data/lib/graphql/static_validation/rules/fragments_are_finite.rb +1 -1
- data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +1 -1
- data/lib/graphql/static_validation/rules/fragments_are_used.rb +17 -6
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +1 -1
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +2 -2
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +5 -5
- data/lib/graphql/static_validation/rules/variables_are_input_types.rb +1 -1
- data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +12 -11
- data/lib/graphql/static_validation/type_stack.rb +33 -2
- data/lib/graphql/static_validation/validation_context.rb +5 -0
- data/lib/graphql/version.rb +1 -1
- data/readme.md +16 -4
- data/spec/graphql/analysis/analyze_query_spec.rb +31 -2
- data/spec/graphql/analysis/query_complexity_spec.rb +24 -0
- data/spec/graphql/argument_spec.rb +1 -1
- data/spec/graphql/define/instance_definable_spec.rb +9 -0
- data/spec/graphql/field_spec.rb +1 -1
- data/spec/graphql/internal_representation/rewrite_spec.rb +3 -3
- data/spec/graphql/language/generation_spec.rb +25 -4
- data/spec/graphql/language/parser_spec.rb +116 -1
- data/spec/graphql/query_spec.rb +10 -0
- data/spec/graphql/relay/array_connection_spec.rb +164 -0
- data/spec/graphql/relay/connection_type_spec.rb +37 -0
- data/spec/graphql/relay/global_node_identification_spec.rb +149 -0
- data/spec/graphql/relay/mutation_spec.rb +55 -0
- data/spec/graphql/relay/page_info_spec.rb +106 -0
- data/spec/graphql/relay/relation_connection_spec.rb +348 -0
- data/spec/graphql/schema/printer_spec.rb +8 -0
- data/spec/graphql/schema/reduce_types_spec.rb +1 -1
- data/spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb +12 -6
- data/spec/graphql/static_validation/rules/arguments_are_defined_spec.rb +8 -4
- 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 +7 -2
- data/spec/graphql/static_validation/rules/fields_have_appropriate_selections_spec.rb +4 -2
- 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 +5 -3
- data/spec/graphql/static_validation/rules/fragments_are_finite_spec.rb +4 -2
- data/spec/graphql/static_validation/rules/fragments_are_on_composite_types_spec.rb +5 -2
- data/spec/graphql/static_validation/rules/fragments_are_used_spec.rb +10 -2
- data/spec/graphql/static_validation/rules/required_arguments_are_present_spec.rb +6 -3
- data/spec/graphql/static_validation/rules/variable_default_values_are_correctly_typed_spec.rb +8 -4
- 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 +6 -3
- data/spec/graphql/static_validation/rules/variables_are_used_and_defined_spec.rb +6 -3
- data/spec/spec_helper.rb +7 -0
- data/spec/support/dairy_app.rb +11 -10
- data/spec/support/star_wars_data.rb +65 -58
- data/spec/support/star_wars_schema.rb +192 -54
- metadata +84 -2
@@ -22,10 +22,12 @@ describe GraphQL::StaticValidation::DirectivesAreDefined do
|
|
22
22
|
expected = [
|
23
23
|
{
|
24
24
|
"message"=>"Directive @nonsense is not defined",
|
25
|
-
"locations"=>[{"line"=>5, "column"=>16}]
|
25
|
+
"locations"=>[{"line"=>5, "column"=>16}],
|
26
|
+
"path"=>["query getCheese", "okCheese", "source"],
|
26
27
|
}, {
|
27
28
|
"message"=>"Directive @moreNonsense is not defined",
|
28
|
-
"locations"=>[{"line"=>7, "column"=>18}]
|
29
|
+
"locations"=>[{"line"=>7, "column"=>18}],
|
30
|
+
"path"=>["query getCheese", "okCheese", "... on Cheese", "flavor"],
|
29
31
|
}
|
30
32
|
]
|
31
33
|
assert_equal(expected, errors)
|
@@ -26,11 +26,13 @@ describe GraphQL::StaticValidation::DirectivesAreInValidLocations do
|
|
26
26
|
expected = [
|
27
27
|
{
|
28
28
|
"message"=> "'@skip' can't be applied to queries (allowed: fields, fragment spreads, inline fragments)",
|
29
|
-
"locations"=>[{"line"=>2, "column"=>21}]
|
29
|
+
"locations"=>[{"line"=>2, "column"=>21}],
|
30
|
+
"path"=>["query getCheese"],
|
30
31
|
},
|
31
32
|
{
|
32
33
|
"message"=>"'@skip' can't be applied to fragment definitions (allowed: fields, fragment spreads, inline fragments)",
|
33
|
-
"locations"=>[{"line"=>12, "column"=>33}]
|
34
|
+
"locations"=>[{"line"=>12, "column"=>33}],
|
35
|
+
"path"=>["fragment whatever"],
|
34
36
|
},
|
35
37
|
]
|
36
38
|
assert_equal(expected, errors)
|
@@ -31,7 +31,11 @@ describe GraphQL::StaticValidation::FieldsAreDefinedOnType do
|
|
31
31
|
|
32
32
|
it "finds invalid fields" do
|
33
33
|
expected_errors = [
|
34
|
-
{
|
34
|
+
{
|
35
|
+
"message"=>"Field 'amountThatILikeIt' doesn't exist on type 'Edible'",
|
36
|
+
"locations"=>[{"line"=>1, "column"=>18}],
|
37
|
+
"path"=>["query getStuff", "favoriteEdible", "amountThatILikeIt"],
|
38
|
+
}
|
35
39
|
]
|
36
40
|
assert_equal(expected_errors, errors)
|
37
41
|
end
|
@@ -51,7 +55,8 @@ describe GraphQL::StaticValidation::FieldsAreDefinedOnType do
|
|
51
55
|
"message"=>"Selections can't be made directly on unions (see selections on DairyProduct)",
|
52
56
|
"locations"=>[
|
53
57
|
{"line"=>3, "column"=>7}
|
54
|
-
]
|
58
|
+
],
|
59
|
+
"path"=>["fragment dbFields", "source"],
|
55
60
|
}
|
56
61
|
]
|
57
62
|
assert_equal(expected_errors, errors)
|
@@ -18,13 +18,15 @@ describe GraphQL::StaticValidation::FieldsHaveAppropriateSelections do
|
|
18
18
|
|
19
19
|
illegal_selection_error = {
|
20
20
|
"message"=>"Selections can't be made on scalars (field 'id' returns Int but has selections [something, someFields])",
|
21
|
-
"locations"=>[{"line"=>5, "column"=>47}]
|
21
|
+
"locations"=>[{"line"=>5, "column"=>47}],
|
22
|
+
"path"=>["query getCheese", "illegalSelectionCheese", "id"],
|
22
23
|
}
|
23
24
|
assert_includes(errors, illegal_selection_error, "finds illegal selections on scalarss")
|
24
25
|
|
25
26
|
selection_required_error = {
|
26
27
|
"message"=>"Objects must have selections (field 'cheese' returns Cheese but has no selections)",
|
27
|
-
"locations"=>[{"line"=>4, "column"=>7}]
|
28
|
+
"locations"=>[{"line"=>4, "column"=>7}],
|
29
|
+
"path"=>["query getCheese", "missingFieldsCheese"],
|
28
30
|
}
|
29
31
|
assert_includes(errors, selection_required_error, "finds objects without selections")
|
30
32
|
end
|
@@ -31,15 +31,18 @@ describe GraphQL::StaticValidation::FragmentSpreadsArePossible do
|
|
31
31
|
expected = [
|
32
32
|
{
|
33
33
|
"message"=>"Fragment on Milk can't be spread inside Cheese",
|
34
|
-
"locations"=>[{"line"=>6, "column"=>9}]
|
34
|
+
"locations"=>[{"line"=>6, "column"=>9}],
|
35
|
+
"path"=>["query getCheese", "cheese", "... on Milk"],
|
35
36
|
},
|
36
37
|
{
|
37
38
|
"message"=>"Fragment milkFields on Milk can't be spread inside Cheese",
|
38
|
-
"locations"=>[{"line"=>4, "column"=>9}]
|
39
|
+
"locations"=>[{"line"=>4, "column"=>9}],
|
40
|
+
"path"=>["query getCheese", "cheese", "... milkFields"],
|
39
41
|
},
|
40
42
|
{
|
41
43
|
"message"=>"Fragment milkFields on Milk can't be spread inside Cheese",
|
42
|
-
"locations"=>[{"line"=>18, "column"=>7}]
|
44
|
+
"locations"=>[{"line"=>18, "column"=>7}],
|
45
|
+
"path"=>["fragment cheeseFields", "... milkFields"],
|
43
46
|
}
|
44
47
|
]
|
45
48
|
assert_equal(expected, errors)
|
@@ -3,7 +3,7 @@ require "spec_helper"
|
|
3
3
|
describe GraphQL::StaticValidation::FragmentTypesExist do
|
4
4
|
let(:query_string) {"
|
5
5
|
query getCheese {
|
6
|
-
|
6
|
+
cheese(id: 1) {
|
7
7
|
... on Cheese { source }
|
8
8
|
... on Nothing { whatever }
|
9
9
|
... somethingFields
|
@@ -27,12 +27,14 @@ describe GraphQL::StaticValidation::FragmentTypesExist do
|
|
27
27
|
assert_equal(2, errors.length)
|
28
28
|
inline_fragment_error = {
|
29
29
|
"message"=>"No such type Something, so it can't be a fragment condition",
|
30
|
-
"locations"=>[{"line"=>11, "column"=>5}]
|
30
|
+
"locations"=>[{"line"=>11, "column"=>5}],
|
31
|
+
"path"=>["fragment somethingFields"],
|
31
32
|
}
|
32
33
|
assert_includes(errors, inline_fragment_error, "on inline fragments")
|
33
34
|
fragment_def_error = {
|
34
35
|
"message"=>"No such type Nothing, so it can't be a fragment condition",
|
35
|
-
"locations"=>[{"line"=>5, "column"=>9}]
|
36
|
+
"locations"=>[{"line"=>5, "column"=>9}],
|
37
|
+
"path"=>["query getCheese", "cheese", "... on Nothing"],
|
36
38
|
}
|
37
39
|
assert_includes(errors, fragment_def_error, "on fragment definitions")
|
38
40
|
end
|
@@ -32,11 +32,13 @@ describe GraphQL::StaticValidation::FragmentsAreFinite do
|
|
32
32
|
expected = [
|
33
33
|
{
|
34
34
|
"message"=>"Fragment sourceField contains an infinite loop",
|
35
|
-
"locations"=>[{"line"=>10, "column"=>5}]
|
35
|
+
"locations"=>[{"line"=>10, "column"=>5}],
|
36
|
+
"path"=>["fragment sourceField"],
|
36
37
|
},
|
37
38
|
{
|
38
39
|
"message"=>"Fragment flavorField contains an infinite loop",
|
39
|
-
"locations"=>[{"line"=>15, "column"=>5}]
|
40
|
+
"locations"=>[{"line"=>15, "column"=>5}],
|
41
|
+
"path"=>["fragment flavorField"],
|
40
42
|
}
|
41
43
|
]
|
42
44
|
assert_equal(expected, errors)
|
@@ -33,15 +33,18 @@ describe GraphQL::StaticValidation::FragmentsAreOnCompositeTypes do
|
|
33
33
|
expected = [
|
34
34
|
{
|
35
35
|
"message"=>"Invalid fragment on type Boolean (must be Union, Interface or Object)",
|
36
|
-
"locations"=>[{"line"=>6, "column"=>11}]
|
36
|
+
"locations"=>[{"line"=>6, "column"=>11}],
|
37
|
+
"path"=>["query getCheese", "cheese", "... on Cheese", "... on Boolean"],
|
37
38
|
},
|
38
39
|
{
|
39
40
|
"message"=>"Invalid fragment on type DairyProductInput (must be Union, Interface or Object)",
|
40
41
|
"locations"=>[{"line"=>14, "column"=>9}],
|
42
|
+
"path"=>["query getCheese", "cheese", "... on DairyProductInput"],
|
41
43
|
},
|
42
44
|
{
|
43
45
|
"message"=>"Invalid fragment on type Int (must be Union, Interface or Object)",
|
44
|
-
"locations"=>[{"line"=>20, "column"=>5}]
|
46
|
+
"locations"=>[{"line"=>20, "column"=>5}],
|
47
|
+
"path"=>["fragment intFields"],
|
45
48
|
},
|
46
49
|
]
|
47
50
|
assert_equal(expected, errors)
|
@@ -16,10 +16,18 @@ describe GraphQL::StaticValidation::FragmentsAreUsed do
|
|
16
16
|
let(:errors) { validator.validate(query)[:errors] }
|
17
17
|
|
18
18
|
it "adds errors for unused fragment definitions" do
|
19
|
-
assert_includes(errors, {
|
19
|
+
assert_includes(errors, {
|
20
|
+
"message"=>"Fragment unusedFields was defined, but not used",
|
21
|
+
"locations"=>[{"line"=>8, "column"=>5}],
|
22
|
+
"path"=>[],
|
23
|
+
})
|
20
24
|
end
|
21
25
|
|
22
26
|
it "adds errors for undefined fragment spreads" do
|
23
|
-
assert_includes(errors, {
|
27
|
+
assert_includes(errors, {
|
28
|
+
"message"=>"Fragment undefinedFields was used, but not defined",
|
29
|
+
"locations"=>[{"line"=>5, "column"=>7}],
|
30
|
+
"path"=>["query getCheese", "... undefinedFields"]
|
31
|
+
})
|
24
32
|
end
|
25
33
|
end
|
@@ -23,19 +23,22 @@ describe GraphQL::StaticValidation::RequiredArgumentsArePresent do
|
|
23
23
|
|
24
24
|
query_root_error = {
|
25
25
|
"message"=>"Field 'cheese' is missing required arguments: id",
|
26
|
-
"locations"=>[{"line"=>4, "column"=>7}]
|
26
|
+
"locations"=>[{"line"=>4, "column"=>7}],
|
27
|
+
"path"=>["query getCheese", "cheese"],
|
27
28
|
}
|
28
29
|
assert_includes(errors, query_root_error)
|
29
30
|
|
30
31
|
fragment_error = {
|
31
32
|
"message"=>"Field 'similarCheese' is missing required arguments: source",
|
32
|
-
"locations"=>[{"line"=>8, "column"=>7}]
|
33
|
+
"locations"=>[{"line"=>8, "column"=>7}],
|
34
|
+
"path"=>["fragment cheeseFields", "similarCheese"],
|
33
35
|
}
|
34
36
|
assert_includes(errors, fragment_error)
|
35
37
|
|
36
38
|
directive_error = {
|
37
39
|
"message"=>"Directive 'skip' is missing required arguments: if",
|
38
|
-
"locations"=>[{"line"=>10, "column"=>10}]
|
40
|
+
"locations"=>[{"line"=>10, "column"=>10}],
|
41
|
+
"path"=>["fragment cheeseFields", "id"],
|
39
42
|
}
|
40
43
|
assert_includes(errors, directive_error)
|
41
44
|
end
|
data/spec/graphql/static_validation/rules/variable_default_values_are_correctly_typed_spec.rb
CHANGED
@@ -24,19 +24,23 @@ describe GraphQL::StaticValidation::VariableDefaultValuesAreCorrectlyTyped do
|
|
24
24
|
expected = [
|
25
25
|
{
|
26
26
|
"message"=>"Default value for $badFloat doesn't match type Float",
|
27
|
-
"locations"=>[{"line"=>6, "column"=>7}]
|
27
|
+
"locations"=>[{"line"=>6, "column"=>7}],
|
28
|
+
"path"=>["query getCheese"],
|
28
29
|
},
|
29
30
|
{
|
30
31
|
"message"=>"Default value for $badInt doesn't match type Int",
|
31
|
-
"locations"=>[{"line"=>7, "column"=>7}]
|
32
|
+
"locations"=>[{"line"=>7, "column"=>7}],
|
33
|
+
"path"=>["query getCheese"],
|
32
34
|
},
|
33
35
|
{
|
34
36
|
"message"=>"Default value for $badInput doesn't match type DairyProductInput",
|
35
|
-
"locations"=>[{"line"=>9, "column"=>7}]
|
37
|
+
"locations"=>[{"line"=>9, "column"=>7}],
|
38
|
+
"path"=>["query getCheese"],
|
36
39
|
},
|
37
40
|
{
|
38
41
|
"message"=>"Non-null variable $nonNull can't have a default value",
|
39
|
-
"locations"=>[{"line"=>10, "column"=>7}]
|
42
|
+
"locations"=>[{"line"=>10, "column"=>7}],
|
43
|
+
"path"=>["query getCheese"],
|
40
44
|
}
|
41
45
|
]
|
42
46
|
assert_equal(expected, errors)
|
@@ -43,19 +43,23 @@ describe GraphQL::StaticValidation::VariableUsagesAreAllowed do
|
|
43
43
|
expected = [
|
44
44
|
{
|
45
45
|
"message"=>"Nullability mismatch on variable $badInt and argument id (Int / Int!)",
|
46
|
-
"locations"=>[{"line"=>14, "column"=>28}]
|
46
|
+
"locations"=>[{"line"=>14, "column"=>28}],
|
47
|
+
"path"=>["query getCheese", "badCheese", "id"],
|
47
48
|
},
|
48
49
|
{
|
49
50
|
"message"=>"Type mismatch on variable $badStr and argument id (String! / Int!)",
|
50
|
-
"locations"=>[{"line"=>15, "column"=>28}]
|
51
|
+
"locations"=>[{"line"=>15, "column"=>28}],
|
52
|
+
"path"=>["query getCheese", "badStrCheese", "id"],
|
51
53
|
},
|
52
54
|
{
|
53
55
|
"message"=>"Nullability mismatch on variable $badAnimals and argument source ([DairyAnimal]! / [DairyAnimal!]!)",
|
54
|
-
"locations"=>[{"line"=>18, "column"=>30}]
|
56
|
+
"locations"=>[{"line"=>18, "column"=>30}],
|
57
|
+
"path"=>["query getCheese", "cheese", "other", "source"],
|
55
58
|
},
|
56
59
|
{
|
57
60
|
"message"=>"List dimension mismatch on variable $deepAnimals and argument source ([[DairyAnimal!]!]! / [DairyAnimal!]!)",
|
58
|
-
"locations"=>[{"line"=>19, "column"=>32}]
|
61
|
+
"locations"=>[{"line"=>19, "column"=>32}],
|
62
|
+
"path"=>["query getCheese", "cheese", "tooDeep", "source"],
|
59
63
|
}
|
60
64
|
]
|
61
65
|
assert_equal(expected, errors)
|
@@ -21,15 +21,18 @@ describe GraphQL::StaticValidation::VariablesAreInputTypes do
|
|
21
21
|
expected = [
|
22
22
|
{
|
23
23
|
"message"=>"AnimalProduct isn't a valid input type (on $interface)",
|
24
|
-
"locations"=>[{"line"=>5, "column"=>7}]
|
24
|
+
"locations"=>[{"line"=>5, "column"=>7}],
|
25
|
+
"path"=>["query getCheese"],
|
25
26
|
},
|
26
27
|
{
|
27
28
|
"message"=>"Milk isn't a valid input type (on $object)",
|
28
|
-
"locations"=>[{"line"=>6, "column"=>7}]
|
29
|
+
"locations"=>[{"line"=>6, "column"=>7}],
|
30
|
+
"path"=>["query getCheese"],
|
29
31
|
},
|
30
32
|
{
|
31
33
|
"message"=>"Cheese isn't a valid input type (on $objects)",
|
32
|
-
"locations"=>[{"line"=>7, "column"=>7}]
|
34
|
+
"locations"=>[{"line"=>7, "column"=>7}],
|
35
|
+
"path"=>["query getCheese"],
|
33
36
|
}
|
34
37
|
]
|
35
38
|
assert_equal(expected, errors)
|
@@ -37,15 +37,18 @@ describe GraphQL::StaticValidation::VariablesAreUsedAndDefined do
|
|
37
37
|
expected = [
|
38
38
|
{
|
39
39
|
"message"=>"Variable $notUsedVar is declared by getCheese but not used",
|
40
|
-
"locations"=>[{"line"=>2, "column"=>5}]
|
40
|
+
"locations"=>[{"line"=>2, "column"=>5}],
|
41
|
+
"path"=>["query getCheese"],
|
41
42
|
},
|
42
43
|
{
|
43
44
|
"message"=>"Variable $undefinedVar is used by getCheese but not declared",
|
44
|
-
"locations"=>[{"line"=>11, "column"=>29}]
|
45
|
+
"locations"=>[{"line"=>11, "column"=>29}],
|
46
|
+
"path"=>["query getCheese", "cheese", "whatever", "undefined"],
|
45
47
|
},
|
46
48
|
{
|
47
49
|
"message"=>"Variable $undefinedFragmentVar is used by innerCheeseFields but not declared",
|
48
|
-
"locations"=>[{"line"=>24, "column"=>26}]
|
50
|
+
"locations"=>[{"line"=>24, "column"=>26}],
|
51
|
+
"path"=>["fragment innerCheeseFields", "source", "notDefined"],
|
49
52
|
},
|
50
53
|
]
|
51
54
|
assert_equal(expected, errors)
|
data/spec/spec_helper.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
require "codeclimate-test-reporter"
|
2
2
|
CodeClimate::TestReporter.start
|
3
|
+
require "sqlite3"
|
4
|
+
require "active_record"
|
5
|
+
require "sequel"
|
3
6
|
require "graphql"
|
4
7
|
require "benchmark"
|
5
8
|
require "minitest/autorun"
|
@@ -16,3 +19,7 @@ Minitest.backtrace_filter = Minitest::BacktraceFilter.new
|
|
16
19
|
|
17
20
|
# # Load support files
|
18
21
|
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
|
22
|
+
|
23
|
+
def query(string, variables={})
|
24
|
+
GraphQL::Query.new(StarWarsSchema, string, variables: variables).result
|
25
|
+
end
|
data/spec/support/dairy_app.rb
CHANGED
@@ -38,7 +38,7 @@ CheeseType = GraphQL::ObjectType.define do
|
|
38
38
|
"Animal which produced the milk for this cheese"
|
39
39
|
|
40
40
|
# Or can define by block, `resolve ->` should override `property:`
|
41
|
-
field :similarCheese, CheeseType, "Cheeses like this one", property: :
|
41
|
+
field :similarCheese, CheeseType, "Cheeses like this one", property: :this_should_be_overriden do
|
42
42
|
argument :source, !types[!DairyAnimalEnum]
|
43
43
|
resolve -> (t, a, c) {
|
44
44
|
# get the strings out:
|
@@ -61,11 +61,12 @@ CheeseType = GraphQL::ObjectType.define do
|
|
61
61
|
resolve -> (t, a, c) { raise("NotImplemented") }
|
62
62
|
end
|
63
63
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
64
|
+
# Keywords can be used for definition methods
|
65
|
+
field :fatContent,
|
66
|
+
property: :fat_content,
|
67
|
+
type: !GraphQL::FLOAT_TYPE,
|
68
|
+
description: "Percentage which is milkfat",
|
69
|
+
deprecation_reason: "Diet fashion has changed"
|
69
70
|
end
|
70
71
|
|
71
72
|
MilkType = GraphQL::ObjectType.define do
|
@@ -216,7 +217,7 @@ FavoriteFieldDefn = GraphQL::Field.define do
|
|
216
217
|
resolve -> (t, a, c) { MILKS[1] }
|
217
218
|
end
|
218
219
|
|
219
|
-
|
220
|
+
DairyAppQueryType = GraphQL::ObjectType.define do
|
220
221
|
name "Query"
|
221
222
|
description "Query root of the system"
|
222
223
|
field :root, types.String do
|
@@ -275,7 +276,7 @@ ReplaceValuesInputType = GraphQL::InputObjectType.define do
|
|
275
276
|
input_field :values, !types[!types.Int]
|
276
277
|
end
|
277
278
|
|
278
|
-
|
279
|
+
DairyAppMutationType = GraphQL::ObjectType.define do
|
279
280
|
name "Mutation"
|
280
281
|
description "The root for mutations in this schema"
|
281
282
|
field :pushValue, !types[!types.Int] do
|
@@ -306,8 +307,8 @@ SubscriptionType = GraphQL::ObjectType.define do
|
|
306
307
|
end
|
307
308
|
|
308
309
|
DummySchema = GraphQL::Schema.new(
|
309
|
-
query:
|
310
|
-
mutation:
|
310
|
+
query: DairyAppQueryType,
|
311
|
+
mutation: DairyAppMutationType,
|
311
312
|
subscription: SubscriptionType,
|
312
313
|
max_depth: 5,
|
313
314
|
types: [HoneyType],
|
@@ -1,71 +1,78 @@
|
|
1
|
-
luke = OpenStruct.new({
|
2
|
-
id: "1000",
|
3
|
-
name: "Luke Skywalker",
|
4
|
-
friends: ["1002", "1003", "2000", "2001"],
|
5
|
-
appearsIn: [4, 5, 6],
|
6
|
-
homePlanet: "Tatooine",
|
7
|
-
})
|
8
1
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
2
|
+
names = [
|
3
|
+
'X-Wing',
|
4
|
+
'Y-Wing',
|
5
|
+
'A-Wing',
|
6
|
+
'Millenium Falcon',
|
7
|
+
'Home One',
|
8
|
+
'TIE Fighter',
|
9
|
+
'TIE Interceptor',
|
10
|
+
'Executor',
|
11
|
+
]
|
16
12
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
appearsIn: [4, 5, 6],
|
22
|
-
})
|
13
|
+
# ActiveRecord::Base.logger = Logger.new(STDOUT)
|
14
|
+
`rm -f ./_test_.db`
|
15
|
+
# Set up "Bases" in ActiveRecord
|
16
|
+
ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: "./_test_.db")
|
23
17
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
18
|
+
ActiveRecord::Schema.define do
|
19
|
+
self.verbose = false
|
20
|
+
create_table :bases do |t|
|
21
|
+
t.column :name, :string
|
22
|
+
t.column :planet, :string
|
23
|
+
t.column :faction_id, :integer
|
24
|
+
end
|
25
|
+
end
|
31
26
|
|
32
|
-
|
33
|
-
|
34
|
-
name: "Wilhuff Tarkin",
|
35
|
-
friends: ["1001"],
|
36
|
-
appearsIn: [4],
|
37
|
-
})
|
27
|
+
class Base < ActiveRecord::Base
|
28
|
+
end
|
38
29
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
}
|
30
|
+
Base.create!(name: "Yavin", planet: "Yavin 4", faction_id: 1)
|
31
|
+
Base.create!(name: "Echo Base", planet: "Hoth", faction_id: 1)
|
32
|
+
Base.create!(name: "Secret Hideout", planet: "Dantooine", faction_id: 1)
|
33
|
+
Base.create!(name: "Death Star", planet: nil, faction_id: 2)
|
34
|
+
Base.create!(name: "Shield Generator", planet: "Endor", faction_id: 2)
|
35
|
+
Base.create!(name: "Headquarters", planet: "Coruscant", faction_id: 2)
|
46
36
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
37
|
+
# Also, set up Bases with Sequel
|
38
|
+
DB = Sequel.sqlite("./_test_.db")
|
39
|
+
class SequelBase < Sequel::Model(:bases)
|
40
|
+
end
|
41
|
+
|
42
|
+
rebels = OpenStruct.new({
|
43
|
+
id: '1',
|
44
|
+
name: 'Alliance to Restore the Republic',
|
45
|
+
ships: ['1', '2', '3', '4', '5'],
|
46
|
+
bases: Base.where(faction_id: 1),
|
47
|
+
basesClone: Base.where(faction_id: 1),
|
53
48
|
})
|
54
49
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
50
|
+
|
51
|
+
empire = OpenStruct.new({
|
52
|
+
id: '2',
|
53
|
+
name: 'Galactic Empire',
|
54
|
+
ships: ['6', '7', '8'],
|
55
|
+
bases: Base.where(faction_id: 2),
|
56
|
+
basesClone: Base.where(faction_id: 2),
|
61
57
|
})
|
62
58
|
|
63
|
-
|
64
|
-
"
|
65
|
-
|
59
|
+
STAR_WARS_DATA = {
|
60
|
+
"Faction" => {
|
61
|
+
"1" => rebels,
|
62
|
+
"2" => empire,
|
63
|
+
},
|
64
|
+
"Ship" => names.each_with_index.reduce({}) do |memo, (name, idx)|
|
65
|
+
id = (idx + 1).to_s
|
66
|
+
memo[id] = OpenStruct.new(name: name, id: id)
|
67
|
+
memo
|
68
|
+
end,
|
69
|
+
"Base" => Hash.new { |h, k| h[k] = Base.find(k) }
|
66
70
|
}
|
67
71
|
|
68
|
-
|
69
|
-
|
70
|
-
|
72
|
+
def STAR_WARS_DATA.create_ship(name, faction_id)
|
73
|
+
new_id = (self["Ship"].keys.map(&:to_i).max + 1).to_s
|
74
|
+
new_ship = OpenStruct.new(id: new_id, name: name)
|
75
|
+
self["Ship"][new_id] = new_ship
|
76
|
+
self["Faction"][faction_id]["ships"] << new_id
|
77
|
+
new_ship
|
71
78
|
end
|