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.
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