graphql 0.17.2 → 0.18.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphql.rb +1 -0
  3. data/lib/graphql/analysis/query_depth.rb +1 -1
  4. data/lib/graphql/base_type.rb +25 -1
  5. data/lib/graphql/define.rb +2 -0
  6. data/lib/graphql/define/assign_connection.rb +11 -0
  7. data/lib/graphql/define/assign_global_id_field.rb +11 -0
  8. data/lib/graphql/define/assign_object_field.rb +21 -20
  9. data/lib/graphql/define/defined_object_proxy.rb +2 -2
  10. data/lib/graphql/define/instance_definable.rb +13 -3
  11. data/lib/graphql/field.rb +1 -1
  12. data/lib/graphql/language/generation.rb +57 -6
  13. data/lib/graphql/language/lexer.rb +434 -212
  14. data/lib/graphql/language/lexer.rl +18 -0
  15. data/lib/graphql/language/nodes.rb +75 -0
  16. data/lib/graphql/language/parser.rb +853 -341
  17. data/lib/graphql/language/parser.y +114 -17
  18. data/lib/graphql/query.rb +15 -1
  19. data/lib/graphql/relay.rb +13 -0
  20. data/lib/graphql/relay/array_connection.rb +80 -0
  21. data/lib/graphql/relay/base_connection.rb +138 -0
  22. data/lib/graphql/relay/connection_field.rb +54 -0
  23. data/lib/graphql/relay/connection_type.rb +25 -0
  24. data/lib/graphql/relay/edge.rb +22 -0
  25. data/lib/graphql/relay/edge_type.rb +14 -0
  26. data/lib/graphql/relay/global_id_resolve.rb +15 -0
  27. data/lib/graphql/relay/global_node_identification.rb +124 -0
  28. data/lib/graphql/relay/mutation.rb +146 -0
  29. data/lib/graphql/relay/page_info.rb +13 -0
  30. data/lib/graphql/relay/relation_connection.rb +98 -0
  31. data/lib/graphql/schema.rb +3 -0
  32. data/lib/graphql/schema/printer.rb +12 -2
  33. data/lib/graphql/static_validation/message.rb +9 -5
  34. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
  35. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +1 -1
  36. data/lib/graphql/static_validation/rules/directives_are_defined.rb +3 -3
  37. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +7 -7
  38. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +4 -4
  39. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +5 -5
  40. data/lib/graphql/static_validation/rules/fields_will_merge.rb +6 -6
  41. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +17 -9
  42. data/lib/graphql/static_validation/rules/fragment_types_exist.rb +1 -1
  43. data/lib/graphql/static_validation/rules/fragments_are_finite.rb +1 -1
  44. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +1 -1
  45. data/lib/graphql/static_validation/rules/fragments_are_used.rb +17 -6
  46. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +1 -1
  47. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +2 -2
  48. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +5 -5
  49. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +1 -1
  50. data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +12 -11
  51. data/lib/graphql/static_validation/type_stack.rb +33 -2
  52. data/lib/graphql/static_validation/validation_context.rb +5 -0
  53. data/lib/graphql/version.rb +1 -1
  54. data/readme.md +16 -4
  55. data/spec/graphql/analysis/analyze_query_spec.rb +31 -2
  56. data/spec/graphql/analysis/query_complexity_spec.rb +24 -0
  57. data/spec/graphql/argument_spec.rb +1 -1
  58. data/spec/graphql/define/instance_definable_spec.rb +9 -0
  59. data/spec/graphql/field_spec.rb +1 -1
  60. data/spec/graphql/internal_representation/rewrite_spec.rb +3 -3
  61. data/spec/graphql/language/generation_spec.rb +25 -4
  62. data/spec/graphql/language/parser_spec.rb +116 -1
  63. data/spec/graphql/query_spec.rb +10 -0
  64. data/spec/graphql/relay/array_connection_spec.rb +164 -0
  65. data/spec/graphql/relay/connection_type_spec.rb +37 -0
  66. data/spec/graphql/relay/global_node_identification_spec.rb +149 -0
  67. data/spec/graphql/relay/mutation_spec.rb +55 -0
  68. data/spec/graphql/relay/page_info_spec.rb +106 -0
  69. data/spec/graphql/relay/relation_connection_spec.rb +348 -0
  70. data/spec/graphql/schema/printer_spec.rb +8 -0
  71. data/spec/graphql/schema/reduce_types_spec.rb +1 -1
  72. data/spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb +12 -6
  73. data/spec/graphql/static_validation/rules/arguments_are_defined_spec.rb +8 -4
  74. data/spec/graphql/static_validation/rules/directives_are_defined_spec.rb +4 -2
  75. data/spec/graphql/static_validation/rules/directives_are_in_valid_locations_spec.rb +4 -2
  76. data/spec/graphql/static_validation/rules/fields_are_defined_on_type_spec.rb +7 -2
  77. data/spec/graphql/static_validation/rules/fields_have_appropriate_selections_spec.rb +4 -2
  78. data/spec/graphql/static_validation/rules/fragment_spreads_are_possible_spec.rb +6 -3
  79. data/spec/graphql/static_validation/rules/fragment_types_exist_spec.rb +5 -3
  80. data/spec/graphql/static_validation/rules/fragments_are_finite_spec.rb +4 -2
  81. data/spec/graphql/static_validation/rules/fragments_are_on_composite_types_spec.rb +5 -2
  82. data/spec/graphql/static_validation/rules/fragments_are_used_spec.rb +10 -2
  83. data/spec/graphql/static_validation/rules/required_arguments_are_present_spec.rb +6 -3
  84. data/spec/graphql/static_validation/rules/variable_default_values_are_correctly_typed_spec.rb +8 -4
  85. data/spec/graphql/static_validation/rules/variable_usages_are_allowed_spec.rb +8 -4
  86. data/spec/graphql/static_validation/rules/variables_are_input_types_spec.rb +6 -3
  87. data/spec/graphql/static_validation/rules/variables_are_used_and_defined_spec.rb +6 -3
  88. data/spec/spec_helper.rb +7 -0
  89. data/spec/support/dairy_app.rb +11 -10
  90. data/spec/support/star_wars_data.rb +65 -58
  91. data/spec/support/star_wars_schema.rb +192 -54
  92. 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
