graphql_connector 1.0.0 → 1.3.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/workflows/ci.yaml +37 -0
- data/.rspec +1 -0
- data/CHANGELOG.md +29 -0
- data/Gemfile.lock +30 -30
- data/README.md +158 -8
- data/examples/departments_service_class_examples.rb +51 -0
- data/examples/mutation_examples.rb +17 -0
- data/examples/query_examples.rb +21 -0
- data/examples/raw_query_examples.rb +24 -0
- data/graphql_connector.gemspec +7 -7
- data/lib/graphql_connector.rb +8 -2
- data/lib/graphql_connector/base_server_type.rb +28 -21
- data/lib/graphql_connector/configuration.rb +4 -2
- data/lib/graphql_connector/formatters/base_format.rb +81 -0
- data/lib/graphql_connector/formatters/mutation_format.rb +14 -0
- data/lib/graphql_connector/formatters/query_format.rb +14 -0
- data/lib/graphql_connector/http_client.rb +28 -10
- data/lib/graphql_connector/service_classable/class_method_validator.rb +31 -0
- data/lib/graphql_connector/service_classable/params_validator.rb +24 -0
- data/lib/graphql_connector/service_classable/queryable.rb +108 -0
- data/lib/graphql_connector/service_classable/return_fields_validator.rb +43 -0
- data/lib/graphql_connector/version.rb +1 -1
- metadata +25 -27
- data/.travis.yml +0 -9
- data/lib/graphql_connector/query_builder.rb +0 -59
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dec05781e16009638ffb57356c4b648730b6d04eb60129211cc1f462c6b1db77
|
4
|
+
data.tar.gz: fde0b8313c159ae15b43b3aa050c53c710902854080459e41d7da28595226c8d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4a30c45c22bc87d78bc34377c1bca7e40c78d72c96a8d1e840ee89aec119cacfc01b1a517c86c5ca2867573a160742382bd3bf9ce02f256e8e8f42313b36aa5b
|
7
|
+
data.tar.gz: 218116c1728b4da4583e709435df2f2e1ba3477edcae34ec0958f398e42ccad3fdee8b80d3de1cc3312c4d7cae9a97add6384273d2cc162a4a86031dd4c5f149
|
@@ -0,0 +1,37 @@
|
|
1
|
+
name: CI
|
2
|
+
|
3
|
+
on: [push]
|
4
|
+
|
5
|
+
jobs:
|
6
|
+
build:
|
7
|
+
runs-on: ubuntu-latest
|
8
|
+
strategy:
|
9
|
+
matrix:
|
10
|
+
ruby: ['2.4.10', '2.5.9', '2.6.7', '2.7.3', '3.0.1']
|
11
|
+
name: "ruby ${{ matrix.ruby }}"
|
12
|
+
steps:
|
13
|
+
- uses: actions/checkout@v1
|
14
|
+
- uses: ruby/setup-ruby@v1
|
15
|
+
with:
|
16
|
+
ruby-version: ${{ matrix.ruby }}
|
17
|
+
- name: Install dependencies
|
18
|
+
run: |
|
19
|
+
gem install bundler
|
20
|
+
bundle install
|
21
|
+
- name: Run Test with rspec
|
22
|
+
run: bundle exec rspec spec
|
23
|
+
rubocop:
|
24
|
+
name: Rubocop
|
25
|
+
runs-on: ubuntu-latest
|
26
|
+
steps:
|
27
|
+
- uses: actions/checkout@v2
|
28
|
+
- uses: ruby/setup-ruby@v1
|
29
|
+
with:
|
30
|
+
ruby-version: 2.7.3
|
31
|
+
- name: Install dependencies
|
32
|
+
run: |
|
33
|
+
gem install bundler
|
34
|
+
bundle install
|
35
|
+
- name: Build and test
|
36
|
+
run: |
|
37
|
+
bundle exec rubocop
|
data/.rspec
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,32 @@
|
|
1
|
+
## 1.3.0 (2021-06-02)
|
2
|
+
|
3
|
+
* add the option to use a connector instead of init header for authorization
|
4
|
+
part of headers
|
5
|
+
|
6
|
+
## 1.2.1 (2021-05-25)
|
7
|
+
|
8
|
+
* relax httparty dependency(`~> 0.17` => `~> 0.16`)
|
9
|
+
|
10
|
+
## 1.2.0 (2020-12-22)
|
11
|
+
|
12
|
+
### Features
|
13
|
+
* Add `mutation` under server namespace and service class inclusion
|
14
|
+
* See `README` for details
|
15
|
+
|
16
|
+
## 1.1.1 (2020-5-04)
|
17
|
+
|
18
|
+
### BugFix
|
19
|
+
* Omit invalid `()` for empty conditions in `query` method
|
20
|
+
|
21
|
+
## 1.1.0 (2020-4-19)
|
22
|
+
|
23
|
+
### Features
|
24
|
+
* Allow building graphql querying in custom classes via `service class inclusion`
|
25
|
+
* See `README` for details about `service class inclusion`
|
26
|
+
|
27
|
+
### BugFix
|
28
|
+
* Forward `variables` when performing a `raw_query`
|
29
|
+
|
1
30
|
## 1.0.0 (2020-1-26)
|
2
31
|
|
3
32
|
### Breaking
|
data/Gemfile.lock
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
graphql_connector (1.
|
5
|
-
httparty (~> 0.
|
4
|
+
graphql_connector (1.3.0)
|
5
|
+
httparty (~> 0.16)
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: https://rubygems.org/
|
@@ -10,45 +10,46 @@ GEM
|
|
10
10
|
ast (2.4.0)
|
11
11
|
coderay (1.1.2)
|
12
12
|
diff-lcs (1.3)
|
13
|
-
httparty (0.
|
13
|
+
httparty (0.18.1)
|
14
14
|
mime-types (~> 3.0)
|
15
15
|
multi_xml (>= 0.5.2)
|
16
|
-
jaro_winkler (1.5.
|
17
|
-
method_source (0.
|
18
|
-
mime-types (3.3)
|
16
|
+
jaro_winkler (1.5.4)
|
17
|
+
method_source (1.0.0)
|
18
|
+
mime-types (3.3.1)
|
19
19
|
mime-types-data (~> 3.2015)
|
20
|
-
mime-types-data (3.
|
20
|
+
mime-types-data (3.2021.0225)
|
21
21
|
multi_xml (0.6.0)
|
22
|
-
parallel (1.
|
23
|
-
parser (2.
|
22
|
+
parallel (1.19.1)
|
23
|
+
parser (2.7.1.1)
|
24
24
|
ast (~> 2.4.0)
|
25
|
-
pry (0.
|
26
|
-
coderay (~> 1.1
|
27
|
-
method_source (~>
|
25
|
+
pry (0.13.1)
|
26
|
+
coderay (~> 1.1)
|
27
|
+
method_source (~> 1.0)
|
28
28
|
rainbow (3.0.0)
|
29
|
-
|
30
|
-
rspec (3.
|
31
|
-
rspec-core (~> 3.
|
32
|
-
rspec-expectations (~> 3.
|
33
|
-
rspec-mocks (~> 3.
|
34
|
-
rspec-core (3.
|
35
|
-
rspec-support (~> 3.
|
36
|
-
rspec-expectations (3.
|
29
|
+
rexml (3.2.5)
|
30
|
+
rspec (3.9.0)
|
31
|
+
rspec-core (~> 3.9.0)
|
32
|
+
rspec-expectations (~> 3.9.0)
|
33
|
+
rspec-mocks (~> 3.9.0)
|
34
|
+
rspec-core (3.9.1)
|
35
|
+
rspec-support (~> 3.9.1)
|
36
|
+
rspec-expectations (3.9.1)
|
37
37
|
diff-lcs (>= 1.2.0, < 2.0)
|
38
|
-
rspec-support (~> 3.
|
39
|
-
rspec-mocks (3.
|
38
|
+
rspec-support (~> 3.9.0)
|
39
|
+
rspec-mocks (3.9.1)
|
40
40
|
diff-lcs (>= 1.2.0, < 2.0)
|
41
|
-
rspec-support (~> 3.
|
42
|
-
rspec-support (3.
|
43
|
-
rubocop (0.
|
41
|
+
rspec-support (~> 3.9.0)
|
42
|
+
rspec-support (3.9.2)
|
43
|
+
rubocop (0.82.0)
|
44
44
|
jaro_winkler (~> 1.5.1)
|
45
45
|
parallel (~> 1.10)
|
46
|
-
parser (>= 2.
|
46
|
+
parser (>= 2.7.0.1)
|
47
47
|
rainbow (>= 2.2.2, < 4.0)
|
48
|
+
rexml
|
48
49
|
ruby-progressbar (~> 1.7)
|
49
|
-
unicode-display_width (>= 1.4.0, <
|
50
|
+
unicode-display_width (>= 1.4.0, < 2.0)
|
50
51
|
ruby-progressbar (1.10.1)
|
51
|
-
unicode-display_width (1.
|
52
|
+
unicode-display_width (1.7.0)
|
52
53
|
|
53
54
|
PLATFORMS
|
54
55
|
ruby
|
@@ -57,9 +58,8 @@ DEPENDENCIES
|
|
57
58
|
bundler (~> 2.0)
|
58
59
|
graphql_connector!
|
59
60
|
pry (~> 0.10)
|
60
|
-
rake (~> 10.0)
|
61
61
|
rspec (~> 3.8)
|
62
62
|
rubocop (~> 0.75)
|
63
63
|
|
64
64
|
BUNDLED WITH
|
65
|
-
2.
|
65
|
+
2.1.4
|
data/README.md
CHANGED
@@ -3,8 +3,7 @@
|
|
3
3
|
|
4
4
|
[](https://badge.fury.io/rb/graphql_connector)
|
6
|
-
[](https://travis-ci.org/Garllon/graphql_connector)
|
6
|
+
[](https://github.com/Garllon/graphql_connector/actions?query=workflow%3ACI)
|
8
7
|
[](https://codeclimate.com/github/Garllon/graphql_connector/maintainability)
|
9
8
|
|
10
9
|
An easy connector to call your `graphql` server. Currently there is no schema
|
@@ -31,21 +30,47 @@ Or install it yourself as:
|
|
31
30
|
You need to configure the `graphql_connector` first:
|
32
31
|
``` ruby
|
33
32
|
GraphqlConnector.configure do |config|
|
34
|
-
config.add_server(name: 'Foo', uri: 'http://foo.com/api/graphql', headers: {})
|
33
|
+
config.add_server(name: 'Foo', uri: 'http://foo.com/api/graphql', headers: {}, connector: {})
|
35
34
|
end
|
35
|
+
```
|
36
36
|
|
37
|
-
|
37
|
+
The connector is expecting that it contains a `base` connector instance and a
|
38
|
+
`method` parameter as string, where it gets the token. Currently like this:
|
39
|
+
```ruby
|
40
|
+
{ base: TokenAgent.new, method: 'get_authorization_header' }
|
38
41
|
```
|
39
42
|
|
43
|
+
Your method should return a hash like this:
|
44
|
+
```ruby
|
45
|
+
{ 'Authorization' => 'Token HERE' }
|
46
|
+
|
47
|
+
When you set a connector, it will override the setting in the headers for
|
48
|
+
Authorization.
|
49
|
+
|
50
|
+
For each graphql server you wish to query use `add_server`.
|
51
|
+
|
52
|
+
Afterwards you will have the following options to fetch and/or mutate data with
|
53
|
+
one or many graphql servers:
|
54
|
+
|
55
|
+
* `raw_query` --> [Examples](examples/raw_query_examples.rb)
|
56
|
+
* `query` --> [Examples](examples/query_examples.rb)
|
57
|
+
* `mutation` --> [Examples](examples/mutation_examples.rb)
|
58
|
+
* `service class inclusion` --> [Examples](examples/departments_service_class_examples.rb)
|
59
|
+
|
60
|
+
See the following sub sections for details
|
61
|
+
|
40
62
|
### raw_query
|
41
63
|
|
42
|
-
|
64
|
+
You can call your graphql_endpoint via:
|
43
65
|
```ruby
|
44
66
|
GraphqlConnector::<name>.raw_query(query_string)
|
45
67
|
```
|
46
68
|
|
47
|
-
Note that `<name>` has to be replaced by any of the ones added via `
|
69
|
+
Note that `<name>` has to be replaced by any of the ones added via `add_server`
|
48
70
|
|
71
|
+
See also [here](examples/raw_query_examples.rb) for example usage
|
72
|
+
|
73
|
+
---
|
49
74
|
### query
|
50
75
|
|
51
76
|
You can also use the more comfortable `query`:
|
@@ -64,9 +89,11 @@ GraphqlConnector::<name>.query(model, condition, selected_fields)
|
|
64
89
|
> supported with OpenStruct, associated objects are still a normal array of
|
65
90
|
> hashes.
|
66
91
|
|
92
|
+
See also [here](examples/query_examples.rb) for example usage
|
93
|
+
|
67
94
|
#### selected_fields
|
68
95
|
|
69
|
-
The
|
96
|
+
The syntax for the associations looks like the following:
|
70
97
|
```
|
71
98
|
['<attribute_name>', <association_name>: ['<attribute_name_of_the_association>']]
|
72
99
|
```
|
@@ -76,6 +103,129 @@ Example:
|
|
76
103
|
['id', 'name', productCategory: ['id', 'name']]
|
77
104
|
```
|
78
105
|
|
106
|
+
---
|
107
|
+
|
108
|
+
### mutation
|
109
|
+
|
110
|
+
Works in the same way as [query](#query)
|
111
|
+
|
112
|
+
See also [here](examples/mutation_examples.rb) for example usage
|
113
|
+
|
114
|
+
### Service class inclusion
|
115
|
+
|
116
|
+
This approach can be used to `graphqlize` **any** kind of ruby (service) class
|
117
|
+
so that it has re-usable graphql `query` and `mutation` **class methods**.
|
118
|
+
|
119
|
+
* First add `extend GraphqlConnector::<server>::Query` in the the class(es) that should be `graphqlized`
|
120
|
+
|
121
|
+
* Then you can aliases as many graphql server types via `add_query` and/or `add_raw_query` and/or `add_mutation`:
|
122
|
+
|
123
|
+
```ruby
|
124
|
+
add_query <alias>: :<graphql_server_type>, params: [...], returns: [...]
|
125
|
+
|
126
|
+
add_raw_query <alias>: 'query { ... }', params: [...]
|
127
|
+
|
128
|
+
add_mutation <alias>: :<graphql_server_type>, params: [...], returns: [...]
|
129
|
+
```
|
130
|
+
* :grey_exclamation: If not needed omit `params`
|
131
|
+
|
132
|
+
See also [here](examples/departments_service_class_examples.rb) and also here for complete example usage:
|
133
|
+
|
134
|
+
```ruby
|
135
|
+
GraphqlConnector.configure do |config|
|
136
|
+
config.add_server(name: 'Foo', uri: 'http://foo.com/api/graphql', headers: {})
|
137
|
+
end
|
138
|
+
|
139
|
+
# product.rb
|
140
|
+
class Product
|
141
|
+
extend GraphqlConnector::Foo::Query
|
142
|
+
|
143
|
+
add_query all: :products,
|
144
|
+
returns: [:id, :name]
|
145
|
+
|
146
|
+
add_query by_id: :products,
|
147
|
+
params: :id,
|
148
|
+
returns: [:name, product_category: [:id, :name]]
|
149
|
+
|
150
|
+
add_query by_names: :products,
|
151
|
+
params: :names,
|
152
|
+
returns: [:id, :name, product_category: [:id, :name]]
|
153
|
+
|
154
|
+
add_query by: :products,
|
155
|
+
params: [:id, :name],
|
156
|
+
returns: [:name]
|
157
|
+
|
158
|
+
add_query by_category_id: :products,
|
159
|
+
params: :product_category,
|
160
|
+
returns: [product_category: [:id, :name]]
|
161
|
+
|
162
|
+
add_mutation create: :createProduct,
|
163
|
+
params: [:name, :catgetoryId],
|
164
|
+
returns: [:id, :name]
|
165
|
+
end
|
166
|
+
|
167
|
+
Product.all
|
168
|
+
=> [OpenStruct<id=1, name='Demo Product', ...]
|
169
|
+
|
170
|
+
Product.by_id(id: 1)
|
171
|
+
=> [OpenStruct<name='Demo Product', product_category=<ProductCategory<id=10, name='Demo Category'>>]
|
172
|
+
|
173
|
+
Product.by_names(names: ['Demo Product', 'Non Demo Product'])
|
174
|
+
=> [OpenStruct<id=1, name='Demo Product', product_category=<ProductCategory<id=10, name='Demo Category'>>, Product<id=2, name='Demo Product' ...]
|
175
|
+
|
176
|
+
Product.by(id: 1, name: 'Demo Product')
|
177
|
+
=> OpenStruct<name='Demo Product'>
|
178
|
+
|
179
|
+
Product.by_category_id(product_category: { id: 10})
|
180
|
+
=> OpenStruct<product_category=<ProductCategory<id=10, name='Demo Category'>>
|
181
|
+
|
182
|
+
Product.create(name: 'Another Product', catgetoryId: 10)
|
183
|
+
=> OpenStruct<id=10, name='Another Product'>
|
184
|
+
```
|
185
|
+
|
186
|
+
Also custom **class methods** can used to call any kind of `query` and do further selection instead:
|
187
|
+
|
188
|
+
```ruby
|
189
|
+
class Product
|
190
|
+
extend GraphqlConnector::Foo::Query
|
191
|
+
|
192
|
+
add_query all: :products, returns: [:name]
|
193
|
+
|
194
|
+
def self.by_id(id:)
|
195
|
+
all.select { |products| products.id == id }.first
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
Product.by_id(id: 1)
|
200
|
+
=> OpenStruct<id=1, name='Demo Product'>>
|
201
|
+
```
|
202
|
+
|
203
|
+
:warning: Ensure that your custom **class method** never has the **same name** as an `<alias>` of `add_query`, `add_raw_query` or `add_mutation`. Otherwise the associated grapqhl query will not be performed because of [Ruby Open Class principle](https://ruby-lang.co/ruby-open-class/)
|
204
|
+
|
205
|
+
|
206
|
+
Example for `raw_query`:
|
207
|
+
|
208
|
+
```ruby
|
209
|
+
class Product
|
210
|
+
extend GraphqlConnector::Foo::Query
|
211
|
+
|
212
|
+
add_raw_query all: ' query { products { id name } } '
|
213
|
+
add_raw_query by: ' query products($id: !ID, $name: !String) '\
|
214
|
+
'{ products(id: $id, name: $name) { id name } }',
|
215
|
+
params: [:id, :name]
|
216
|
+
|
217
|
+
end
|
218
|
+
|
219
|
+
Product.all
|
220
|
+
=> [ { id: '1', name: 'Demo Product' }, ...]
|
221
|
+
|
222
|
+
Product.by(id: '1', name: 'Demo Product')
|
223
|
+
=> { id: '1', name: 'Demo Product' }
|
224
|
+
|
225
|
+
```
|
226
|
+
|
227
|
+
:exclamation: There is no `add_raw_mutation` since `add_raw_query` does already cover such a case
|
228
|
+
|
79
229
|
## Development
|
80
230
|
|
81
231
|
After checking out the repo, run
|
@@ -100,4 +250,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
|
|
100
250
|
|
101
251
|
## Code of Conduct
|
102
252
|
|
103
|
-
Everyone interacting in the GraphqlConnector project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/
|
253
|
+
Everyone interacting in the GraphqlConnector project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/Garllon/graphql_connector/blob/master/CODE_OF_CONDUCT.md).
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
4
|
+
# ! The following examples are used together with
|
5
|
+
# ! https://github.com/sushie1984/rails-graphql-server
|
6
|
+
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
7
|
+
|
8
|
+
uri = 'http://rails-graphql-server.herokuapp.com/api/graphql'
|
9
|
+
GraphqlConnector.configure do |config|
|
10
|
+
config.add_server(name: 'RailsGraphqlServer', uri: uri, headers: {})
|
11
|
+
end
|
12
|
+
|
13
|
+
# Service class for fetching department data
|
14
|
+
class Department
|
15
|
+
extend GraphqlConnector::RailsGraphqlServer::Query
|
16
|
+
|
17
|
+
add_query all: :departments, returns: [:id, :name, employees: [:yearlySalary]]
|
18
|
+
|
19
|
+
add_query by_id: :departments,
|
20
|
+
params: [:id],
|
21
|
+
returns: [:id, :name, employees: [:yearlySalary]]
|
22
|
+
|
23
|
+
add_raw_query all_raw: 'query {
|
24
|
+
departments {
|
25
|
+
id name employees { yearlySalary }
|
26
|
+
}
|
27
|
+
}'
|
28
|
+
|
29
|
+
add_raw_query by_id_raw: 'query departments($id: [ID!]) {
|
30
|
+
departments(id: $id) {
|
31
|
+
name employees { name }
|
32
|
+
}
|
33
|
+
}',
|
34
|
+
params: [:id]
|
35
|
+
|
36
|
+
# We use a nested 'input' as of convention for
|
37
|
+
# https://github.com/sushie1984/rails-graphql-server/blob/master/app/graphql/input_objects/department_attributes.rb
|
38
|
+
add_mutation create: :createDepartment,
|
39
|
+
params: :input,
|
40
|
+
returns: [department: %i[id name location]]
|
41
|
+
end
|
42
|
+
|
43
|
+
Department.all
|
44
|
+
|
45
|
+
Department.by_id(id: %w[1 2])
|
46
|
+
|
47
|
+
Department.all_raw
|
48
|
+
|
49
|
+
Department.by_id_raw(id: %w[1 2])
|
50
|
+
|
51
|
+
Department.create(input: { attributes: { name: 'One', location: 'Berlin' } })
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
4
|
+
# ! The following examples are used together with
|
5
|
+
# ! https://github.com/sushie1984/rails-graphql-server
|
6
|
+
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
7
|
+
|
8
|
+
uri = 'http://rails-graphql-server.herokuapp.com/api/graphql'
|
9
|
+
GraphqlConnector.configure do |config|
|
10
|
+
config.add_server(name: 'RailsGraphqlServer', uri: uri, headers: {})
|
11
|
+
end
|
12
|
+
|
13
|
+
department_input = { attributes: { name: 'One', location: 'Berlin' } }
|
14
|
+
return_fields = ['department': ['id', 'name', 'employees' => ['yearlySalary']]]
|
15
|
+
GraphqlConnector::RailsGraphqlServer.mutation('createDepartment',
|
16
|
+
{ input: department_input },
|
17
|
+
return_fields)
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
4
|
+
# ! The following examples are used together with
|
5
|
+
# ! https://github.com/sushie1984/rails-graphql-server
|
6
|
+
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
7
|
+
|
8
|
+
uri = 'http://rails-graphql-server.herokuapp.com/api/graphql'
|
9
|
+
GraphqlConnector.configure do |config|
|
10
|
+
config.add_server(name: 'RailsGraphqlServer', uri: uri, headers: {})
|
11
|
+
end
|
12
|
+
|
13
|
+
GraphqlConnector::RailsGraphqlServer.query('departments',
|
14
|
+
{},
|
15
|
+
['id', 'name',
|
16
|
+
'employees' => ['yearlySalary']])
|
17
|
+
|
18
|
+
GraphqlConnector::RailsGraphqlServer.query('departments',
|
19
|
+
{ id: %w[1 2] },
|
20
|
+
['id', 'name',
|
21
|
+
'employees' => ['yearlySalary']])
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
4
|
+
# ! The following examples are used together with
|
5
|
+
# ! https://github.com/sushie1984/rails-graphql-server
|
6
|
+
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
7
|
+
|
8
|
+
GraphqlConnector.configure do |config|
|
9
|
+
config.add_server(name: 'RailsGraphqlServer',
|
10
|
+
uri: 'http://rails-graphql-server.herokuapp.com/api/graphql',
|
11
|
+
headers: {})
|
12
|
+
end
|
13
|
+
|
14
|
+
GraphqlConnector::RailsGraphqlServer.raw_query(
|
15
|
+
'query { departments { id name employees { yearlySalary } } }'
|
16
|
+
)
|
17
|
+
|
18
|
+
GraphqlConnector::RailsGraphqlServer.raw_query(
|
19
|
+
'query departments($id: [ID!]) {
|
20
|
+
departments(id: $id) { name employees { name }
|
21
|
+
}
|
22
|
+
}',
|
23
|
+
variables: { id: %w[1 2] }
|
24
|
+
)
|
data/graphql_connector.gemspec
CHANGED
@@ -7,12 +7,13 @@ require 'graphql_connector/version'
|
|
7
7
|
Gem::Specification.new do |spec|
|
8
8
|
spec.name = 'graphql_connector'
|
9
9
|
spec.version = GraphqlConnector::VERSION
|
10
|
-
spec.authors = [
|
11
|
-
spec.email = ['palluthe.bennet@gmail.com']
|
10
|
+
spec.authors = %w[Garllon sushie1984]
|
11
|
+
spec.email = ['palluthe.bennet@gmail.com', 'sascha_burku@yahoo.de']
|
12
12
|
|
13
|
-
spec.summary = '
|
14
|
-
spec.description = '
|
15
|
-
'
|
13
|
+
spec.summary = 'GraphQL client'
|
14
|
+
spec.description = 'Grahql client to query with your own raw string, '\
|
15
|
+
'with the small helper method query or with service '\
|
16
|
+
'class inclusion.'
|
16
17
|
spec.homepage = 'https://github.com/Garllon/graphql_connector/blob/master/README.md'
|
17
18
|
spec.license = 'MIT'
|
18
19
|
|
@@ -30,11 +31,10 @@ Gem::Specification.new do |spec|
|
|
30
31
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
31
32
|
spec.require_paths = ['lib']
|
32
33
|
|
33
|
-
spec.add_dependency 'httparty', '~> 0.
|
34
|
+
spec.add_dependency 'httparty', '~> 0.16'
|
34
35
|
|
35
36
|
spec.add_development_dependency 'bundler', '~> 2.0'
|
36
37
|
spec.add_development_dependency 'pry', '~> 0.10'
|
37
|
-
spec.add_development_dependency 'rake', '~> 10.0'
|
38
38
|
spec.add_development_dependency 'rspec', '~> 3.8'
|
39
39
|
spec.add_development_dependency 'rubocop', '~> 0.75'
|
40
40
|
end
|
data/lib/graphql_connector.rb
CHANGED
@@ -1,10 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'graphql_connector/version'
|
4
|
-
require 'graphql_connector/
|
4
|
+
require 'graphql_connector/formatters/base_format'
|
5
|
+
require 'graphql_connector/formatters/query_format'
|
6
|
+
require 'graphql_connector/formatters/mutation_format'
|
5
7
|
require 'graphql_connector/configuration'
|
6
8
|
require 'graphql_connector/http_client'
|
7
9
|
require 'graphql_connector/base_server_type'
|
10
|
+
require 'graphql_connector/service_classable/class_method_validator'
|
11
|
+
require 'graphql_connector/service_classable/params_validator'
|
12
|
+
require 'graphql_connector/service_classable/return_fields_validator'
|
13
|
+
require 'graphql_connector/service_classable/queryable'
|
8
14
|
require 'graphql_connector/custom_attribute_error'
|
9
15
|
require 'httparty'
|
10
16
|
|
@@ -21,7 +27,7 @@ module GraphqlConnector
|
|
21
27
|
end
|
22
28
|
|
23
29
|
def self.reset
|
24
|
-
@configuration
|
30
|
+
@configuration.reset!
|
25
31
|
end
|
26
32
|
|
27
33
|
def self.configure
|
@@ -5,12 +5,12 @@ module GraphqlConnector
|
|
5
5
|
# Class to wrap http_client calls under a specific namespaced class
|
6
6
|
class BaseServerType
|
7
7
|
class << self
|
8
|
-
def build(name, uri, headers)
|
8
|
+
def build(name, uri, headers, connector = {})
|
9
9
|
verify_new_client_type_for!(name)
|
10
|
-
base_class = class_with(uri, headers)
|
10
|
+
base_class = class_with(uri, headers, connector)
|
11
11
|
base_object = GraphqlConnector.const_set(name, base_class)
|
12
|
-
|
13
|
-
|
12
|
+
inject_http_client_delegations(base_object)
|
13
|
+
create_service_class_module(base_object)
|
14
14
|
|
15
15
|
base_object
|
16
16
|
end
|
@@ -25,30 +25,37 @@ module GraphqlConnector
|
|
25
25
|
'configuration!'
|
26
26
|
end
|
27
27
|
|
28
|
-
def
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
end
|
28
|
+
def create_service_class_module(base_object)
|
29
|
+
base_object.class_eval <<-METHOD, __FILE__, __LINE__ + 1
|
30
|
+
module Query
|
31
|
+
def self.extended(base)
|
32
|
+
base.extend(GraphqlConnector::ServiceClassable::Queryable)
|
33
|
+
end
|
35
34
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
@http_client ||= GraphqlConnector::HttpClient.new(@uri, @headers)
|
35
|
+
def http_client
|
36
|
+
#{base_object}.http_client
|
37
|
+
end
|
40
38
|
end
|
39
|
+
METHOD
|
40
|
+
end
|
41
|
+
|
42
|
+
def class_with(uri, headers, connector = {})
|
43
|
+
Class.new do
|
44
|
+
attr_accessor :uri, :headers, :connector
|
45
|
+
@uri = uri
|
46
|
+
@headers = headers
|
47
|
+
@connector = connector
|
41
48
|
end
|
42
49
|
end
|
43
50
|
|
44
|
-
def
|
51
|
+
def inject_http_client_delegations(base_object)
|
45
52
|
base_object.instance_eval do
|
46
|
-
|
47
|
-
|
48
|
-
end
|
53
|
+
extend SingleForwardable
|
54
|
+
def_delegators :http_client, :query, :raw_query, :mutation
|
49
55
|
|
50
|
-
def
|
51
|
-
http_client
|
56
|
+
def http_client
|
57
|
+
@http_client ||=
|
58
|
+
GraphqlConnector::HttpClient.new(@uri, @headers, @connector)
|
52
59
|
end
|
53
60
|
end
|
54
61
|
end
|
@@ -9,12 +9,14 @@ module GraphqlConnector
|
|
9
9
|
@base_server_types = {}
|
10
10
|
end
|
11
11
|
|
12
|
-
def add_server(name:, uri:, headers:)
|
13
|
-
@base_server_types[name] =
|
12
|
+
def add_server(name:, uri:, headers:, connector: {})
|
13
|
+
@base_server_types[name] =
|
14
|
+
BaseServerType.build(name, uri, headers, connector)
|
14
15
|
end
|
15
16
|
|
16
17
|
def reset!
|
17
18
|
@base_server_types.keys.each do |name|
|
19
|
+
GraphqlConnector.const_get(name).send :remove_const, 'Query'
|
18
20
|
GraphqlConnector.send :remove_const, name
|
19
21
|
end
|
20
22
|
@base_server_types = {}
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphqlConnector
|
4
|
+
module Formatters
|
5
|
+
# Class that returns in query or mutation string format
|
6
|
+
class BaseFormat
|
7
|
+
def initialize(model, conditions, selected_fields)
|
8
|
+
@model = model
|
9
|
+
@conditions = conditions
|
10
|
+
@selected_fields = selected_fields
|
11
|
+
end
|
12
|
+
|
13
|
+
def create
|
14
|
+
<<-STRING
|
15
|
+
#{query_type} {
|
16
|
+
#{@model}#{arguments} {
|
17
|
+
#{parse_fields(@selected_fields)}
|
18
|
+
}
|
19
|
+
}
|
20
|
+
STRING
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def arguments
|
26
|
+
conditions = @conditions.each_with_object([]) do |(key, value), array|
|
27
|
+
array << "#{key}: #{value_as_parameter(value)}"
|
28
|
+
end
|
29
|
+
|
30
|
+
return '' if conditions.empty?
|
31
|
+
|
32
|
+
"(#{conditions.join(', ')})"
|
33
|
+
end
|
34
|
+
|
35
|
+
def value_as_parameter(value)
|
36
|
+
case value
|
37
|
+
when Array
|
38
|
+
casted_values = value.map { |v| value_as_parameter(v) }
|
39
|
+
"[#{casted_values.join(',')}]"
|
40
|
+
when Hash
|
41
|
+
casted_values = value.map { |k, v| "#{k}: #{value_as_parameter(v)}" }
|
42
|
+
"{#{casted_values.join(',')}}"
|
43
|
+
else
|
44
|
+
scalar_types(value)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def scalar_types(value)
|
49
|
+
case value
|
50
|
+
when TrueClass, FalseClass, Integer, Float
|
51
|
+
value
|
52
|
+
else # fallback to string
|
53
|
+
'"' + value.to_s + '"'
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def parse_fields(selected_fields)
|
58
|
+
results = selected_fields.map do |field|
|
59
|
+
case field
|
60
|
+
when Hash
|
61
|
+
handle_association(field)
|
62
|
+
else
|
63
|
+
field
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
results.join(' ')
|
68
|
+
end
|
69
|
+
|
70
|
+
def handle_association(hash)
|
71
|
+
hash.map do |key, fields|
|
72
|
+
"#{key} { #{parse_fields(fields)} }"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def query_type
|
77
|
+
raise 'query_type undefined'
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -3,26 +3,31 @@
|
|
3
3
|
module GraphqlConnector
|
4
4
|
# Wrapper class for HTTParty post query
|
5
5
|
class HttpClient
|
6
|
-
def initialize(uri, headers)
|
6
|
+
def initialize(uri, headers, connector = {})
|
7
7
|
@uri = uri
|
8
8
|
@headers = headers
|
9
|
+
@connector = connector
|
9
10
|
end
|
10
11
|
|
11
12
|
def query(model, conditions, selected_fields)
|
12
|
-
query_string =
|
13
|
-
|
14
|
-
selected_fields).create
|
13
|
+
query_string =
|
14
|
+
Formatters::QueryFormat.new(model, conditions, selected_fields).create
|
15
15
|
parsed_body = raw_query(query_string)
|
16
|
-
|
17
|
-
|
16
|
+
format_body(parsed_body['data'][model.to_s])
|
17
|
+
end
|
18
18
|
|
19
|
-
|
19
|
+
def mutation(model, inputs, selected_fields)
|
20
|
+
query_string =
|
21
|
+
Formatters::MutationFormat.new(model, inputs, selected_fields).create
|
22
|
+
parsed_body = raw_query(query_string)
|
23
|
+
format_body(parsed_body['data'][model.to_s])
|
20
24
|
end
|
21
25
|
|
22
|
-
def raw_query(query_string)
|
26
|
+
def raw_query(query_string, variables: {})
|
23
27
|
response = HTTParty.post(@uri,
|
24
|
-
headers:
|
25
|
-
body: { query: query_string
|
28
|
+
headers: handle_headers,
|
29
|
+
body: { query: query_string,
|
30
|
+
variables: variables })
|
26
31
|
parsed_body = JSON.parse(response.body)
|
27
32
|
verify_response!(parsed_body)
|
28
33
|
parsed_body
|
@@ -30,6 +35,19 @@ module GraphqlConnector
|
|
30
35
|
|
31
36
|
private
|
32
37
|
|
38
|
+
def handle_headers
|
39
|
+
return @headers if @connector.empty?
|
40
|
+
|
41
|
+
@headers
|
42
|
+
.merge(@connector[:base].send(@connector[:method]))
|
43
|
+
end
|
44
|
+
|
45
|
+
def format_body(response_body)
|
46
|
+
return OpenStruct.new(response_body) unless response_body.is_a? Array
|
47
|
+
|
48
|
+
response_body.map { |entry| OpenStruct.new(entry) }
|
49
|
+
end
|
50
|
+
|
33
51
|
def verify_response!(parsed_body)
|
34
52
|
return unless parsed_body.key? 'errors'
|
35
53
|
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphqlConnector
|
4
|
+
module ServiceClassable
|
5
|
+
class ClassMethodAlreadyImplementedError < StandardError; end
|
6
|
+
class InvalidClassTypeError < StandardError; end
|
7
|
+
# Checks whether a class method for a specific graphql query is in an
|
8
|
+
# expected format
|
9
|
+
class ClassMethodValidator
|
10
|
+
class << self
|
11
|
+
def validate_class_method(class_method_name, invoked_class)
|
12
|
+
return unless invoked_class.singleton_methods
|
13
|
+
.map(&:to_s)
|
14
|
+
.include?(class_method_name.to_s)
|
15
|
+
|
16
|
+
error_msg = "The method '#{class_method_name}: ... ' is "\
|
17
|
+
'already implemented within the context of '\
|
18
|
+
"#{invoked_class} and therefore cannot be used again!"
|
19
|
+
raise ClassMethodAlreadyImplementedError, error_msg
|
20
|
+
end
|
21
|
+
|
22
|
+
def validate_element_class_type(element, class_types)
|
23
|
+
return if element.class == class_types
|
24
|
+
|
25
|
+
raise InvalidClassTypeError, "Please ensure that #{element} is a"\
|
26
|
+
"#{class_types}!"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphqlConnector
|
4
|
+
module ServiceClassable
|
5
|
+
class InvalidParamsError < StandardError; end
|
6
|
+
# Checks whether params for a specifc graphql query are in an expected
|
7
|
+
# format
|
8
|
+
class ParamsValidator
|
9
|
+
class << self
|
10
|
+
def validate(query_params)
|
11
|
+
params = [query_params].flatten
|
12
|
+
return if params.empty? ||
|
13
|
+
params.map(&:class).uniq == [Symbol] ||
|
14
|
+
params.map(&:class).uniq == [String]
|
15
|
+
|
16
|
+
raise InvalidParamsError,
|
17
|
+
"Please ensure that #{query_params} are either "\
|
18
|
+
'Symbols/Strings as described in the README '\
|
19
|
+
'(e.g.: params: [:id, :name])'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphqlConnector
|
4
|
+
module ServiceClassable
|
5
|
+
# Module that allows to build query methods within the context of
|
6
|
+
# service class
|
7
|
+
module Queryable
|
8
|
+
CONDITIONS = 'binding.local_variables.map do |var|
|
9
|
+
[var, binding.local_variable_get(var)]
|
10
|
+
end.to_h'
|
11
|
+
|
12
|
+
def add_query(params: [], returns:, **method_to_query)
|
13
|
+
class_method_name = method_to_query.first[0]
|
14
|
+
query_type = method_to_query.first[1]
|
15
|
+
ReturnFieldsValidator.validate(returns)
|
16
|
+
ClassMethodValidator.validate_class_method(class_method_name, self)
|
17
|
+
ClassMethodValidator.validate_element_class_type(query_type, Symbol)
|
18
|
+
|
19
|
+
if params.empty?
|
20
|
+
return query_method(class_method_name, query_type, returns)
|
21
|
+
end
|
22
|
+
|
23
|
+
ParamsValidator.validate(params)
|
24
|
+
query_keyword_method(class_method_name, query_type, params, returns)
|
25
|
+
end
|
26
|
+
|
27
|
+
def add_raw_query(params: [], **method_to_raw_query)
|
28
|
+
class_method_name = method_to_raw_query.first[0]
|
29
|
+
query_string = method_to_raw_query.first[1]
|
30
|
+
ClassMethodValidator.validate_class_method(class_method_name, self)
|
31
|
+
ClassMethodValidator.validate_element_class_type(query_string, String)
|
32
|
+
|
33
|
+
if params.empty?
|
34
|
+
return raw_query_method(class_method_name, query_string)
|
35
|
+
end
|
36
|
+
|
37
|
+
ParamsValidator.validate(params)
|
38
|
+
raw_query_keyword_method(class_method_name, query_string, params)
|
39
|
+
end
|
40
|
+
|
41
|
+
def add_mutation(params: [], returns:, **method_to_query)
|
42
|
+
class_method_name = method_to_query.first[0]
|
43
|
+
query_type = method_to_query.first[1]
|
44
|
+
ReturnFieldsValidator.validate(returns)
|
45
|
+
ClassMethodValidator.validate_class_method(class_method_name, self)
|
46
|
+
ClassMethodValidator.validate_element_class_type(query_type, Symbol)
|
47
|
+
|
48
|
+
if params.empty?
|
49
|
+
return mutation_method(class_method_name, query_type, returns)
|
50
|
+
end
|
51
|
+
|
52
|
+
ParamsValidator.validate(params)
|
53
|
+
mutation_keyword_method(class_method_name, query_type, params, returns)
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def query_method(class_method_name, query_type, return_fields)
|
59
|
+
define_singleton_method class_method_name do
|
60
|
+
http_client.query(query_type, {}, return_fields.to_a)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def raw_query_method(class_method_name, query_string)
|
65
|
+
define_singleton_method class_method_name do
|
66
|
+
http_client.raw_query(query_string)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def query_keyword_method(name, query_type, keywords, return_fields)
|
71
|
+
keywords = [keywords].flatten
|
72
|
+
instance_eval <<-METHOD, __FILE__, __LINE__ + 1
|
73
|
+
def #{name}(#{keywords.map { |keyword| "#{keyword}:" }.join(', ')})
|
74
|
+
http_client.query("#{query_type}",
|
75
|
+
#{CONDITIONS},
|
76
|
+
#{return_fields.to_a})
|
77
|
+
end
|
78
|
+
METHOD
|
79
|
+
end
|
80
|
+
|
81
|
+
def raw_query_keyword_method(name, query_string, keywords)
|
82
|
+
keywords = [keywords].flatten
|
83
|
+
instance_eval <<-METHOD, __FILE__, __LINE__ + 1
|
84
|
+
def #{name}(#{keywords.map { |keyword| "#{keyword}:" }.join(', ')})
|
85
|
+
http_client.raw_query("#{query_string}", variables: #{CONDITIONS})
|
86
|
+
end
|
87
|
+
METHOD
|
88
|
+
end
|
89
|
+
|
90
|
+
def mutation_method(class_method_name, query_type, return_fields)
|
91
|
+
define_singleton_method class_method_name do
|
92
|
+
http_client.mutation(query_type, {}, return_fields.to_a)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def mutation_keyword_method(name, query_type, keywords, return_fields)
|
97
|
+
keywords = [keywords].flatten
|
98
|
+
instance_eval <<-METHOD, __FILE__, __LINE__ + 1
|
99
|
+
def #{name}(#{keywords.map { |keyword| "#{keyword}:" }.join(', ')})
|
100
|
+
http_client.mutation("#{query_type}",
|
101
|
+
#{CONDITIONS},
|
102
|
+
#{return_fields.to_a})
|
103
|
+
end
|
104
|
+
METHOD
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphqlConnector
|
4
|
+
module ServiceClassable
|
5
|
+
class ReturnFieldsErrors < StandardError; end
|
6
|
+
# Valdations for return fields set within the context of a service class
|
7
|
+
class ReturnFieldsValidator
|
8
|
+
class << self
|
9
|
+
def validate(return_fields)
|
10
|
+
unless return_fields.is_a?(Array)
|
11
|
+
raise ReturnFieldsErrors, 'Please ensure that returns is followed '\
|
12
|
+
'by an array. E.g. returns: [:id]'
|
13
|
+
end
|
14
|
+
|
15
|
+
return_fields.each { |entry| recursive_validation(entry) }
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def recursive_validation(entry)
|
21
|
+
case entry
|
22
|
+
when Hash
|
23
|
+
hash_validation(entry)
|
24
|
+
when Array
|
25
|
+
entry.each { |item| recursive_validation(item) }
|
26
|
+
else
|
27
|
+
return if [String, Symbol].member?(entry.class)
|
28
|
+
|
29
|
+
raise ReturnFieldsErrors, "The #{entry} is neither a String nor a"\
|
30
|
+
'Symbol!'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def hash_validation(hash)
|
35
|
+
hash.each do |key, value|
|
36
|
+
recursive_validation(key)
|
37
|
+
recursive_validation(value)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: graphql_connector
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Garllon
|
8
|
-
|
8
|
+
- sushie1984
|
9
|
+
autorequire:
|
9
10
|
bindir: exe
|
10
11
|
cert_chain: []
|
11
|
-
date:
|
12
|
+
date: 2021-06-02 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
14
15
|
name: httparty
|
@@ -16,14 +17,14 @@ dependencies:
|
|
16
17
|
requirements:
|
17
18
|
- - "~>"
|
18
19
|
- !ruby/object:Gem::Version
|
19
|
-
version: '0.
|
20
|
+
version: '0.16'
|
20
21
|
type: :runtime
|
21
22
|
prerelease: false
|
22
23
|
version_requirements: !ruby/object:Gem::Requirement
|
23
24
|
requirements:
|
24
25
|
- - "~>"
|
25
26
|
- !ruby/object:Gem::Version
|
26
|
-
version: '0.
|
27
|
+
version: '0.16'
|
27
28
|
- !ruby/object:Gem::Dependency
|
28
29
|
name: bundler
|
29
30
|
requirement: !ruby/object:Gem::Requirement
|
@@ -52,20 +53,6 @@ dependencies:
|
|
52
53
|
- - "~>"
|
53
54
|
- !ruby/object:Gem::Version
|
54
55
|
version: '0.10'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: rake
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - "~>"
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '10.0'
|
62
|
-
type: :development
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - "~>"
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '10.0'
|
69
56
|
- !ruby/object:Gem::Dependency
|
70
57
|
name: rspec
|
71
58
|
requirement: !ruby/object:Gem::Requirement
|
@@ -94,19 +81,20 @@ dependencies:
|
|
94
81
|
- - "~>"
|
95
82
|
- !ruby/object:Gem::Version
|
96
83
|
version: '0.75'
|
97
|
-
description:
|
98
|
-
|
84
|
+
description: Grahql client to query with your own raw string, with the small helper
|
85
|
+
method query or with service class inclusion.
|
99
86
|
email:
|
100
87
|
- palluthe.bennet@gmail.com
|
88
|
+
- sascha_burku@yahoo.de
|
101
89
|
executables: []
|
102
90
|
extensions: []
|
103
91
|
extra_rdoc_files: []
|
104
92
|
files:
|
93
|
+
- ".github/workflows/ci.yaml"
|
105
94
|
- ".gitignore"
|
106
95
|
- ".rspec"
|
107
96
|
- ".rubocop.yml"
|
108
97
|
- ".rubocop_todo.yml"
|
109
|
-
- ".travis.yml"
|
110
98
|
- CHANGELOG.md
|
111
99
|
- CODE_OF_CONDUCT.md
|
112
100
|
- Gemfile
|
@@ -114,13 +102,23 @@ files:
|
|
114
102
|
- LICENSE.txt
|
115
103
|
- README.md
|
116
104
|
- bin/console
|
105
|
+
- examples/departments_service_class_examples.rb
|
106
|
+
- examples/mutation_examples.rb
|
107
|
+
- examples/query_examples.rb
|
108
|
+
- examples/raw_query_examples.rb
|
117
109
|
- graphql_connector.gemspec
|
118
110
|
- lib/graphql_connector.rb
|
119
111
|
- lib/graphql_connector/base_server_type.rb
|
120
112
|
- lib/graphql_connector/configuration.rb
|
121
113
|
- lib/graphql_connector/custom_attribute_error.rb
|
114
|
+
- lib/graphql_connector/formatters/base_format.rb
|
115
|
+
- lib/graphql_connector/formatters/mutation_format.rb
|
116
|
+
- lib/graphql_connector/formatters/query_format.rb
|
122
117
|
- lib/graphql_connector/http_client.rb
|
123
|
-
- lib/graphql_connector/
|
118
|
+
- lib/graphql_connector/service_classable/class_method_validator.rb
|
119
|
+
- lib/graphql_connector/service_classable/params_validator.rb
|
120
|
+
- lib/graphql_connector/service_classable/queryable.rb
|
121
|
+
- lib/graphql_connector/service_classable/return_fields_validator.rb
|
124
122
|
- lib/graphql_connector/version.rb
|
125
123
|
homepage: https://github.com/Garllon/graphql_connector/blob/master/README.md
|
126
124
|
licenses:
|
@@ -129,7 +127,7 @@ metadata:
|
|
129
127
|
homepage_uri: https://github.com/Garllon/graphql_connector/blob/master/README.md
|
130
128
|
source_code_uri: https://github.com/Garllon/graphql_connector
|
131
129
|
changelog_uri: https://github.com/Garllon/graphql_connector/blob/master/CHANGELOG.md
|
132
|
-
post_install_message:
|
130
|
+
post_install_message:
|
133
131
|
rdoc_options: []
|
134
132
|
require_paths:
|
135
133
|
- lib
|
@@ -144,8 +142,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
144
142
|
- !ruby/object:Gem::Version
|
145
143
|
version: '0'
|
146
144
|
requirements: []
|
147
|
-
rubygems_version: 3.
|
148
|
-
signing_key:
|
145
|
+
rubygems_version: 3.1.4
|
146
|
+
signing_key:
|
149
147
|
specification_version: 4
|
150
|
-
summary:
|
148
|
+
summary: GraphQL client
|
151
149
|
test_files: []
|
data/.travis.yml
DELETED
@@ -1,59 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module GraphqlConnector
|
4
|
-
# create the graphql query_string out of the given attributes.
|
5
|
-
class QueryBuilder
|
6
|
-
def initialize(model, conditions, selected_fields)
|
7
|
-
@model = model
|
8
|
-
@conditions = conditions
|
9
|
-
@selected_fields = selected_fields
|
10
|
-
end
|
11
|
-
|
12
|
-
def create
|
13
|
-
"query { #{main_filter} { #{parse_fields(@selected_fields)} } }"
|
14
|
-
end
|
15
|
-
|
16
|
-
private
|
17
|
-
|
18
|
-
def main_filter
|
19
|
-
conditions = @conditions.each_with_object([]) do |(key, value), array|
|
20
|
-
next if value.is_a? Hash # will be processed in #field_with_filter
|
21
|
-
|
22
|
-
array << "#{key}: #{value_as_parameter(value)}"
|
23
|
-
end
|
24
|
-
|
25
|
-
"#{@model}(#{conditions.join(', ')})"
|
26
|
-
end
|
27
|
-
|
28
|
-
def value_as_parameter(value)
|
29
|
-
case value
|
30
|
-
when TrueClass, FalseClass, Integer, Float
|
31
|
-
value
|
32
|
-
when Array
|
33
|
-
casted_values = value.map { |v| value_as_parameter(v) }
|
34
|
-
"[#{casted_values.join(',')}]"
|
35
|
-
else # fallback to string
|
36
|
-
'"' + value.to_s + '"'
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
def parse_fields(selected_fields)
|
41
|
-
results = selected_fields.map do |field|
|
42
|
-
case field
|
43
|
-
when Hash
|
44
|
-
handle_association(field)
|
45
|
-
else
|
46
|
-
field
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
results.join(' ')
|
51
|
-
end
|
52
|
-
|
53
|
-
def handle_association(hash)
|
54
|
-
hash.map do |key, fields|
|
55
|
-
"#{key} { #{parse_fields(fields)} }"
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|