graphql-preview 0.0.6 → 0.0.7

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cc975ff4b49ae763232e7658f510a8bac187efa2
4
- data.tar.gz: 779d52ef6311effa305f09154353f3996e0859d8
3
+ metadata.gz: 4dead6d1a5f54b189170b3d4da9cb77d4f31a9d3
4
+ data.tar.gz: 400454ff941ed04a48bf3ada71a45527c2f3764a
5
5
  SHA512:
6
- metadata.gz: 887ee46c24ca8613d3dc8af6b0b6ebc5212072dcf5d97b7a02babbb90ef28f4fe61fad47a7a83a6d71f5d93ca341f57444bc0ccbdc6df583ab8161eff968d3c9
7
- data.tar.gz: 44ac0b9b7ee55894cb044363bec954e326264bc8ce13bdca8998ed7899938b8af7830c234bb17d7d5d962044eb430a502b857ede3bab46114b8d53bd85a99f5c
6
+ metadata.gz: f18cea3be7ff3f17632e4a3cc302473025974f0cc72759f9d8971878076f901539ff116573b7b59d289e9d59899fbd5628f7b18f1d27e75e0c0a94eee2b9eb64
7
+ data.tar.gz: 6e6f0b25d10af928191be4e1ea08c01fe9f078db98121aa247d4552a3038585fa2fa6125085dcacb8ed8e46a900c76ff40ada8b58f0bbb58a4fceba577b464ad
data/README.md CHANGED
@@ -48,15 +48,15 @@ class TestPreview < GraphQLPreview::SchemaModification
48
48
 
49
49
  # The parts of your GraphQL schema you want toggled by this preview
50
50
  toggled_on [
51
- Library::Author, # an object
52
- Library::ExtraInfo, # an interface,
53
- Library::Author.fields["socialSecurityNumber"], # a field
54
- Library::Book.fields["author"].arguments["includeMiddleInitial"], # an argument
55
- Library::Likeable, # a union,
56
- Library::Cover, # an enum
57
- Library::Cover.values["DIGITAL"], # an enum value
58
- Library::BookOrder, # an input object
59
- Library::AddLike, # a mutation
51
+ "Author", # an object
52
+ "ExtraInfo", # an interface,
53
+ "Author.socialSecurityNumber", # a field
54
+ "Book.author.includeMiddleInitial", # an argument
55
+ "Likeable", # a union,
56
+ "Cover", # an enum
57
+ "Cover.DIGITAL", # an enum value
58
+ "BookOrder", # an input object
59
+ "Mutation.addLike", # a mutation
60
60
  ]
61
61
  end
62
62
  ```
@@ -66,6 +66,17 @@ end
66
66
  This gem introduces a new method to apply on your schema, `enabled_previews`. It takes an array,
67
67
  and you should pass in the list of preview classes you want enabled on your schema. For example:
68
68
 
69
+ ``` ruby
70
+ class Schema < GraphQL::Schema
71
+ query(query_type)
72
+ enabled_previews [
73
+ TestPreview
74
+ ]
75
+ end
76
+ ```
77
+
78
+ If you are using `graphql-ruby`'s `.define` DSL a similar API is provided:
79
+
69
80
  ``` ruby
70
81
  GraphQL::Schema.define do
71
82
  query(query_type)
@@ -2,10 +2,20 @@ require "graphql"
2
2
  require "graphql-preview/version"
3
3
  require "graphql-preview/schema_modification"
4
4
  require "graphql-preview/mask"
5
+ require "graphql-preview/member_from_path"
5
6
  require "graphql-preview/extensions/enabled_previews"
6
7
 
7
8
  module GraphQLPreview
9
+ def self.visible?(member, context:)
10
+ return true unless member.respond_to?(:metadata)
11
+ return true unless member.metadata[:preview_toggled_by]
8
12
 
13
+ unless context.key?(:schema_previews)
14
+ raise ArgumentError, "[GraphQLPreview] `:schema_previews` was not provided to the `context`"
15
+ end
16
+
17
+ context[:schema_previews].include?(member.metadata[:preview_toggled_by].toggled_by)
18
+ end
9
19
  end
10
20
 
11
21
  module GraphQL
@@ -9,11 +9,13 @@ module GraphQLPreview
9
9
  end
10
10
 
11
11
  previews.each do |preview|
12
- unless preview.ancestors.any? { |ancestor| ancestor == GraphQLPreview::SchemaModification }
13
- raise ArgumentError, "One of your `enabled_previews` items does not descend from `GraphQLPreview::SchemaModification`"
12
+ unless preview < GraphQLPreview::SchemaModification
13
+ raise ArgumentError, "Preview #{preview} must inherit from `GraphQLPreview::SchemaModification`"
14
14
  end