- {"message"=>"Field 'amountThatILikeIt' doesn't exist on type 'Edible'", "locations"=>[{"line"=>1, "column"=>18}]}
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
- cheeese(id: 1) {
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, {"message"=>"Fragment unusedFields was defined, but not used", "locations"=>[{"line"=>8, "column"=>5}]})
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, {"message"=>"Fragment undefinedFields was used, but not defined", "locations"=>[{"line"=>5, "column"=>7}]})
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
@@ -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)
@@ -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
@@ -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: :nonsense do
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
- field :fatContent, property: :fat_content do
65
- type(!GraphQL::FLOAT_TYPE)
66
- description("Percentage which is milkfat")
67
- deprecation_reason("Diet fashion has changed")
68
- end
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
- QueryType = GraphQL::ObjectType.define do
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
- MutationType = GraphQL::ObjectType.define do
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: QueryType,
310
- mutation: MutationType,
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
- vader = OpenStruct.new({
10
- id: "1001",
11
- name: "Darth Vader",
12
- friends: ["1004"],
13
- appearsIn: [4, 5, 6],
14
- homePlanet: "Tatooine",
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
- han = OpenStruct.new({
18
- id: "1002",
19
- name: "Han Solo",
20
- friends: ["1000", "1003", "2001"],
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
- leia = OpenStruct.new({
25
- id: "1003",
26
- name: "Leia Organa",
27
- friends: ["1000", "1002", "2000", "2001"],
28
- appearsIn: [4, 5, 6],
29
- homePlanet: "Alderaan",
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
- tarkin = OpenStruct.new({
33
- id: "1004",
34
- name: "Wilhuff Tarkin",
35
- friends: ["1001"],
36
- appearsIn: [4],
37
- })
27
+ class Base < ActiveRecord::Base
28
+ end
38
29
 
39
- HUMAN_DATA = {
40
- "1000" => luke,
41
- "1001" => vader,
42
- "1002" => han,
43
- "1003" => leia,
44
- "1004" => tarkin,
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
- threepio = OpenStruct.new({
48
- id: "2000",
49
- name: "C-3PO",
50
- friends: ["1000", "1002", "1003", "2001"],
51
- appearsIn: [4, 5, 6],
52
- primaryFunction: "Protocol",
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
- artoo = OpenStruct.new({
56
- id: "2001",
57
- name: "R2-D2",
58
- friends: ["1000", "1002", "1003"],
59
- appearsIn: [4, 5, 6],
60
- primaryFunction: "Astromech",
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
- DROID_DATA = {
64
- "2000" => threepio,
65
- "2001" => artoo,
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
- # Get friends from IDs
69
- GET_FRIENDS = -> (obj, args, ctx) do
70
- obj.friends.map { |id| HUMAN_DATA[id] || DROID_DATA[id]}
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