gqli 0.3.0 → 0.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a2253633cb84598f7d7150f620b9161152c0c5961c92124ea2d517e97e7452b7
4
- data.tar.gz: 84ceda416865f6295632b9044eeeeaeba29b24822a988a45e3cf8e1e6f85bfa9
3
+ metadata.gz: 972ad0f4a3e57ffe7e87a9492805b5d206ff0825ac335dbbf4a24b4981aed375
4
+ data.tar.gz: d60e39618526584c5291bfe1fa050e1639cc458e01d1038bb62e88693764c833
5
5
  SHA512:
6
- metadata.gz: 298ecee49c25bca164942b594298fefe8ddd23d3757cac7ef3a5bd1c725aa4ee72be6ef583adf35469ff28f6a3d42bd9a7ec3ded93d76542109a35eda803ced4
7
- data.tar.gz: bc5e10415ab97c885a816e856e5b2da73f18e3e49d6c34d81933f5bc80b6841b1be15c4596193cd270ac82bc51e2e5af4e59a99bd788ee2a692fd46f9ef5144c
6
+ metadata.gz: 40b7e0a94c6c543993131280bb00dc56e9d7600c9dc698970f66ccb3ff67613820c35199d60f74d7c2ec75417f52bd73ce528b9263193b70ed7e5a6498bc835f
7
+ data.tar.gz: 00c23e2e51019bcf85a608507062d0fb46662b008674e09c546aa6151bedbb45d3c4098fd0e7fcc247d39794d96315003544429a9dd097dda172bec6ee2f36d1
@@ -29,3 +29,6 @@ Style/MutableConstant:
29
29
 
30
30
  Style/SignalException:
31
31
  EnforcedStyle: 'semantic'
32
+
33
+ Style/DoubleNegation:
34
+ Enabled: false
@@ -2,6 +2,10 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## v0.4.0
6
+ ### Added
7
+ * Add directive support.
8
+
5
9
  ## v0.3.0
6
10
  ### Added
7
11
  * Refactored validations to their own `Validation` class, which now provide better error messages upon validation failure.
data/README.md CHANGED
@@ -291,6 +291,34 @@ query = GQLi::DSL.query {
291
291
  }
