graphql-extras 0.2.4 → 0.3.2

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
- SHA1:
3
- metadata.gz: 18eadb182c9a76519d6d2edeb5b0d4e1878fa09d
4
- data.tar.gz: 2c25c5003f3734e0c7c2c083cc47a76531eda759
2
+ SHA256:
3
+ metadata.gz: eb6a2324dfea95555ab147de0f4d79601603e21ca7dde008939795b12d40064c
4
+ data.tar.gz: ef735334a0b5be7ac0286c45886aa60d507482b73a95c0af89a2d1b5dfae27cc
5
5
  SHA512:
6
- metadata.gz: 7966e2f06aa836e34f0f42eecfdc1606f5a278f83d0c717f6001ab5c234424e6f50a3dd959ec57c477d9f74f9a35b25e25bbf38e47cda60216b70af3633b3231
7
- data.tar.gz: 291c570bd60ce89c6eb3beef5beab2a420967286c74ffbf19543f7623b3387feb70dc6871a3746463e01a2b611356d92e41d3fa3487755ec9061afe92db59b7b
6
+ metadata.gz: b412b43cd6d6c3865726770b1bd54d121e5a122fdafcd0f4f0e141edb6cd9e83ca13c47f73530025be3d16498144f97f3ddc40c02897049679bfebad8189ed56
7
+ data.tar.gz: '018ccec04e7e67b563e460fcbe7d1649a097087846b488985c34072004bcd2839162e4a3f3131c76718ea99a1d15633bc5c9f7ec3190cef65de203eb6c533a4b'
@@ -0,0 +1,25 @@
1
+ name: Build
2
+ on: [push]
3
+ jobs:
4
+ build:
5
+ runs-on: ubuntu-latest
6
+ steps:
7
+ - name: Checkout
8
+ uses: actions/checkout@v2
9
+
10
+ - name: Setup Ruby
11
+ uses: actions/setup-ruby@v1
12
+ with:
13
+ ruby-version: 2.6.x
14
+
15
+ - name: Install packages
16
+ run: sudo apt-get install libsqlite3-dev
17
+
18
+ - name: Install bundler
19
+ run: gem install bundler
20
+
21
+ - name: Install dependencies
22
+ run: bundle install
23
+
24
+ - name: Test
25
+ run: bundle exec rspec
@@ -0,0 +1,41 @@
1
+ name: Publish
2
+ on:
3
+ release:
4
+ types: [published]
5
+ jobs:
6
+ publish:
7
+ runs-on: ubuntu-latest
8
+ steps:
9
+ - name: Checkout
10
+ uses: actions/checkout@v2
11
+
12
+ - name: Setup Ruby
13
+ uses: actions/setup-ruby@v1
14
+ with:
15
+ ruby-version: 2.6.x
16
+
17
+ - name: Install packages
18
+ run: sudo apt-get install libsqlite3-dev
19
+
20
+ - name: Install bundler
21
+ run: gem install bundler
22
+
23
+ - name: Install dependencies
24
+ run: bundle install
25
+
26
+ - name: Test
27
+ run: bundle exec rspec
28
+
29
+ - name: Set version
30
+ run: perl -pi -e "s/0\.0\.0/${GITHUB_REF:11}/" lib/graphql/extras/version.rb
31
+
32
+ - name: Publish
33
+ run: |
34
+ mkdir -p $HOME/.gem
35
+ touch $HOME/.gem/credentials
36
+ chmod 0600 $HOME/.gem/credentials
37
+ printf -- "---\n:rubygems_api_key: ${RUBYGEMS_TOKEN}\n" > $HOME/.gem/credentials
38
+ gem build *.gemspec
39
+ gem push *.gem
40
+ env:
41
+ RUBYGEMS_TOKEN: ${{ secrets.RUBYGEMS_TOKEN }}
data/README.md CHANGED
@@ -1,7 +1,30 @@
1
- # GraphQL::Extras [![Build Status](https://travis-ci.org/rzane/graphql-extras.svg?branch=master)](https://travis-ci.org/rzane/graphql-extras)
1
+ <h1 align="center">GraphQL::Extras</h1>
2
+
3
+ <div align="center">
4
+
5
+ ![Build](https://github.com/rzane/graphql-extras/workflows/Build/badge.svg)
6
+ ![Version](https://img.shields.io/gem/v/graphql-extras)
7
+
8
+ </div>
2
9
 
3
10
  A collection of utilities for building GraphQL APIs.
4
11
 
12
+ **Table of Contents**
13
+
14
+ - [Installation](#installation)
15
+ - [Usage](#usage)
16
+ - [GraphQL::Extras::Controller](#graphqlextrascontroller)
17
+ - [GraphQL::Extras::AssociationLoader](#graphqlextrasassociationloader)
18
+ - [GraphQL::Extras::Preload](#graphqlextraspreload)
19
+ - [GraphQL::Extras::Types](#graphqlextrastypes)
20
+ - [Date](#date)
21
+ - [DateTime](#datetime)
22
+ - [Decimal](#decimal)
23
+ - [Upload](#upload)
24
+ - [GraphQL::Extras::Test](#graphqlextrastest)
25
+ - [Development](#development)
26
+ - [Contributing](#contributing)
27
+
5
28
  ## Installation
6
29
 
7
30
  Add this line to your application's Gemfile:
@@ -30,30 +53,36 @@ class GraphqlController < ApplicationController
30
53
  end
31
54
  ```
32
55
 
33
- ### GraphQL::Extras::Batch::AssociationLoader
56
+ ### GraphQL::Extras::AssociationLoader
34
57
 
35
58
  This is a subclass of [`GraphQL::Batch::Loader`](https://github.com/Shopify/graphql-batch) that performs eager loading of Active Record associations.
36
59
 
37
60
  ```ruby
38
- loader = GraphQL::Extras::Batch::AssociationLoader.for(:blog)
61
+ loader = GraphQL::Extras::AssociationLoader.for(:blog)
39
62
  loader.load(Post.first)
40
63
  loader.load_many(Post.all)
41
64
  ```
42
65
 
43
- ### GraphQL::Extras::Batch::Resolvers
66
+ ### GraphQL::Extras::Preload
44
67
 
45
- This includes a set of convenience methods for query batching.
68
+ This allows you to preload associations before resolving fields.
46
69
 
47
70
  ```ruby
48
- class Post < GraphQL::Schema::Object
49
- include GraphQL::Extras::Batch::Resolver
71
+ class BaseField < GraphQL::Schema::Field
72
+ prepend GraphQL::Extras::Preload
73
+ end
74
+
75
+ class BaseObject < GraphQL::Schema::Object
76
+ field_class BaseField
77
+ end
50
78
 
51
- field :blog, BlogType, resolve: association(:blog), null: false
52
- field :comments, [CommentType], resolve: association(:comments, preload: { comments: :user }), null: false
53
- field :blog_title, String, null: false
79
+ class PostType < BaseObject
80
+ field :author, AuthorType, preload: :author, null: false
81
+ field :author_posts, [PostType], preload: {author: :posts}, null: false
82
+ field :depends_on_author, Integer, preload: :author, null: false
54
83
 
55
- def blog_title
56
- association(object, :blog).then(&:title)
84
+ def author_posts
85
+ object.author.posts
57
86
  end
58
87
  end
59
88
  ```
@@ -88,7 +117,7 @@ This scalar takes a `DateTime` and transmits it as a string, using ISO 8601 form
88
117
  field :created_at, DateTime, required: true
89
118
  ```
90
119
 
91
- *Note: This is just an alias for the `ISO8601DateTime` type that is included in the `graphql` gem.*
120
+ _Note: This is just an alias for the `ISO8601DateTime` type that is included in the `graphql` gem._
92
121
 
93
122
  #### Decimal
94
123
 
@@ -119,36 +148,44 @@ Take note of the correspondence between the value `"image"` and the additional H
119
148
 
120
149
  See [apollo-link-upload](https://github.com/rzane/apollo-link-upload) for the client-side implementation.
121
150
 
122
- ### RSpec integration
151
+ ### GraphQL::Extras::Test
123
152
 
124
- Add the following to your `rails_helper.rb` (or `spec_helper.rb`).
153
+ This module makes it really easy to test your schema.
154
+
155
+ First, create a test schema:
125
156
 
126
157
  ```ruby
127
- require "graphql/extras/rspec"
158
+ # spec/support/test_schema.rb
159
+ require "graphql/extras/test"
160
+
161
+ class TestSchema < GraphQL::Extras::Test::Schema
162
+ configure schema: Schema, queries: "spec/**/*.graphql"
163
+ end
128
164
  ```
129
165
 
130
166
  Now, you can run tests like so:
131
167
 
132
168
  ```ruby
169
+ require "support/test_schema"
170
+
133
171
  RSpec.describe "hello" do
134
172
  let(:context) { { name: "Ray" } }
135
- let(:schema) { use_schema(Schema, context: context) }
136
- let(:queries) { graphql_fixture("hello.graphql") }
173
+ let(:schema) { TestSchema.new(context) }
137
174
 
138
175
  it "allows easily executing queries" do
139
- result = schema.execute(queries.hello)
176
+ query = schema.hello
140
177
 
141
- expect(result).to be_successful_query
142
- expect(result['data']['hello']).to eq("world")
178
+ expect(query).to be_successful
179
+ expect(query.data["hello"]).to eq("world")
143
180
  end
144
- end
145
- ```
146
181
 
147
- The `graphql_fixture` method assumes that your queries live in `spec/fixtures/graphql`. You can change this assumption with the following configuration:
182
+ it "parses errors" do
183
+ query = schema.kaboom
148
184
 
149
- ```ruby
150
- RSpec.configure do |config|
151
- config.graphql_fixture_path = '/path/to/queries'
185
+ expect(query).not_to be_successful
186
+ expect(query.errors[0].message).to eq("Invalid")
187
+ expect(query.errors[0].code).to eq("VALIDATION_ERROR")
188
+ end
152
189
  end
153
190
  ```
154
191
 
@@ -10,10 +10,10 @@ Gem::Specification.new do |spec|
10
10
 
11
11
  spec.summary = %q{Utiltities for building GraphQL APIs.}
12
12
  spec.description = %q{A set of modules and types for buildign GraphQL APIs.}
13
- spec.homepage = "https://github.com/promptworks/graphql-extras"
13
+ spec.homepage = "https://github.com/rzane/graphql-extras"
14
14
 
15
15
  spec.metadata["homepage_uri"] = spec.homepage
16
- spec.metadata["source_code_uri"] = "https://github.com/promptworks/graphql-extras"
16
+ spec.metadata["source_code_uri"] = "https://github.com/rzane/graphql-extras"
17
17
 
18
18
  # Specify which files should be added to the gem when it is released.
19
19
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
@@ -25,13 +25,13 @@ Gem::Specification.new do |spec|
25
25
  spec.require_paths = ["lib"]
26
26
 
27
27
  spec.add_dependency "activesupport", ">= 5.2"
28
- spec.add_dependency "graphql", "~> 1.9"
28
+ spec.add_dependency "graphql", "~> 1.12"
29
29
  spec.add_dependency "graphql-batch", "~> 0.4"
30
30
 
31
31
  spec.add_development_dependency "bundler", "~> 2.0"
32
- spec.add_development_dependency "rake", "~> 10.0"
32
+ spec.add_development_dependency "rake", "~> 13.0"
33
33
  spec.add_development_dependency "rspec", "~> 3.0"
34
- spec.add_development_dependency "rspec-rails", "~> 3.8"
34
+ spec.add_development_dependency "rspec-rails", "~> 4.0"
35
35
  spec.add_development_dependency "actionpack", ">= 5.2"
36
36
  spec.add_development_dependency "activerecord", ">= 5.2"
37
37
  spec.add_development_dependency "sqlite3", "~> 1.4"
@@ -1,7 +1,8 @@
1
1
  require "graphql/extras/version"
2
2
  require "graphql/extras/types"
3
3
  require "graphql/extras/controller"
4
- require "graphql/extras/batch"
4
+ require "graphql/extras/association_loader"
5
+ require "graphql/extras/preload"
5
6
 
6
7
  module GraphQL
7
8
  module Extras
@@ -0,0 +1,24 @@
1
+ require "graphql/batch"
2
+
3
+ module GraphQL
4
+ module Extras
5
+ class AssociationLoader < GraphQL::Batch::Loader
6
+ def initialize(preload)
7
+ @preload = preload
8
+ end
9
+
10
+ def cache_key(record)
11
+ record.object_id
12
+ end
13
+
14
+ def perform(records)
15
+ preloader = ActiveRecord::Associations::Preloader.new
16
+ preloader.preload(records, @preload)
17
+
18
+ records.each do |record|
19
+ fulfill(record, nil) unless fulfilled?(record)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,23 @@
1
+ require "graphql/extras/association_loader"
2
+
3
+ module GraphQL
4
+ module Extras
5
+ module Preload
6
+ # @override
7
+ def initialize(*args, preload: nil, **opts, &block)
8
+ @preload = preload
9
+ super(*args, **opts, &block)
10
+ end
11
+
12
+ # @override
13
+ def resolve(object, args, ctx)
14
+ return super unless @preload
15
+
16
+ loader = AssociationLoader.for(@preload)
17
+ loader.load(object.object).then do
18
+ super(object, args, ctx)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1 @@
1
+ require "graphql/extras/test/schema"
@@ -0,0 +1,59 @@
1
+ module GraphQL
2
+ module Extras
3
+ module Test
4
+ class Loader
5
+ FragmentNotFoundError = Class.new(StandardError)
6
+
7
+ attr_reader :fragments
8
+ attr_reader :operations
9
+
10
+ def initialize
11
+ @fragments = {}
12
+ @operations = {}
13
+ end
14
+
15
+ def load(path)
16
+ document = ::GraphQL.parse_file(path)
17
+ document.definitions.each do |node|
18
+ case node
19
+ when Nodes::FragmentDefinition
20
+ fragments[node.name] = node
21
+ when Nodes::OperationDefinition
22
+ operations[node.name] = node
23
+ end
24
+ end
25
+ end
26
+
27
+ def print(operation)
28
+ printer = ::GraphQL::Language::Printer.new
29
+ nodes = [operation, *resolve_fragments(operation)]
30
+ nodes.map { |node| printer.print(node) }.join("\n")
31
+ end
32
+
33
+ private
34
+
35
+ Nodes = ::GraphQL::Language::Nodes
36
+
37
+ # Recursively iterate through the node's fields and find
38
+ # resolve all of the fragment definitions that are needed.
39
+ def resolve_fragments(node)
40
+ node.selections.flat_map do |field|
41
+ case field
42
+ when Nodes::FragmentSpread
43
+ fragment = fetch_fragment!(field.name)
44
+ [fragment, *resolve_fragments(fragment)]
45
+ else
46
+ resolve_fragments(field)
47
+ end
48
+ end
49
+ end
50
+
51
+ def fetch_fragment!(name)
52
+ fragments.fetch(name) do
53
+ raise FragmentNotFoundError, "Fragment `#{name}` is not defined"
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,37 @@
1
+ module GraphQL
2
+ module Extras
3
+ module Test
4
+ class Response
5
+ attr_reader :data
6
+ attr_reader :errors
7
+
8
+ def initialize(payload)
9
+ @data = payload["data"]
10
+ @errors = payload.fetch("errors", []).map do |error|
11
+ Error.new(error)
12
+ end
13
+ end
14
+
15
+ def successful?
16
+ errors.empty?
17
+ end
18
+
19
+ class Error
20
+ attr_reader :message
21
+ attr_reader :extensions
22
+ attr_reader :code
23
+ attr_reader :path
24
+ attr_reader :locations
25
+
26
+ def initialize(payload)
27
+ @message = payload["message"]
28
+ @path = payload["path"]
29
+ @locations = payload["locations"]
30
+ @extensions = payload["extensions"]
31
+ @code = payload.dig("extensions", "code")
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,57 @@
1
+ require "securerandom"
2
+ require "active_support/inflector"
3
+ require "active_support/core_ext/hash"
4
+ require "graphql/extras/test/loader"
5
+ require "graphql/extras/test/response"
6
+
7
+ module GraphQL
8
+ module Extras
9
+ module Test
10
+ class Schema
11
+ def self.configure(schema:, queries:)
12
+ loader = Loader.new
13
+
14
+ Dir.glob(queries) do |path|
15
+ loader.load(path)
16
+ end
17
+
18
+ loader.operations.each do |name, operation|
19
+ query = loader.print(operation)
20
+
21
+ define_method(name.underscore) do |variables = {}|
22
+ __execute(schema, query, variables)
23
+ end
24
+ end
25
+ end
26
+
27
+ def initialize(context = {})
28
+ @context = context
29
+ end
30
+
31
+ private
32
+
33
+ def __execute(schema, query, variables)
34
+ uploads = {}
35
+
36
+ variables = variables.deep_transform_keys do |key|
37
+ key.to_s.camelize(:lower)
38
+ end
39
+
40
+ variables = variables.deep_transform_values do |value|
41
+ if value.respond_to? :tempfile
42
+ id = SecureRandom.uuid
43
+ uploads[id] = value
44
+ id
45
+ else
46
+ value
47
+ end
48
+ end
49
+
50
+ context = @context.merge(uploads: uploads)
51
+ result = schema.execute(query, variables: variables, context: context)
52
+ Response.new(result.to_h)
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -1,5 +1,5 @@
1
1
  module GraphQL
2
2
  module Extras
3
- VERSION = "0.2.4"
3
+ VERSION = "0.3.2"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphql-extras
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.4
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ray Zane
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-10-04 00:00:00.000000000 Z
11
+ date: 2021-02-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '1.9'
33
+ version: '1.12'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '1.9'
40
+ version: '1.12'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: graphql-batch
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -72,14 +72,14 @@ dependencies:
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '10.0'
75
+ version: '13.0'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '10.0'
82
+ version: '13.0'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: rspec
85
85
  requirement: !ruby/object:Gem::Requirement
@@ -100,14 +100,14 @@ dependencies:
100
100
  requirements:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: '3.8'
103
+ version: '4.0'
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: '3.8'
110
+ version: '4.0'
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: actionpack
113
113
  requirement: !ruby/object:Gem::Requirement
@@ -157,9 +157,10 @@ executables: []
157
157
  extensions: []
158
158
  extra_rdoc_files: []
159
159
  files:
160
+ - ".github/workflows/build.yml"
161
+ - ".github/workflows/publish.yml"
160
162
  - ".gitignore"
161
163
  - ".rspec"
162
- - ".travis.yml"
163
164
  - Gemfile
164
165
  - README.md
165
166
  - Rakefile
@@ -167,16 +168,20 @@ files:
167
168
  - bin/setup
168
169
  - graphql-extras.gemspec
169
170
  - lib/graphql/extras.rb
170
- - lib/graphql/extras/batch.rb
171
+ - lib/graphql/extras/association_loader.rb
171
172
  - lib/graphql/extras/controller.rb
172
- - lib/graphql/extras/rspec.rb
173
+ - lib/graphql/extras/preload.rb
174
+ - lib/graphql/extras/test.rb
175
+ - lib/graphql/extras/test/loader.rb
176
+ - lib/graphql/extras/test/response.rb
177
+ - lib/graphql/extras/test/schema.rb
173
178
  - lib/graphql/extras/types.rb
174
179
  - lib/graphql/extras/version.rb
175
- homepage: https://github.com/promptworks/graphql-extras
180
+ homepage: https://github.com/rzane/graphql-extras
176
181
  licenses: []
177
182
  metadata:
178
- homepage_uri: https://github.com/promptworks/graphql-extras
179
- source_code_uri: https://github.com/promptworks/graphql-extras
183
+ homepage_uri: https://github.com/rzane/graphql-extras
184
+ source_code_uri: https://github.com/rzane/graphql-extras
180
185
  post_install_message:
181
186
  rdoc_options: []
182
187
  require_paths:
@@ -192,8 +197,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
192
197
  - !ruby/object:Gem::Version
193
198
  version: '0'
194
199
  requirements: []
195
- rubyforge_project:
196
- rubygems_version: 2.6.14
200
+ rubygems_version: 3.0.3
197
201
  signing_key:
198
202
  specification_version: 4
199
203
  summary: Utiltities for building GraphQL APIs.
data/.travis.yml DELETED
@@ -1,7 +0,0 @@
1
- ---
2
- sudo: false
3
- language: ruby
4
- cache: bundler
5
- rvm:
6
- - 2.6.3
7
- before_install: gem install bundler -v 2.0.2
@@ -1,47 +0,0 @@
1
- require "graphql/batch"
2
-
3
- module GraphQL
4
- module Extras
5
- module Batch
6
- class AssociationLoader < GraphQL::Batch::Loader
7
- def initialize(name, preload: name)
8
- @name = name
9
- @preload = preload
10
- end
11
-
12
- def cache_key(record)
13
- record.object_id
14
- end
15
-
16
- def perform(records)
17
- preloader = ActiveRecord::Associations::Preloader.new
18
- preloader.preload(records, @preload)
19
-
20
- records.each do |record|
21
- fulfill(record, record.public_send(@name))
22
- end
23
- end
24
- end
25
-
26
- module Resolvers
27
- def self.included(base)
28
- base.extend ClassMethods
29
- end
30
-
31
- module ClassMethods
32
- def association(name)
33
- lambda do |record, _args, _ctx|
34
- loader = AssociationLoader.for(name)
35
- loader.load(record)
36
- end
37
- end
38
- end
39
-
40
- def association(record, name)
41
- loader = AssociationLoader.for(name)
42
- loader.load(record)
43
- end
44
- end
45
- end
46
- end
47
- end
@@ -1,103 +0,0 @@
1
- require "yaml"
2
- require "active_support/inflector"
3
- require "active_support/core_ext/hash"
4
-
5
- module GraphQL
6
- module Extras
7
- module RSpec
8
- class Queries
9
- def initialize(values)
10
- values.each do |key, value|
11
- define_singleton_method(key) { value }
12
- end
13
- end
14
- end
15
-
16
- class Schema
17
- def initialize(schema, context: {})
18
- @schema = schema
19
- @context = context
20
- end
21
-
22
- def execute(query, variables = {})
23
- variables = deep_camelize_keys(variables)
24
- variables, uploads = extract_uploads(variables)
25
- context = @context.merge(uploads: uploads)
26
-
27
- result = @schema.execute(query, variables: variables, context: context)
28
- result.to_h
29
- end
30
-
31
- private
32
-
33
- def extract_uploads(variables)
34
- uploads = {}
35
- variables = deep_transform_values(variables) { |value|
36
- if upload?(value)
37
- SecureRandom.hex.tap { |key| uploads.merge!(key => value) }
38
- else
39
- value
40
- end
41
- }
42
-
43
- [variables, uploads]
44
- end
45
-
46
- def deep_camelize_keys(variables)
47
- variables.deep_transform_keys { |key| key.to_s.camelize(:lower) }
48
- end
49
-
50
- def deep_transform_values(data, &block)
51
- case data
52
- when Array
53
- data.map { |v| deep_transform_values(v, &block) }
54
- when Hash
55
- data.transform_values { |v| deep_transform_values(v, &block) }
56
- else
57
- yield data
58
- end
59
- end
60
-
61
- def upload?(value)
62
- value.respond_to?(:tempfile) && value.respond_to?(:original_filename)
63
- end
64
- end
65
-
66
- def graphql_fixture(filename)
67
- root = ::RSpec.configuration.graphql_fixture_path
68
- contents = File.read(File.join(root, filename))
69
-
70
- parts = contents.split(/^(?=fragment|query|mutation|subscription)/)
71
- queries, fragments = parts.partition { |query| query !~ /^fragment/ }
72
-
73
- result = queries.reduce({}) { |acc, query|
74
- name = query.split(/\W+/).at(1).underscore.to_sym
75
- acc.merge(name => [*fragments, query].join)
76
- }
77
-
78
- Queries.new(result)
79
- end
80
-
81
- def use_schema(*args)
82
- Schema.new(*args)
83
- end
84
- end
85
- end
86
- end
87
-
88
- RSpec::Matchers.define :be_successful_query do
89
- match do |result|
90
- result['errors'].nil?
91
- end
92
-
93
- failure_message do |result|
94
- errors = result['errors'].map(&:deep_stringify_keys)
95
- message = "expected query to be successful, but encountered errors:\n"
96
- message + errors.to_yaml.lines.drop(1).join.indent(2)
97
- end
98
- end
99
-
100
- RSpec.configure do |config|
101
- config.add_setting :graphql_fixture_path, default: "spec/fixtures/graphql"
102
- config.include GraphQL::Extras::RSpec, type: :graphql
103
- end