15
15
  end
16
16
 
17
+ previews.each { |preview| preview.apply_to_schema(self) }
18
+
17
19
  @enabled_previews = previews
18
20
  end
19
21
 
@@ -1,13 +1,7 @@
1
1
  module GraphQLPreview
2
2
  class Mask
3
3
  def self.call(member, context)
4
- return false unless member.respond_to?(:metadata)
5
- return false unless member.metadata.key?(:preview_toggled_by)
6
- unless context.key?(:schema_previews)
7
- raise ArgumentError, "You are using the `GraphQLPreview::Mask`, but key `:schema_previews` was not provided to the `context`"
8
- end
9
-
10
- !context[:schema_previews].include?(member.metadata[:preview_toggled_by].toggled_by)
4
+ !GraphQLPreview.visible?(member, context: context)
11
5
  end
12
6
  end
13
7
  end
@@ -0,0 +1,135 @@
1
+ module GraphQLPreview
2
+ class MemberFromPath
3
+ class MemberNotFoundError < ArgumentError; end
4
+
5
+ def initialize(schema)
6
+ @schema = schema
7
+ end
8
+
9
+ def find(path)
10
+ path = path.split(".")
11
+ type_or_directive = path.shift
12
+
13
+ if type_or_directive.start_with?("@")
14
+ directive = schema.directives[type_or_directive[1..-1]]
15
+
16
+ if directive.nil?
17
+ raise MemberNotFoundError, "Could not find directive `#{type_or_directive}` in schema."
18
+ end
19
+
20
+ return directive if path.empty?
21
+
22
+ find_in_directive(directive, path: path)
23
+ else
24
+ type = schema.types[type_or_directive]
25
+
26
+ if type.nil?
27
+ raise MemberNotFoundError, "Could not find type `#{type_or_directive}` in schema."
28
+ end
29
+
30
+ return type if path.empty?
31
+
32
+ find_in_type(type, path: path)
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ attr_reader :schema
39
+
40
+ def find_in_directive(directive, path:)
41
+ argument_name = path.shift
42
+ argument = directive.arguments[argument_name]
43
+
44
+ if argument.nil?
45
+ raise MemberNotFoundError, "Could not find argument `#{argument_name}` on directive #{directive}."
46
+ end
47
+
48
+ argument
49
+ end
50
+
51
+ def find_in_type(type, path:)
52
+ case type
53
+ when GraphQL::ObjectType
54
+ find_in_fields_type(type, kind: "object", path: path)
55
+ when GraphQL::InterfaceType
56
+ find_in_fields_type(type, kind: "interface", path: path)
57
+ when GraphQL::InputObjectType
58
+ find_in_input_object(type, path: path)
59
+ when GraphQL::UnionType
60
+ # Error out if path that was provided is too long
61
+ # i.e UnionType.PossibleType.aField
62
+ # Use PossibleType.aField instead.
63
+ if invalid = path.first
64
+ raise MemberNotFoundError, "Cannot select union possible type `#{invalid}`. Select the type directly instead."
65
+ end
66
+ when GraphQL::EnumType
67
+ find_in_enum_type(type, path: path)
68
+ end
69
+ end
70
+
71
+ def find_in_fields_type(type, kind:, path:)
72
+ field_name = path.shift
73
+ field = type.fields[field_name]
74
+
75
+ if field.nil?
76
+ raise MemberNotFoundError, "Could not find field `#{field_name}` on #{kind} type `#{type}`."
77
+ end
78
+
79
+ return field if path.empty?
80
+
81
+ find_in_field(field, path: path)
82
+ end
83
+
84
+ def find_in_field(field, path:)
85
+ argument_name = path.shift
86
+ argument = field.arguments[argument_name]
87
+
88
+ if argument.nil?
89
+ raise MemberNotFoundError, "Could not find argument `#{argument_name}` on field `#{field.name}`."
90
+ end
91
+
92
+ # Error out if path that was provided is too long
93
+ # i.e Type.field.argument.somethingBad
94
+ if invalid = path.first
95
+ raise MemberNotFoundError, "Cannot select member `#{invalid}` on a field."
96
+ end
97
+
98
+ argument
99
+ end
100
+
101
+ def find_in_input_object(input_object, path:)
102
+ field_name = path.shift
103
+ input_field = input_object.input_fields[field_name]
104
+
105
+ if input_field.nil?
106
+ raise MemberNotFoundError, "Could not find input field `#{field_name}` on input object type `#{input_object}`."
107
+ end
108
+
109
+ # Error out if path that was provided is too long
110
+ # i.e InputType.inputField.bad
111
+ if invalid = path.first
112
+ raise MemberNotFoundError, "Cannot select member `#{invalid}` on an input field."
113
+ end
114
+
115
+ input_field
116
+ end
117
+
118
+ def find_in_enum_type(enum_type, path:)
119
+ value_name = path.shift
120
+ enum_value = enum_type.values[value_name]
121
+
122
+ if enum_value.nil?
123
+ raise MemberNotFoundError, "Could not find enum value `#{value_name}` on enum type `#{enum_type}`."
124
+ end
125
+
126
+ # Error out if path that was provided is too long
127
+ # i.e Enum.VALUE.wat
128
+ if invalid = path.first
129
+ raise MemberNotFoundError, "Cannot select member `#{invalid}` on an enum value."
130
+ end
131
+
132
+ enum_value
133
+ end
134
+ end
135
+ end
@@ -59,34 +59,55 @@ module GraphQLPreview
59
59
  @updates
