graphql-activerecord 0.10.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.circleci/config.yml +21 -0
- data/.rubocop.yml +125 -0
- data/.rubocop_todo.yml +48 -0
- data/CHANGELOG.md +9 -3
- data/Gemfile +1 -0
- data/Rakefile +2 -1
- data/bin/rubocop +17 -0
- data/bin/ruby-parse +17 -0
- data/bin/ruby-rewrite +17 -0
- data/graphql-activerecord.gemspec +10 -8
- data/lib/graphql/activerecord.rb +2 -2
- data/lib/graphql/models/active_record_extension.rb +5 -4
- data/lib/graphql/models/association_load_request.rb +3 -3
- data/lib/graphql/models/attribute_loader.rb +1 -0
- data/lib/graphql/models/backed_by_model.rb +7 -6
- data/lib/graphql/models/database_types.rb +1 -0
- data/lib/graphql/models/definer.rb +5 -4
- data/lib/graphql/models/definition_helpers.rb +6 -6
- data/lib/graphql/models/definition_helpers/associations.rb +23 -22
- data/lib/graphql/models/definition_helpers/attributes.rb +4 -3
- data/lib/graphql/models/hash_combiner.rb +1 -0
- data/lib/graphql/models/helpers.rb +1 -0
- data/lib/graphql/models/middleware.rb +1 -0
- data/lib/graphql/models/monkey_patches/graphql_query_context.rb +1 -0
- data/lib/graphql/models/mutation_field_map.rb +11 -10
- data/lib/graphql/models/mutation_helpers/apply_changes.rb +11 -11
- data/lib/graphql/models/mutation_helpers/authorization.rb +1 -0
- data/lib/graphql/models/mutation_helpers/print_input_fields.rb +3 -2
- data/lib/graphql/models/mutation_helpers/validation.rb +7 -8
- data/lib/graphql/models/mutation_helpers/validation_error.rb +6 -7
- data/lib/graphql/models/mutator.rb +6 -5
- data/lib/graphql/models/promise_relation_connection.rb +1 -0
- data/lib/graphql/models/reflection.rb +4 -3
- data/lib/graphql/models/relation_load_request.rb +2 -3
- data/lib/graphql/models/relation_loader.rb +3 -3
- data/lib/graphql/models/version.rb +2 -1
- metadata +22 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0898e348a67f2ffea03d24b07bad53f4ee4e303c
|
4
|
+
data.tar.gz: fe1f6ef15222a43dabb77ee545a8fbb22bf5509c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d224b60c12152281cba045789a6c0122740b65368ea14e9327ca794a87db2ba82a1415b8ab63cff0565b04be8cf803004c7ad5c7f3b55d0468d31bf24e68eb82
|
7
|
+
data.tar.gz: 3568541b0befd15885528e980a63a18295764ccc35f47207400d0d48439a3ee42d1121efa143303f3de2fca7941def87c414ca420bb2208c082ef210a5aaf79f
|
@@ -0,0 +1,21 @@
|
|
1
|
+
version: 2
|
2
|
+
jobs:
|
3
|
+
build:
|
4
|
+
working_directory: /graphql-activerecord
|
5
|
+
docker:
|
6
|
+
- image: ruby:2.3.1
|
7
|
+
steps:
|
8
|
+
- checkout
|
9
|
+
|
10
|
+
# Install dependencies
|
11
|
+
- restore_cache:
|
12
|
+
key: bundler-{{ checksum "graphql-activerecord.gemspec" }}
|
13
|
+
- run: bundle install --path=vendor/gems
|
14
|
+
- save_cache:
|
15
|
+
key: bundler-{{ checksum "graphql-activerecord.gemspec" }}
|
16
|
+
paths:
|
17
|
+
- vendor/gems
|
18
|
+
|
19
|
+
# Tests
|
20
|
+
- run: rubocop
|
21
|
+
- run: rspec
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
inherit_from: .rubocop_todo.yml
|
2
|
+
AllCops:
|
3
|
+
TargetRubyVersion: 2.3
|
4
|
+
Exclude:
|
5
|
+
- bin/**/*
|
6
|
+
- vendor/gems/**/*
|
7
|
+
|
8
|
+
Lint/EndAlignment:
|
9
|
+
EnforcedStyleAlignWith: variable
|
10
|
+
Enabled: false
|
11
|
+
|
12
|
+
Lint/UnusedBlockArgument:
|
13
|
+
AllowUnusedKeywordArguments: true
|
14
|
+
|
15
|
+
Lint/UnusedMethodArgument:
|
16
|
+
AllowUnusedKeywordArguments: true
|
17
|
+
IgnoreEmptyMethods: true
|
18
|
+
|
19
|
+
Metrics/BlockLength:
|
20
|
+
CountComments: false
|
21
|
+
Max: 96
|
22
|
+
|
23
|
+
Metrics/ClassLength:
|
24
|
+
Max: 337
|
25
|
+
|
26
|
+
Metrics/CyclomaticComplexity:
|
27
|
+
Max: 13
|
28
|
+
|
29
|
+
Metrics/MethodLength:
|
30
|
+
CountComments: false
|
31
|
+
|
32
|
+
Metrics/ModuleLength:
|
33
|
+
CountComments: false
|
34
|
+
Max: 222
|
35
|
+
|
36
|
+
Metrics/PerceivedComplexity:
|
37
|
+
Max: 18
|
38
|
+
|
39
|
+
Style/Documentation:
|
40
|
+
Enabled: false
|
41
|
+
|
42
|
+
Style/DoubleNegation:
|
43
|
+
Enabled: false
|
44
|
+
|
45
|
+
Style/ExtraSpacing:
|
46
|
+
AllowForAlignment: false
|
47
|
+
|
48
|
+
Style/FrozenStringLiteralComment:
|
49
|
+
EnforcedStyle: always
|
50
|
+
|
51
|
+
Style/GlobalVars:
|
52
|
+
AllowedVariables: [$redis_pool]
|
53
|
+
|
54
|
+
Style/HashSyntax:
|
55
|
+
EnforcedStyle: ruby19_no_mixed_keys
|
56
|
+
|
57
|
+
Style/IfUnlessModifier:
|
58
|
+
Enabled: false
|
59
|
+
|
60
|
+
Style/IndentArray:
|
61
|
+
EnforcedStyle: consistent
|
62
|
+
|
63
|
+
Style/IndentHash:
|
64
|
+
EnforcedStyle: consistent
|
65
|
+
|
66
|
+
Style/Lambda:
|
67
|
+
EnforcedStyle: literal
|
68
|
+
|
69
|
+
Style/MultilineMethodCallIndentation:
|
70
|
+
Enabled: false
|
71
|
+
|
72
|
+
Style/NegatedIf:
|
73
|
+
Enabled: false
|
74
|
+
|
75
|
+
Style/NegatedWhile:
|
76
|
+
Enabled: false
|
77
|
+
|
78
|
+
Style/StringLiterals:
|
79
|
+
Enabled: false
|
80
|
+
|
81
|
+
Style/TrailingCommaInLiteral:
|
82
|
+
EnforcedStyleForMultiline: consistent_comma
|
83
|
+
|
84
|
+
Style/Attr:
|
85
|
+
Enabled: false
|
86
|
+
|
87
|
+
Style/SpaceInLambdaLiteral:
|
88
|
+
EnforcedStyle: require_space
|
89
|
+
|
90
|
+
Style/AlignParameters:
|
91
|
+
EnforcedStyle: with_fixed_indentation
|
92
|
+
|
93
|
+
Style/WordArray:
|
94
|
+
EnforcedStyle: percent
|
95
|
+
MinSize: 5
|
96
|
+
|
97
|
+
Style/StringLiteralsInInterpolation:
|
98
|
+
Enabled: false
|
99
|
+
|
100
|
+
Style/TrailingUnderscoreVariable:
|
101
|
+
Enabled: false
|
102
|
+
|
103
|
+
Style/TernaryParentheses:
|
104
|
+
Enabled: false
|
105
|
+
|
106
|
+
Style/PredicateName:
|
107
|
+
Enabled: false
|
108
|
+
|
109
|
+
Style/NumericPredicate:
|
110
|
+
Enabled: false
|
111
|
+
|
112
|
+
Style/NumericLiterals:
|
113
|
+
MinDigits: 5
|
114
|
+
|
115
|
+
Style/ClassAndModuleChildren:
|
116
|
+
Enabled: false
|
117
|
+
|
118
|
+
Style/CaseIndentation:
|
119
|
+
EnforcedStyle: end
|
120
|
+
|
121
|
+
Style/BracesAroundHashParameters:
|
122
|
+
Enabled: false
|
123
|
+
|
124
|
+
Style/IndentationWidth:
|
125
|
+
Enabled: false
|
data/.rubocop_todo.yml
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
# This configuration was generated by
|
2
|
+
# `rubocop --auto-gen-config`
|
3
|
+
# on 2017-03-12 22:31:48 -0500 using RuboCop version 0.47.1.
|
4
|
+
# The point is for the user to remove these configuration records
|
5
|
+
# one by one as the offenses are removed from the code base.
|
6
|
+
# Note that changes in the inspected code, or installation of new
|
7
|
+
# versions of RuboCop, may require this file to be generated again.
|
8
|
+
|
9
|
+
# Offense count: 3
|
10
|
+
Lint/UselessAssignment:
|
11
|
+
Exclude:
|
12
|
+
- 'lib/graphql/models/definition_helpers.rb'
|
13
|
+
- 'lib/graphql/models/definition_helpers/attributes.rb'
|
14
|
+
- 'lib/graphql/models/mutation_helpers/print_input_fields.rb'
|
15
|
+
|
16
|
+
# Offense count: 5
|
17
|
+
Metrics/AbcSize:
|
18
|
+
Max: 83
|
19
|
+
|
20
|
+
# Offense count: 1
|
21
|
+
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
|
22
|
+
# URISchemes: http, https
|
23
|
+
Metrics/LineLength:
|
24
|
+
Max: 201
|
25
|
+
|
26
|
+
# Offense count: 3
|
27
|
+
# Configuration parameters: CountComments.
|
28
|
+
Metrics/MethodLength:
|
29
|
+
Max: 56
|
30
|
+
|
31
|
+
# Offense count: 5
|
32
|
+
# Configuration parameters: CountKeywordArgs.
|
33
|
+
Metrics/ParameterLists:
|
34
|
+
Max: 9
|
35
|
+
|
36
|
+
# Offense count: 5
|
37
|
+
# Configuration parameters: MinBodyLength.
|
38
|
+
Style/GuardClause:
|
39
|
+
Exclude:
|
40
|
+
- 'lib/graphql/models/association_load_request.rb'
|
41
|
+
- 'lib/graphql/models/mutation_field_map.rb'
|
42
|
+
- 'lib/graphql/models/mutation_helpers/apply_changes.rb'
|
43
|
+
- 'lib/graphql/models/mutation_helpers/validation.rb'
|
44
|
+
|
45
|
+
# Offense count: 2
|
46
|
+
Style/IdenticalConditionalBranches:
|
47
|
+
Exclude:
|
48
|
+
- 'lib/graphql/models/definition_helpers.rb'
|
data/CHANGELOG.md
CHANGED
@@ -1,11 +1,15 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
# 0.11.0
|
4
|
+
Breaking Bug Fix: Turns out that 0.10.0 was _supposed_ to introduce (non)nullability on attributes, but it didn’t quite work. That’s
|
5
|
+
fixed in 0.11.0 (and, I _really_ need to write some tests for this gem).
|
6
|
+
|
3
7
|
# 0.10.0
|
4
8
|
There are a few breaking changes:
|
5
9
|
- Added automatic nullability checking for attributes. It’s enabled by default; see the README for more info.
|
6
10
|
- The gem now assumes that the object types for your models are called "ModelNameType" instead of "ModelNameGraph",
|
7
11
|
to bring it more in line with common practice. You can get the old behavior by adding this to an initializer:
|
8
|
-
|
12
|
+
|
9
13
|
```ruby
|
10
14
|
GraphQL::Models.model_to_graphql_type -> (model_class) { "#{model_class.name}Graph".safe_constantize }
|
11
15
|
```
|
@@ -13,9 +17,11 @@ There are a few breaking changes:
|
|
13
17
|
- Fixed a bug with the `has_many_connection` helper, which deserves some explanation. This helper constructs a
|
14
18
|
connection field that returns an ActiveRecord relation. There isn't an easy way to inject functionality into the resolvers
|
15
19
|
that are used by connections (to my knowledge) - eg, by using middleware - so this helper had some GoCo-specific code
|
16
|
-
baked into it, which probably caused odd errors about an undefined constant `GraphSupport` whenever it was used. I can’t
|
20
|
+
baked into it, which probably caused odd errors about an undefined constant `GraphSupport` whenever it was used. ~~I can’t
|
17
21
|
quite remove that functionality yet, but I did take it one step closer by having the code first check to see if the constant
|
18
|
-
was defined, and bypass it if it’s not
|
22
|
+
was defined, and bypass it if it’s not.~~ That code has been removed from the gem now!
|
23
|
+
|
24
|
+
- Fixed a bug where the HashCombiner would sometimes not merge hashes together (if their keys were sorted differently)
|
19
25
|
|
20
26
|
## 0.9.0
|
21
27
|
- Support for graphql version 1.2.1 and higher, but it no longer works with 0.x versions
|
data/Gemfile
CHANGED
data/Rakefile
CHANGED
data/bin/rubocop
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
#
|
4
|
+
# This file was generated by Bundler.
|
5
|
+
#
|
6
|
+
# The application 'rubocop' is installed as part of a gem, and
|
7
|
+
# this file is here to facilitate running it.
|
8
|
+
#
|
9
|
+
|
10
|
+
require "pathname"
|
11
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
12
|
+
Pathname.new(__FILE__).realpath)
|
13
|
+
|
14
|
+
require "rubygems"
|
15
|
+
require "bundler/setup"
|
16
|
+
|
17
|
+
load Gem.bin_path("rubocop", "rubocop")
|
data/bin/ruby-parse
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
#
|
4
|
+
# This file was generated by Bundler.
|
5
|
+
#
|
6
|
+
# The application 'ruby-parse' is installed as part of a gem, and
|
7
|
+
# this file is here to facilitate running it.
|
8
|
+
#
|
9
|
+
|
10
|
+
require "pathname"
|
11
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
12
|
+
Pathname.new(__FILE__).realpath)
|
13
|
+
|
14
|
+
require "rubygems"
|
15
|
+
require "bundler/setup"
|
16
|
+
|
17
|
+
load Gem.bin_path("parser", "ruby-parse")
|
data/bin/ruby-rewrite
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
#
|
4
|
+
# This file was generated by Bundler.
|
5
|
+
#
|
6
|
+
# The application 'ruby-rewrite' is installed as part of a gem, and
|
7
|
+
# this file is here to facilitate running it.
|
8
|
+
#
|
9
|
+
|
10
|
+
require "pathname"
|
11
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
12
|
+
Pathname.new(__FILE__).realpath)
|
13
|
+
|
14
|
+
require "rubygems"
|
15
|
+
require "bundler/setup"
|
16
|
+
|
17
|
+
load Gem.bin_path("parser", "ruby-rewrite")
|
@@ -1,22 +1,23 @@
|
|
1
1
|
# coding: utf-8
|
2
|
+
# frozen_string_literal: true
|
2
3
|
lib = File.expand_path('../lib', __FILE__)
|
3
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
5
|
require 'graphql/models/version'
|
5
6
|
|
6
7
|
Gem::Specification.new do |spec|
|
7
|
-
spec.name
|
8
|
-
spec.version
|
9
|
-
spec.authors
|
10
|
-
spec.email
|
8
|
+
spec.name = "graphql-activerecord"
|
9
|
+
spec.version = GraphQL::Models::VERSION
|
10
|
+
spec.authors = ["Ryan Foster"]
|
11
|
+
spec.email = ["theorygeek@gmail.com"]
|
11
12
|
|
12
13
|
spec.summary = "ActiveRecord helpers for GraphQL + Relay"
|
13
14
|
spec.description = "Build Relay-compatible GraphQL schemas based on ActiveRecord models"
|
14
|
-
spec.homepage =
|
15
|
+
spec.homepage = "http://github.com/goco-inc/graphql-activerecord"
|
15
16
|
spec.license = "MIT"
|
16
17
|
|
17
|
-
spec.files
|
18
|
-
spec.bindir
|
19
|
-
spec.executables
|
18
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
19
|
+
spec.bindir = "exe"
|
20
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
21
|
spec.require_paths = ["lib"]
|
21
22
|
|
22
23
|
spec.add_runtime_dependency "activesupport", ">= 4.2", '< 5'
|
@@ -28,4 +29,5 @@ Gem::Specification.new do |spec|
|
|
28
29
|
spec.add_development_dependency "rake", "~> 10.0"
|
29
30
|
spec.add_development_dependency "rspec", "~> 3.0"
|
30
31
|
spec.add_development_dependency "pry"
|
32
|
+
spec.add_development_dependency "rubocop", '~> 0.47.1'
|
31
33
|
end
|
data/lib/graphql/activerecord.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'active_support'
|
2
3
|
require 'active_record'
|
3
4
|
require 'graphql'
|
@@ -34,7 +35,6 @@ require 'graphql/models/mutation_field_map'
|
|
34
35
|
require 'graphql/models/backed_by_model'
|
35
36
|
require 'graphql/models/mutator'
|
36
37
|
|
37
|
-
|
38
38
|
module GraphQL
|
39
39
|
module Models
|
40
40
|
class << self
|
@@ -94,7 +94,7 @@ module GraphQL
|
|
94
94
|
|
95
95
|
def self.get_graphql_type!(model_class)
|
96
96
|
type = get_graphql_type(model_class)
|
97
|
-
|
97
|
+
raise "Could not locate GraphQL type for model #{model_class}" if type.nil?
|
98
98
|
type
|
99
99
|
end
|
100
100
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module GraphQL
|
2
3
|
module Models
|
3
4
|
module ActiveRecordExtension
|
@@ -38,14 +39,14 @@ module GraphQL
|
|
38
39
|
name = "#{self.name}#{attribute.to_s.classify}"
|
39
40
|
description = "#{attribute.to_s.titleize} field on #{self.name.titleize}"
|
40
41
|
|
41
|
-
if defined_enums.include?(attribute.to_s)
|
42
|
-
|
42
|
+
values = if defined_enums.include?(attribute.to_s)
|
43
|
+
defined_enums[attribute.to_s].keys
|
43
44
|
else
|
44
|
-
|
45
|
+
Reflection.possible_values(self, attribute)
|
45
46
|
end
|
46
47
|
|
47
48
|
if values.nil?
|
48
|
-
|
49
|
+
raise ArgumentError, "Could not auto-detect the values for enum #{attribute} on #{self.name}"
|
49
50
|
end
|
50
51
|
|
51
52
|
type = GraphQL::EnumType.define do
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module GraphQL
|
2
3
|
module Models
|
3
4
|
class AssociationLoadRequest
|
@@ -9,7 +10,7 @@ module GraphQL
|
|
9
10
|
@context = context
|
10
11
|
|
11
12
|
if reflection.is_a?(ActiveRecord::Reflection::ThroughReflection)
|
12
|
-
|
13
|
+
raise ArgumentError, "You cannot batch-load a has_many :through association. Instead, load each association individually."
|
13
14
|
end
|
14
15
|
end
|
15
16
|
|
@@ -33,7 +34,7 @@ module GraphQL
|
|
33
34
|
#################################################################
|
34
35
|
|
35
36
|
def target_class
|
36
|
-
|
37
|
+
if reflection.polymorphic?
|
37
38
|
base_model.send(reflection.foreign_type).constantize
|
38
39
|
else
|
39
40
|
reflection.klass
|
@@ -49,7 +50,6 @@ module GraphQL
|
|
49
50
|
def reflection
|
50
51
|
association.reflection
|
51
52
|
end
|
52
|
-
|
53
53
|
end
|
54
54
|
end
|
55
55
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module GraphQL
|
2
3
|
module Models
|
3
4
|
class BackedByModel
|
@@ -44,10 +45,10 @@ module GraphQL
|
|
44
45
|
name: name,
|
45
46
|
nullable: nullable,
|
46
47
|
description: description,
|
47
|
-
deprecation_reason: deprecation_reason
|
48
|
+
deprecation_reason: deprecation_reason,
|
48
49
|
}
|
49
50
|
|
50
|
-
DefinitionHelpers.define_attribute(@graph_type, @base_model_type, @model_type, @path, attribute, @object_to_model, options,
|
51
|
+
DefinitionHelpers.define_attribute(@graph_type, @base_model_type, @model_type, @path, attribute, @object_to_model, options, @detect_nulls, &block)
|
51
52
|
end
|
52
53
|
|
53
54
|
# Flattens an associated model into the graph type, allowing to you adds its attributes as if they existed on the parent model.
|
@@ -63,7 +64,7 @@ module GraphQL
|
|
63
64
|
name: name,
|
64
65
|
nullable: nullable,
|
65
66
|
description: description,
|
66
|
-
deprecation_reason: deprecation_reason
|
67
|
+
deprecation_reason: deprecation_reason,
|
67
68
|
}
|
68
69
|
|
69
70
|
DefinitionHelpers.define_has_one(@graph_type, @base_model_type, @model_type, @path, association, @object_to_model, options, @detect_nulls)
|
@@ -76,7 +77,7 @@ module GraphQL
|
|
76
77
|
name: name,
|
77
78
|
nullable: nullable,
|
78
79
|
description: description,
|
79
|
-
deprecation_reason: deprecation_reason
|
80
|
+
deprecation_reason: deprecation_reason,
|
80
81
|
})
|
81
82
|
|
82
83
|
DefinitionHelpers.define_has_many_connection(@graph_type, @base_model_type, @model_type, @path, association, @object_to_model, options, @detect_nulls)
|
@@ -90,7 +91,7 @@ module GraphQL
|
|
90
91
|
type: type,
|
91
92
|
nullable: nullable,
|
92
93
|
description: description,
|
93
|
-
deprecation_reason: deprecation_reason
|
94
|
+
deprecation_reason: deprecation_reason,
|
94
95
|
}
|
95
96
|
|
96
97
|
DefinitionHelpers.define_has_many_array(@graph_type, @base_model_type, @model_type, @path, association, @object_to_model, options, @detect_nulls)
|
@@ -107,7 +108,7 @@ module GraphQL
|
|
107
108
|
path: @path,
|
108
109
|
base_model_type: @base_model_type,
|
109
110
|
model_type: @model_type,
|
110
|
-
object_to_base_model: @object_to_model
|
111
|
+
object_to_base_model: @object_to_model,
|
111
112
|
})
|
112
113
|
|
113
114
|
defined_field
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
# This is a helper class. It lets you build simple DSL's. Methods called against the class are
|
2
3
|
# converted into attributes in a hash.
|
3
4
|
module GraphQL
|
@@ -7,12 +8,12 @@ module GraphQL
|
|
7
8
|
@values = {}
|
8
9
|
methods.each do |m|
|
9
10
|
define_singleton_method(m) do |*args|
|
10
|
-
if args.blank?
|
11
|
-
|
11
|
+
@values[m] = if args.blank?
|
12
|
+
nil
|
12
13
|
elsif args.length == 1
|
13
|
-
|
14
|
+
args[0]
|
14
15
|
else
|
15
|
-
|
16
|
+
args
|
16
17
|
end
|
17
18
|
end
|
18
19
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'ostruct'
|
2
3
|
|
3
4
|
module GraphQL
|
@@ -10,16 +11,16 @@ module GraphQL
|
|
10
11
|
# Returns a promise that will eventually resolve to the model that is at the end of the path
|
11
12
|
def self.load_and_traverse(current_model, path, context)
|
12
13
|
cache_model(context, current_model)
|
13
|
-
return Promise.resolve(current_model) if path.
|
14
|
+
return Promise.resolve(current_model) if path.empty? || current_model.nil?
|
14
15
|
|
15
16
|
association = current_model.association(path[0])
|
16
17
|
|
17
|
-
while path.
|
18
|
+
while !path.empty? && (association.loaded? || attempt_cache_load(current_model, association, context))
|
18
19
|
current_model = association.target
|
19
20
|
path = path[1..-1]
|
20
21
|
cache_model(context, current_model)
|
21
22
|
|
22
|
-
return Promise.resolve(current_model) if path.
|
23
|
+
return Promise.resolve(current_model) if path.empty? || current_model.nil?
|
23
24
|
|
24
25
|
association = current_model.association(path[0])
|
25
26
|
end
|
@@ -31,7 +32,6 @@ module GraphQL
|
|
31
32
|
# First step, load the :through association (ie, the :open_enrollments)
|
32
33
|
through = association.reflection.options[:through]
|
33
34
|
load_and_traverse(current_model, [through], context).then do |intermediate_models|
|
34
|
-
|
35
35
|
# Now, for each of the intermediate models (OpenEnrollment), load the source association (:health_line)
|
36
36
|
sources = intermediate_models.map do |im|
|
37
37
|
load_and_traverse(im, [association.reflection.source_reflection_name], context)
|
@@ -107,14 +107,14 @@ module GraphQL
|
|
107
107
|
association.set_inverse_instance(target) unless target.nil?
|
108
108
|
end
|
109
109
|
|
110
|
-
def self.traverse_path(base_model, path,
|
110
|
+
def self.traverse_path(base_model, path, _context)
|
111
111
|
model = base_model
|
112
112
|
path.each do |segment|
|
113
113
|
return nil unless model
|
114
114
|
model = model.public_send(segment)
|
115
115
|
end
|
116
116
|
|
117
|
-
|
117
|
+
model
|
118
118
|
end
|
119
119
|
|
120
120
|
# Stores metadata about GraphQL fields that are available on this model's GraphQL type.
|
@@ -1,11 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module GraphQL
|
2
3
|
module Models
|
3
4
|
module DefinitionHelpers
|
4
5
|
def self.define_proxy(graph_type, base_model_type, model_type, path, association, object_to_model, detect_nulls, &block)
|
5
6
|
reflection = model_type.reflect_on_association(association)
|
6
|
-
raise ArgumentError
|
7
|
-
raise ArgumentError
|
8
|
-
raise ArgumentError
|
7
|
+
raise ArgumentError, "Association #{association} wasn't found on model #{model_type.name}" unless reflection
|
8
|
+
raise ArgumentError, "Cannot proxy to polymorphic association #{association} on model #{model_type.name}" if reflection.polymorphic?
|
9
|
+
raise ArgumentError, "Cannot proxy to #{reflection.macro} association #{association} on model #{model_type.name}" unless [:has_one, :belongs_to].include?(reflection.macro)
|
9
10
|
|
10
11
|
return unless block_given?
|
11
12
|
|
@@ -34,7 +35,7 @@ module GraphQL
|
|
34
35
|
valid_types = Reflection.possible_values(model_type, reflection.foreign_type)
|
35
36
|
|
36
37
|
if valid_types.blank?
|
37
|
-
|
38
|
+
raise ArgumentError, "Cannot include polymorphic #{reflection.name} association on model #{model_type.name}, because it does not define an inclusion validator on #{reflection.foreign_type}"
|
38
39
|
end
|
39
40
|
|
40
41
|
graph_types = valid_types.map { |t| GraphQL::Models.get_graphql_type(t) }.compact
|
@@ -54,8 +55,8 @@ module GraphQL
|
|
54
55
|
def self.define_has_one(graph_type, base_model_type, model_type, path, association, object_to_model, options, detect_nulls)
|
55
56
|
reflection = model_type.reflect_on_association(association)
|
56
57
|
|
57
|
-
|
58
|
-
|
58
|
+
raise ArgumentError, "Association #{association} wasn't found on model #{model_type.name}" unless reflection
|
59
|
+
raise ArgumentError, "Cannot include #{reflection.macro} association #{association} on model #{model_type.name} with has_one" unless [:has_one, :belongs_to].include?(reflection.macro)
|
59
60
|
|
60
61
|
# Define the field for the association itself
|
61
62
|
|
@@ -70,7 +71,7 @@ module GraphQL
|
|
70
71
|
association: association,
|
71
72
|
base_model_type: base_model_type,
|
72
73
|
model_type: model_type,
|
73
|
-
object_to_base_model: object_to_model
|
74
|
+
object_to_base_model: object_to_model,
|
74
75
|
})
|
75
76
|
|
76
77
|
graph_type.fields[camel_name.to_s] = GraphQL::Field.define do
|
@@ -79,7 +80,7 @@ module GraphQL
|
|
79
80
|
description options[:description] if options.include?(:description)
|
80
81
|
deprecation_reason options[:deprecation_reason] if options.include?(:deprecation_reason)
|
81
82
|
|
82
|
-
resolve -> (model,
|
83
|
+
resolve -> (model, _args, context) do
|
83
84
|
return nil unless model
|
84
85
|
DefinitionHelpers.load_and_traverse(model, [association], context)
|
85
86
|
end
|
@@ -96,7 +97,7 @@ module GraphQL
|
|
96
97
|
association: association,
|
97
98
|
base_model_type: base_model_type,
|
98
99
|
model_type: model_type,
|
99
|
-
object_to_base_model: object_to_model
|
100
|
+
object_to_base_model: object_to_model,
|
100
101
|
})
|
101
102
|
|
102
103
|
can_use_optimized = reflection.macro == :belongs_to
|
@@ -110,7 +111,7 @@ module GraphQL
|
|
110
111
|
type id_field_type
|
111
112
|
deprecation_reason options[:deprecation_reason] if options.include?(:deprecation_reason)
|
112
113
|
|
113
|
-
resolve -> (model,
|
114
|
+
resolve -> (model, _args, context) do
|
114
115
|
return nil unless model
|
115
116
|
|
116
117
|
if can_use_optimized
|
@@ -130,8 +131,8 @@ module GraphQL
|
|
130
131
|
def self.define_has_many_array(graph_type, base_model_type, model_type, path, association, object_to_model, options, detect_nulls)
|
131
132
|
reflection = model_type.reflect_on_association(association)
|
132
133
|
|
133
|
-
|
134
|
-
|
134
|
+
raise ArgumentError, "Association #{association} wasn't found on model #{model_type.name}" unless reflection
|
135
|
+
raise ArgumentError, "Cannot include #{reflection.macro} association #{association} on model #{model_type.name} with has_many_array" unless [:has_many].include?(reflection.macro)
|
135
136
|
|
136
137
|
association_type = options[:type] || GraphQL::Models.get_graphql_type!(reflection.klass)
|
137
138
|
|
@@ -144,7 +145,7 @@ module GraphQL
|
|
144
145
|
# The has_many associations are a little special. Instead of checking for a presence validator, we instead assume
|
145
146
|
# that the outer type should be non-null, unless detect_nulls is false. In other words, we prefer an empty
|
146
147
|
# array for the association, rather than null.
|
147
|
-
if (options[:nullable]
|
148
|
+
if (options[:nullable].nil? && detect_nulls) || options[:nullable] == false
|
148
149
|
association_type = association_type.to_non_null_type
|
149
150
|
id_field_type = id_field_type.to_non_null_type
|
150
151
|
end
|
@@ -158,7 +159,7 @@ module GraphQL
|
|
158
159
|
association: association,
|
159
160
|
base_model_type: base_model_type,
|
160
161
|
model_type: model_type,
|
161
|
-
object_to_base_model: object_to_model
|
162
|
+
object_to_base_model: object_to_model,
|
162
163
|
})
|
163
164
|
|
164
165
|
graph_type.fields[camel_name.to_s] = GraphQL::Field.define do
|
@@ -167,7 +168,7 @@ module GraphQL
|
|
167
168
|
description options[:description] if options.include?(:description)
|
168
169
|
deprecation_reason options[:deprecation_reason] if options.include?(:deprecation_reason)
|
169
170
|
|
170
|
-
resolve -> (model,
|
171
|
+
resolve -> (model, _args, context) do
|
171
172
|
return nil unless model
|
172
173
|
DefinitionHelpers.load_and_traverse(model, [association], context).then do |result|
|
173
174
|
Array.wrap(result)
|
@@ -185,7 +186,7 @@ module GraphQL
|
|
185
186
|
association: association,
|
186
187
|
base_model_type: base_model_type,
|
187
188
|
model_type: model_type,
|
188
|
-
object_to_base_model: object_to_model
|
189
|
+
object_to_base_model: object_to_model,
|
189
190
|
})
|
190
191
|
|
191
192
|
graph_type.fields[id_field_name.to_s] = GraphQL::Field.define do
|
@@ -193,7 +194,7 @@ module GraphQL
|
|
193
194
|
type id_field_type
|
194
195
|
deprecation_reason options[:deprecation_reason] if options.include?(:deprecation_reason)
|
195
196
|
|
196
|
-
resolve -> (model,
|
197
|
+
resolve -> (model, _args, context) do
|
197
198
|
return nil unless model
|
198
199
|
DefinitionHelpers.load_and_traverse(model, [association], context).then do |result|
|
199
200
|
Array.wrap(result).map(&:gid)
|
@@ -205,12 +206,12 @@ module GraphQL
|
|
205
206
|
def self.define_has_many_connection(graph_type, base_model_type, model_type, path, association, object_to_model, options, detect_nulls)
|
206
207
|
reflection = model_type.reflect_on_association(association)
|
207
208
|
|
208
|
-
|
209
|
-
|
209
|
+
raise ArgumentError, "Association #{association} wasn't found on model #{model_type.name}" unless reflection
|
210
|
+
raise ArgumentError, "Cannot include #{reflection.macro} association #{association} on model #{model_type.name} with has_many_connection" unless [:has_many].include?(reflection.macro)
|
210
211
|
|
211
212
|
connection_type = GraphQL::Models.get_graphql_type!(reflection.klass).connection_type
|
212
213
|
|
213
|
-
if (options[:nullable]
|
214
|
+
if (options[:nullable].nil? && detect_nulls) || options[:nullable] == false
|
214
215
|
connection_type = connection_type.to_non_null_type
|
215
216
|
end
|
216
217
|
|
@@ -223,11 +224,11 @@ module GraphQL
|
|
223
224
|
association: association,
|
224
225
|
base_model_type: base_model_type,
|
225
226
|
model_type: model_type,
|
226
|
-
object_to_base_model: object_to_model
|
227
|
+
object_to_base_model: object_to_model,
|
227
228
|
})
|
228
229
|
|
229
230
|
GraphQL::Define::AssignConnection.call(graph_type, camel_name, connection_type) do
|
230
|
-
resolve -> (model,
|
231
|
+
resolve -> (model, _args, _context) do
|
231
232
|
return nil unless model
|
232
233
|
model.public_send(association)
|
233
234
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module GraphQL
|
2
3
|
module Models
|
3
4
|
module DefinitionHelpers
|
@@ -8,7 +9,7 @@ module GraphQL
|
|
8
9
|
# attribute itself.
|
9
10
|
nullable = options[:nullable]
|
10
11
|
|
11
|
-
if nullable
|
12
|
+
if nullable.nil?
|
12
13
|
nullable = !(detect_nulls && Reflection.is_required(model_class, attribute_or_association))
|
13
14
|
end
|
14
15
|
|
@@ -32,7 +33,7 @@ module GraphQL
|
|
32
33
|
attribute: attribute,
|
33
34
|
base_model_class: base_model_class,
|
34
35
|
model_class: model_class,
|
35
|
-
object_to_base_model: object_to_model
|
36
|
+
object_to_base_model: object_to_model,
|
36
37
|
})
|
37
38
|
|
38
39
|
graph_type.fields[field_name.to_s] = GraphQL::Field.define do
|
@@ -41,7 +42,7 @@ module GraphQL
|
|
41
42
|
description options[:description] if options.include?(:description)
|
42
43
|
deprecation_reason options[:deprecation_reason] if options.include?(:deprecation_reason)
|
43
44
|
|
44
|
-
resolve -> (model,
|
45
|
+
resolve -> (model, _args, _context) do
|
45
46
|
model&.public_send(attribute)
|
46
47
|
end
|
47
48
|
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module GraphQL::Models
|
2
3
|
class MutationFieldMap
|
3
4
|
attr_accessor :model_type, :find_by, :null_behavior, :fields, :nested_maps
|
@@ -6,8 +7,8 @@ module GraphQL::Models
|
|
6
7
|
attr_accessor :name, :association, :has_many, :required, :path
|
7
8
|
|
8
9
|
def initialize(model_type, find_by:, null_behavior:)
|
9
|
-
|
10
|
-
|
10
|
+
raise ArgumentError, "model_type must be a model" if model_type && !(model_type <= ActiveRecord::Base)
|
11
|
+
raise ArgumentError, "null_behavior must be :set_null or :leave_unchanged" unless [:set_null, :leave_unchanged].include?(null_behavior)
|
11
12
|
|
12
13
|
@fields = []
|
13
14
|
@nested_maps = []
|
@@ -27,7 +28,7 @@ module GraphQL::Models
|
|
27
28
|
attribute = attribute.to_sym if attribute.is_a?(String)
|
28
29
|
|
29
30
|
if type.nil? && !model_type
|
30
|
-
|
31
|
+
raise ArgumentError, "You must specify a type for attribute #{name}, because its model type is not known until runtime."
|
31
32
|
end
|
32
33
|
|
33
34
|
if type.nil? && (attribute == :id || foreign_keys.include?(attribute))
|
@@ -51,7 +52,7 @@ module GraphQL::Models
|
|
51
52
|
name: name,
|
52
53
|
attribute: attribute,
|
53
54
|
type: type,
|
54
|
-
required: required
|
55
|
+
required: required,
|
55
56
|
})
|
56
57
|
end
|
57
58
|
|
@@ -62,7 +63,7 @@ module GraphQL::Models
|
|
62
63
|
|
63
64
|
if reflection
|
64
65
|
unless [:belongs_to, :has_one].include?(reflection.macro)
|
65
|
-
|
66
|
+
raise ArgumentError, "Cannot proxy to #{reflection.macro} association #{association} from #{model_type.name}"
|
66
67
|
end
|
67
68
|
|
68
69
|
klass = reflection.polymorphic? ? nil : reflection.klass
|
@@ -83,7 +84,7 @@ module GraphQL::Models
|
|
83
84
|
attribute: field[:attribute],
|
84
85
|
type: field[:type],
|
85
86
|
required: field[:required],
|
86
|
-
path: [association] + Array.wrap(field[:path])
|
87
|
+
path: [association] + Array.wrap(field[:path]),
|
87
88
|
})
|
88
89
|
end
|
89
90
|
|
@@ -95,18 +96,18 @@ module GraphQL::Models
|
|
95
96
|
|
96
97
|
def nested(association, find_by: nil, null_behavior:, name: nil, has_many: false, &block)
|
97
98
|
unless model_type
|
98
|
-
|
99
|
+
raise ArgumentError, "Cannot use `nested` unless the model type is known at build time."
|
99
100
|
end
|
100
101
|
|
101
102
|
association = association.to_sym if association.is_a?(String)
|
102
103
|
reflection = model_type.reflect_on_association(association)
|
103
104
|
|
104
105
|
unless reflection
|
105
|
-
|
106
|
+
raise ArgumentError, "Could not find association #{association} on #{model_type.name}"
|
106
107
|
end
|
107
108
|
|
108
109
|
if reflection.polymorphic?
|
109
|
-
|
110
|
+
raise ArgumentError, "Cannot used `nested` with polymorphic association #{association} on #{model_type.name}"
|
110
111
|
end
|
111
112
|
|
112
113
|
has_many = reflection.macro == :has_many
|
@@ -133,7 +134,7 @@ module GraphQL::Models
|
|
133
134
|
|
134
135
|
def detect_field_conflict(name)
|
135
136
|
if fields.any? { |f| f[name] == name } || nested_maps.any? { |n| n.name == name }
|
136
|
-
|
137
|
+
raise ArgumentError, "The field #{name} is defined more than once."
|
137
138
|
end
|
138
139
|
end
|
139
140
|
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module GraphQL::Models
|
2
3
|
module MutationHelpers
|
3
4
|
def self.apply_changes(field_map, model, inputs, context)
|
@@ -40,7 +41,7 @@ module GraphQL::Models
|
|
40
41
|
end
|
41
42
|
end
|
42
43
|
|
43
|
-
|
44
|
+
changes
|
44
45
|
end
|
45
46
|
|
46
47
|
def self.handle_nested_map(parent_map, parent_model, inputs, context, child_map)
|
@@ -66,7 +67,7 @@ module GraphQL::Models
|
|
66
67
|
changes.concat(child_changes)
|
67
68
|
end
|
68
69
|
|
69
|
-
|
70
|
+
changes
|
70
71
|
end
|
71
72
|
|
72
73
|
def self.match_inputs_to_models(model, child_map, next_inputs, changes)
|
@@ -92,7 +93,7 @@ module GraphQL::Models
|
|
92
93
|
changes.push({ model_instance: child_model, action: :create })
|
93
94
|
end
|
94
95
|
|
95
|
-
|
96
|
+
[{ child_model: child_model, child_inputs: next_inputs }]
|
96
97
|
else
|
97
98
|
next_inputs = [] if next_inputs.nil?
|
98
99
|
|
@@ -108,7 +109,7 @@ module GraphQL::Models
|
|
108
109
|
end
|
109
110
|
end
|
110
111
|
|
111
|
-
def self.match_inputs_by_position(
|
112
|
+
def self.match_inputs_by_position(_model, _child_map, next_inputs, changes, associated_models)
|
112
113
|
count = [associated_models.length, next_inputs.length].max
|
113
114
|
|
114
115
|
matches = []
|
@@ -130,10 +131,10 @@ module GraphQL::Models
|
|
130
131
|
matches.push({ child_model: child_model, child_inputs: inputs, input_path: idx })
|
131
132
|
end
|
132
133
|
|
133
|
-
|
134
|
+
matches
|
134
135
|
end
|
135
136
|
|
136
|
-
def self.match_inputs_by_fields(
|
137
|
+
def self.match_inputs_by_fields(_model, child_map, next_inputs, changes, associated_models, find_by)
|
137
138
|
# Convert the find_by into the field definitions, so that we properly unmap aliased fields
|
138
139
|
find_by_defs = find_by.map { |name| child_map.fields.detect { |f| f[:attribute].to_s == name.to_s } }
|
139
140
|
name_to_attr = find_by_defs.map { |f| [f[:name], f[:attribute].to_s] }.to_h
|
@@ -175,7 +176,7 @@ module GraphQL::Models
|
|
175
176
|
matches.push({ child_model: child_model, child_inputs: inputs, input_path: next_inputs.index(inputs) })
|
176
177
|
end
|
177
178
|
|
178
|
-
|
179
|
+
matches
|
179
180
|
end
|
180
181
|
|
181
182
|
# Returns the instance of the model that will be changed for this field. If new models are created along the way,
|
@@ -197,7 +198,7 @@ module GraphQL::Models
|
|
197
198
|
model_to_change = next_model
|
198
199
|
end
|
199
200
|
|
200
|
-
|
201
|
+
model_to_change
|
201
202
|
end
|
202
203
|
|
203
204
|
def self.apply_field_value(model, field_def, value, context, changes)
|
@@ -206,7 +207,7 @@ module GraphQL::Models
|
|
206
207
|
target_model = GraphQL::Models.model_from_id.call(value, context)
|
207
208
|
|
208
209
|
unless target_model
|
209
|
-
|
210
|
+
raise GraphQL::ExecutionError, "The value provided for #{field_def[:name]} does not refer to a valid model."
|
210
211
|
end
|
211
212
|
|
212
213
|
value = target_model.id
|
@@ -219,7 +220,7 @@ module GraphQL::Models
|
|
219
220
|
model_instance: model,
|
220
221
|
input_path: field_def[:name],
|
221
222
|
attribute: field_def[:attribute],
|
222
|
-
action: model.new_record? ? :create : :update
|
223
|
+
action: model.new_record? ? :create : :update,
|
223
224
|
})
|
224
225
|
end
|
225
226
|
end
|
@@ -250,6 +251,5 @@ module GraphQL::Models
|
|
250
251
|
|
251
252
|
values
|
252
253
|
end
|
253
|
-
|
254
254
|
end
|
255
255
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module GraphQL::Models
|
2
3
|
module MutationHelpers
|
3
4
|
def self.print_input_fields(field_map, definer, map_name_prefix)
|
@@ -14,8 +15,8 @@ module GraphQL::Models
|
|
14
15
|
|
15
16
|
if field_map.leave_null_unchanged?
|
16
17
|
field_names = field_map.fields.select { |f| !f[:required] }.map { |f| f[:name] }
|
17
|
-
field_names += field_map.nested_maps.reject(&:required).map
|
18
|
-
field_names = field_names.
|
18
|
+
field_names += field_map.nested_maps.reject(&:required).map(&:name)
|
19
|
+
field_names = field_names.sort
|
19
20
|
|
20
21
|
unless field_names.empty?
|
21
22
|
enum = GraphQL::EnumType.define do
|
@@ -1,12 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module GraphQL::Models
|
2
3
|
module MutationHelpers
|
3
|
-
def self.validate_changes(inputs, field_map, root_model,
|
4
|
+
def self.validate_changes(inputs, field_map, root_model, _context, all_changes)
|
4
5
|
invalid_fields = {}
|
5
6
|
unknown_errors = []
|
6
7
|
|
7
8
|
changed_models = all_changes.group_by { |c| c[:model_instance] }
|
8
9
|
|
9
|
-
changed_models.reject { |m,
|
10
|
+
changed_models.reject { |m, _v| m.valid? }.each do |model, changes|
|
10
11
|
attrs_to_field = changes
|
11
12
|
.select { |c| c[:attribute] && c[:input_path] }
|
12
13
|
.map { |c| [c[:attribute], c[:input_path]] }
|
@@ -29,7 +30,7 @@ module GraphQL::Models
|
|
29
30
|
modelType: model.class.name,
|
30
31
|
modelRid: model.id,
|
31
32
|
attribute: attribute,
|
32
|
-
message: message
|
33
|
+
message: message,
|
33
34
|
})
|
34
35
|
end
|
35
36
|
end
|
@@ -37,11 +38,11 @@ module GraphQL::Models
|
|
37
38
|
end
|
38
39
|
|
39
40
|
unless invalid_fields.empty? && unknown_errors.empty?
|
40
|
-
|
41
|
+
raise ValidationError.new(invalid_fields, unknown_errors)
|
41
42
|
end
|
42
43
|
end
|
43
44
|
|
44
|
-
def self.add_error(
|
45
|
+
def self.add_error(_attribute, message, path, invalid_fields)
|
45
46
|
path = Array.wrap(path)
|
46
47
|
|
47
48
|
current = invalid_fields
|
@@ -96,9 +97,7 @@ module GraphQL::Models
|
|
96
97
|
end
|
97
98
|
end
|
98
99
|
|
99
|
-
|
100
|
+
nil
|
100
101
|
end
|
101
|
-
|
102
|
-
|
103
102
|
end
|
104
103
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module GraphQL::Models
|
2
3
|
module MutationHelpers
|
3
4
|
class ValidationError < GraphQL::ExecutionError
|
@@ -13,16 +14,14 @@ module GraphQL::Models
|
|
13
14
|
'message' => "Some of your changes could not be saved.",
|
14
15
|
'kind' => "INVALID_ARGUMENTS",
|
15
16
|
'invalidArguments' => invalid_arguments,
|
16
|
-
'unknownErrors' => unknown_errors
|
17
|
+
'unknownErrors' => unknown_errors,
|
17
18
|
}
|
18
19
|
|
19
20
|
if ast_node
|
20
|
-
values
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
}]
|
25
|
-
})
|
21
|
+
values['locations'] = [{
|
22
|
+
"line" => ast_node.line,
|
23
|
+
"column" => ast_node.col,
|
24
|
+
},]
|
26
25
|
end
|
27
26
|
|
28
27
|
values
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module GraphQL::Models
|
2
3
|
class Mutator
|
3
4
|
attr_accessor :field_map, :root_model, :inputs, :context
|
@@ -10,28 +11,28 @@ module GraphQL::Models
|
|
10
11
|
end
|
11
12
|
|
12
13
|
def apply_changes
|
13
|
-
|
14
|
+
raise StandardError, "Called apply_changes twice for the same mutator" if @all_changes
|
14
15
|
@all_changes = MutationHelpers.apply_changes(field_map, root_model, inputs, context)
|
15
16
|
changed_models
|
16
17
|
end
|
17
18
|
|
18
19
|
def changed_models
|
19
|
-
|
20
|
+
raise StandardError, "Need to call apply_changes before #{__method__}" unless @all_changes
|
20
21
|
@all_changes.map { |c| c[:model_instance] }.uniq
|
21
22
|
end
|
22
23
|
|
23
24
|
def validate!
|
24
|
-
|
25
|
+
raise StandardError, "Need to call apply_changes before #{__method__}" unless @all_changes
|
25
26
|
MutationHelpers.validate_changes(inputs, field_map, root_model, context, @all_changes)
|
26
27
|
end
|
27
28
|
|
28
29
|
def authorize!
|
29
|
-
|
30
|
+
raise StandardError, "Need to call apply_changes before #{__method__}" unless @all_changes
|
30
31
|
MutationHelpers.authorize_changes(context, @all_changes)
|
31
32
|
end
|
32
33
|
|
33
34
|
def save!
|
34
|
-
|
35
|
+
raise StandardError, "Need to call apply_changes before #{__method__}" unless @all_changes
|
35
36
|
|
36
37
|
ActiveRecord::Base.transaction(requires_new: true) do
|
37
38
|
changed_models.each do |model|
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
# Exposes utility methods for getting metadata out of active record models
|
2
3
|
module GraphQL::Models
|
3
4
|
module Reflection
|
@@ -10,7 +11,7 @@ module GraphQL::Models
|
|
10
11
|
# Ignore any inclusion validators that are using the 'if' or 'unless' options
|
11
12
|
validators = validators.reject { |v| v.options.include?(:if) || v.options.include?(:unless) || v.options[:in].blank? }
|
12
13
|
return nil unless validators.any?
|
13
|
-
|
14
|
+
validators.map { |v| v.options[:in] }.reduce(:&)
|
14
15
|
end
|
15
16
|
|
16
17
|
# Determines if the attribute (or association) is required by examining presence validators
|
@@ -43,13 +44,13 @@ module GraphQL::Models
|
|
43
44
|
active_record_type = model_class.type_for_attribute(attribute.to_s)
|
44
45
|
|
45
46
|
if active_record_type.type.nil?
|
46
|
-
|
47
|
+
raise ArgumentError, "The type for attribute #{attribute} wasn't found on #{model_class.name}"
|
47
48
|
end
|
48
49
|
|
49
50
|
result = DatabaseTypes.registered_type(active_record_type.type)
|
50
51
|
|
51
52
|
if !result
|
52
|
-
|
53
|
+
raise "The type #{active_record_type} is not registered with DatabaseTypes (attribute #{attribute} on #{model_class.name})"
|
53
54
|
end
|
54
55
|
|
55
56
|
# Arrays: Rails doesn't have a generalized way to detect arrays, so we use this method to do it:
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module GraphQL
|
2
3
|
module Models
|
3
4
|
class RelationLoadRequest
|
@@ -26,8 +27,7 @@ module GraphQL
|
|
26
27
|
end
|
27
28
|
|
28
29
|
# When the request is fulfilled, this method is called so that it can do whatever caching, etc. is needed
|
29
|
-
def fulfilled(result)
|
30
|
-
end
|
30
|
+
def fulfilled(result); end
|
31
31
|
|
32
32
|
def load
|
33
33
|
loader.load(self)
|
@@ -46,7 +46,6 @@ module GraphQL
|
|
46
46
|
def loader
|
47
47
|
@loader ||= RelationLoader.for(target_class)
|
48
48
|
end
|
49
|
-
|
50
49
|
end
|
51
50
|
end
|
52
51
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module GraphQL
|
2
3
|
module Models
|
3
4
|
class RelationLoader < GraphQL::Batch::Loader
|
@@ -8,7 +9,6 @@ module GraphQL
|
|
8
9
|
end
|
9
10
|
|
10
11
|
def perform(load_requests)
|
11
|
-
|
12
12
|
# Group the requests to load by id into a single relation, and we'll fan it back out after
|
13
13
|
# we have the results
|
14
14
|
|
@@ -38,7 +38,7 @@ module GraphQL
|
|
38
38
|
end
|
39
39
|
|
40
40
|
# Generate a CASE column that will tell us whether the row matches this particular relation
|
41
|
-
slicing_columns = relations.each_with_index.map do |
|
41
|
+
slicing_columns = relations.each_with_index.map do |_relation, index|
|
42
42
|
%{ CASE WHEN "#{model_class.table_name}"."#{model_class.primary_key}" IN (#{selection_clauses[index]}) THEN 1 ELSE 0 END AS "in_relation_#{index}" }
|
43
43
|
end
|
44
44
|
|
@@ -64,7 +64,7 @@ module GraphQL
|
|
64
64
|
# Build the query that will select any of the rows that match the selection clauses
|
65
65
|
main_relation = model_class
|
66
66
|
.where("id in ((#{selection_clauses.join(") UNION (")}))")
|
67
|
-
.select(%
|
67
|
+
.select(%( "#{model_class.table_name}".* ))
|
68
68
|
|
69
69
|
main_relation = slicing_columns.reduce(main_relation) { |relation, memo| relation.select(memo) }
|
70
70
|
main_relation = sorting_columns.reduce(main_relation) { |relation, memo| relation.select(memo) }
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: graphql-activerecord
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.11.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryan Foster
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-04-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -140,6 +140,20 @@ dependencies:
|
|
140
140
|
- - ">="
|
141
141
|
- !ruby/object:Gem::Version
|
142
142
|
version: '0'
|
143
|
+
- !ruby/object:Gem::Dependency
|
144
|
+
name: rubocop
|
145
|
+
requirement: !ruby/object:Gem::Requirement
|
146
|
+
requirements:
|
147
|
+
- - "~>"
|
148
|
+
- !ruby/object:Gem::Version
|
149
|
+
version: 0.47.1
|
150
|
+
type: :development
|
151
|
+
prerelease: false
|
152
|
+
version_requirements: !ruby/object:Gem::Requirement
|
153
|
+
requirements:
|
154
|
+
- - "~>"
|
155
|
+
- !ruby/object:Gem::Version
|
156
|
+
version: 0.47.1
|
143
157
|
description: Build Relay-compatible GraphQL schemas based on ActiveRecord models
|
144
158
|
email:
|
145
159
|
- theorygeek@gmail.com
|
@@ -148,8 +162,11 @@ extensions: []
|
|
148
162
|
extra_rdoc_files: []
|
149
163
|
files:
|
150
164
|
- ".bundle/config"
|
165
|
+
- ".circleci/config.yml"
|
151
166
|
- ".gitignore"
|
152
167
|
- ".rspec"
|
168
|
+
- ".rubocop.yml"
|
169
|
+
- ".rubocop_todo.yml"
|
153
170
|
- ".travis.yml"
|
154
171
|
- CHANGELOG.md
|
155
172
|
- CODE_OF_CONDUCT.md
|
@@ -168,6 +185,9 @@ files:
|
|
168
185
|
- bin/pry
|
169
186
|
- bin/rake
|
170
187
|
- bin/rspec
|
188
|
+
- bin/rubocop
|
189
|
+
- bin/ruby-parse
|
190
|
+
- bin/ruby-rewrite
|
171
191
|
- bin/setup
|
172
192
|
- bin/thor
|
173
193
|
- graphql-activerecord.gemspec
|