292
292
  ```
293
293
 
294
+ ### Directives
295
+
296
+ In GraphQL, nodes can be selectively included or removed by the usage of directives, there are 2 directives available for the querying specification to do this: `@include` and `@skip`.
297
+
298
+ ```ruby
299
+ query = GQLi::DSL.query {
300
+ someNode(:@include => {if: object.includes_some_node?})
301
+ }
302
+ ```
303
+
304
+ This will get transformed to:
305
+
306
+ ```graphql
307
+ query {
308
+ someNode @include(if: true) # or false
309
+ }
310
+ ```
311
+
312
+ This behaviour is equivalent to using native Ruby to include/exclude a field from the query:
313
+
314
+ ```ruby
315
+ query = GQLi::DSL.query {
316
+ someNode if object.includes_some_node?
317
+ }
318
+ ```
319
+
320
+ The difference is that by using the native implementation, in case of the condition not being met, the node will be completely not included in the outgoing query.
321
+
294
322
  ## Yet to be implemented
295
323
 
296
324
  * Mutation queries
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GQLi
4
+ # Wrapper for Enum values
5
+ class EnumValue
6
+ attr_reader :value
7
+
8
+ def initialize(value)
9
+ @value = value
10
+ end
11
+
12
+ # Serializes the enum value to string
13
+ def to_s
14
+ value
15
+ end
16
+ end
17
+ end
@@ -15,7 +15,7 @@ module GQLi
15
15
  # Serializes to a GraphQL string
16
16
  def to_gql
17
17
  result = ' ' * __depth + __name
18
- result += '(' + __params_to_s(__params, true) + ')' unless __params.empty?
18
+ result += __params_to_s(__params, true) unless __params.empty?
19
19
  unless __nodes.empty?
20
20
  result += " {\n"
21
21
  result += __nodes.map(&:to_gql).join("\n")
@@ -27,14 +27,27 @@ module GQLi
27
27
 
28
28
  private
29
29
 
30
+ def __directive?(params)
31
+ params.size == 1 && params.keys.first.to_s.start_with?('@')
32
+ end
33
+
34
+ def __directive(params)
35
+ params.first.tap do |directive, directive_params|
36
+ return " #{directive}#{__params_to_s(directive_params, true)}"
37
+ end
38
+ end
39
+
30
40
  def __params_to_s(params, initial = false)
31
41
  case params
32
42
  when ::Hash
43
+ return __directive(params) if __directive?(params)
44
+
33
45
  result = params.map do |k, v|
34
46
  "#{k}: #{__params_to_s(v)}"
35
47
  end.join(', ')
36
48
 
37
- return result if initial
49
+ return "(#{result})" if initial
50
+
38
51
  "{#{result}}"
39
52
  when ::Array
40
53
  "[#{params.map { |p| __params_to_s(p) }.join(', ')}]"
@@ -44,7 +44,7 @@ module GQLi
44
44
  end
45
45
 
46
46
  def validate_node(parent_type, node)
47
- return if parent_type.kind == 'SCALAR'
47
+ validate_directives(node)
48
48
 
49
49
  return valid_match_node?(parent_type, node) if node.__name.start_with?('... on')
50
50
 
@@ -66,8 +66,26 @@ module GQLi
66
66
  fail "Match type '#{node.__name.gsub('... on ', '')}' invalid"
67
67
  end
68
68
 
69
+ def validate_directives(node)
70
+ return unless node.__params.size == 1
71
+ node.__params.first.tap do |k, v|
72
+ break unless k.to_s.start_with?('@')
73
+
74
+ fail "Directive unknown '#{k}'" unless %i[@include @skip].include?(k)
75
+ fail "Missing arguments for directive '#{k}'" if v.nil? || !v.is_a?(::Hash) || v.empty?
76
+ v.each do |arg, value|
77
+ begin
78
+ fail "Invalid argument '#{arg}' for directive '#{k}'" if arg.to_s != 'if'
79
+ fail "Invalid value for 'if`, must be a boolean" if value != !!value
80
+ rescue StandardError => e
81
+ errors << e
82
+ end
83
+ end
84
+ end
85
+ end
86
+
69
87
  def validate_params(node_type, node)
70
- node.__params.each do |param, value|
88
+ node.__params.reject { |p, _| p.to_s.start_with?('@') }.each do |param, value|
71
89
  begin
72
90
  arg = node_type.fetch('args', []).find { |a| a.name == param.to_s }
73
91
  fail "Invalid argument '#{param}'" if arg.nil?
@@ -3,5 +3,5 @@
3
3
  # GraphQL Client and DSL library
4
4
  module GQLi
5
5
  # Gem version
6
- VERSION = '0.3.0'
6
+ VERSION = '0.4.0'
7
7
  end
@@ -116,6 +116,20 @@ describe GQLi::DSL do
116
116
  GRAPHQL
117
117
  end
118
118
 
119
+ it 'nodes can have directives' do
120
+ query = subject.query {
121
+ someNode(:@include => {if: true})
122
+ otherNode(:@skip => {if: false})
123
+ }
124
+
125
+ expect(query.to_gql).to eq <<~GRAPHQL
126
+ query {
127
+ someNode @include(if: true)
128
+ otherNode @skip(if: false)
129
+ }
130
+ GRAPHQL
131
+ end
132
+
119
133
  it 'nodes can have arbitrarily nested nodes' do
