graphiti 2.0.0.beta.3 → 2.0.0.beta.4
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/.github/workflows/ci.yml +30 -86
- data/.github/workflows/docs.yml +60 -0
- data/.github/workflows/release.yml +8 -8
- data/.gitignore +7 -0
- data/.npmrc +9 -0
- data/.standard.yml +4 -1
- data/Appraisals +33 -32
- data/CHANGELOG.md +34 -0
- data/README.md +13 -2
- data/UPGRADING.md +2 -58
- data/docs/concepts/backends-and-models.md +122 -0
- data/docs/concepts/endpoints.md +183 -0
- data/docs/concepts/links.md +212 -0
- data/docs/concepts/overview.md +80 -0
- data/docs/concepts/persisting.md +376 -0
- data/docs/concepts/relationships.md +527 -0
- data/docs/concepts/resources.md +677 -0
- data/docs/getting-started/first-api.md +289 -0
- data/docs/getting-started/installation.md +185 -0
- data/docs/intro.md +307 -0
- data/docs/js/authentication.md +63 -0
- data/docs/js/ddau.md +20 -0
- data/docs/js/extra-params.md +41 -0
- data/docs/js/index.md +112 -0
- data/docs/js/installation.md +120 -0
- data/docs/js/middleware.md +72 -0
- data/docs/js/models.md +202 -0
- data/docs/js/reads.md +494 -0
- data/docs/js/state-syncing.md +100 -0
- data/docs/js/writes.md +373 -0
- data/docs/reference/vandal.md +63 -0
- data/docs/reference/why.md +13 -0
- data/docs/topics/authorization.md +155 -0
- data/docs/topics/caching.md +55 -0
- data/docs/topics/customizing-sideloads.md +156 -0
- data/docs/topics/debugging.md +216 -0
- data/docs/topics/error-handling.md +210 -0
- data/docs/topics/etags.md +46 -0
- data/docs/topics/hopping-relationships.md +149 -0
- data/docs/topics/json-attributes.md +77 -0
- data/docs/topics/openstruct-models.md +50 -0
- data/docs/topics/remote-resources.md +291 -0
- data/docs/topics/testing.md +894 -0
- data/docs/topics/without-activerecord.md +324 -0
- data/docs/tutorial/index.md +58 -0
- data/docs/tutorial/step_0.md +107 -0
- data/docs/tutorial/step_1.md +199 -0
- data/docs/tutorial/step_2.md +312 -0
- data/docs/tutorial/step_3.md +142 -0
- data/docs/tutorial/step_4.md +135 -0
- data/docs/tutorial/step_5.md +69 -0
- data/docs/tutorial/step_6.md +82 -0
- data/docs/tutorial/step_7.md +205 -0
- data/docs/tutorial/step_8.md +128 -0
- data/docs/tutorial/step_9.md +171 -0
- data/docs/upgrading.md +265 -0
- data/gemfiles/rails_7_1.gemfile +4 -3
- data/gemfiles/{rails_7_2_graphiti_rails.gemfile → rails_7_2.gemfile} +3 -3
- data/gemfiles/{rails_8_1_graphiti_rails.gemfile → rails_8_0.gemfile} +3 -3
- data/gemfiles/{rails_8_0_graphiti_rails.gemfile → rails_8_1.gemfile} +3 -3
- data/graphiti.gemspec +7 -5
- data/{deprecated_generators → lib/generators}/graphiti/api_test_generator.rb +7 -1
- data/{deprecated_generators → lib/generators}/graphiti/generator_mixin.rb +14 -1
- data/{deprecated_generators → lib/generators}/graphiti/install_generator.rb +19 -13
- data/{deprecated_generators → lib/generators}/graphiti/resource_generator.rb +43 -6
- data/{deprecated_generators → lib/generators}/graphiti/templates/index_request_spec.rb.erb +1 -1
- data/{deprecated_generators → lib/generators}/graphiti/templates/resource_reads_spec.rb.erb +6 -6
- data/{deprecated_generators → lib/generators}/graphiti/templates/show_request_spec.rb.erb +1 -1
- data/lib/graphiti/configuration.rb +2 -2
- data/lib/graphiti/error_serializers/conflict_request.rb +19 -0
- data/lib/graphiti/error_serializers/deprecated_constants.rb +48 -0
- data/lib/graphiti/error_serializers/invalid_request.rb +56 -0
- data/lib/graphiti/error_serializers/validation.rb +143 -0
- data/lib/graphiti/errors.rb +4 -4
- data/lib/graphiti/query.rb +1 -1
- data/lib/graphiti/rails/context.rb +33 -0
- data/lib/graphiti/rails/controller.rb +41 -0
- data/lib/graphiti/rails/debugging.rb +18 -0
- data/lib/graphiti/rails/exception_handlers.rb +77 -0
- data/lib/graphiti/rails/railtie.rb +139 -0
- data/lib/graphiti/rails/responders.rb +21 -0
- data/lib/graphiti/rails/test_helpers.rb +22 -0
- data/lib/graphiti/rails.rb +47 -29
- data/lib/graphiti/resource/configuration.rb +1 -0
- data/lib/graphiti/resource/interface.rb +2 -2
- data/lib/graphiti/resource/remote.rb +2 -2
- data/lib/graphiti/resource/sideloading.rb +1 -1
- data/lib/graphiti/resource.rb +13 -1
- data/lib/graphiti/responders.rb +7 -20
- data/lib/graphiti/schema.rb +5 -1
- data/lib/graphiti/schema_diff.rb +4 -0
- data/lib/graphiti/scope.rb +45 -37
- data/lib/graphiti/serializer.rb +6 -0
- data/lib/graphiti/sideload/belongs_to.rb +38 -5
- data/lib/graphiti/sideload/polymorphic_belongs_to.rb +27 -23
- data/lib/graphiti/sideload.rb +54 -35
- data/lib/graphiti/spec_helpers/errors.rb +73 -0
- data/lib/graphiti/spec_helpers/errors_proxy.rb +75 -0
- data/lib/graphiti/spec_helpers/helpers.rb +107 -0
- data/lib/graphiti/spec_helpers/node.rb +88 -0
- data/lib/graphiti/spec_helpers/rspec.rb +147 -0
- data/lib/graphiti/spec_helpers.rb +53 -0
- data/lib/graphiti/util/include_params.rb +2 -2
- data/lib/graphiti/util/serializer_relationships.rb +41 -5
- data/lib/graphiti/version.rb +1 -1
- data/lib/graphiti-rails.rb +11 -0
- data/lib/graphiti.rb +34 -10
- data/lib/graphiti_errors.rb +11 -0
- data/lib/graphiti_spec_helpers/rspec.rb +3 -0
- data/lib/graphiti_spec_helpers.rb +11 -0
- data/lib/{graphiti/deprecated_tasks.rb → tasks/graphiti.rake} +6 -1
- data/package-lock.json +6199 -0
- data/package.json +5 -4
- data/website/.gitignore +20 -0
- data/website/README.md +43 -0
- data/website/docusaurus.config.js +141 -0
- data/website/package-lock.json +19474 -0
- data/website/package.json +46 -0
- data/website/sidebars.js +82 -0
- data/website/src/css/custom.css +58 -0
- data/website/src/pages/markdown-page.mdx +7 -0
- data/website/static/.nojekyll +0 -0
- data/website/static/1.13/2019/03/31/graphiti-1-0.html +205 -0
- data/website/static/1.13/2019/05/08/graphiti-1-1.html +212 -0
- data/website/static/1.13/2019/05/20/graphiti-1-2.html +214 -0
- data/website/static/1.13/2019/10/14/tutorial.html +198 -0
- data/website/static/1.13/CNAME +1 -0
- data/website/static/1.13/README.md +16 -0
- data/website/static/1.13/assets/css/syntax.css +60 -0
- data/website/static/1.13/assets/favicons/android-chrome-192x192.png +0 -0
- data/website/static/1.13/assets/favicons/android-chrome-256x256.png +0 -0
- data/website/static/1.13/assets/favicons/apple-touch-icon.png +0 -0
- data/website/static/1.13/assets/favicons/browserconfig.xml +9 -0
- data/website/static/1.13/assets/favicons/favicon-16x16.png +0 -0
- data/website/static/1.13/assets/favicons/favicon-32x32.png +0 -0
- data/website/static/1.13/assets/favicons/favicon.ico +0 -0
- data/website/static/1.13/assets/favicons/mstile-150x150.png +0 -0
- data/website/static/1.13/assets/favicons/safari-pinned-tab.svg +1 -0
- data/website/static/1.13/assets/favicons/site.webmanifest +19 -0
- data/website/static/1.13/assets/img/backend.gif +0 -0
- data/website/static/1.13/assets/img/conformity.png +0 -0
- data/website/static/1.13/assets/img/error_payload.png +0 -0
- data/website/static/1.13/assets/img/gh.png +0 -0
- data/website/static/1.13/assets/img/lifecycle.gif +0 -0
- data/website/static/1.13/assets/img/logo-500.png +0 -0
- data/website/static/1.13/assets/img/logo.png +0 -0
- data/website/static/1.13/assets/img/love-graffiti.jpg +0 -0
- data/website/static/1.13/assets/img/meta_total_count.png +0 -0
- data/website/static/1.13/assets/img/persist.jpg +0 -0
- data/website/static/1.13/assets/img/resource.gif +0 -0
- data/website/static/1.13/assets/img/rest-graffiti.jpg +0 -0
- data/website/static/1.13/assets/img/rest1.gif +0 -0
- data/website/static/1.13/assets/img/rest2.gif +0 -0
- data/website/static/1.13/assets/img/rest3.gif +0 -0
- data/website/static/1.13/assets/img/rethink-rest-graffiti.jpg +0 -0
- data/website/static/1.13/assets/img/why.png +0 -0
- data/website/static/1.13/assets/js/highlight.pack.js +2 -0
- data/website/static/1.13/assets/main.css +15518 -0
- data/website/static/1.13/assets/main.css.map +1 -0
- data/website/static/1.13/bin/bundle +109 -0
- data/website/static/1.13/bin/jekyll +27 -0
- data/website/static/1.13/bin/kramdown +27 -0
- data/website/static/1.13/bin/listen +27 -0
- data/website/static/1.13/bin/rake +27 -0
- data/website/static/1.13/bin/rougify +27 -0
- data/website/static/1.13/bin/safe_yaml +27 -0
- data/website/static/1.13/bin/sass +27 -0
- data/website/static/1.13/bin/sass-convert +27 -0
- data/website/static/1.13/bin/scss +27 -0
- data/website/static/1.13/blog.html +259 -0
- data/website/static/1.13/cheatsheet.html +316 -0
- data/website/static/1.13/cookbooks/authorization.md +0 -0
- data/website/static/1.13/cookbooks/caching.md +0 -0
- data/website/static/1.13/cookbooks/customizing-sideloads.html +325 -0
- data/website/static/1.13/cookbooks/etags.md +0 -0
- data/website/static/1.13/cookbooks/hopping-relationships.html +324 -0
- data/website/static/1.13/cookbooks/json_attributes.md +0 -0
- data/website/static/1.13/cookbooks/openstruct-models.md +0 -0
- data/website/static/1.13/cookbooks/remote-resources.md +0 -0
- data/website/static/1.13/cookbooks/without-activerecord.html +510 -0
- data/website/static/1.13/features.html +249 -0
- data/website/static/1.13/feed.xml +106 -0
- data/website/static/1.13/guides/concepts/backends-and-models.html +467 -0
- data/website/static/1.13/guides/concepts/debugging.html +440 -0
- data/website/static/1.13/guides/concepts/endpoints.html +432 -0
- data/website/static/1.13/guides/concepts/error-handling.html +396 -0
- data/website/static/1.13/guides/concepts/links.html +501 -0
- data/website/static/1.13/guides/concepts/remote-resources.html +536 -0
- data/website/static/1.13/guides/concepts/resources.html +2176 -0
- data/website/static/1.13/guides/concepts/testing.html +1469 -0
- data/website/static/1.13/guides/getting-started/installation.html +420 -0
- data/website/static/1.13/guides/graphiti-rails-migration.html +242 -0
- data/website/static/1.13/guides/index.html +269 -0
- data/website/static/1.13/guides/overview.html +325 -0
- data/website/static/1.13/guides/upgrading-2-0.html +193 -0
- data/website/static/1.13/guides/upgrading.html +314 -0
- data/website/static/1.13/guides/vandal.html +282 -0
- data/website/static/1.13/guides/why.html +1121 -0
- data/website/static/1.13/index.html +72 -0
- data/website/static/1.13/js/authentication.html +295 -0
- data/website/static/1.13/js/ddau.html +238 -0
- data/website/static/1.13/js/extra-params.html +270 -0
- data/website/static/1.13/js/index.html +321 -0
- data/website/static/1.13/js/installation.html +637 -0
- data/website/static/1.13/js/introduction.html +257 -0
- data/website/static/1.13/js/middleware.html +318 -0
- data/website/static/1.13/js/reads/fieldsets.html +271 -0
- data/website/static/1.13/js/reads/filtering.html +289 -0
- data/website/static/1.13/js/reads/includes.html +260 -0
- data/website/static/1.13/js/reads/index.html +497 -0
- data/website/static/1.13/js/reads/nested-queries.html +353 -0
- data/website/static/1.13/js/reads/pagination.html +260 -0
- data/website/static/1.13/js/reads/sorting.html +265 -0
- data/website/static/1.13/js/reads/statistics.html +289 -0
- data/website/static/1.13/js/state-syncing.html +340 -0
- data/website/static/1.13/js/writes/deferred.html +296 -0
- data/website/static/1.13/js/writes/dirty-tracking.html +399 -0
- data/website/static/1.13/js/writes/index.html +391 -0
- data/website/static/1.13/js/writes/nested.html +330 -0
- data/website/static/1.13/js/writes/validations.html +272 -0
- data/website/static/1.13/quickstart.html +660 -0
- data/website/static/1.13/template +161 -0
- data/website/static/1.13/tutorial/index.html +250 -0
- data/website/static/1.13/tutorial/step_0.html +292 -0
- data/website/static/1.13/tutorial/step_1.html +517 -0
- data/website/static/1.13/tutorial/step_2.html +481 -0
- data/website/static/1.13/tutorial/step_3.html +323 -0
- data/website/static/1.13/tutorial/step_4.html +318 -0
- data/website/static/1.13/tutorial/step_5.html +265 -0
- data/website/static/1.13/tutorial/step_6.html +276 -0
- data/website/static/1.13/tutorial/step_7.html +390 -0
- data/website/static/1.13/tutorial/step_8.html +316 -0
- data/website/static/1.13/tutorial/step_9.html +365 -0
- data/website/static/assets/img/error_payload.png +0 -0
- data/website/static/assets/img/legacy/legacy-0378a3bb39.png +0 -0
- data/website/static/assets/img/legacy/legacy-05bbd3e5fd.png +0 -0
- data/website/static/assets/img/legacy/legacy-07aa104495.png +0 -0
- data/website/static/assets/img/legacy/legacy-0c75a16b3a.gif +0 -0
- data/website/static/assets/img/legacy/legacy-3076df6209.png +0 -0
- data/website/static/assets/img/legacy/legacy-7f6889bc89.png +0 -0
- data/website/static/assets/img/legacy/legacy-a2cc4363c3.png +0 -0
- data/website/static/assets/img/legacy/legacy-f67cfa89ab.png +0 -0
- data/website/static/assets/img/meta_total_count.png +0 -0
- data/website/static/img/docusaurus-social-card.jpg +0 -0
- data/website/static/img/docusaurus.png +0 -0
- data/website/static/img/favicon.ico +0 -0
- data/website/static/img/logo.png +0 -0
- data/website/static/img/logo.svg +1 -0
- data/website/static/img/undraw_docusaurus_mountain.svg +171 -0
- data/website/static/img/undraw_docusaurus_react.svg +170 -0
- data/website/static/img/undraw_docusaurus_tree.svg +40 -0
- metadata +245 -46
- data/gemfiles/rails_6.gemfile +0 -18
- data/gemfiles/rails_6_graphiti_rails.gemfile +0 -19
- data/gemfiles/rails_7.gemfile +0 -18
- data/gemfiles/rails_7_1_graphiti_rails.gemfile +0 -19
- data/gemfiles/rails_7_graphiti_rails.gemfile +0 -19
- data/lib/graphiti/railtie.rb +0 -121
- /data/{deprecated_generators → lib/generators}/graphiti/resource_test_generator.rb +0 -0
- /data/{deprecated_generators → lib/generators}/graphiti/templates/application_resource.rb.erb +0 -0
- /data/{deprecated_generators → lib/generators}/graphiti/templates/controller.rb.erb +0 -0
- /data/{deprecated_generators → lib/generators}/graphiti/templates/create_request_spec.rb.erb +0 -0
- /data/{deprecated_generators → lib/generators}/graphiti/templates/destroy_request_spec.rb.erb +0 -0
- /data/{deprecated_generators → lib/generators}/graphiti/templates/resource.rb.erb +0 -0
- /data/{deprecated_generators → lib/generators}/graphiti/templates/resource_writes_spec.rb.erb +0 -0
- /data/{deprecated_generators → lib/generators}/graphiti/templates/update_request_spec.rb.erb +0 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
module Graphiti
|
|
2
|
+
module SpecHelpers
|
|
3
|
+
class ErrorsProxy
|
|
4
|
+
class Error
|
|
5
|
+
attr_reader :json
|
|
6
|
+
|
|
7
|
+
def initialize(json)
|
|
8
|
+
@json = json
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def attribute
|
|
12
|
+
@json[:meta][:attribute]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# TODO: move to top-level code in errorable
|
|
16
|
+
def code
|
|
17
|
+
@json[:meta][:code]
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def message
|
|
21
|
+
@json[:meta][:message]
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def title
|
|
25
|
+
@json[:title]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def detail
|
|
29
|
+
@json[:detail]
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def status
|
|
33
|
+
@json[:status]
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
include Enumerable
|
|
38
|
+
|
|
39
|
+
def initialize(array)
|
|
40
|
+
@errors = array.map { |e| Error.new(e) }
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def [](key)
|
|
44
|
+
@errors[key]
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def each(&blk)
|
|
48
|
+
@errors.each(&blk)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def length
|
|
52
|
+
count
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def to_h
|
|
56
|
+
{}.tap do |hash|
|
|
57
|
+
@errors.each do |e|
|
|
58
|
+
hash[e.attribute] = e.message
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def method_missing(id, *args, &blk)
|
|
64
|
+
matches = @errors.select { |e| e.attribute.to_sym == id }
|
|
65
|
+
matches.length == 1 ? matches[0] : matches
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Any name is answered: an attribute with no matching error yields an empty
|
|
69
|
+
# array rather than raising NoMethodError.
|
|
70
|
+
def respond_to_missing?(id, include_private = false)
|
|
71
|
+
true
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
module Graphiti
|
|
2
|
+
module SpecHelpers
|
|
3
|
+
module Helpers
|
|
4
|
+
extend ActiveSupport::Concern
|
|
5
|
+
|
|
6
|
+
def json
|
|
7
|
+
if response&.body
|
|
8
|
+
JSON.parse(response.body).with_indifferent_access
|
|
9
|
+
else
|
|
10
|
+
raise Errors::NoResponse.new
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def jsonapi_data
|
|
15
|
+
@jsonapi_data ||= if _jsonapi_data.is_a?(Hash)
|
|
16
|
+
node(from: _jsonapi_data)
|
|
17
|
+
else
|
|
18
|
+
_jsonapi_data.map { |datum| node(from: datum) }
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def jsonapi_included(type = nil)
|
|
23
|
+
variable = :"@jsonapi_included#{type}"
|
|
24
|
+
memo = instance_variable_get(variable)
|
|
25
|
+
return memo if memo
|
|
26
|
+
|
|
27
|
+
nodes = _jsonapi_included.map { |i| node(from: i) }
|
|
28
|
+
if type
|
|
29
|
+
nodes.select! { |n| n.jsonapi_type == type.to_s }
|
|
30
|
+
end
|
|
31
|
+
instance_variable_set(variable, nodes)
|
|
32
|
+
nodes
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def jsonapi_errors
|
|
36
|
+
@jsonapi_errors ||= ErrorsProxy.new(json["errors"] || [])
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def jsonapi_meta
|
|
40
|
+
@jsonapi_errors = json["meta"] || raise(Errors::NoMeta.new(json))
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def jsonapi_headers
|
|
44
|
+
media_type = "application/vnd.api+json"
|
|
45
|
+
{
|
|
46
|
+
"CONTENT_TYPE" => media_type,
|
|
47
|
+
"HTTP_ACCEPT" => media_type
|
|
48
|
+
}
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def jsonapi_get(url, params: {}, headers: {})
|
|
52
|
+
get url_for(url), params: params, headers: jsonapi_headers.merge(headers)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def jsonapi_post(url, payload, headers: {})
|
|
56
|
+
post url_for(url), params: payload.to_json, headers: jsonapi_headers.merge(headers)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def jsonapi_put(url, payload, headers: {})
|
|
60
|
+
put url_for(url), params: payload.to_json, headers: jsonapi_headers.merge(headers)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def jsonapi_patch(url, payload, headers: {})
|
|
64
|
+
patch url_for(url), params: payload.to_json, headers: jsonapi_headers.merge(headers)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def jsonapi_delete(url, headers: {})
|
|
68
|
+
delete url_for(url), headers: jsonapi_headers.merge(headers)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def json_datetime(value)
|
|
72
|
+
Graphiti::Types[:datetime][:read][value].as_json
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def json_date(value)
|
|
76
|
+
Graphiti::Types[:date][:read][value].as_json
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# @api private
|
|
80
|
+
def node(from: nil)
|
|
81
|
+
from = json if from.nil?
|
|
82
|
+
data = from.has_key?("data") ? from["data"] : from
|
|
83
|
+
hash = {}
|
|
84
|
+
hash["id"] = data["id"]
|
|
85
|
+
hash["jsonapi_type"] = data["type"]
|
|
86
|
+
hash.merge!(data["attributes"]) if data.has_key?("attributes")
|
|
87
|
+
Node.new(hash, data["relationships"], self)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
private
|
|
91
|
+
|
|
92
|
+
# @api private
|
|
93
|
+
def _jsonapi_data
|
|
94
|
+
json["data"] || raise(Errors::NoData.new(json))
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# @api private
|
|
98
|
+
def _jsonapi_included
|
|
99
|
+
if json.has_key?("included")
|
|
100
|
+
json["included"]
|
|
101
|
+
else
|
|
102
|
+
raise Errors::NoSideloads.new(json)
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
module Graphiti
|
|
2
|
+
module SpecHelpers
|
|
3
|
+
class Node
|
|
4
|
+
attr_reader :attributes, :relationships
|
|
5
|
+
|
|
6
|
+
def initialize(attributes, relationships, context)
|
|
7
|
+
@attributes = attributes.with_indifferent_access
|
|
8
|
+
@relationships = relationships.with_indifferent_access if relationships
|
|
9
|
+
@context = context
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def id
|
|
13
|
+
Integer(rawid) # Only convert if using integer ids
|
|
14
|
+
rescue ArgumentError
|
|
15
|
+
rawid
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def rawid
|
|
19
|
+
@attributes["id"]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def jsonapi_type
|
|
23
|
+
@attributes["jsonapi_type"]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def has_key?(key)
|
|
27
|
+
@attributes.has_key?(key)
|
|
28
|
+
end
|
|
29
|
+
alias_method :key?, :has_key?
|
|
30
|
+
|
|
31
|
+
def [](key)
|
|
32
|
+
@attributes[key] || @attributes[key.to_s]
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def []=(key, val)
|
|
36
|
+
@attributes[key] = val
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
alias_method :to_hash, :attributes
|
|
40
|
+
|
|
41
|
+
def method_missing(id, *args, &blk)
|
|
42
|
+
if @attributes.has_key?(id)
|
|
43
|
+
@attributes[id]
|
|
44
|
+
else
|
|
45
|
+
raise Errors::NoAttribute.new(id)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def respond_to_missing?(id, include_private = false)
|
|
50
|
+
@attributes.has_key?(id) || super
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def link(relationship_name, name)
|
|
54
|
+
if @relationships.has_key?(relationship_name)
|
|
55
|
+
links = @relationships[relationship_name][:links]
|
|
56
|
+
raise Errors::LinksNotFound.new(relationship_name) unless links
|
|
57
|
+
links[name]
|
|
58
|
+
else
|
|
59
|
+
raise Errors::SideloadNotFound.new(relationship_name)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def sideload(relationship_name)
|
|
64
|
+
unless @relationships.has_key?(relationship_name)
|
|
65
|
+
raise Errors::SideloadNotFound.new(relationship_name)
|
|
66
|
+
end
|
|
67
|
+
rel = @relationships[relationship_name]
|
|
68
|
+
rel = rel[:data]
|
|
69
|
+
return if rel.nil?
|
|
70
|
+
if rel.is_a?(Hash)
|
|
71
|
+
include_for(rel[:type], rel[:id])
|
|
72
|
+
else
|
|
73
|
+
rel.map { |r| include_for(r[:type], r[:id]) }
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
alias_method :sideloads, :sideload
|
|
77
|
+
|
|
78
|
+
private
|
|
79
|
+
|
|
80
|
+
def include_for(type, id)
|
|
81
|
+
data = @context.json["included"].find do |i|
|
|
82
|
+
i["type"] == type && i["id"] == id
|
|
83
|
+
end
|
|
84
|
+
@context.node(from: data)
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
require "rspec/core"
|
|
2
|
+
require "graphiti/spec_helpers"
|
|
3
|
+
|
|
4
|
+
module Graphiti
|
|
5
|
+
module SpecHelpers
|
|
6
|
+
class ContextProxy < OpenStruct
|
|
7
|
+
def initialize(proxied, *args)
|
|
8
|
+
@__proxied = proxied
|
|
9
|
+
super(*args)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# variables defined in the rspec context should remain lazy
|
|
13
|
+
def current_user
|
|
14
|
+
super || __proxied_current_user
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def params
|
|
18
|
+
super || __proxied_params
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def __proxied_current_user
|
|
24
|
+
@__proxied.current_user if @__proxied.respond_to?(:current_user)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def __proxied_params
|
|
28
|
+
@__proxied.params if @__proxied.respond_to?(:params)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Registered under both names. The graphiti-prefixed name is canonical. The bare
|
|
35
|
+
# one is kept for suites that include it explicitly, and carries no `type:`
|
|
36
|
+
# metadata so a `type: :resource` group does not pick the context up twice.
|
|
37
|
+
resource_testing = proc do
|
|
38
|
+
let(:resource) { described_class }
|
|
39
|
+
let(:params) { {} }
|
|
40
|
+
|
|
41
|
+
around do |e|
|
|
42
|
+
original = Graphiti::Resource.validate_endpoints
|
|
43
|
+
Graphiti::Resource.validate_endpoints = false
|
|
44
|
+
|
|
45
|
+
Graphiti.with_context graphiti_context do
|
|
46
|
+
e.run
|
|
47
|
+
end
|
|
48
|
+
ensure
|
|
49
|
+
Graphiti::Resource.validate_endpoints = original
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def graphiti_context
|
|
53
|
+
@graphiti_context ||= Graphiti::SpecHelpers::ContextProxy.new(self)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# If you need to set context:
|
|
57
|
+
#
|
|
58
|
+
# Graphiti.with_context my_context, {} do
|
|
59
|
+
# render
|
|
60
|
+
# end
|
|
61
|
+
def render(runtime_options = {})
|
|
62
|
+
json = proxy.to_jsonapi(runtime_options)
|
|
63
|
+
response.body = json
|
|
64
|
+
json
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def proxy
|
|
68
|
+
@proxy ||= begin
|
|
69
|
+
args = [params]
|
|
70
|
+
args << base_scope if defined?(base_scope)
|
|
71
|
+
resource.all(*args)
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def records
|
|
76
|
+
proxy.data
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def response
|
|
80
|
+
@response ||= OpenStruct.new
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
remote_api = proc do
|
|
85
|
+
# Fake request headers
|
|
86
|
+
around do |e|
|
|
87
|
+
ctx = OpenStruct.new \
|
|
88
|
+
request: OpenStruct.new(headers: OpenStruct.new)
|
|
89
|
+
Graphiti.with_context(ctx) { e.run }
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def mock_api(url, json, call_count = 1)
|
|
93
|
+
api_response = double(body: json.to_json)
|
|
94
|
+
expect(Faraday).to receive(:get)
|
|
95
|
+
.with(url, anything, anything)
|
|
96
|
+
.exactly(call_count).times
|
|
97
|
+
.and_return(api_response)
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Was a top-level constant, and reopening it to add context methods was a way
|
|
102
|
+
# suites customised graphiti_context. Remove in 3.0.
|
|
103
|
+
GraphitiContextProxy = ActiveSupport::Deprecation::DeprecatedConstantProxy.new(
|
|
104
|
+
"GraphitiContextProxy",
|
|
105
|
+
"Graphiti::SpecHelpers::ContextProxy",
|
|
106
|
+
Graphiti::DEPRECATOR
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
::RSpec.shared_context("graphiti resource testing", type: :resource, &resource_testing)
|
|
110
|
+
::RSpec.shared_context("resource testing", &resource_testing)
|
|
111
|
+
|
|
112
|
+
::RSpec.shared_context("graphiti remote api", &remote_api)
|
|
113
|
+
::RSpec.shared_context("remote api", &remote_api)
|
|
114
|
+
|
|
115
|
+
module Graphiti
|
|
116
|
+
module SpecHelpers
|
|
117
|
+
module RSpec
|
|
118
|
+
def self.included(klass)
|
|
119
|
+
klass.send(:include, Graphiti::SpecHelpers)
|
|
120
|
+
|
|
121
|
+
::RSpec.configure do |rspec|
|
|
122
|
+
rspec.include_context "graphiti resource testing", type: :resource
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def self.schema!(resources = nil)
|
|
127
|
+
::RSpec.describe "Graphiti Schema" do
|
|
128
|
+
it "generates a backwards-compatible schema" do
|
|
129
|
+
message = <<~MSG
|
|
130
|
+
Found backwards-incompatibilities in schema! Run with FORCE_SCHEMA=true to ignore.
|
|
131
|
+
|
|
132
|
+
Incompatibilities:
|
|
133
|
+
|
|
134
|
+
MSG
|
|
135
|
+
|
|
136
|
+
errors = Graphiti::Schema.generate!(resources)
|
|
137
|
+
errors.each do |e|
|
|
138
|
+
message << "#{e}\n"
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
expect(errors.empty?).to eq(true), message
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Merged in from the standalone graphiti_spec_helpers gem, retired as of
|
|
2
|
+
# Graphiti 2.0. The GraphitiSpecHelpers namespace and the
|
|
3
|
+
# "graphiti_spec_helpers/rspec" require path are kept verbatim so existing spec
|
|
4
|
+
# suites need no changes beyond dropping the gem from their Gemfile.
|
|
5
|
+
require "json"
|
|
6
|
+
require "active_support/core_ext/string"
|
|
7
|
+
require "active_support/core_ext/hash"
|
|
8
|
+
require "graphiti"
|
|
9
|
+
|
|
10
|
+
require "graphiti/spec_helpers/helpers"
|
|
11
|
+
require "graphiti/spec_helpers/node"
|
|
12
|
+
require "graphiti/spec_helpers/errors_proxy"
|
|
13
|
+
require "graphiti/spec_helpers/errors"
|
|
14
|
+
|
|
15
|
+
module Graphiti
|
|
16
|
+
module SpecHelpers
|
|
17
|
+
def self.included(klass)
|
|
18
|
+
klass.send(:include, Helpers)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
class TestRunner < ::Graphiti::Runner
|
|
22
|
+
def current_user
|
|
23
|
+
nil
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
module Sugar
|
|
28
|
+
def d
|
|
29
|
+
jsonapi_data
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def included(type = nil)
|
|
33
|
+
jsonapi_included(type)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def errors
|
|
37
|
+
jsonapi_errors
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def dt(*args)
|
|
41
|
+
json_datetime(*args)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def datetime(*args)
|
|
45
|
+
json_datetime(*args)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def date(*args)
|
|
49
|
+
json_date(*args)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -7,9 +7,9 @@ module Graphiti
|
|
|
7
7
|
#
|
|
8
8
|
# GET /posts?include=comments.author
|
|
9
9
|
#
|
|
10
|
-
# But
|
|
10
|
+
# But the controller had this code:
|
|
11
11
|
#
|
|
12
|
-
# sideload_allowlist
|
|
12
|
+
# self.sideload_allowlist = {index: [:comments]}
|
|
13
13
|
#
|
|
14
14
|
# We should drop the 'author' sideload from the request.
|
|
15
15
|
#
|
|
@@ -19,7 +19,14 @@ module Graphiti
|
|
|
19
19
|
private
|
|
20
20
|
|
|
21
21
|
def apply?(sideload)
|
|
22
|
-
@serializer.relationship_blocks[sideload.name].nil?
|
|
22
|
+
return true if @serializer.relationship_blocks[sideload.name].nil?
|
|
23
|
+
|
|
24
|
+
# A subclass inherits its parent's relationship blocks, each closed
|
|
25
|
+
# over the parent's sideload. Redeclaring the relationship has to
|
|
26
|
+
# replace that block or the override never reaches the payload.
|
|
27
|
+
# Anything not generated here was written by hand, so leave it.
|
|
28
|
+
applied = @serializer.relationship_sideloads[sideload.name]
|
|
29
|
+
!applied.nil? && !applied.equal?(sideload)
|
|
23
30
|
end
|
|
24
31
|
end
|
|
25
32
|
|
|
@@ -32,6 +39,10 @@ module Graphiti
|
|
|
32
39
|
|
|
33
40
|
def apply
|
|
34
41
|
sideload = @sideload
|
|
42
|
+
# Reassign rather than mutate: ancestors share the hash by reference
|
|
43
|
+
# until a subclass writes to it.
|
|
44
|
+
@serializer.relationship_sideloads =
|
|
45
|
+
@serializer.relationship_sideloads.merge(@sideload.name => @sideload)
|
|
35
46
|
@serializer.relationship(@sideload.name, if: -> { sideload.readable? }, &block)
|
|
36
47
|
end
|
|
37
48
|
|
|
@@ -53,9 +64,25 @@ module Graphiti
|
|
|
53
64
|
proc do
|
|
54
65
|
data { instance_eval(&data_proc_ref) }
|
|
55
66
|
|
|
56
|
-
#
|
|
57
|
-
#
|
|
58
|
-
|
|
67
|
+
# An included relationship is already loaded, and a customized
|
|
68
|
+
# sideload can resolve it to something the foreign key alone would
|
|
69
|
+
# not predict, so the loaded records win. Only the un-included case
|
|
70
|
+
# is worth short-circuiting.
|
|
71
|
+
if sideload_ref.linkage_from_foreign_key? &&
|
|
72
|
+
!self_ref.send(:included_anywhere?, @proxy.query.include_hash, sideload_ref.name)
|
|
73
|
+
linkage always: sideload_ref.always_include_resource_ids? do
|
|
74
|
+
foreign_key = @object.public_send(sideload_ref.foreign_key)
|
|
75
|
+
|
|
76
|
+
unless foreign_key.nil?
|
|
77
|
+
{
|
|
78
|
+
type: sideload_ref.resource.type,
|
|
79
|
+
id: foreign_key.to_s
|
|
80
|
+
}
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
else
|
|
84
|
+
linkage always: sideload_ref.always_include_resource_ids?
|
|
85
|
+
end
|
|
59
86
|
|
|
60
87
|
if link_ref
|
|
61
88
|
if @proxy.query.links?
|
|
@@ -69,6 +96,15 @@ module Graphiti
|
|
|
69
96
|
end
|
|
70
97
|
end
|
|
71
98
|
|
|
99
|
+
# A relationship nested under another one is still loaded and can still
|
|
100
|
+
# be narrowed by a deep filter, so the foreign key is not a safe
|
|
101
|
+
# stand-in for what the request actually returns.
|
|
102
|
+
def included_anywhere?(include_hash, name)
|
|
103
|
+
include_hash.any? do |key, nested|
|
|
104
|
+
key == name || included_anywhere?(nested, name)
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
72
108
|
def data_proc
|
|
73
109
|
sideload_ref = @sideload
|
|
74
110
|
->(_) {
|
|
@@ -85,7 +121,7 @@ module Graphiti
|
|
|
85
121
|
end
|
|
86
122
|
|
|
87
123
|
def eagerly_validate_links?
|
|
88
|
-
# TODO: Maybe handle this in
|
|
124
|
+
# TODO: Maybe handle this in the Rails integration
|
|
89
125
|
if defined?(::Rails) && (app = ::Rails.application)
|
|
90
126
|
app.config.eager_load
|
|
91
127
|
else
|
data/lib/graphiti/version.rb
CHANGED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Deprecated entry point. The graphiti-rails gem was absorbed into graphiti in
|
|
2
|
+
# 2.0, and its integration loads automatically whenever Rails is defined, so
|
|
3
|
+
# this require is no longer needed. It is kept so an explicit
|
|
4
|
+
# `require "graphiti-rails"` left over from 1.x does not raise. Remove in 3.0.
|
|
5
|
+
require "graphiti"
|
|
6
|
+
require "graphiti/rails"
|
|
7
|
+
|
|
8
|
+
Graphiti::DEPRECATOR.warn(
|
|
9
|
+
'require "graphiti-rails" is no longer needed. graphiti-rails is part of graphiti as of 2.0, ' \
|
|
10
|
+
"and the Rails integration is loaded for you when Rails is present."
|
|
11
|
+
)
|
data/lib/graphiti.rb
CHANGED
|
@@ -3,6 +3,12 @@ require "forwardable"
|
|
|
3
3
|
require "uri"
|
|
4
4
|
require "ostruct" unless defined?(::OpenStruct)
|
|
5
5
|
|
|
6
|
+
# The umbrella require, not just the core_ext files below: Graphiti.broadcast
|
|
7
|
+
# calls ActiveSupport::Notifications.instrument, which reaches for
|
|
8
|
+
# ActiveSupport::IsolatedExecutionState. That constant is autoloaded here and
|
|
9
|
+
# nowhere else, so without this a non-Rails app raises NameError on the first
|
|
10
|
+
# render unless something else happened to load ActiveSupport for us.
|
|
11
|
+
require "active_support"
|
|
6
12
|
require "active_support/version"
|
|
7
13
|
require "active_support/deprecation"
|
|
8
14
|
require "active_support/deprecator" if ::ActiveSupport.version >= Gem::Version.new("7.1")
|
|
@@ -14,12 +20,34 @@ require "active_support/concern"
|
|
|
14
20
|
require "active_support/time"
|
|
15
21
|
|
|
16
22
|
require "dry-types"
|
|
17
|
-
require "graphiti_errors"
|
|
18
23
|
|
|
19
24
|
require "jsonapi/serializable"
|
|
20
25
|
|
|
26
|
+
# These gems are merged into graphiti as of 2.0, but their 1.x/0.x releases
|
|
27
|
+
# still resolve against graphiti 2.x. Leaving one installed is never harmless:
|
|
28
|
+
# graphiti_spec_helpers and graphiti-rails ship files that collide with ours
|
|
29
|
+
# (lib/graphiti_spec_helpers.rb, lib/graphiti/rails.rb), so which copy a require
|
|
30
|
+
# picks up comes down to load path order, and graphiti_errors installs a second,
|
|
31
|
+
# competing exception handler on any controller that includes it. Fail loudly
|
|
32
|
+
# rather than let either happen quietly. Checked here because graphiti is loaded
|
|
33
|
+
# either way, whichever copy wins.
|
|
34
|
+
{
|
|
35
|
+
"graphiti_spec_helpers" => 'The "graphiti_spec_helpers/rspec" require and the GraphitiSpecHelpers namespace are unchanged.',
|
|
36
|
+
"graphiti-rails" => 'Graphiti::Rails and its config.graphiti options are unchanged. Drop the "graphiti-rails" require if you have one.',
|
|
37
|
+
"graphiti_errors" => "Exception handling now goes through rescue_registry. Remove `include GraphitiErrors` from your controllers — Graphiti registers its own handlers, and you can add yours with `register_exception`."
|
|
38
|
+
}.each do |gem_name, guidance|
|
|
39
|
+
next unless Gem.loaded_specs.key?(gem_name)
|
|
40
|
+
|
|
41
|
+
raise <<~MSG
|
|
42
|
+
#{gem_name} is merged into graphiti as of 2.0 and is no longer published
|
|
43
|
+
separately. Remove it from your Gemfile.
|
|
44
|
+
|
|
45
|
+
#{guidance}
|
|
46
|
+
MSG
|
|
47
|
+
end
|
|
48
|
+
|
|
21
49
|
module Graphiti
|
|
22
|
-
DEPRECATOR = ActiveSupport::Deprecation.new("
|
|
50
|
+
DEPRECATOR = ActiveSupport::Deprecation.new("3.0", "Graphiti")
|
|
23
51
|
|
|
24
52
|
# @api private
|
|
25
53
|
def self.context
|
|
@@ -203,6 +231,10 @@ require "graphiti/query"
|
|
|
203
231
|
require "graphiti/debugger"
|
|
204
232
|
require "graphiti/util/cache_debug"
|
|
205
233
|
require "graphiti/util/uri_decoder"
|
|
234
|
+
require "graphiti/error_serializers/validation"
|
|
235
|
+
require "graphiti/error_serializers/invalid_request"
|
|
236
|
+
require "graphiti/error_serializers/conflict_request"
|
|
237
|
+
require "graphiti/error_serializers/deprecated_constants"
|
|
206
238
|
|
|
207
239
|
if defined?(ActiveRecord)
|
|
208
240
|
require "graphiti/adapters/active_record"
|
|
@@ -210,14 +242,6 @@ end
|
|
|
210
242
|
|
|
211
243
|
if defined?(Rails)
|
|
212
244
|
require "graphiti/rails"
|
|
213
|
-
require "graphiti/responders"
|
|
214
|
-
|
|
215
|
-
# graphiti-rails has own Railtie
|
|
216
|
-
begin
|
|
217
|
-
require "graphiti-rails"
|
|
218
|
-
rescue LoadError
|
|
219
|
-
require "graphiti/railtie"
|
|
220
|
-
end
|
|
221
245
|
end
|
|
222
246
|
|
|
223
247
|
require "graphiti/runner"
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Deprecated entry point. graphiti_errors was absorbed into graphiti in 2.0 and
|
|
2
|
+
# graphiti required it for you in 1.x, so an explicit require left in an
|
|
3
|
+
# initializer or spec_helper would otherwise raise LoadError. Only the
|
|
4
|
+
# serializers survived. See graphiti/error_serializers/deprecated_constants.rb.
|
|
5
|
+
# Remove in 3.0.
|
|
6
|
+
require "graphiti"
|
|
7
|
+
|
|
8
|
+
Graphiti::DEPRECATOR.warn(
|
|
9
|
+
'require "graphiti_errors" is no longer needed. graphiti_errors is part of graphiti as of 2.0, ' \
|
|
10
|
+
"and its exception handling is replaced by rescue_registry."
|
|
11
|
+
)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Deprecated entry point. The spec helpers moved under Graphiti::SpecHelpers
|
|
2
|
+
# when the graphiti_spec_helpers gem was absorbed into graphiti in 2.0. This
|
|
3
|
+
# keeps `require "graphiti_spec_helpers"` and the old constant working.
|
|
4
|
+
# Remove in 3.0.
|
|
5
|
+
require "graphiti/spec_helpers"
|
|
6
|
+
|
|
7
|
+
GraphitiSpecHelpers = ActiveSupport::Deprecation::DeprecatedConstantProxy.new(
|
|
8
|
+
"GraphitiSpecHelpers",
|
|
9
|
+
"Graphiti::SpecHelpers",
|
|
10
|
+
Graphiti::DEPRECATOR
|
|
11
|
+
)
|