graphql_connector 1.1.0 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 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