120
134
  query = subject.query {
121
135
  aNode {
@@ -155,5 +155,98 @@ describe GQLi::Introspection do
155
155
  expect(validation.errors).not_to be_empty
156
156
  expect(validation.errors.map(&:to_s)).to include("Value is 'String, Enum or ID', but should be 'Int' for 'limit'")
157
157
  end
158
+
159
+ describe 'directives' do
160
+ it 'can create a query with a directive and validations should not fail' do
161
+ query = dsl.query {
162
+ catCollection {
163
+ items {
164
+ name(:@include => { if: true })
165
+ }
166
+ }
167
+ }
168
+
169
+ validation = subject.validate(query)
170
+ expect(validation.valid?).to be_truthy
171
+ end
172
+
173
+ it 'unknown directives will fail' do
174
+ query = dsl.query {
175
+ catCollection(:@unknownDirective => nil)
176
+ }
177
+
178
+ validation = subject.validate(query)
179
+ expect(validation.valid?).to be_falsey
180
+ expect(validation.errors).not_to be_empty
181
+ expect(validation.errors.map(&:to_s)).to include("Directive unknown '@unknownDirective'")
182
+ end
183
+
184
+ it 'known directive will fail if no arguments are passed' do
185
+ query = dsl.query {
186
+ catCollection(:@include => nil)
187
+ }
188
+
189
+ validation = subject.validate(query)
190
+ expect(validation.valid?).to be_falsey
191
+ expect(validation.errors).not_to be_empty
192
+ expect(validation.errors.map(&:to_s)).to include("Missing arguments for directive '@include'")
193
+ end
194
+
195
+ it 'known directive will fail if arguments are empty' do
196
+ query = dsl.query {
197
+ catCollection(:@include => {})
198
+ }
199
+
200
+ validation = subject.validate(query)
201
+ expect(validation.valid?).to be_falsey
202
+ expect(validation.errors).not_to be_empty
203
+ expect(validation.errors.map(&:to_s)).to include("Missing arguments for directive '@include'")
204
+ end
205
+
206
+ it 'known directive will fail if arguments is not if' do
207
+ query = dsl.query {
208
+ catCollection {
209
+ items {
210
+ name(:@include => { else: true })
211
+ }
212
+ }
213
+ }
214
+
215
+ validation = subject.validate(query)
216
+ expect(validation.valid?).to be_falsey
217
+ expect(validation.errors).not_to be_empty
218
+ expect(validation.errors.map(&:to_s)).to include("Invalid argument 'else' for directive '@include'")
219
+ end
220
+
221
+ it 'known directive will fail when if value is not boolean' do
222
+ query = dsl.query {
223
+ catCollection {
224
+ items {
225
+ name(:@include => { if: 123 })
226
+ }
227
+ }
228
+ }
229
+
230
+ validation = subject.validate(query)
231
+ expect(validation.valid?).to be_falsey
232
+ expect(validation.errors).not_to be_empty
233
+ expect(validation.errors.map(&:to_s)).to include("Invalid value for 'if`, must be a boolean")
234
+ end
235
+
236
+ it 'known directive will fail when multiple arguments are passed' do
237
+ query = dsl.query {
238
+ catCollection {
239
+ items {
240
+ name(:@include => { if: true, else: false })
241
+ }
242
+ }
243
+ }
244
+
245
+ validation = subject.validate(query)
246
+ expect(validation.valid?).to be_falsey
247
+ expect(validation.errors).not_to be_empty
248
+ expect(validation.errors.map(&:to_s)).to include("Invalid argument 'else' for directive '@include'")
249
+ end
250
+ end
158
251
  end
159
252
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gqli
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Contentful GmbH (David Litvak Bruno)
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-10-19 00:00:00.000000000 Z
11
+ date: 2018-11-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: http
@@ -311,6 +311,7 @@ files:
311
311
  - doc/GQLi/Base.html
312
312
  - doc/GQLi/Client.html
313
313
  - doc/GQLi/DSL.html
314
+ - doc/GQLi/EnumValue.html
314
315
  - doc/GQLi/Fragment.html
315
316
  - doc/GQLi/Introspection.html
316
317
  - doc/GQLi/Node.html
@@ -338,6 +339,7 @@ files:
338
339
  - lib/gqli/base.rb
339
340
  - lib/gqli/client.rb
340
341
  - lib/gqli/dsl.rb
342
+ - lib/gqli/enum_value.rb
341
343
  - lib/gqli/fragment.rb
342
344
  - lib/gqli/introspection.rb
343
345
  - lib/gqli/node.rb