60
60
  end
61
61
 
62
- def self.toggled_on(types = nil)
63
- if types
64
- types.each do |type|
65
- unless type.respond_to?(:metadata)
66
- raise MethodError, "`#{type}` cannot have its metadata set"
67
- end
68
-
69
- if type.metadata.key?(:preview_toggled_by)
70
- raise ArgumentError, "Couldn't add `#{self.toggled_by}` to `#{type.name}`: it's already toggled with `#{type.metadata[:preview_toggled_by].toggled_by}`"
71
- end
72
-
73
- type.metadata[:preview_toggled_by] = self
74
-
75
- if type.is_a?(GraphQL::InterfaceType)
76
- mark_children(type)
62
+ def self.toggled_on(member_paths = nil)
63
+ if member_paths
64
+ member_paths.each do |path|
65
+ unless path.is_a?(String)
66
+ raise ArgumentError, "Provide string paths to `toggled_on`. For example, to toggle on a field called `name` on a type `Author`, use `\"Author.name\"``"
77
67
  end
78
68
  end
79
- @toggled_on = types
69
+
70
+ @member_paths = member_paths
80
71
  else
81
- @toggled_on
72
+ @member_paths
82
73
  end
83
74
  end
84
75
 
76
+ def self.unset(schema)
77
+ set_preview_toggled_by_on_members(schema, nil)
78
+ end
79
+
80
+ def self.apply_to_schema(schema)
81
+ set_preview_toggled_by_on_members(schema, self)
82
+ end
83
+
85
84
  private
86
85
 
87
- def self.mark_children(type)
88
- type.fields.each_value do |field|
89
- field.metadata[:preview_toggled_by] = self
86
+ def self.set_preview_toggled_by_on_members(schema, value)
87
+ member_from_path = GraphQLPreview::MemberFromPath.new(schema)
88
+ members = @member_paths.map { |path| member_from_path.find(path) }
89
+
90
+ members.each do |member|
91
+ unless member.respond_to?(:metadata)
92
+ raise NoMethodError, "`#{member}` cannot have its metadata set"
93
+ end
94
+
95
+ # unless we're unsetting the preview, don't allow adding a new value
96
+ if value && member.metadata[:preview_toggled_by]
97
+ raise ArgumentError, "Couldn't add `#{self.toggled_by}` to `#{member.name}`: it's already toggled with `#{member.metadata[:preview_toggled_by].toggled_by}`"
98
+ end
99
+
100
+ member.metadata[:preview_toggled_by] = value
101
+
102
+ if member.is_a?(GraphQL::InterfaceType)
103
+ member.fields.each_value do |field|
104
+ field.metadata[:preview_toggled_by] = value
105
+ end
106
+ end
107
+
108
+ if member.respond_to?(:mutation) && member.mutation
109
+ member.mutation.metadata[:preview_toggled_by] = value
110
+ end
90
111
  end
91
112
  end
92
113
  end
@@ -1,3 +1,3 @@
1
1
  module GraphQLPreview
2
- VERSION = "0.0.6"
2
+ VERSION = "0.0.7"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphql-preview
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Garen J. Torikian
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2018-01-10 00:00:00.000000000 Z
12
+ date: 2018-01-24 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: graphql
@@ -130,6 +130,7 @@ files:
130
130
  - lib/graphql-preview.rb
131
131
  - lib/graphql-preview/extensions/enabled_previews.rb
132
132
  - lib/graphql-preview/mask.rb
133
+ - lib/graphql-preview/member_from_path.rb
133
134
  - lib/graphql-preview/schema_modification.rb
134
135
  - lib/graphql-preview/version.rb
135
136
  - script/single_test