graphlient 0.7.0 → 0.9.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 +4 -4
- data/.github/ISSUE_TEMPLATE/bug_report.md +38 -38
- data/.github/ISSUE_TEMPLATE/feature_request.md +20 -20
- data/.github/workflows/ci.yml +33 -29
- data/.github/workflows/danger-comment.yml +10 -0
- data/.github/workflows/danger.yml +13 -22
- data/.github/workflows/rubocop.yml +19 -19
- data/.gitignore +59 -52
- data/.rspec +1 -1
- data/.rubocop.yml +26 -28
- data/.rubocop_todo.yml +72 -48
- data/CHANGELOG.md +128 -107
- data/CONTRIBUTING.md +125 -125
- data/Dangerfile +24 -24
- data/Gemfile +35 -27
- data/LICENSE +21 -21
- data/README.md +800 -508
- data/RELEASING.md +63 -63
- data/Rakefile +15 -15
- data/UPGRADING.md +23 -23
- data/graphlient.gemspec +19 -19
- data/lib/graphlient/adapters/http/adapter.rb +41 -41
- data/lib/graphlient/adapters/http/faraday_adapter.rb +79 -45
- data/lib/graphlient/adapters/http/http_adapter.rb +40 -39
- data/lib/graphlient/adapters/http.rb +3 -3
- data/lib/graphlient/adapters.rb +1 -1
- data/lib/graphlient/client.rb +98 -73
- data/lib/graphlient/errors/client_error.rb +6 -6
- data/lib/graphlient/errors/connection_failed_error.rb +6 -6
- data/lib/graphlient/errors/error.rb +13 -12
- data/lib/graphlient/errors/execution_error.rb +29 -29
- data/lib/graphlient/errors/faraday_server_error.rb +12 -12
- data/lib/graphlient/errors/graphql_error.rb +53 -52
- data/lib/graphlient/errors/http_options_error.rb +6 -6
- data/lib/graphlient/errors/http_server_error.rb +13 -13
- data/lib/graphlient/errors/server_error.rb +7 -7
- data/lib/graphlient/errors/timeout_error.rb +6 -6
- data/lib/graphlient/errors.rb +10 -10
- data/lib/graphlient/extensions/query.rb +15 -15
- data/lib/graphlient/extensions.rb +1 -1
- data/lib/graphlient/query/directive.rb +47 -0
- data/lib/graphlient/query/serializer/arguments.rb +67 -0
- data/lib/graphlient/query/serializer/directives.rb +17 -0
- data/lib/graphlient/query/serializer/evaluator.rb +15 -0
- data/lib/graphlient/query/serializer/fragments.rb +28 -0
- data/lib/graphlient/query/serializer/scalars.rb +63 -0
- data/lib/graphlient/query/serializer.rb +153 -0
- data/lib/graphlient/query.rb +29 -128
- data/lib/graphlient/schema.rb +27 -26
- data/lib/graphlient/version.rb +3 -3
- data/lib/graphlient.rb +8 -8
- data/spec/graphlient/adapters/http/faraday_adapter_spec.rb +172 -112
- data/spec/graphlient/adapters/http/http_adapter_spec.rb +60 -60
- data/spec/graphlient/client_dsl_spec.rb +153 -0
- data/spec/graphlient/client_query_spec.rb +369 -346
- data/spec/graphlient/client_schema_spec.rb +75 -55
- data/spec/graphlient/extensions/query_spec.rb +16 -16
- data/spec/graphlient/github_query_spec.rb +32 -32
- data/spec/graphlient/query_dsl_spec.rb +231 -0
- data/spec/graphlient/query_spec.rb +105 -105
- data/spec/graphlient/schema_spec.rb +56 -56
- data/spec/graphlient/static_client_query_spec.rb +75 -68
- data/spec/graphlient/webmock_client_query_spec.rb +41 -41
- data/spec/spec_helper.rb +26 -14
- data/spec/support/context/dummy_client.rb +33 -26
- data/spec/support/context/github_client.rb +18 -18
- data/spec/support/dummy_app.rb +21 -19
- data/spec/support/dummy_schema.rb +17 -17
- data/spec/support/fixtures/github/schema.yml +14282 -14282
- data/spec/support/fixtures/github/user.yml +76 -76
- data/spec/support/fixtures/github/viewer.yml +76 -76
- data/spec/support/fixtures/invoice_api.json +1288 -1288
- data/spec/support/mutations/create_invoice.rb +18 -18
- data/spec/support/queries/query.rb +48 -47
- data/spec/support/schema/github.json +44479 -44479
- data/spec/support/types/invoice_type.rb +13 -13
- data/spec/support/types/mutation_type.rb +5 -5
- data/spec/support/vcr.rb +9 -9
- metadata +13 -8
- data/Gemfile.danger +0 -5
|
@@ -1,55 +1,75 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
require 'tempfile'
|
|
3
|
-
|
|
4
|
-
describe Graphlient::Client do
|
|
5
|
-
let(:client) { described_class.new(url) }
|
|
6
|
-
let(:url) { 'http://graph.biz/graphql' }
|
|
7
|
-
|
|
8
|
-
describe '#schema' do
|
|
9
|
-
before do
|
|
10
|
-
stub_request(:post, url).to_return(
|
|
11
|
-
body: DummySchema.execute(GraphQL::Introspection::INTROSPECTION_QUERY).to_json,
|
|
12
|
-
headers: { 'Content-Type' => 'application/json' }
|
|
13
|
-
)
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
context 'when server returns error' do
|
|
17
|
-
before do
|
|
18
|
-
stub_request(:post, url).to_return(
|
|
19
|
-
status: 500,
|
|
20
|
-
body: {
|
|
21
|
-
errors: [
|
|
22
|
-
{ message: 'test message', extensions: { code: 'SOMETHING', timestamp: Time.now } }
|
|
23
|
-
]
|
|
24
|
-
}.to_json,
|
|
25
|
-
headers: { 'Content-Type' => 'application/json' }
|
|
26
|
-
)
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
it 'fails with an exception' do
|
|
30
|
-
expect do
|
|
31
|
-
client.schema
|
|
32
|
-
end.to raise_error Graphlient::Errors::FaradayServerError do |e|
|
|
33
|
-
expect(e.to_s).to
|
|
34
|
-
expect(e.status_code).to eq 500
|
|
35
|
-
expect(e.response['errors'].size).to eq 1
|
|
36
|
-
expect(e.response['errors'].first['message']).to eq 'test message'
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
context 'when introspection request is sucessfull' do
|
|
42
|
-
it 'returns Graphlient::Schema instance' do
|
|
43
|
-
expect(client.schema).to be_a(Graphlient::Schema)
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
context 'when schema path option is not String' do
|
|
48
|
-
let(:client) { described_class.new(url, schema_path: Pathname.new('config/schema.json')) }
|
|
49
|
-
|
|
50
|
-
it 'converts path to string' do
|
|
51
|
-
expect(client.schema.path).to eq 'config/schema.json'
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'tempfile'
|
|
3
|
+
|
|
4
|
+
describe Graphlient::Client do
|
|
5
|
+
let(:client) { described_class.new(url) }
|
|
6
|
+
let(:url) { 'http://graph.biz/graphql' }
|
|
7
|
+
|
|
8
|
+
describe '#schema' do
|
|
9
|
+
before do
|
|
10
|
+
stub_request(:post, url).to_return(
|
|
11
|
+
body: DummySchema.execute(GraphQL::Introspection::INTROSPECTION_QUERY).to_json,
|
|
12
|
+
headers: { 'Content-Type' => 'application/json' }
|
|
13
|
+
)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
context 'when server returns error' do
|
|
17
|
+
before do
|
|
18
|
+
stub_request(:post, url).to_return(
|
|
19
|
+
status: 500,
|
|
20
|
+
body: {
|
|
21
|
+
errors: [
|
|
22
|
+
{ message: 'test message', extensions: { code: 'SOMETHING', timestamp: Time.now } }
|
|
23
|
+
]
|
|
24
|
+
}.to_json,
|
|
25
|
+
headers: { 'Content-Type' => 'application/json' }
|
|
26
|
+
)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it 'fails with an exception' do
|
|
30
|
+
expect do
|
|
31
|
+
client.schema
|
|
32
|
+
end.to raise_error Graphlient::Errors::FaradayServerError do |e|
|
|
33
|
+
expect(e.to_s).to include('the server responded with status 500')
|
|
34
|
+
expect(e.status_code).to eq 500
|
|
35
|
+
expect(e.response['errors'].size).to eq 1
|
|
36
|
+
expect(e.response['errors'].first['message']).to eq 'test message'
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
context 'when introspection request is sucessfull' do
|
|
42
|
+
it 'returns Graphlient::Schema instance' do
|
|
43
|
+
expect(client.schema).to be_a(Graphlient::Schema)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
context 'when schema path option is not String' do
|
|
48
|
+
let(:client) { described_class.new(url, schema_path: Pathname.new('config/schema.json')) }
|
|
49
|
+
|
|
50
|
+
it 'converts path to string' do
|
|
51
|
+
expect(client.schema.path).to eq 'config/schema.json'
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
context 'when preloaded schema is provided' do
|
|
56
|
+
let(:schema) { Graphlient::Schema.new(url, 'spec/support/fixtures/invoice_api.json') }
|
|
57
|
+
let(:client) { described_class.new(url, schema: schema) }
|
|
58
|
+
|
|
59
|
+
it 'returns the passed in schema' do
|
|
60
|
+
expect(client.schema).not_to be_nil
|
|
61
|
+
expect(client.schema).to eq(schema)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
context 'when and a schema and a schema path are provided' do
|
|
66
|
+
let(:schema) { Graphlient::Schema.new(url, 'spec/support/fixtures/invoice_api.json') }
|
|
67
|
+
let(:client) { described_class.new(url, schema: schema, schema_path: 'spec/support/fixtures/invoice_api.json') }
|
|
68
|
+
|
|
69
|
+
it 'raises an invalid configuration error' do
|
|
70
|
+
expect { client }.to raise_error(Graphlient::Client::InvalidConfigurationError,
|
|
71
|
+
/schema_path and schema cannot both be provided/)
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
|
|
3
|
-
describe Graphlient::Extensions::Query do
|
|
4
|
-
describe 'Query' do
|
|
5
|
-
include Graphlient::Extensions::Query
|
|
6
|
-
|
|
7
|
-
it 'returns correct query' do
|
|
8
|
-
query = query do
|
|
9
|
-
invoice(id: 10) do
|
|
10
|
-
line_items
|
|
11
|
-
end
|
|
12
|
-
end
|
|
13
|
-
expect(query.to_s).to eq("query{\n invoice(id: 10){\n line_items\n }\n }")
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
end
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Graphlient::Extensions::Query do
|
|
4
|
+
describe 'Query' do
|
|
5
|
+
include Graphlient::Extensions::Query
|
|
6
|
+
|
|
7
|
+
it 'returns correct query' do
|
|
8
|
+
query = query do
|
|
9
|
+
invoice(id: 10) do
|
|
10
|
+
line_items
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
expect(query.to_s).to eq("query{\n invoice(id: 10){\n line_items\n }\n }")
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -1,32 +1,32 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
|
|
3
|
-
describe Graphlient::Client do
|
|
4
|
-
include_context 'Github Client'
|
|
5
|
-
|
|
6
|
-
it 'has a schema', vcr: { cassette_name: 'github/schema' } do
|
|
7
|
-
expect(client.schema).to be_a Graphlient::Schema
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
it 'queries current user', vcr: { cassette_name: 'github/viewer' } do
|
|
11
|
-
rc = client.query <<-GRAPHQL
|
|
12
|
-
query {
|
|
13
|
-
viewer {
|
|
14
|
-
name
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
GRAPHQL
|
|
18
|
-
expect(rc.data.viewer.name).to eq 'Daniel Doubrovkine (dB.) @dblockdotorg'
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
it 'queries with a parameter', vcr: { cassette_name: 'github/user' } do
|
|
22
|
-
query = <<-GRAPHQL
|
|
23
|
-
query($login: String!) {
|
|
24
|
-
user(login: $login) {
|
|
25
|
-
name
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
GRAPHQL
|
|
29
|
-
rc = client.query query, login: 'orta'
|
|
30
|
-
expect(rc.data.user.name).to eq 'Orta'
|
|
31
|
-
end
|
|
32
|
-
end
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Graphlient::Client do
|
|
4
|
+
include_context 'Github Client'
|
|
5
|
+
|
|
6
|
+
it 'has a schema', vcr: { cassette_name: 'github/schema' } do
|
|
7
|
+
expect(client.schema).to be_a Graphlient::Schema
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it 'queries current user', vcr: { cassette_name: 'github/viewer' } do
|
|
11
|
+
rc = client.query <<-GRAPHQL
|
|
12
|
+
query {
|
|
13
|
+
viewer {
|
|
14
|
+
name
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
GRAPHQL
|
|
18
|
+
expect(rc.data.viewer.name).to eq 'Daniel Doubrovkine (dB.) @dblockdotorg'
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it 'queries with a parameter', vcr: { cassette_name: 'github/user' } do
|
|
22
|
+
query = <<-GRAPHQL
|
|
23
|
+
query($login: String!) {
|
|
24
|
+
user(login: $login) {
|
|
25
|
+
name
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
GRAPHQL
|
|
29
|
+
rc = client.query query, login: 'orta'
|
|
30
|
+
expect(rc.data.user.name).to eq 'Orta'
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
# Specs for DSL extensions: directives, inline fragments, fragment definitions,
|
|
4
|
+
# spread + directive, and custom scalar registration.
|
|
5
|
+
# These operate on the Query string builder only -- no HTTP or schema access.
|
|
6
|
+
|
|
7
|
+
RSpec.describe Graphlient::Query do
|
|
8
|
+
def build(&block)
|
|
9
|
+
described_class.new(&block).to_s
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# --- Directives -----------------------------------------------------------
|
|
13
|
+
|
|
14
|
+
describe 'directives (_name convention → @name)' do
|
|
15
|
+
it 'applies @skip to a field' do
|
|
16
|
+
result = build do
|
|
17
|
+
query(skip_fee: :boolean!) do
|
|
18
|
+
invoice(id: 10) do
|
|
19
|
+
id
|
|
20
|
+
feeInCents _skip(if: :skip_fee)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
expect(result).to include('@skip(if: $skip_fee)')
|
|
25
|
+
expect(result).to include('feeInCents @skip(if: $skip_fee)')
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it 'applies @include to a field' do
|
|
29
|
+
result = build do
|
|
30
|
+
query(show_fee: :boolean!) do
|
|
31
|
+
invoice(id: 10) do
|
|
32
|
+
feeInCents _include(if: :show_fee)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
expect(result).to include('feeInCents @include(if: $show_fee)')
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it 'applies multiple directives to one field' do
|
|
40
|
+
result = build do
|
|
41
|
+
query(skip_fee: :boolean!, show_desc: :boolean!) do
|
|
42
|
+
invoice(id: 10) do
|
|
43
|
+
feeInCents _skip(if: :skip_fee), _include(if: :show_desc)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
expect(result).to include('@skip(if: $skip_fee)')
|
|
48
|
+
expect(result).to include('@include(if: $show_desc)')
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
it 'applies a directive with no arguments' do
|
|
52
|
+
result = build do
|
|
53
|
+
query do
|
|
54
|
+
invoice(id: 10) do
|
|
55
|
+
id _deprecated
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
expect(result).to include('id @deprecated')
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it 'does not confuse ___ fragment constant with a directive' do
|
|
63
|
+
result = build do
|
|
64
|
+
query do
|
|
65
|
+
invoice(id: 10) { id }
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
expect(result).not_to include('@__')
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# --- Fragment spreads with directives ------------------------------------
|
|
73
|
+
|
|
74
|
+
describe 'spread with directive' do
|
|
75
|
+
it 'appends directive after the spread name' do
|
|
76
|
+
result = build do
|
|
77
|
+
query(skip_invoice: :boolean!) do
|
|
78
|
+
spread :InvoiceFields, _skip(if: :skip_invoice)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
expect(result).to include('...InvoiceFields @skip(if: $skip_invoice)')
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
it 'spread without directive is unchanged' do
|
|
85
|
+
result = build do
|
|
86
|
+
query { spread :InvoiceFields }
|
|
87
|
+
end
|
|
88
|
+
expect(result).to include('...InvoiceFields')
|
|
89
|
+
expect(result).not_to include('@')
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# --- Inline fragments ----------------------------------------------------
|
|
94
|
+
|
|
95
|
+
# Inline fragments use the same `spread` verb as named fragment spreads, with the
|
|
96
|
+
# `on:` keyword (the same keyword as `fragment(name, on:)`) — one consistent entry point.
|
|
97
|
+
describe 'spread(on: :Type) — inline fragment' do
|
|
98
|
+
it 'generates ... on Type { }' do
|
|
99
|
+
result = build do
|
|
100
|
+
query do
|
|
101
|
+
invoice(id: 10) do
|
|
102
|
+
spread(on: :PaidInvoice) do
|
|
103
|
+
amountPaid
|
|
104
|
+
end
|
|
105
|
+
spread(on: :UnpaidInvoice) do
|
|
106
|
+
amountDue
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
expect(result).to include('... on PaidInvoice')
|
|
112
|
+
expect(result).to include('amountPaid')
|
|
113
|
+
expect(result).to include('... on UnpaidInvoice')
|
|
114
|
+
expect(result).to include('amountDue')
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
it 'applies a directive on the inline fragment' do
|
|
118
|
+
result = build do
|
|
119
|
+
query(skip_draft: :boolean!) do
|
|
120
|
+
invoice(id: 10) do
|
|
121
|
+
spread(_skip(if: :skip_draft), on: :DraftInvoice) do
|
|
122
|
+
draftId
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
expect(result).to include('... on DraftInvoice @skip(if: $skip_draft)')
|
|
128
|
+
expect(result).to include('draftId')
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
it 'inline fragment without block (bare type condition)' do
|
|
132
|
+
result = build do
|
|
133
|
+
query { spread(on: :Invoice) }
|
|
134
|
+
end
|
|
135
|
+
expect(result).to include('... on Invoice')
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# --- spread argument validation -----------------------------------------
|
|
140
|
+
|
|
141
|
+
describe 'spread requires a name or an inline type condition' do
|
|
142
|
+
it 'raises when given neither a fragment name nor on:' do
|
|
143
|
+
expect { build { query { spread } } }
|
|
144
|
+
.to raise_error(Graphlient::Errors::Error, /requires a fragment name/)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
it 'raises when a named spread is given a block' do
|
|
148
|
+
expect { build { query { spread(:InvoiceFields) { id } } } }
|
|
149
|
+
.to raise_error(Graphlient::Errors::Error, /takes no block/)
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# --- Fragment definitions ------------------------------------------------
|
|
154
|
+
|
|
155
|
+
describe 'fragment(:Name, on: :Type)' do
|
|
156
|
+
it 'appends the fragment definition after the main query' do
|
|
157
|
+
result = build do
|
|
158
|
+
fragment(:InvoiceFields, on: :Invoice) do
|
|
159
|
+
id
|
|
160
|
+
feeInCents
|
|
161
|
+
end
|
|
162
|
+
query do
|
|
163
|
+
invoice(id: 10) do
|
|
164
|
+
spread :InvoiceFields
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
expect(result).to include('...InvoiceFields')
|
|
169
|
+
expect(result).to include('fragment InvoiceFields on Invoice')
|
|
170
|
+
expect(result).to include('feeInCents')
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
it 'separates query and fragment with a blank line' do
|
|
174
|
+
result = build do
|
|
175
|
+
fragment(:F, on: :T) { id }
|
|
176
|
+
query { spread :F }
|
|
177
|
+
end
|
|
178
|
+
parts = result.split("\n\n")
|
|
179
|
+
expect(parts.length).to eq 2
|
|
180
|
+
expect(parts.last).to start_with('fragment F on T')
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
it 'supports multiple fragment definitions' do
|
|
184
|
+
result = build do
|
|
185
|
+
fragment(:FragA, on: :TypeA) { field_a }
|
|
186
|
+
fragment(:FragB, on: :TypeB) { field_b }
|
|
187
|
+
query do
|
|
188
|
+
spread :FragA
|
|
189
|
+
spread :FragB
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
expect(result).to include('fragment FragA on TypeA')
|
|
193
|
+
expect(result).to include('fragment FragB on TypeB')
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
# --- Custom scalar registration ------------------------------------------
|
|
198
|
+
|
|
199
|
+
describe 'custom scalar registration' do
|
|
200
|
+
before { described_class::Serializer.scalar(:date, 'Date') }
|
|
201
|
+
|
|
202
|
+
it 'uses the registered type in variable declarations' do
|
|
203
|
+
result = build do
|
|
204
|
+
query(created_after: :date) do
|
|
205
|
+
invoices(created_after: :created_after) { id }
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
# Variable names are not camelized -- snake_case keys output as-is
|
|
209
|
+
expect(result).to include('$created_after: Date')
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
it 'supports non-null custom scalars with !' do
|
|
213
|
+
result = build do
|
|
214
|
+
query(started_at: :date!) do
|
|
215
|
+
invoices(started_at: :started_at) { id }
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
expect(result).to include('$started_at: Date!')
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
it 'built-in scalars still work alongside custom ones' do
|
|
222
|
+
result = build do
|
|
223
|
+
query(id: :int, created_after: :date) do
|
|
224
|
+
invoice(id: :id) { id }
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
expect(result).to include('$id: Int')
|
|
228
|
+
expect(result).to include('$created_after: Date')
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
end
|
|
@@ -1,105 +1,105 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
|
|
3
|
-
describe Graphlient::Query do
|
|
4
|
-
describe '#initialize' do
|
|
5
|
-
context 'query' do
|
|
6
|
-
it 'returns expected query with block' do
|
|
7
|
-
query = Graphlient::Query.new do
|
|
8
|
-
query do
|
|
9
|
-
invoice do
|
|
10
|
-
line_items
|
|
11
|
-
end
|
|
12
|
-
end
|
|
13
|
-
end
|
|
14
|
-
expect(query.to_s).to eq "query{\n invoice{\n line_items\n }\n }"
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
it 'returns expected query with block and attributes' do
|
|
18
|
-
query = Graphlient::Query.new do
|
|
19
|
-
query do
|
|
20
|
-
invoice(id: 10) do
|
|
21
|
-
line_items
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
expect(query.to_s).to eq "query{\n invoice(id: 10){\n line_items\n }\n }"
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
it 'returns expected query with block and attributes' do
|
|
29
|
-
query = Graphlient::Query.new do
|
|
30
|
-
query do
|
|
31
|
-
invoice(id: 10) do
|
|
32
|
-
line_items(name: 'test')
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
expect(query.to_s).to eq "query{\n invoice(id: 10){\n line_items(name: \"test\")\n }\n }"
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
it 'returns expected query with block and local variables with proper type' do
|
|
40
|
-
int_arg = 10
|
|
41
|
-
float_arg = 10.3
|
|
42
|
-
str_arg = 'new name'
|
|
43
|
-
array_arg = ['str_item', 2]
|
|
44
|
-
query = Graphlient::Query.new do
|
|
45
|
-
query do
|
|
46
|
-
invoice(id: int_arg, threshold: float_arg, item_list: array_arg) do
|
|
47
|
-
line_items(name: str_arg)
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
expect(query.to_s).to eq "query{\n invoice(id: 10, threshold: 10.3, item_list: [\"str_item\", 2]){\n line_items(name: \"new name\")\n }\n }"
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
it 'returns proper query' do
|
|
55
|
-
query = Graphlient::Query.new do
|
|
56
|
-
query do
|
|
57
|
-
invoice(id: 10) do
|
|
58
|
-
line_items do
|
|
59
|
-
line_item_type
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
end
|
|
64
|
-
expect(query.to_s).to eq "query{\n invoice(id: 10){\n line_items{\n line_item_type\n }\n }\n }"
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
it 'returns proper query with query variables' do
|
|
68
|
-
query = Graphlient::Query.new do
|
|
69
|
-
query(invoice_id: :int, names: [:string!]) do
|
|
70
|
-
invoice(id: :invoice_id, name: :names) do
|
|
71
|
-
line_items do
|
|
72
|
-
line_item_type
|
|
73
|
-
end
|
|
74
|
-
end
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
expect(query.to_s).to eq "query($invoice_id: Int, $names: [String!]){\n invoice(id: $invoice_id, name: $names){\n line_items{\n line_item_type\n }\n }\n }"
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
context 'mutation' do
|
|
82
|
-
it 'returns proper mutation with arguments' do
|
|
83
|
-
mutation = Graphlient::Query.new do
|
|
84
|
-
mutation do
|
|
85
|
-
invoice(type: 'test', fee_in_cents: 20_000, total_cents: 50_000, line_items: %w[li1 li2]) do
|
|
86
|
-
id
|
|
87
|
-
end
|
|
88
|
-
end
|
|
89
|
-
end
|
|
90
|
-
expect(mutation.to_s).to eq "mutation{\n invoice(type: \"test\", fee_in_cents: 20000, total_cents: 50000, line_items: [\"li1\", \"li2\"]){\n id\n }\n }"
|
|
91
|
-
end
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
it 'returns proper mutation for relay style mutation' do
|
|
95
|
-
mutation = Graphlient::Query.new do
|
|
96
|
-
mutation do
|
|
97
|
-
invoice(input: { type: 'test', fee_in_cents: 20_000, total_cents: 50_000, line_items: %w[li1 li2] }) do
|
|
98
|
-
id
|
|
99
|
-
end
|
|
100
|
-
end
|
|
101
|
-
end
|
|
102
|
-
expect(mutation.to_s).to eq "mutation{\n invoice(input: { type: \"test\", fee_in_cents: 20000, total_cents: 50000, line_items: [\"li1\", \"li2\"] }){\n id\n }\n }"
|
|
103
|
-
end
|
|
104
|
-
end
|
|
105
|
-
end
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Graphlient::Query do
|
|
4
|
+
describe '#initialize' do
|
|
5
|
+
context 'query' do
|
|
6
|
+
it 'returns expected query with block' do
|
|
7
|
+
query = Graphlient::Query.new do
|
|
8
|
+
query do
|
|
9
|
+
invoice do
|
|
10
|
+
line_items
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
expect(query.to_s).to eq "query{\n invoice{\n line_items\n }\n }"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it 'returns expected query with block and attributes' do
|
|
18
|
+
query = Graphlient::Query.new do
|
|
19
|
+
query do
|
|
20
|
+
invoice(id: 10) do
|
|
21
|
+
line_items
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
expect(query.to_s).to eq "query{\n invoice(id: 10){\n line_items\n }\n }"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it 'returns expected query with block and attributes' do
|
|
29
|
+
query = Graphlient::Query.new do
|
|
30
|
+
query do
|
|
31
|
+
invoice(id: 10) do
|
|
32
|
+
line_items(name: 'test')
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
expect(query.to_s).to eq "query{\n invoice(id: 10){\n line_items(name: \"test\")\n }\n }"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it 'returns expected query with block and local variables with proper type' do
|
|
40
|
+
int_arg = 10
|
|
41
|
+
float_arg = 10.3
|
|
42
|
+
str_arg = 'new name'
|
|
43
|
+
array_arg = ['str_item', 2]
|
|
44
|
+
query = Graphlient::Query.new do
|
|
45
|
+
query do
|
|
46
|
+
invoice(id: int_arg, threshold: float_arg, item_list: array_arg) do
|
|
47
|
+
line_items(name: str_arg)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
expect(query.to_s).to eq "query{\n invoice(id: 10, threshold: 10.3, item_list: [\"str_item\", 2]){\n line_items(name: \"new name\")\n }\n }"
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it 'returns proper query' do
|
|
55
|
+
query = Graphlient::Query.new do
|
|
56
|
+
query do
|
|
57
|
+
invoice(id: 10) do
|
|
58
|
+
line_items do
|
|
59
|
+
line_item_type
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
expect(query.to_s).to eq "query{\n invoice(id: 10){\n line_items{\n line_item_type\n }\n }\n }"
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it 'returns proper query with query variables' do
|
|
68
|
+
query = Graphlient::Query.new do
|
|
69
|
+
query(invoice_id: :int, names: [:string!]) do
|
|
70
|
+
invoice(id: :invoice_id, name: :names) do
|
|
71
|
+
line_items do
|
|
72
|
+
line_item_type
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
expect(query.to_s).to eq "query($invoice_id: Int, $names: [String!]){\n invoice(id: $invoice_id, name: $names){\n line_items{\n line_item_type\n }\n }\n }"
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
context 'mutation' do
|
|
82
|
+
it 'returns proper mutation with arguments' do
|
|
83
|
+
mutation = Graphlient::Query.new do
|
|
84
|
+
mutation do
|
|
85
|
+
invoice(type: 'test', fee_in_cents: 20_000, total_cents: 50_000, line_items: %w[li1 li2]) do
|
|
86
|
+
id
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
expect(mutation.to_s).to eq "mutation{\n invoice(type: \"test\", fee_in_cents: 20000, total_cents: 50000, line_items: [\"li1\", \"li2\"]){\n id\n }\n }"
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
it 'returns proper mutation for relay style mutation' do
|
|
95
|
+
mutation = Graphlient::Query.new do
|
|
96
|
+
mutation do
|
|
97
|
+
invoice(input: { type: 'test', fee_in_cents: 20_000, total_cents: 50_000, line_items: %w[li1 li2] }) do
|
|
98
|
+
id
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
expect(mutation.to_s).to eq "mutation{\n invoice(input: { type: \"test\", fee_in_cents: 20000, total_cents: 50000, line_items: [\"li1\", \"li2\"] }){\n id\n }\n }"
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|