graphql_connector 1.1.0 → 1.3.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bf451963eb895b192df3959d06d56ea22588c2a38c284743f8289ecbebdc4e7e
4
- data.tar.gz: 73b57eb9b9569feb90497f96eb286192cd96d08370a181f92ab15a8855b56294
3
+ metadata.gz: 4b8c2af2590f1daf462e0f348e64078c530a4c7f6833a7d8692e6bada0f11291
4
+ data.tar.gz: 52edb3725223b2538f91b1904fa57a071ab0b43b853f37f23242e1dbb8d7eb50
5
5
  SHA512:
6
- metadata.gz: e41d9ba90e6c33af01647e08243600e19d8c0d412c7701f3d8e0d4c4d0cecd3e3b5b7312c881b8db3782ab28c911b2e5d7541f8bf655fef21e6b980923a65c55
7
- data.tar.gz: 9f496a3930e93affe9401a2e7ea0217471d2438619126ba243854202696fba634ed5b592b2a6a87c78daeb592bc4e1a509d9948a7c6012e72b9105a1265c5d3b
6
+ metadata.gz: c82b787552cf4590bae68e4eb15103252a47660ba4a8b2d7645deb9e218034cadbca24feaf9ef610818106e322fc7916a91fdd3726d251e49c0051224666d3c2
7
+ data.tar.gz: 491988a32bc66f1d597d32dbf0164b5f5a23a87923ac6d4da3c0fbc8272de1b6721ba8657b35e99ad221a9bcb2860431964e22281fcba341da36f3f5dd49ba1e
@@ -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/CHANGELOG.md CHANGED
@@ -1,3 +1,29 @@
1
+ ## 1.3.1 (2021-06-04)
2
+
3
+ * add more specs to test headers and connectors
4
+ * make the headers option optinal
5
+ * update the readme to explain the connector functionality better
6
+
7
+ ## 1.3.0 (2021-06-02)
8
+
9
+ * add the option to use a connector instead of init header for authorization
10
+ part of headers
11
+
12
+ ## 1.2.1 (2021-05-25)
13
+
14
+ * relax httparty dependency(`~> 0.17` => `~> 0.16`)
15
+
16
+ ## 1.2.0 (2020-12-22)
17
+
18
+ ### Features
19
+ * Add `mutation` under server namespace and service class inclusion
20
+ * See `README` for details
21
+
22
+ ## 1.1.1 (2020-5-04)
23
+
24
+ ### BugFix
25
+ * Omit invalid `()` for empty conditions in `query` method
26
+
1
27
  ## 1.1.0 (2020-4-19)
2
28
 
3
29
  ### Features
data/Gemfile.lock CHANGED
@@ -1,8 +1,8 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- graphql_connector (1.1.0)
5
- httparty (~> 0.17)
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.17.3)
13
+ httparty (0.18.1)
14
14
  mime-types (~> 3.0)
15
15
  multi_xml (>= 0.5.2)
16
- jaro_winkler (1.5.3)
17
- method_source (0.9.2)
16
+ jaro_winkler (1.5.4)
17
+ method_source (1.0.0)
18
18
  mime-types (3.3.1)
19
19
  mime-types-data (~> 3.2015)
20
- mime-types-data (3.2019.1009)
20
+ mime-types-data (3.2021.0225)
21
21
  multi_xml (0.6.0)
22
- parallel (1.17.0)
23
- parser (2.6.5.0)
22
+ parallel (1.19.1)
23
+ parser (2.7.1.1)
24
24
  ast (~> 2.4.0)
25
- pry (0.12.2)
26
- coderay (~> 1.1.0)
27
- method_source (~> 0.9.0)
25
+ pry (0.13.1)
26
+ coderay (~> 1.1)
27
+ method_source (~> 1.0)
28
28
  rainbow (3.0.0)
29
- rake (10.5.0)
30
- rspec (3.8.0)
31
- rspec-core (~> 3.8.0)
32
- rspec-expectations (~> 3.8.0)
33
- rspec-mocks (~> 3.8.0)
34
- rspec-core (3.8.2)
35
- rspec-support (~> 3.8.0)
36
- rspec-expectations (3.8.5)
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.8.0)
39
- rspec-mocks (3.8.2)
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.8.0)
42
- rspec-support (3.8.3)
43
- rubocop (0.75.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.6)
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, < 1.7)
50
+ unicode-display_width (>= 1.4.0, < 2.0)
50
51
  ruby-progressbar (1.10.1)
