gqli 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -0
- data/CHANGELOG.md +4 -0
- data/README.md +28 -0
- data/lib/gqli/enum_value.rb +17 -0
- data/lib/gqli/node.rb +15 -2
- data/lib/gqli/validation.rb +20 -2
- data/lib/gqli/version.rb +1 -1
- data/spec/lib/gqli/dsl_spec.rb +14 -0
- data/spec/lib/gqli/introspection_spec.rb +93 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 972ad0f4a3e57ffe7e87a9492805b5d206ff0825ac335dbbf4a24b4981aed375
|
4
|
+
data.tar.gz: d60e39618526584c5291bfe1fa050e1639cc458e01d1038bb62e88693764c833
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 40b7e0a94c6c543993131280bb00dc56e9d7600c9dc698970f66ccb3ff67613820c35199d60f74d7c2ec75417f52bd73ce528b9263193b70ed7e5a6498bc835f
|
7
|
+
data.tar.gz: 00c23e2e51019bcf85a608507062d0fb46662b008674e09c546aa6151bedbb45d3c4098fd0e7fcc247d39794d96315003544429a9dd097dda172bec6ee2f36d1
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
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
|
data/lib/gqli/node.rb
CHANGED
@@ -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 +=
|
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(', ')}]"
|
data/lib/gqli/validation.rb
CHANGED
@@ -44,7 +44,7 @@ module GQLi
|
|
44
44
|
end
|
45
45
|
|
46
46
|
def validate_node(parent_type, node)
|
47
|
-
|
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?
|
data/lib/gqli/version.rb
CHANGED
data/spec/lib/gqli/dsl_spec.rb
CHANGED
@@ -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.
|
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-
|
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
|