hq-graphql 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: be9de36cb5b0f12696e98d85156404d89acdc6d5
4
+ data.tar.gz: 0e887aabc0d14374ad192e464a8b1e3e4ac4ea8f
5
+ SHA512:
6
+ metadata.gz: 7ec2755f98cd6045e93da317edec985a3a148c4baef5a7e30d24c1568020327f455d4a7efb14b117d482c0b51106e69ad67f0db33c6051c8b42d750f951086c8
7
+ data.tar.gz: aae1f46e971c88db6a4e87d919dc354e0235931041bf485172df0109520892f1e0294a10b99c81943ca71132b92ed1bfd56f76fdda5d2cb0e3b9e9323bc56665
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2018 Danny Jones
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,55 @@
1
+ # HQ::GraphQL
2
+
3
+ OneHQ GraphQL interface to [Ruby Graphql](https://github.com/rmosolgo/graphql-ruby).
4
+
5
+ [![CircleCI](https://img.shields.io/circleci/project/github/OneHQ/hq-graphql.svg)](https://circleci.com/gh/OneHQ/hq-graphql/tree/master)
6
+ [![GitHub tag](https://img.shields.io/github/tag/OneHQ/hq-graphql.svg)](https://github.com/OneHQ/hq-graphql)
7
+
8
+ ## Configuration
9
+
10
+ You can pass configuration options as a block to `::HQ::GraphQL.configure`.
11
+
12
+ ```ruby
13
+ # The gem assumes that if your model is called `MyModel`, the corresponding type is `MyModelType`.
14
+ # You can override that convention.
15
+ # Default is: -> (model_class) { "#{model_class.name.demodulize}Type" }
16
+ ::HQ::GraphQL.config do |config|
17
+ config.model_to_graphql_type = -> (model_class) { "::CustomNameSpace::#{model_class.name}Type" }
18
+ end
19
+ ```
20
+
21
+ ## Usage
22
+
23
+ Create a new ::HQ::GraphQL::Object
24
+ ```ruby
25
+ class AdvisorType < ::HQ::GraphQL::Object
26
+ # Supports graphql-ruby functionality
27
+ field :id, Int, null: false
28
+
29
+ # Lazy Loading
30
+ # Useful for loading data from the database to generate a schema
31
+ lazy_load do
32
+ load_data_from_db.each do |name|
33
+ field name, String, null: false
34
+ end
35
+ end
36
+
37
+ # Attach the GraphQL object to an ActiveRecord Model
38
+ # First argument is the string form of your ActiveRecord model.
39
+ #
40
+ # attributes:
41
+ # Set it to false if you don't want to auto-include your model's attributes.
42
+ # Defaults to true.
43
+ #
44
+ # associations:
45
+ # Set it to false if you don't want to auto-include your model's associations.
46
+ # Defaults to true.
47
+ with_model "Advisor", attributes: true, associations: false
48
+
49
+ # Remove attributes that were included by `with_model`
50
+ remove_attrs :id, :created_at, :updated_at
51
+
52
+ # Remove associations that were included by `with_model`
53
+ remove_associations :organization, :created_by
54
+ end
55
+ ```
data/Rakefile ADDED
@@ -0,0 +1,17 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'HQ::GraphQL'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.rdoc')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ require 'bundler/gem_tasks'
data/lib/hq-graphql.rb ADDED
@@ -0,0 +1 @@
1
+ require "hq/graphql"
data/lib/hq/graphql.rb ADDED
@@ -0,0 +1,32 @@
1
+ require "graphql"
2
+
3
+ module HQ
4
+ module GraphQL
5
+ def self.config
6
+ @config ||= ::ActiveSupport::OrderedOptions.new
7
+ end
8
+
9
+ def self.configure(&block)
10
+ config.instance_eval(&block)
11
+ end
12
+
13
+ # The gem assumes that if your model is called `MyModel`, the corresponding type is `MyModelType`.
14
+ # You can override that convention.
15
+ #
16
+ # ::HQ::GraphQL.config do |config|
17
+ # config.model_to_graphql_type = -> (model_class) { "::CustomNameSpace::#{model_class.name}Type" }
18
+ # end
19
+ def self.model_to_graphql_type
20
+ config.model_to_graphql_type ||
21
+ @model_to_graphql_type ||= -> (model_class) { "#{model_class.name.demodulize}Type" }
22
+ end
23
+
24
+ def self.graphql_type_from_model(model_class)
25
+ model_to_graphql_type.call(model_class)
26
+ end
27
+ end
28
+ end
29
+
30
+ require "hq/graphql/object"
31
+ require "hq/graphql/types"
32
+ require "hq/graphql/engine"
@@ -0,0 +1,6 @@
1
+ module HQ
2
+ module GraphQL
3
+ class Engine < ::Rails::Engine
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,117 @@
1
+ module HQ
2
+ module GraphQL
3
+ class Object < ::GraphQL::Schema::Object
4
+ class Error < StandardError
5
+ MISSING_MODEL_MSG = "Can't perform %{action} without connecting to a model: `::HQ::GraphQL::Object.with_model 'User'`".freeze
6
+ MISSING_ATTR_MSG = "Can't find attr %{model}.%{attr}'`".freeze
7
+ MISSING_ASSOC_MSG = "Can't find association %{model}.%{assoc}'`".freeze
8
+ end
9
+
10
+ def self.lazy_load(&block)
11
+ @lazy_load ||= []
12
+ @lazy_load << block if block
13
+ @lazy_load
14
+ end
15
+
16
+ def self.with_model(model_name, attributes: true, associations: true)
17
+ self.model_name = model_name
18
+
19
+ lazy_load do
20
+ if attributes
21
+ model_klass.columns.reject { |c| removed_attrs.include?(c.name.to_sym) }.each do |column|
22
+ field_from_column column
23
+ end
24
+ end
25
+
26
+ if associations
27
+ model_klass.reflect_on_all_associations.reject { |a| removed_associations.include?(a.name.to_sym) }.each do |association|
28
+ field_from_association association
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ def self.add_attr(attr)
35
+ lazy_load do
36
+ validate_model!(:add_attr)
37
+ field_from_column model_column(attr)
38
+ end
39
+ end
40
+
41
+ def self.remove_attrs(*attrs)
42
+ removed_attrs.concat attrs.map(&:to_sym)
43
+ end
44
+
45
+ def self.remove_associations(*associations)
46
+ removed_associations.concat associations.map(&:to_sym)
47
+ end
48
+
49
+ def self.add_association(association)
50
+ lazy_load do
51
+ validate_model!(:add_association)
52
+ field_from_association model_association(association)
53
+ end
54
+ end
55
+
56
+ def self.to_graphql
57
+ lazy_load!
58
+ super
59
+ end
60
+
61
+ class << self
62
+ private
63
+
64
+ attr_accessor :model_name
65
+ attr_writer :removed_attrs, :removed_associations
66
+
67
+ def lazy_load!
68
+ lazy_load.map(&:call)
69
+ @lazy_load = []
70
+ end
71
+
72
+ def model_klass
73
+ @model_klass ||= model_name&.constantize
74
+ end
75
+
76
+ def model_column(attr)
77
+ model_klass.columns_hash[attr.to_s] || raise(Error, Error::MISSING_ATTR_MSG % { model: model_name, attr: attr })
78
+ end
79
+
80
+ def model_association(association)
81
+ model_klass.reflect_on_association(association) || raise(Error, Error::MISSING_ASSOC_MSG % { model: model_name, assoc: association })
82
+ end
83
+
84
+ def removed_attrs
85
+ @removed_attrs ||= []
86
+ end
87
+
88
+ def removed_associations
89
+ @removed_associations ||= []
90
+ end
91
+
92
+ def validate_model!(action)
93
+ unless model_name
94
+ raise Error, Error::MISSING_MODEL_MSG % { action: action }
95
+ end
96
+ end
97
+
98
+ def field_from_association(association)
99
+ name = association.name
100
+ type = ::HQ::GraphQL::Types[association.klass]
101
+ case association.macro
102
+ when :has_many
103
+ field name, [type], null: false
104
+ else
105
+ field name, type, null: true
106
+ end
107
+ end
108
+
109
+ def field_from_column(column)
110
+ field column.name, ::HQ::GraphQL::Types.type_from_column(column), null: column.null
111
+ end
112
+
113
+ end
114
+
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,55 @@
1
+ require "hq/graphql/types/uuid"
2
+
3
+ module HQ
4
+ module GraphQL
5
+ module Types
6
+
7
+ def self.[](key)
8
+ @schema_objects ||= Hash.new do |hash, klass|
9
+ hash[klass] = klass_for(klass)
10
+ end
11
+ @schema_objects[key]
12
+ end
13
+
14
+ def self.type_from_column(column)
15
+ case column&.cast_type&.type
16
+ when :uuid
17
+ ::HQ::GraphQL::Types::UUID
18
+ when :integer
19
+ ::GraphQL::INT_TYPE
20
+ when :decimal
21
+ ::GraphQL::FLOAT_TYPE
22
+ when :boolean
23
+ ::GraphQL::BOOLEAN_TYPE
24
+ else
25
+ ::GraphQL::STRING_TYPE
26
+ end
27
+ end
28
+
29
+ # Only being used in testing
30
+ def self.reset!
31
+ @schema_objects = nil
32
+ end
33
+
34
+ class << self
35
+ private
36
+
37
+ def klass_for(klass)
38
+ hql_klass_name = ::HQ::GraphQL.graphql_type_from_model(klass)
39
+ hql_klass = hql_klass_name.safe_constantize
40
+ return hql_klass if hql_klass
41
+
42
+ module_name = hql_klass_name.deconstantize.presence
43
+ hql_module = module_name ? (module_name.safe_constantize || ::Object.const_set(module_name, Module.new)) : ::Object
44
+
45
+ hql_klass = Class.new(::HQ::GraphQL::Object) do
46
+ with_model klass.name
47
+ end
48
+
49
+ hql_module.const_set(hql_klass_name.demodulize, hql_klass)
50
+ end
51
+ end
52
+
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,33 @@
1
+ module HQ
2
+ module GraphQL
3
+ module Types
4
+ class UUID < ::GraphQL::Schema::Scalar
5
+ description "UUID"
6
+
7
+ class << self
8
+ def self.coerce_input(value, context)
9
+ validate_and_return_uuid(value)
10
+ end
11
+
12
+ def self.coerce_result(value, context)
13
+ validate_and_return_uuid(value)
14
+ end
15
+
16
+ private
17
+
18
+ def validate_and_return_uuid(value)
19
+ if validate_uuid(value)
20
+ value
21
+ else
22
+ raise ::GraphQL::CoercionError, "#{value.inspect} is not a valid UUID"
23
+ end
24
+ end
25
+
26
+ def validate_uuid(value)
27
+ !!value.match(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/)
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,5 @@
1
+ module HQ
2
+ module GraphQL
3
+ VERSION = "0.0.2"
4
+ end
5
+ end
@@ -0,0 +1,6 @@
1
+ FactoryBot.define do
2
+ factory :advisor do
3
+ name { Faker::Name.name }
4
+ organization { FactoryBot.build(:organization) }
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ FactoryBot.define do
2
+ factory :organization do
3
+ name { Faker::Company.name }
4
+ end
5
+ end
@@ -0,0 +1,6 @@
1
+ FactoryBot.define do
2
+ factory :user do
3
+ name { Faker::Name.name }
4
+ organization { FactoryBot.build(:organization) }
5
+ end
6
+ end
@@ -0,0 +1,18 @@
1
+ class Query < GraphQL::Schema::Object
2
+ graphql_name "Query"
3
+
4
+ field :users, [HQ::GraphQL::Types[User]], null: false
5
+ field :advisors, [HQ::GraphQL::Types[Advisor]], null: false
6
+
7
+ def users
8
+ User.all
9
+ end
10
+
11
+ def users_custom
12
+ users
13
+ end
14
+
15
+ def advisors
16
+ Advisor.all
17
+ end
18
+ end
@@ -0,0 +1,3 @@
1
+ class Schema < GraphQL::Schema
2
+ query(Query)
3
+ end
@@ -0,0 +1,3 @@
1
+ class UserType < HQ::GraphQL::Object
2
+ with_model "User"
3
+ end
@@ -0,0 +1,3 @@
1
+ class Advisor < ActiveRecord::Base
2
+ belongs_to :organization
3
+ end
@@ -0,0 +1,3 @@
1
+ class Organization < ::ActiveRecord::Base
2
+ has_many :users, inverse_of: :organization
3
+ end
@@ -0,0 +1,3 @@
1
+ class User < ::ActiveRecord::Base
2
+ belongs_to :organization, inverse_of: :users
3
+ end
@@ -0,0 +1,24 @@
1
+ common: &common
2
+ adapter: postgresql
3
+ encoding: utf8
4
+ host: <%= ENV["DBHOST"] || "127.0.0.1" %>
5
+ port: <%= ENV["DBPORT"] || "5432" %>
6
+ database: <%= ENV["DBNAME"] || "hq-graphql" %>
7
+ username: <%= ENV["DBUSER"] || "postgres" %>
8
+ password: <%= ENV["DBPASSWORD"] || "" %>
9
+ pool: 5
10
+ reconnect: true
11
+ timeout: 5000
12
+
13
+ development:
14
+ <<: *common
15
+
16
+ test:
17
+ <<: *common
18
+
19
+ staging:
20
+ <<: *common
21
+
22
+ production:
23
+ <<: *common
24
+ pool: 10
@@ -0,0 +1,8 @@
1
+ test:
2
+ adapter: postgresql
3
+ database: <%= ENV['DB'] || 'hq-graphql_test' %>
4
+ username: <%= ENV['DB_USERNAME'] || %x[id -un] %> # `id -un` returns the active user in OSX (at least as of 10.10)
5
+ password:
6
+ timeout: 5000
7
+ encoding: utf8
8
+ pool: 25
@@ -0,0 +1,21 @@
1
+ ActiveRecord::Schema.define do
2
+ enable_extension "uuid-ossp"
3
+
4
+ create_table "organizations", force: true, id: :uuid do |t|
5
+ t.string :name, limit: 63, null: false
6
+ t.timestamps null: false
7
+ end
8
+
9
+ create_table "users", force: true do |t|
10
+ t.belongs_to :organization, null: false, index: true, foreign_key: true, type: :uuid
11
+ t.string :name, null: false
12
+ t.timestamps null: false
13
+ end
14
+
15
+ create_table "advisors", force: true do |t|
16
+ t.references :organization, null: false, index: true, foreign_key: true, type: :uuid
17
+ t.string :name, null: false
18
+ t.timestamps null: false
19
+ end
20
+
21
+ end
@@ -0,0 +1,198 @@
1
+ require 'rails_helper'
2
+
3
+ describe ::HQ::GraphQL::Object do
4
+
5
+ describe ".lazy_load" do
6
+ let(:lazy_load_class) do
7
+ Class.new(described_class) do
8
+ graphql_name "LazyLoadQuery"
9
+
10
+ @counter = 0
11
+
12
+ lazy_load do
13
+ @counter += 1
14
+ end
15
+
16
+ def self.counter
17
+ @counter
18
+ end
19
+ end
20
+ end
21
+
22
+ it "lazy loads once" do
23
+ # First time it works
24
+ expect { lazy_load_class.to_graphql }.to change { lazy_load_class.counter }.by(1)
25
+ # Second time it does nothing
26
+ expect { lazy_load_class.to_graphql }.to change { lazy_load_class.counter }.by(0)
27
+ end
28
+ end
29
+
30
+ describe ".with_model" do
31
+ let(:hql_object_klass) do
32
+ Class.new(described_class) do
33
+ graphql_name "TestQuery"
34
+ end
35
+ end
36
+
37
+ it "adds everything by default" do
38
+ hql_object_klass.class_eval do
39
+ with_model "Advisor"
40
+ end
41
+
42
+ expect(hql_object_klass.fields.keys).to be_empty
43
+ hql_object_klass.to_graphql
44
+ expected = ["createdAt", "id", "name", "organization", "organizationId", "updatedAt"]
45
+ expect(hql_object_klass.fields.keys).to contain_exactly(*expected)
46
+ end
47
+
48
+ it "removes an attribute" do
49
+ hql_object_klass.class_eval do
50
+ remove_attrs :created_at, :id, :organization_id
51
+ with_model "Advisor"
52
+ end
53
+
54
+ expect(hql_object_klass.fields.keys).to be_empty
55
+ hql_object_klass.to_graphql
56
+ expected = ["name", "organization", "updatedAt"]
57
+ expect(hql_object_klass.fields.keys).to contain_exactly(*expected)
58
+ end
59
+
60
+ it "removes an association" do
61
+ hql_object_klass.class_eval do
62
+ remove_associations :organization, :doesntexist
63
+ with_model "Advisor"
64
+ end
65
+
66
+ expect(hql_object_klass.fields.keys).to be_empty
67
+ hql_object_klass.to_graphql
68
+ expected = ["createdAt", "id", "name", "organizationId", "updatedAt"]
69
+ expect(hql_object_klass.fields.keys).to contain_exactly(*expected)
70
+ end
71
+
72
+ context "with attributes and associations turned off" do
73
+ it "doesn't have any fields by default" do
74
+ hql_object_klass.to_graphql
75
+ expect(hql_object_klass.fields.keys).to be_empty
76
+ end
77
+
78
+ it "doesn't have any fields when disabling model attrs/associations" do
79
+ hql_object_klass.class_eval do
80
+ with_model "Advisor", attributes: false, associations: false
81
+ end
82
+ hql_object_klass.to_graphql
83
+ expect(hql_object_klass.fields.keys).to be_empty
84
+ end
85
+
86
+ it "blows up when adding an attribute to an object without a model" do
87
+ hql_object_klass.class_eval do
88
+ add_attr :name
89
+ end
90
+
91
+ expect { hql_object_klass.to_graphql }.to raise_error(described_class::Error)
92
+ end
93
+
94
+ it "blows up when adding an attribute that doesn't exist" do
95
+ hql_object_klass.class_eval do
96
+ add_attr :doesnt_exist
97
+
98
+ with_model "Advisor", attributes: false, associations: false
99
+ end
100
+
101
+ expect { hql_object_klass.to_graphql }.to raise_error(described_class::Error)
102
+ end
103
+
104
+ it "adds attributes once connected to a model" do
105
+ hql_object_klass.class_eval do
106
+ # Order shouldn't matter....but let's test it anyway
107
+
108
+ # First
109
+ add_attr :name
110
+
111
+ # Second
112
+ with_model "Advisor", attributes: false, associations: false
113
+ end
114
+
115
+ expect(hql_object_klass.fields.keys).to be_empty
116
+ hql_object_klass.to_graphql
117
+ expect(hql_object_klass.fields.keys).to contain_exactly("name")
118
+ end
119
+
120
+ it "blows up when adding an association to an object without a model" do
121
+ hql_object_klass.class_eval do
122
+ add_association :organization
123
+ end
124
+
125
+ expect { hql_object_klass.to_graphql }.to raise_error(described_class::Error)
126
+ end
127
+
128
+ it "blows up when adding an association that doesn't exist" do
129
+ hql_object_klass.class_eval do
130
+ add_association :doesnt_exist
131
+
132
+ with_model "Advisor", attributes: false, associations: false
133
+ end
134
+
135
+ expect { hql_object_klass.to_graphql }.to raise_error(described_class::Error)
136
+ end
137
+
138
+ it "adds associations once connected to a model" do
139
+ hql_object_klass.class_eval do
140
+ # Order shouldn't matter....but let's test it anyway
141
+
142
+ # First
143
+ add_association :organization
144
+
145
+ # Second
146
+ with_model "Advisor", attributes: false, associations: false
147
+ end
148
+
149
+ expect(hql_object_klass.fields.keys).to be_empty
150
+ hql_object_klass.to_graphql
151
+ expect(hql_object_klass.fields.keys).to contain_exactly("organization")
152
+ end
153
+
154
+ end
155
+
156
+ context "with a schema" do
157
+ let(:user_1) { FactoryBot.create(:user) }
158
+ let(:user_2) { FactoryBot.create(:user, organization: user_1.organization) }
159
+
160
+ before(:each) do
161
+ user_1
162
+ user_2
163
+ end
164
+
165
+ it "executes graphql" do
166
+ query_str = <<-GRAPHQ
167
+ query {
168
+ users {
169
+ name
170
+ organizationId
171
+
172
+ organization {
173
+ name
174
+ }
175
+ }
176
+ }
177
+ GRAPHQ
178
+
179
+ result = ::Schema.execute(query_str)
180
+
181
+ aggregate_failures do
182
+ user_1_data, user_2_data = result["data"]["users"]
183
+ # User 1
184
+ expect(user_1_data["name"]).to eql(user_1.name)
185
+ expect(user_1_data["organizationId"]).to eql(user_1.organization_id)
186
+ expect(user_1_data["organization"]["name"]).to eql(user_1.organization.name)
187
+
188
+ # User 2
189
+ expect(user_2_data["name"]).to eql(user_2.name)
190
+ expect(user_2_data["organizationId"]).to eql(user_2.organization_id)
191
+ expect(user_2_data["organization"]["name"]).to eql(user_2.organization.name)
192
+ end
193
+ end
194
+ end
195
+
196
+ end
197
+
198
+ end
@@ -0,0 +1,60 @@
1
+ require 'rails_helper'
2
+
3
+ describe ::HQ::GraphQL::Types do
4
+
5
+ describe ".[]" do
6
+ before(:each) do
7
+ described_class.reset!
8
+ end
9
+
10
+ after(:each) do
11
+ described_class.reset!
12
+ end
13
+
14
+ it "generates a new class with columns & associations" do
15
+ # Unique Classes
16
+ allow(::HQ::GraphQL).to receive(:model_to_graphql_type) { -> (model_class) { "#{model_class.name.demodulize}TypeTest" } }
17
+
18
+ advisor_klass = described_class[Advisor]
19
+ user_klass = described_class[User]
20
+ advisor_user_fields = ["id", "organizationId", "name", "createdAt", "updatedAt", "organization"]
21
+
22
+ #### Advisor Schema ####
23
+ expect(advisor_klass.name).to eql(::HQ::GraphQL.graphql_type_from_model(Advisor))
24
+ expect(advisor_klass.fields.keys).to be_empty
25
+ ### Build GraphQL schema
26
+ advisor_klass.to_graphql
27
+ expect(advisor_klass.fields.keys).to contain_exactly(*advisor_user_fields)
28
+
29
+ #### User Schema ####
30
+ expect(user_klass.name).to eql(::HQ::GraphQL.graphql_type_from_model(User))
31
+ expect(user_klass.fields.keys).to be_empty
32
+ user_klass.to_graphql
33
+ expect(user_klass.fields.keys).to contain_exactly(*advisor_user_fields)
34
+
35
+ organization_klass = ::HQ::GraphQL.graphql_type_from_model(Organization).constantize
36
+ expect(organization_klass.fields.keys).to be_empty
37
+ organization_klass.to_graphql
38
+ organization_fields = ["id", "name", "createdAt", "updatedAt", "users"]
39
+ expect(organization_klass.fields.keys).to contain_exactly(*organization_fields)
40
+ end
41
+
42
+ it "users the existing class if one exists" do
43
+ allow(::HQ::GraphQL).to receive(:model_to_graphql_type) { -> (model_class) { "#{model_class.name.demodulize}TypeTestTwo" } }
44
+
45
+ klass = Class.new(::HQ::GraphQL::Object) do
46
+ graphql_name "TestQuery"
47
+
48
+ field :custom_field, String, null: false
49
+ end
50
+ advisor_klass = stub_const(::HQ::GraphQL.graphql_type_from_model(Advisor), klass)
51
+
52
+ expect(advisor_klass).to eql(described_class[Advisor])
53
+ expect(advisor_klass.fields.keys).to contain_exactly("customField")
54
+ advisor_klass.to_graphql
55
+ expect(advisor_klass.fields.keys).to contain_exactly("customField")
56
+ end
57
+
58
+ end
59
+
60
+ end
@@ -0,0 +1,41 @@
1
+ require "testhq/coverage" # Needs to be require at the top of this file!
2
+ # Coverage must also be enabled in the environment by setting
3
+ # environment variables, e.g. `COVERAGE=true` or `CODECLIMATE_REPO_TOKEN=...`.
4
+ # See https://github.com/OneHQ/testhq#code-coverage.
5
+
6
+ require "bundler/setup"
7
+ require "combustion"
8
+
9
+ silence_stream(STDOUT) do # Hides a lot of output from Combustion init such as schema loading.
10
+ Combustion.initialize! :all do
11
+ # Disable strong parameters
12
+ config.action_controller.permit_all_parameters = true
13
+ end
14
+ end
15
+
16
+ require "byebug"
17
+ require "rspec/rails"
18
+ require "testhq"
19
+
20
+ RSpec.configure do |config|
21
+ config.expect_with :rspec do |c|
22
+ c.syntax = [:expect]
23
+ end
24
+
25
+ config.use_transactional_fixtures = false
26
+
27
+ config.include FactoryBot::Syntax::Methods
28
+
29
+ config.before(:suite) do
30
+ DatabaseCleaner.strategy = :transaction
31
+ DatabaseCleaner.clean_with :truncation # Clear everything
32
+ end
33
+
34
+ config.before(:each) do
35
+ DatabaseCleaner.start
36
+ end
37
+
38
+ config.after(:each) do
39
+ DatabaseCleaner.clean
40
+ end
41
+ end
@@ -0,0 +1,22 @@
1
+ RSpec.configure do |config|
2
+ config.expect_with :rspec do |expectations|
3
+ # This option will default to `true` in RSpec 4. It makes the `description`
4
+ # and `failure_message` of custom matchers include text for helper methods
5
+ # defined using `chain`, e.g.:
6
+ # be_bigger_than(2).and_smaller_than(4).description
7
+ # # => "be bigger than 2 and smaller than 4"
8
+ # ...rather than:
9
+ # # => "be bigger than 2"
10
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
11
+ end
12
+
13
+ # rspec-mocks config goes here. You can use an alternate test double
14
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
15
+ config.mock_with :rspec do |mocks|
16
+ # Prevents you from mocking or stubbing a method that does not exist on
17
+ # a real object. This is generally recommended, and will default to
18
+ # `true` in RSpec 4.
19
+ mocks.verify_partial_doubles = true
20
+ end
21
+ config.order = :random
22
+ end
metadata ADDED
@@ -0,0 +1,160 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hq-graphql
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Danny Jones
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-08-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '4.2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '4.2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: graphql
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.0'
34
+ - - ">="
35
+ - !ruby/object:Gem::Version
36
+ version: 1.8.7
37
+ type: :runtime
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - "~>"
42
+ - !ruby/object:Gem::Version
43
+ version: '1.0'
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: 1.8.7
47
+ - !ruby/object:Gem::Dependency
48
+ name: rspec_junit_formatter
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '0.3'
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: 0.3.0
57
+ type: :development
58
+ prerelease: false
59
+ version_requirements: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - "~>"
62
+ - !ruby/object:Gem::Version
63
+ version: '0.3'
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: 0.3.0
67
+ - !ruby/object:Gem::Dependency
68
+ name: testhq
69
+ requirement: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - "~>"
72
+ - !ruby/object:Gem::Version
73
+ version: '1.0'
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: 1.0.0
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - "~>"
82
+ - !ruby/object:Gem::Version
83
+ version: '1.0'
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: 1.0.0
87
+ description: OneHQ GraphQL Library
88
+ email:
89
+ - dpjones09@gmail.com
90
+ executables: []
91
+ extensions: []
92
+ extra_rdoc_files: []
93
+ files:
94
+ - MIT-LICENSE
95
+ - README.md
96
+ - Rakefile
97
+ - lib/hq-graphql.rb
98
+ - lib/hq/graphql.rb
99
+ - lib/hq/graphql/engine.rb
100
+ - lib/hq/graphql/object.rb
101
+ - lib/hq/graphql/types.rb
102
+ - lib/hq/graphql/types/uuid.rb
103
+ - lib/hq/graphql/version.rb
104
+ - spec/factories/advisors.rb
105
+ - spec/factories/organizations.rb
106
+ - spec/factories/users.rb
107
+ - spec/internal/app/graphql/query.rb
108
+ - spec/internal/app/graphql/schema.rb
109
+ - spec/internal/app/graphql/user_type.rb
110
+ - spec/internal/app/models/advisor.rb
111
+ - spec/internal/app/models/organization.rb
112
+ - spec/internal/app/models/user.rb
113
+ - spec/internal/config/database.circleci.yml
114
+ - spec/internal/config/database.yml
115
+ - spec/internal/db/schema.rb
116
+ - spec/lib/object_spec.rb
117
+ - spec/lib/types_spec.rb
118
+ - spec/rails_helper.rb
119
+ - spec/spec_helper.rb
120
+ homepage: https://github.com/OneHQ/hq-graphql
121
+ licenses:
122
+ - MIT
123
+ metadata: {}
124
+ post_install_message:
125
+ rdoc_options: []
126
+ require_paths:
127
+ - lib
128
+ required_ruby_version: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
133
+ required_rubygems_version: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ version: '0'
138
+ requirements: []
139
+ rubyforge_project:
140
+ rubygems_version: 2.5.2.2
141
+ signing_key:
142
+ specification_version: 4
143
+ summary: OneHQ GraphQL Library
144
+ test_files:
145
+ - spec/spec_helper.rb
146
+ - spec/internal/app/models/advisor.rb
147
+ - spec/internal/app/models/organization.rb
148
+ - spec/internal/app/models/user.rb
149
+ - spec/internal/app/graphql/schema.rb
150
+ - spec/internal/app/graphql/query.rb
151
+ - spec/internal/app/graphql/user_type.rb
152
+ - spec/internal/config/database.circleci.yml
153
+ - spec/internal/config/database.yml
154
+ - spec/internal/db/schema.rb
155
+ - spec/factories/organizations.rb
156
+ - spec/factories/advisors.rb
157
+ - spec/factories/users.rb
158
+ - spec/lib/object_spec.rb
159
+ - spec/lib/types_spec.rb
160
+ - spec/rails_helper.rb