51
- unicode-display_width (1.6.0)
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.1.2
65
+ 2.1.4
data/README.md CHANGED
@@ -3,8 +3,7 @@
3
3
 
4
4
  [![Gem
5
5
  Version](https://badge.fury.io/rb/graphql_connector.svg)](https://badge.fury.io/rb/graphql_connector)
6
- [![Build
7
- Status](https://travis-ci.org/Garllon/graphql_connector.svg?branch=master)](https://travis-ci.org/Garllon/graphql_connector)
6
+ [![CI](https://github.com/Garllon/graphql_connector/workflows/CI/badge.svg)](https://github.com/Garllon/graphql_connector/actions?query=workflow%3ACI)
8
7
  [![Maintainability](https://api.codeclimate.com/v1/badges/548db3cf0d078b379c84/maintainability)](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,10 +30,31 @@ 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: {})
34
+ end
35
+ ```
36
+
37
+ The connector is expecting that it contains a `base` connector instance and a
38
+ `method` parameter as string, where it gets the token. WE expect that the
39
+ method is a public method in your connector class. Currently like this:
40
+ ```ruby
41
+ { base: TokenAgent.new, method: 'get_authorization_header' }
42
+ ```
43
+
44
+ Your method should return a hash like this:
45
+ ```ruby
46
+ class TokenAgent
47
+ [...]
48
+ def get_authorization_header
49
+ [...]
50
+ { 'Authorization' => 'Token HERE' }
51
+ end
35
52
  end
36
53
  ```
37
54
 
55
+ When you set a connector, it will override the setting in the headers for
56
+ Authorization.
57
+
38
58
  For each graphql server you wish to query use `add_server`.
39
59
 
40
60
  Afterwards you will have the following options to fetch and/or mutate data with
@@ -42,6 +62,7 @@ one or many graphql servers:
42
62
 
43
63
  * `raw_query` --> [Examples](examples/raw_query_examples.rb)
44
64
  * `query` --> [Examples](examples/query_examples.rb)
65
+ * `mutation` --> [Examples](examples/mutation_examples.rb)
45
66
  * `service class inclusion` --> [Examples](examples/departments_service_class_examples.rb)
46
67
 
47
68
  See the following sub sections for details
@@ -92,18 +113,31 @@ Example:
92
113
 
93
114
  ---
94
115
 
116
+ ### mutation
117
+
118
+ Works in the same way as [query](#query)
119
+
120
+ See also [here](examples/mutation_examples.rb) for example usage
121
+
95
122
  ### Service class inclusion
96
123
 
97
124
  This approach can be used to `graphqlize` **any** kind of ruby (service) class
98
- so that it has re-usable graphql query methods.
125
+ so that it has re-usable graphql `query` and `mutation` **class methods**.
99
126
 
100
127
  * First add `extend GraphqlConnector::<server>::Query` in the the class(es) that should be `graphqlized`
101
- * Next for each mapping add a `add_query` or `add_raw_query` aliasing the graphql server type supports as follows:
102
- * `add_query <alias>: <query type in graphql server>, params: [<any kind of query type params>], returns: [<selected_fields>]`
103
- * `add_raw_query <alias>: <query string>, params: [<any kind of query type params>]`
104
- * If <query type>/<query string> does not need them, omit `params`
105
128
 
106
- See also [here](examples/departments_service_class_examples.rb) for example usage as also in the following:
129
+ * Then you can aliases as many graphql server types via `add_query` and/or `add_raw_query` and/or `add_mutation`:
130
+
131
+ ```ruby
132
+ add_query <alias>: :<graphql_server_type>, params: [...], returns: [...]
133
+
134
+ add_raw_query <alias>: 'query { ... }', params: [...]
135
+
136
+ add_mutation <alias>: :<graphql_server_type>, params: [...], returns: [...]
137
+ ```
138
+ * :grey_exclamation: If not needed omit `params`
139
+
140
+ See also [here](examples/departments_service_class_examples.rb) and also here for complete example usage:
107
141
 
108
142
  ```ruby
109
143
  GraphqlConnector.configure do |config|
@@ -132,6 +166,10 @@ class Product
132
166
  add_query by_category_id: :products,
133
167
  params: :product_category,
134
168
  returns: [product_category: [:id, :name]]
169
+
170
+ add_mutation create: :createProduct,
171
+ params: [:name, :catgetoryId],
172
+ returns: [:id, :name]
135
173
  end
136
174
 
137
175
  Product.all
@@ -148,6 +186,9 @@ Product.by(id: 1, name: 'Demo Product')
148
186
 
149
187
  Product.by_category_id(product_category: { id: 10})
150
188
  => OpenStruct<product_category=<ProductCategory<id=10, name='Demo Category'>>
189
+
190
+ Product.create(name: 'Another Product', catgetoryId: 10)
191
+ => OpenStruct<id=10, name='Another Product'>
151
192
  ```
152
193
 
153
194
  Also custom **class methods** can used to call any kind of `query` and do further selection instead:
@@ -167,6 +208,9 @@ Product.by_id(id: 1)
167
208
  => OpenStruct<id=1, name='Demo Product'>>
168
209
  ```
169
210
 
211
+ :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/)
212
+
213
+
170
214
  Example for `raw_query`:
171
215
 
172
216
  ```ruby
@@ -188,6 +232,8 @@ Product.by(id: '1', name: 'Demo Product')
188
232
 
189
233
  ```
190
234
 
235
+ :exclamation: There is no `add_raw_mutation` since `add_raw_query` does already cover such a case
236
+
191
237
  ## Development
192
238
 
193
239
  After checking out the repo, run
@@ -1,5 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
4
+ # ! The following examples are used together with
5
+ # ! https://github.com/sushie1984/rails-graphql-server
6
+ # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
7
+
3
8
  uri = 'http://rails-graphql-server.herokuapp.com/api/graphql'
4
9
  GraphqlConnector.configure do |config|
5
10
  config.add_server(name: 'RailsGraphqlServer', uri: uri, headers: {})
@@ -27,6 +32,12 @@ class Department
27
32
  }
28
33
  }',
29
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]]
30
41
  end
31
42
 
32
43
  Department.all
@@ -36,3 +47,5 @@ Department.by_id(id: %w[1 2])
36
47
  Department.all_raw
37
48
 
38
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)
@@ -1,5 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
4
+ # ! The following examples are used together with
5
+ # ! https://github.com/sushie1984/rails-graphql-server
6
+ # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
7
+
3
8
  uri = 'http://rails-graphql-server.herokuapp.com/api/graphql'
4
9
  GraphqlConnector.configure do |config|
5
10
  config.add_server(name: 'RailsGraphqlServer', uri: uri, headers: {})
@@ -1,5 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
4
+ # ! The following examples are used together with
5
+ # ! https://github.com/sushie1984/rails-graphql-server
6
+ # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
7
+
3
8
  GraphqlConnector.configure do |config|
4
9
  config.add_server(name: 'RailsGraphqlServer',
5
10
  uri: 'http://rails-graphql-server.herokuapp.com/api/graphql',
@@ -31,11 +31,10 @@ Gem::Specification.new do |spec|
31
31
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
32
32
  spec.require_paths = ['lib']
33
33
 
34
- spec.add_dependency 'httparty', '~> 0.17'
34
+ spec.add_dependency 'httparty', '~> 0.16'
35
35
 
36
36
  spec.add_development_dependency 'bundler', '~> 2.0'
37
37
  spec.add_development_dependency 'pry', '~> 0.10'
38
- spec.add_development_dependency 'rake', '~> 10.0'
39
38
  spec.add_development_dependency 'rspec', '~> 3.8'
40
39
  spec.add_development_dependency 'rubocop', '~> 0.75'
41
40
  end
@@ -1,7 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'graphql_connector/version'
4
- require 'graphql_connector/query_builder'
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'
@@ -5,12 +5,11 @@ 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
- inject_http_client(base_object)
13
- inject_query_methods(base_object)
12
+ inject_http_client_delegations(base_object)
14
13
  create_service_class_module(base_object)
15
14
 
16
15
  base_object
@@ -40,30 +39,23 @@ module GraphqlConnector
40
39
  METHOD
41
40
  end
42
41
 
43
- def class_with(uri, headers)
42
+ def class_with(uri, headers = {}, connector = {})
44
43
  Class.new do
45
- attr_accessor :uri, :headers
46
- @uri = uri
47
- @headers = headers
44
+ attr_accessor :uri, :headers, :connector
45
+ @uri = uri
46
+ @headers = headers
47
+ @connector = connector
48
48
  end
49
49
  end
50
50
 
51
- def inject_http_client(base_object)
51
+ def inject_http_client_delegations(base_object)
52
52
  base_object.instance_eval do
53
- def http_client
54
- @http_client ||= GraphqlConnector::HttpClient.new(@uri, @headers)
55
- end
56
- end
57
- end
53
+ extend SingleForwardable
54
+ def_delegators :http_client, :query, :raw_query, :mutation
58
55
 
59
- def inject_query_methods(base_object)
60
- base_object.instance_eval do
61
- def query(model, conditions, selected_fields)
62
- http_client.query(model, conditions, selected_fields)
63
- end
64
-
65
- def raw_query(query_string, variables: {})
66
- http_client.raw_query(query_string, variables: variables)
56
+ def http_client
57
+ @http_client ||=
58
+ GraphqlConnector::HttpClient.new(@uri, @headers, @connector)
67
59
  end
68
60
  end
69
61
  end
@@ -9,8 +9,9 @@ module GraphqlConnector
9
9
  @base_server_types = {}
10
10
  end
11
11
 
12
- def add_server(name:, uri:, headers:)
13
- @base_server_types[name] = BaseServerType.build(name, uri, headers)
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!
@@ -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
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphqlConnector
4
+ module Formatters
5
+ # Class that returns in mutation string format
6
+ class MutationFormat < BaseFormat
7
+ private
8
+
9
+ def query_type
10
+ 'mutation'
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphqlConnector
4
+ module Formatters
5
+ # Class that returns in query string format
6
+ class QueryFormat < BaseFormat
7
+ private
8
+
9
+ def query_type
10
+ 'query'
11
+ end
12
+ end
13
+ end
14
+ end
@@ -3,25 +3,29 @@
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 = GraphqlConnector::QueryBuilder.new(model,
13
- conditions,
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
- result = parsed_body['data'][model.to_s]
17
- return OpenStruct.new(result) unless result.is_a? Array
16
+ format_body(parsed_body['data'][model.to_s])
17
+ end
18
18
 
19
- result.map { |entry| OpenStruct.new(entry) }
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
26
  def raw_query(query_string, variables: {})
23
27
  response = HTTParty.post(@uri,
24
- headers: @headers,
28
+ headers: handle_headers,
25
29
  body: { query: query_string,
26
30
  variables: variables })
27
31
  parsed_body = JSON.parse(response.body)
@@ -31,6 +35,19 @@ module GraphqlConnector
31
35
 
32
36
  private
33
37
 
38
+ def handle_headers
39
+ return @headers if @connector.empty?
40
+
41
+ @headers
42
+ .merge(@connector[:base].public_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
+
34
51
  def verify_response!(parsed_body)
35
52
  return unless parsed_body.key? 'errors'
36
53
 
@@ -13,9 +13,9 @@ module GraphqlConnector
13
13
  .map(&:to_s)
14
14
  .include?(class_method_name.to_s)
15
15
 
16
- error_msg = "The (raw_)add_query '#{class_method_name}: ... ' is "\
16
+ error_msg = "The method '#{class_method_name}: ... ' is "\
17
17
  'already implemented within the context of '\
18
- "#{invoked_class} and therefore cannot be used!"
18
+ "#{invoked_class} and therefore cannot be used again!"
19
19
  raise ClassMethodAlreadyImplementedError, error_msg
20
20
  end
21
21
 
@@ -38,6 +38,21 @@ module GraphqlConnector
38
38
  raw_query_keyword_method(class_method_name, query_string, params)
39
39
  end
40
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
+
41
56
  private
42
57
 
43
58
  def query_method(class_method_name, query_type, return_fields)
@@ -71,6 +86,23 @@ module GraphqlConnector
71
86
  end
72
87
  METHOD
73
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
74
106
  end
75
107
  end
76
108
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GraphqlConnector
4
- VERSION = '1.1.0'
4
+ VERSION = '1.3.1'
5
5
  end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphql_connector
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Garllon
8
8
  - sushie1984
9
- autorequire:
9
+ autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2020-04-20 00:00:00.000000000 Z
12
+ date: 2021-06-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: httparty
@@ -17,14 +17,14 @@ dependencies:
17
17
  requirements:
18
18
  - - "~>"
19
19
  - !ruby/object:Gem::Version
20
- version: '0.17'
20
+ version: '0.16'
21
21
  type: :runtime
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
25
  - - "~>"
26
26
  - !ruby/object:Gem::Version
27
- version: '0.17'
27
+ version: '0.16'
28
28
  - !ruby/object:Gem::Dependency
29
29
  name: bundler
30
30
  requirement: !ruby/object:Gem::Requirement
@@ -53,20 +53,6 @@ dependencies:
53
53
  - - "~>"
54
54
  - !ruby/object:Gem::Version
55
55
  version: '0.10'
56
- - !ruby/object:Gem::Dependency
57
- name: rake
58
- requirement: !ruby/object:Gem::Requirement
59
- requirements:
60
- - - "~>"
61
- - !ruby/object:Gem::Version
62
- version: '10.0'
63
- type: :development
64
- prerelease: false
65
- version_requirements: !ruby/object:Gem::Requirement
66
- requirements:
67
- - - "~>"
68
- - !ruby/object:Gem::Version
69
- version: '10.0'
70
56
  - !ruby/object:Gem::Dependency
71
57
  name: rspec
72
58
  requirement: !ruby/object:Gem::Requirement
@@ -104,11 +90,11 @@ executables: []
104
90
  extensions: []
105
91
  extra_rdoc_files: []
106
92
  files:
93
+ - ".github/workflows/ci.yaml"
107
94
  - ".gitignore"
108
95
  - ".rspec"
109
96
  - ".rubocop.yml"
110
97
  - ".rubocop_todo.yml"
111
- - ".travis.yml"
112
98
  - CHANGELOG.md
113
99
  - CODE_OF_CONDUCT.md
114
100
  - Gemfile
@@ -117,6 +103,7 @@ files:
117
103
  - README.md
118
104
  - bin/console
119
105
  - examples/departments_service_class_examples.rb
106
+ - examples/mutation_examples.rb
120
107
  - examples/query_examples.rb
121
108
  - examples/raw_query_examples.rb
122
109
  - graphql_connector.gemspec
@@ -124,8 +111,10 @@ files:
124
111
  - lib/graphql_connector/base_server_type.rb
125
112
  - lib/graphql_connector/configuration.rb
126
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
127
117
  - lib/graphql_connector/http_client.rb
128
- - lib/graphql_connector/query_builder.rb
129
118
  - lib/graphql_connector/service_classable/class_method_validator.rb
130
119
  - lib/graphql_connector/service_classable/params_validator.rb
131
120
  - lib/graphql_connector/service_classable/queryable.rb
@@ -138,7 +127,7 @@ metadata:
138
127
  homepage_uri: https://github.com/Garllon/graphql_connector/blob/master/README.md
139
128
  source_code_uri: https://github.com/Garllon/graphql_connector
140
129
  changelog_uri: https://github.com/Garllon/graphql_connector/blob/master/CHANGELOG.md
141
- post_install_message:
130
+ post_install_message:
142
131
  rdoc_options: []
143
132
  require_paths:
144
133
  - lib
@@ -153,8 +142,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
153
142
  - !ruby/object:Gem::Version
154
143
  version: '0'
155
144
  requirements: []
156
- rubygems_version: 3.0.6
157
- signing_key:
145
+ rubygems_version: 3.2.7
146
+ signing_key:
158
147
  specification_version: 4
159
148
  summary: GraphQL client
160
149
  test_files: []
data/.travis.yml DELETED
@@ -1,10 +0,0 @@
1
- ---
2
- sudo: false
3
- language: ruby
4
- cache: bundler
5
- rvm:
6
- - 2.4.9
7
- - 2.5.7
8
- - 2.6.5
9
- script:
10
- - bundle exec rspec spec
@@ -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