graphiti 2.0.0.beta.7 → 2.0.0.beta.8
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/.git-blame-ignore-revs +2 -0
- data/.github/workflows/ci.yml +55 -3
- data/.github/workflows/docs.yml +1 -1
- data/.github/workflows/notify-example-app.yml +18 -0
- data/.gitignore +2 -0
- data/.standard.yml +6 -0
- data/CHANGELOG.md +45 -0
- data/CONTRIBUTING.md +3 -1
- data/README.md +13 -206
- data/Rakefile +6 -3
- data/UPGRADING.md +1 -1
- data/graphiti.gemspec +8 -4
- data/lib/generators/graphiti/generator_mixin.rb +1 -1
- data/lib/generators/graphiti/install_generator.rb +1 -1
- data/lib/generators/graphiti/resource_generator.rb +6 -3
- data/lib/generators/graphiti/templates/application_resource.rb.erb +19 -0
- data/lib/generators/graphiti/templates/controller.rb.erb +26 -8
- data/lib/graphiti/audit/report.rb +6 -6
- data/lib/graphiti/audit.rb +3 -4
- data/lib/graphiti/delegates/pagination.rb +2 -2
- data/lib/graphiti/deserializer.rb +3 -3
- data/lib/graphiti/errors.rb +6 -6
- data/lib/graphiti/extensions/temp_id.rb +1 -1
- data/lib/graphiti/query.rb +3 -3
- data/lib/graphiti/rails/context.rb +2 -1
- data/lib/graphiti/rails/controller.rb +3 -0
- data/lib/graphiti/rails/debugging.rb +1 -1
- data/lib/graphiti/rails/responders.rb +2 -1
- data/lib/graphiti/resource/configuration.rb +1 -0
- data/lib/graphiti/resource/dsl.rb +2 -2
- data/lib/graphiti/resource/links.rb +1 -1
- data/lib/graphiti/resource/persistence.rb +1 -1
- data/lib/graphiti/resource/polymorphism.rb +1 -1
- data/lib/graphiti/resource.rb +2 -2
- data/lib/graphiti/resource_proxy.rb +0 -1
- data/lib/graphiti/scoping/filter.rb +5 -3
- data/lib/graphiti/scoping/paginate.rb +1 -1
- data/lib/graphiti/scoping/sort.rb +1 -1
- data/lib/graphiti/sideload/has_many.rb +1 -1
- data/lib/graphiti/spec_helpers/errors_proxy.rb +1 -1
- data/lib/graphiti/spec_helpers/matchers.rb +1 -1
- data/lib/graphiti/types.rb +5 -1
- data/lib/graphiti/util/cache_debug.rb +3 -3
- data/lib/graphiti/util/hash.rb +1 -1
- data/lib/graphiti/util/persistence.rb +6 -6
- data/lib/graphiti/util/serializer_relationships.rb +1 -1
- data/lib/graphiti/version.rb +1 -1
- data/lib/tasks/graphiti.rake +1 -1
- metadata +31 -197
- data/docs/concepts/backends-and-models.md +0 -122
- data/docs/concepts/endpoints.md +0 -183
- data/docs/concepts/links.md +0 -212
- data/docs/concepts/overview.md +0 -80
- data/docs/concepts/persisting.md +0 -376
- data/docs/concepts/relationships.md +0 -627
- data/docs/concepts/resources.md +0 -677
- data/docs/getting-started/first-api.md +0 -289
- data/docs/getting-started/installation.md +0 -185
- data/docs/intro.md +0 -307
- data/docs/js/authentication.md +0 -63
- data/docs/js/ddau.md +0 -20
- data/docs/js/extra-params.md +0 -41
- data/docs/js/index.md +0 -112
- data/docs/js/installation.md +0 -120
- data/docs/js/middleware.md +0 -72
- data/docs/js/models.md +0 -202
- data/docs/js/reads.md +0 -494
- data/docs/js/state-syncing.md +0 -100
- data/docs/js/writes.md +0 -373
- data/docs/reference/vandal.md +0 -63
- data/docs/reference/why.md +0 -13
- data/docs/topics/authorization.md +0 -155
- data/docs/topics/caching.md +0 -55
- data/docs/topics/customizing-sideloads.md +0 -156
- data/docs/topics/debugging.md +0 -242
- data/docs/topics/error-handling.md +0 -210
- data/docs/topics/etags.md +0 -46
- data/docs/topics/hopping-relationships.md +0 -149
- data/docs/topics/json-attributes.md +0 -77
- data/docs/topics/openstruct-models.md +0 -50
- data/docs/topics/remote-resources.md +0 -291
- data/docs/topics/testing.md +0 -916
- data/docs/topics/without-activerecord.md +0 -324
- data/docs/tutorial/index.md +0 -58
- data/docs/tutorial/step_0.md +0 -107
- data/docs/tutorial/step_1.md +0 -199
- data/docs/tutorial/step_2.md +0 -312
- data/docs/tutorial/step_3.md +0 -142
- data/docs/tutorial/step_4.md +0 -135
- data/docs/tutorial/step_5.md +0 -69
- data/docs/tutorial/step_6.md +0 -82
- data/docs/tutorial/step_7.md +0 -205
- data/docs/tutorial/step_8.md +0 -128
- data/docs/tutorial/step_9.md +0 -171
- data/docs/upgrading.md +0 -267
- data/website/.gitignore +0 -20
- data/website/README.md +0 -43
- data/website/docusaurus.config.js +0 -197
- data/website/package-lock.json +0 -19474
- data/website/package.json +0 -46
- data/website/sidebars.js +0 -82
- data/website/src/css/custom.css +0 -85
- data/website/src/pages/markdown-page.mdx +0 -7
- data/website/static/.nojekyll +0 -0
- data/website/static/1.13/2019/03/31/graphiti-1-0.html +0 -205
- data/website/static/1.13/2019/05/08/graphiti-1-1.html +0 -212
- data/website/static/1.13/2019/05/20/graphiti-1-2.html +0 -214
- data/website/static/1.13/2019/10/14/tutorial.html +0 -198
- data/website/static/1.13/CNAME +0 -1
- data/website/static/1.13/README.md +0 -16
- data/website/static/1.13/assets/css/syntax.css +0 -60
- 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 +0 -9
- 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 +0 -1
- data/website/static/1.13/assets/favicons/site.webmanifest +0 -19
- 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/fancy-cushion.png +0 -0
- data/website/static/1.13/assets/img/gh.png +0 -0
- data/website/static/1.13/assets/img/home-bg.jpg +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/sunrise.png +0 -0
- data/website/static/1.13/assets/img/why.png +0 -0
- data/website/static/1.13/assets/js/highlight.pack.js +0 -2
- data/website/static/1.13/assets/main.css +0 -15518
- data/website/static/1.13/assets/main.css.map +0 -1
- data/website/static/1.13/bin/bundle +0 -109
- data/website/static/1.13/bin/jekyll +0 -27
- data/website/static/1.13/bin/kramdown +0 -27
- data/website/static/1.13/bin/listen +0 -27
- data/website/static/1.13/bin/rake +0 -27
- data/website/static/1.13/bin/rougify +0 -27
- data/website/static/1.13/bin/safe_yaml +0 -27
- data/website/static/1.13/bin/sass +0 -27
- data/website/static/1.13/bin/sass-convert +0 -27
- data/website/static/1.13/bin/scss +0 -27
- data/website/static/1.13/blog.html +0 -259
- data/website/static/1.13/cheatsheet.html +0 -316
- 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 +0 -325
- data/website/static/1.13/cookbooks/etags.md +0 -0
- data/website/static/1.13/cookbooks/hopping-relationships.html +0 -324
- 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 +0 -510
- data/website/static/1.13/features.html +0 -249
- data/website/static/1.13/feed.xml +0 -106
- data/website/static/1.13/guides/concepts/backends-and-models.html +0 -467
- data/website/static/1.13/guides/concepts/debugging.html +0 -440
- data/website/static/1.13/guides/concepts/endpoints.html +0 -432
- data/website/static/1.13/guides/concepts/error-handling.html +0 -396
- data/website/static/1.13/guides/concepts/links.html +0 -501
- data/website/static/1.13/guides/concepts/remote-resources.html +0 -536
- data/website/static/1.13/guides/concepts/resources.html +0 -2176
- data/website/static/1.13/guides/concepts/testing.html +0 -1469
- data/website/static/1.13/guides/getting-started/installation.html +0 -420
- data/website/static/1.13/guides/graphiti-rails-migration.html +0 -242
- data/website/static/1.13/guides/index.html +0 -269
- data/website/static/1.13/guides/overview.html +0 -325
- data/website/static/1.13/guides/upgrading-2-0.html +0 -193
- data/website/static/1.13/guides/upgrading.html +0 -314
- data/website/static/1.13/guides/vandal.html +0 -282
- data/website/static/1.13/guides/why.html +0 -1121
- data/website/static/1.13/index.html +0 -72
- data/website/static/1.13/js/authentication.html +0 -295
- data/website/static/1.13/js/ddau.html +0 -238
- data/website/static/1.13/js/extra-params.html +0 -270
- data/website/static/1.13/js/index.html +0 -321
- data/website/static/1.13/js/installation.html +0 -637
- data/website/static/1.13/js/introduction.html +0 -257
- data/website/static/1.13/js/middleware.html +0 -318
- data/website/static/1.13/js/reads/fieldsets.html +0 -271
- data/website/static/1.13/js/reads/filtering.html +0 -289
- data/website/static/1.13/js/reads/includes.html +0 -260
- data/website/static/1.13/js/reads/index.html +0 -497
- data/website/static/1.13/js/reads/nested-queries.html +0 -353
- data/website/static/1.13/js/reads/pagination.html +0 -260
- data/website/static/1.13/js/reads/sorting.html +0 -265
- data/website/static/1.13/js/reads/statistics.html +0 -289
- data/website/static/1.13/js/state-syncing.html +0 -340
- data/website/static/1.13/js/writes/deferred.html +0 -296
- data/website/static/1.13/js/writes/dirty-tracking.html +0 -399
- data/website/static/1.13/js/writes/index.html +0 -391
- data/website/static/1.13/js/writes/nested.html +0 -330
- data/website/static/1.13/js/writes/validations.html +0 -272
- data/website/static/1.13/quickstart.html +0 -660
- data/website/static/1.13/template +0 -161
- data/website/static/1.13/tutorial/index.html +0 -250
- data/website/static/1.13/tutorial/step_0.html +0 -292
- data/website/static/1.13/tutorial/step_1.html +0 -517
- data/website/static/1.13/tutorial/step_2.html +0 -481
- data/website/static/1.13/tutorial/step_3.html +0 -323
- data/website/static/1.13/tutorial/step_4.html +0 -318
- data/website/static/1.13/tutorial/step_5.html +0 -265
- data/website/static/1.13/tutorial/step_6.html +0 -276
- data/website/static/1.13/tutorial/step_7.html +0 -390
- data/website/static/1.13/tutorial/step_8.html +0 -316
- data/website/static/1.13/tutorial/step_9.html +0 -365
- data/website/static/CNAME +0 -1
- 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 +0 -1
- data/website/static/img/undraw_docusaurus_mountain.svg +0 -171
- data/website/static/img/undraw_docusaurus_react.svg +0 -170
- data/website/static/img/undraw_docusaurus_tree.svg +0 -40
|
@@ -60,7 +60,7 @@ module Graphiti
|
|
|
60
60
|
|
|
61
61
|
section_heading(label, color, ISSUE_HEADINGS.fetch(check, check.to_s.tr("_", " "))) +
|
|
62
62
|
lines_grouped_by_resource(group.map { |row, finding| [row, finding.message] }) +
|
|
63
|
-
(fixes.size == 1 ? [fix_line(fixes.first), ""] : [])
|
|
63
|
+
((fixes.size == 1) ? [fix_line(fixes.first), ""] : [])
|
|
64
64
|
end
|
|
65
65
|
|
|
66
66
|
def loading_section
|
|
@@ -71,7 +71,7 @@ module Graphiti
|
|
|
71
71
|
lines_grouped_by_resource(rows.map { |row| [row, nil] }) +
|
|
72
72
|
[" #{paint("That is a query per record rendered.", :dim)}",
|
|
73
73
|
fix_line("preload the association in base_scope, or drop `resource_ids`"),
|
|
74
|
-
" #{paint("See
|
|
74
|
+
" #{paint("See graphiti.dev/concepts/relationships#customizing-relationships", :dim)}",
|
|
75
75
|
""]
|
|
76
76
|
end
|
|
77
77
|
|
|
@@ -83,7 +83,7 @@ module Graphiti
|
|
|
83
83
|
rows = @rows.select(&:would_start_loading?)
|
|
84
84
|
return [] if rows.empty?
|
|
85
85
|
|
|
86
|
-
verb = rows.size == 1 ? "renders" : "render"
|
|
86
|
+
verb = (rows.size == 1) ? "renders" : "render"
|
|
87
87
|
|
|
88
88
|
section_heading("FYI", :blue, "#{count(rows.size, "belongs_to relationship")} #{verb} no resource ids") +
|
|
89
89
|
lines_grouped_by_resource(rows.map { |row| [row, nil] }) +
|
|
@@ -95,7 +95,7 @@ module Graphiti
|
|
|
95
95
|
["",
|
|
96
96
|
" #{paint("Either would load the association on every render. That potential performance cost is why ids are opt-in.", :dim)}",
|
|
97
97
|
" #{paint("Preloading the association in base_scope keeps that load cheap.", :dim)}",
|
|
98
|
-
" #{paint("See
|
|
98
|
+
" #{paint("See graphiti.dev/concepts/relationships#belongs-to-resource-ids", :dim)}",
|
|
99
99
|
""]
|
|
100
100
|
end
|
|
101
101
|
|
|
@@ -189,7 +189,7 @@ module Graphiti
|
|
|
189
189
|
|
|
190
190
|
rows.map do |cells|
|
|
191
191
|
line = cells.each_with_index.map { |cell, index|
|
|
192
|
-
index == cells.size - 1 ? cell.painted : cell.pad_to(widths[index])
|
|
192
|
+
(index == cells.size - 1) ? cell.painted : cell.pad_to(widths[index])
|
|
193
193
|
}.join(" ")
|
|
194
194
|
indent + line
|
|
195
195
|
end
|
|
@@ -203,7 +203,7 @@ module Graphiti
|
|
|
203
203
|
counts = [
|
|
204
204
|
count(@rows.group_by(&:resource).size, "resource"),
|
|
205
205
|
count(@rows.size, "relationship"),
|
|
206
|
-
paint(count(errors, "error"), errors > 0 ? :red : nil)
|
|
206
|
+
paint(count(errors, "error"), (errors > 0) ? :red : nil)
|
|
207
207
|
]
|
|
208
208
|
counts << paint("#{loading} loading ids without preloading", :yellow) if loading > 0
|
|
209
209
|
counts << "#{no_ids} without resource ids" if no_ids > 0
|
data/lib/graphiti/audit.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
module Graphiti
|
|
2
2
|
# Resources register themselves as they load, so eager load before auditing.
|
|
3
3
|
class Audit
|
|
4
|
-
Finding = Struct.new(:severity, :check, :message, :remedy
|
|
4
|
+
Finding = Struct.new(:severity, :check, :message, :remedy) do
|
|
5
5
|
def error?
|
|
6
6
|
severity == :error
|
|
7
7
|
end
|
|
@@ -18,8 +18,7 @@ module Graphiti
|
|
|
18
18
|
:resource_ids_blocker,
|
|
19
19
|
:preloaded,
|
|
20
20
|
:options,
|
|
21
|
-
:findings
|
|
22
|
-
keyword_init: true
|
|
21
|
+
:findings
|
|
23
22
|
) do
|
|
24
23
|
def would_start_loading?
|
|
25
24
|
return false if resource_ids_default == :never
|
|
@@ -75,7 +74,7 @@ module Graphiti
|
|
|
75
74
|
resource_ids_source_if_always: resource_ids_source_if_always(resource_class, sideload),
|
|
76
75
|
resource_ids_default: resource_class.belongs_to_resource_ids_by_default,
|
|
77
76
|
resource_ids_blocker: sideload.resource_ids_blocker,
|
|
78
|
-
preloaded: source == :load ? association_preloaded?(resource_class, sideload) : nil,
|
|
77
|
+
preloaded: (source == :load) ? association_preloaded?(resource_class, sideload) : nil,
|
|
79
78
|
options: declaration_options(sideload),
|
|
80
79
|
findings: [
|
|
81
80
|
missing_association_method(sideload, model),
|
|
@@ -32,7 +32,7 @@ module Graphiti
|
|
|
32
32
|
private
|
|
33
33
|
|
|
34
34
|
def pagination_params
|
|
35
|
-
@pagination_params ||= @proxy.query.params.
|
|
35
|
+
@pagination_params ||= @proxy.query.params.except(:action, :controller, :format)
|
|
36
36
|
end
|
|
37
37
|
|
|
38
38
|
def pagination_link(page)
|
|
@@ -109,7 +109,7 @@ module Graphiti
|
|
|
109
109
|
end
|
|
110
110
|
|
|
111
111
|
def page_param
|
|
112
|
-
@page_param ||=
|
|
112
|
+
@page_param ||= @proxy.query.hash[:page] || {}
|
|
113
113
|
end
|
|
114
114
|
end
|
|
115
115
|
end
|
|
@@ -85,7 +85,7 @@ class Graphiti::Deserializer
|
|
|
85
85
|
def meta(action: :update)
|
|
86
86
|
{
|
|
87
87
|
type: data[:type],
|
|
88
|
-
temp_id: data[:
|
|
88
|
+
temp_id: data[:"temp-id"],
|
|
89
89
|
method: action,
|
|
90
90
|
payload_path: ["data"]
|
|
91
91
|
}
|
|
@@ -162,12 +162,12 @@ class Graphiti::Deserializer
|
|
|
162
162
|
end
|
|
163
163
|
|
|
164
164
|
def process_relationship_datum(datum)
|
|
165
|
-
temp_id = datum[:
|
|
165
|
+
temp_id = datum[:"temp-id"]
|
|
166
166
|
included_object = included.find { |i|
|
|
167
167
|
next unless i[:type] == datum[:type]
|
|
168
168
|
|
|
169
169
|
(i[:id] && i[:id] == datum[:id]) ||
|
|
170
|
-
(i[:
|
|
170
|
+
(i[:"temp-id"] && i[:"temp-id"] == temp_id)
|
|
171
171
|
}
|
|
172
172
|
included_idx = included.index(included_object)
|
|
173
173
|
|
data/lib/graphiti/errors.rb
CHANGED
|
@@ -270,7 +270,7 @@ module Graphiti
|
|
|
270
270
|
#{@resource_class.name}: error occurred while sideloading "#{@sideload_name}"!
|
|
271
271
|
|
|
272
272
|
The error was raised while attempting to build query parameters for the associated Resource.
|
|
273
|
-
Read more about sideload scoping here:
|
|
273
|
+
Read more about sideload scoping here: graphiti.dev/concepts/relationships#customizing-scope
|
|
274
274
|
|
|
275
275
|
A good way to debug is to put a debugger within the 'params' block.
|
|
276
276
|
|
|
@@ -294,7 +294,7 @@ module Graphiti
|
|
|
294
294
|
|
|
295
295
|
The error was raised while attempting to build the scope for the associated Resource.
|
|
296
296
|
|
|
297
|
-
Read more about sideload scoping here:
|
|
297
|
+
Read more about sideload scoping here: graphiti.dev/concepts/relationships#customizing-scope
|
|
298
298
|
|
|
299
299
|
Here's the original, underlying error:
|
|
300
300
|
|
|
@@ -315,7 +315,7 @@ module Graphiti
|
|
|
315
315
|
#{@resource_class.name}: error occurred while sideloading "#{@sideload_name}"!
|
|
316
316
|
|
|
317
317
|
The error was raised while attempting to assign relevant model instances. Read
|
|
318
|
-
more about sideload assignment here:
|
|
318
|
+
more about sideload assignment here: graphiti.dev/concepts/relationships#customizing-assignment
|
|
319
319
|
|
|
320
320
|
A good way to debug is to put a debugger within the 'assign' block.
|
|
321
321
|
|
|
@@ -449,7 +449,7 @@ module Graphiti
|
|
|
449
449
|
|
|
450
450
|
self.validate_endpoints = false
|
|
451
451
|
|
|
452
|
-
See https://
|
|
452
|
+
See https://graphiti.dev/concepts/links for more information.
|
|
453
453
|
|
|
454
454
|
The current endpoints allowed for this resource are: #{@resource_class.endpoints.inspect}
|
|
455
455
|
MSG
|
|
@@ -731,7 +731,7 @@ module Graphiti
|
|
|
731
731
|
|
|
732
732
|
<<~MSG
|
|
733
733
|
|
|
734
|
-
resource_ids is set on this relationship, so every render reads the association, not just requests that include it. See
|
|
734
|
+
resource_ids is set on this relationship, so every render reads the association, not just requests that include it. See graphiti.dev/concepts/relationships#customizing-relationships.
|
|
735
735
|
MSG
|
|
736
736
|
end
|
|
737
737
|
end
|
|
@@ -909,7 +909,7 @@ module Graphiti
|
|
|
909
909
|
def initialize(resource, filter_names, required)
|
|
910
910
|
@resource = resource
|
|
911
911
|
@filter_names = filter_names
|
|
912
|
-
@required_label = required == :all ? "All" : "One"
|
|
912
|
+
@required_label = (required == :all) ? "All" : "One"
|
|
913
913
|
end
|
|
914
914
|
|
|
915
915
|
def message
|
data/lib/graphiti/query.rb
CHANGED
|
@@ -235,7 +235,7 @@ module Graphiti
|
|
|
235
235
|
|
|
236
236
|
scrubbed.filter do |key, value|
|
|
237
237
|
sideload = @resource.class.sideload(key)
|
|
238
|
-
sideload.nil?
|
|
238
|
+
sideload.nil? || sideload.readable?
|
|
239
239
|
end
|
|
240
240
|
end
|
|
241
241
|
end
|
|
@@ -311,7 +311,7 @@ module Graphiti
|
|
|
311
311
|
return false unless association?
|
|
312
312
|
|
|
313
313
|
split = name.to_s.split(".")
|
|
314
|
-
query_names = split[0
|
|
314
|
+
query_names = split[0..-2].map(&:to_sym)
|
|
315
315
|
my_names = parents.map(&:association_name).compact + [association_name].compact
|
|
316
316
|
query_names == my_names
|
|
317
317
|
end
|
|
@@ -343,7 +343,7 @@ module Graphiti
|
|
|
343
343
|
end
|
|
344
344
|
|
|
345
345
|
def sort_hash(attr)
|
|
346
|
-
value = attr[0] == "-" ? :desc : :asc
|
|
346
|
+
value = (attr[0] == "-") ? :desc : :asc
|
|
347
347
|
key = attr.sub("-", "").to_sym
|
|
348
348
|
|
|
349
349
|
{key => value}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
module Graphiti
|
|
2
2
|
module Rails
|
|
3
|
-
# Wraps controller actions in a [Graphiti Context](https://
|
|
3
|
+
# Wraps controller actions in a [Graphiti Context](https://graphiti.dev/concepts/resources#context) which points to the
|
|
4
4
|
# controller instance by default.
|
|
5
5
|
module Context
|
|
6
6
|
def self.included(klass)
|
|
7
7
|
klass.class_eval do
|
|
8
8
|
include Graphiti::Context
|
|
9
|
+
|
|
9
10
|
around_action :wrap_graphiti_context
|
|
10
11
|
end
|
|
11
12
|
end
|
|
@@ -17,6 +17,9 @@ module Graphiti
|
|
|
17
17
|
included do
|
|
18
18
|
include Graphiti::Rails::Context
|
|
19
19
|
include Graphiti::Rails::Debugging
|
|
20
|
+
# ActionController::API strips this out, but Graphiti serves multiple
|
|
21
|
+
# formats (jsonapi/json/xml), so respond_to has to work everywhere.
|
|
22
|
+
include ActionController::MimeResponds
|
|
20
23
|
|
|
21
24
|
# Broad, but the handler only renders formats listed in
|
|
22
25
|
# config.graphiti.handled_exception_formats and hands everything else
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
module Graphiti
|
|
2
2
|
module Rails
|
|
3
|
-
# Wraps controller actions in a [Graphiti Debugger](https://
|
|
3
|
+
# Wraps controller actions in a [Graphiti Debugger](https://graphiti.dev/topics/debugging#debugger).
|
|
4
4
|
module Debugging
|
|
5
5
|
def self.included(klass)
|
|
6
6
|
klass.around_action :debug_graphiti
|
|
@@ -6,6 +6,7 @@ module Graphiti
|
|
|
6
6
|
|
|
7
7
|
included do
|
|
8
8
|
include ActionController::MimeResponds
|
|
9
|
+
|
|
9
10
|
respond_to(*Graphiti::Rails.respond_to_formats)
|
|
10
11
|
end
|
|
11
12
|
|
|
@@ -14,7 +15,7 @@ module Graphiti
|
|
|
14
15
|
opts = args.extract_options!
|
|
15
16
|
opts[:location] = nil
|
|
16
17
|
args << opts
|
|
17
|
-
super
|
|
18
|
+
super
|
|
18
19
|
end
|
|
19
20
|
end
|
|
20
21
|
end
|
|
@@ -9,7 +9,7 @@ module Graphiti
|
|
|
9
9
|
opts = args.extract_options!
|
|
10
10
|
type_override = args[0]
|
|
11
11
|
|
|
12
|
-
if (att =
|
|
12
|
+
if (att = attributes[name] || extra_attributes[name])
|
|
13
13
|
# We're opting in to filtering, so force this
|
|
14
14
|
# UNLESS the filter is guarded at the attribute level
|
|
15
15
|
att[:filterable] = true if att[:filterable] == false
|
|
@@ -27,7 +27,7 @@ module Graphiti
|
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
required = att[:filterable] == :required || !!opts[:required]
|
|
30
|
-
schema = !!opts[:via_attribute_dsl] ? att[:schema] : opts[:schema] != false
|
|
30
|
+
schema = (!!opts[:via_attribute_dsl]) ? att[:schema] : opts[:schema] != false
|
|
31
31
|
|
|
32
32
|
config[:filters][name.to_sym] = {
|
|
33
33
|
aliases: aliases,
|
|
@@ -65,7 +65,7 @@ module Graphiti
|
|
|
65
65
|
def add_callback(kind, lifecycle, method, only, &blk)
|
|
66
66
|
config[:callbacks][kind] ||= {}
|
|
67
67
|
config[:callbacks][kind][lifecycle] ||= []
|
|
68
|
-
config[:callbacks][kind][lifecycle] << {callback:
|
|
68
|
+
config[:callbacks][kind][lifecycle] << {callback: method || blk, only: Array(only)}
|
|
69
69
|
end
|
|
70
70
|
end
|
|
71
71
|
|
data/lib/graphiti/resource.rb
CHANGED
|
@@ -137,14 +137,14 @@ module Graphiti
|
|
|
137
137
|
|
|
138
138
|
# TODO: make foreign_key a keyword once the satellite gems are rolled in - they call these positionally
|
|
139
139
|
def assign_with_relationships(meta, attributes, relationships, caller_model = nil, foreign_key = nil, model_instance: nil)
|
|
140
|
-
persistence = Graphiti::Util::Persistence
|
|
140
|
+
persistence = Graphiti::Util::Persistence
|
|
141
141
|
.new(self, meta, attributes, relationships, caller_model, foreign_key,
|
|
142
142
|
assigned_model: model_instance)
|
|
143
143
|
persistence.assign
|
|
144
144
|
end
|
|
145
145
|
|
|
146
146
|
def persist_with_relationships(meta, attributes, relationships, caller_model = nil, foreign_key = nil, assigned_model: nil)
|
|
147
|
-
persistence = Graphiti::Util::Persistence
|
|
147
|
+
persistence = Graphiti::Util::Persistence
|
|
148
148
|
.new(self, meta, attributes, relationships, caller_model, foreign_key,
|
|
149
149
|
assigned_model: assigned_model)
|
|
150
150
|
persistence.run
|
|
@@ -82,7 +82,7 @@ module Graphiti
|
|
|
82
82
|
if is_array
|
|
83
83
|
@resource.typecast(name, value, :filterable)
|
|
84
84
|
else
|
|
85
|
-
value = value.nil? || value.is_a?(Hash) ? [value] : Array(value)
|
|
85
|
+
value = (value.nil? || value.is_a?(Hash)) ? [value] : Array(value)
|
|
86
86
|
value.map { |v| @resource.typecast(name, v, :filterable) }
|
|
87
87
|
end
|
|
88
88
|
end
|
|
@@ -100,7 +100,7 @@ module Graphiti
|
|
|
100
100
|
|
|
101
101
|
param_value.map do |operator, value|
|
|
102
102
|
if type == :hash
|
|
103
|
-
value, operator =
|
|
103
|
+
value, operator =
|
|
104
104
|
parse_hash_value(filter, param_value, value, operator)
|
|
105
105
|
end
|
|
106
106
|
|
|
@@ -209,7 +209,9 @@ module Graphiti
|
|
|
209
209
|
end
|
|
210
210
|
|
|
211
211
|
def parse_string_null(filter, value)
|
|
212
|
-
return
|
|
212
|
+
return value unless filter[:allow_nil]
|
|
213
|
+
return value.map { |item| (item == "null") ? nil : item } if value.is_a?(Array)
|
|
214
|
+
return if value == "null"
|
|
213
215
|
|
|
214
216
|
value
|
|
215
217
|
end
|
|
@@ -62,7 +62,7 @@ module Graphiti
|
|
|
62
62
|
|
|
63
63
|
def method_missing(id, *args, &blk)
|
|
64
64
|
matches = @errors.select { |e| e.attribute.to_sym == id }
|
|
65
|
-
matches.length == 1 ? matches[0] : matches
|
|
65
|
+
(matches.length == 1) ? matches[0] : matches
|
|
66
66
|
end
|
|
67
67
|
|
|
68
68
|
# Any name is answered: an attribute with no matching error yields an empty
|
|
@@ -73,7 +73,7 @@ module Graphiti
|
|
|
73
73
|
attr_reader :target, :opts, :resource
|
|
74
74
|
|
|
75
75
|
def assert_opt(opt)
|
|
76
|
-
asserted_opt = opt == :resource ? :resource_class : opt
|
|
76
|
+
asserted_opt = (opt == :resource) ? :resource_class : opt
|
|
77
77
|
return true if config.send(asserted_opt) == opts[opt]
|
|
78
78
|
|
|
79
79
|
@opt_failures << opt_failure_message(opt, opts[opt], config.send(asserted_opt))
|
data/lib/graphiti/types.rb
CHANGED
|
@@ -82,6 +82,10 @@ module Graphiti
|
|
|
82
82
|
Dry::Types["params.hash"][input]
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
+
ParamArray = Dry::Types["strict.array"].constructor { |input|
|
|
86
|
+
input.is_a?(String) ? [input] : input
|
|
87
|
+
}
|
|
88
|
+
|
|
85
89
|
REQUIRED_KEYS = [:params, :read, :write, :kind, :description]
|
|
86
90
|
|
|
87
91
|
def self.map
|
|
@@ -193,7 +197,7 @@ module Graphiti
|
|
|
193
197
|
|
|
194
198
|
arrays[:"array_of_#{name.to_s.pluralize}"] = {
|
|
195
199
|
canonical_name: name,
|
|
196
|
-
params:
|
|
200
|
+
params: ParamArray.of(map[:params]),
|
|
197
201
|
read: Dry::Types["strict.array"].of(map[:read]),
|
|
198
202
|
test: Dry::Types["strict.array"].of(map[:test]),
|
|
199
203
|
write: Dry::Types["strict.array"].of(map[:write]),
|
|
@@ -28,7 +28,7 @@ module Graphiti
|
|
|
28
28
|
expires_in: proxy.cache_expires_in,
|
|
29
29
|
etag: proxy.etag,
|
|
30
30
|
miss_count: last_version[:miss_count].to_i + (changed_key? ? 1 : 0),
|
|
31
|
-
hit_count: last_version[:hit_count].to_i + (!changed_key? && !new_key? ? 1 : 0),
|
|
31
|
+
hit_count: last_version[:hit_count].to_i + ((!changed_key? && !new_key?) ? 1 : 0),
|
|
32
32
|
request_count: last_version[:request_count].to_i + (last_version.present? ? 1 : 0)
|
|
33
33
|
}
|
|
34
34
|
end
|
|
@@ -76,8 +76,8 @@ module Graphiti
|
|
|
76
76
|
end
|
|
77
77
|
|
|
78
78
|
def changes
|
|
79
|
-
sub_keys_old = last_version[:cache_key]&.scan(/\w+\/query-[a-z0-9-]+\/args-[a-z0-9-]+/).to_a
|
|
80
|
-
sub_keys_new = current_version[:cache_key]&.scan(/\w+\/query-[a-z0-9-]+\/args-[a-z0-9-]+/).to_a
|
|
79
|
+
sub_keys_old = last_version[:cache_key]&.scan(/\w+\/query-[a-z0-9-]+\/args-[a-z0-9-]+/).to_a
|
|
80
|
+
sub_keys_new = current_version[:cache_key]&.scan(/\w+\/query-[a-z0-9-]+\/args-[a-z0-9-]+/).to_a
|
|
81
81
|
|
|
82
82
|
[sub_keys_old, sub_keys_new]
|
|
83
83
|
end
|
data/lib/graphiti/util/hash.rb
CHANGED
|
@@ -43,7 +43,7 @@ module Graphiti
|
|
|
43
43
|
# @return [Hash] the merged hash
|
|
44
44
|
# @api private
|
|
45
45
|
def self.deep_merge!(hash, other)
|
|
46
|
-
merger = proc { |key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2 }
|
|
46
|
+
merger = proc { |key, v1, v2| (Hash === v1 && Hash === v2) ? v1.merge(v2, &merger) : v2 }
|
|
47
47
|
hash.merge!(other, &merger)
|
|
48
48
|
end
|
|
49
49
|
|
|
@@ -156,12 +156,12 @@ class Graphiti::Util::Persistence
|
|
|
156
156
|
|
|
157
157
|
def persist_object(method, attributes)
|
|
158
158
|
case method
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
159
|
+
when :destroy
|
|
160
|
+
call_resource_method(:destroy, attributes[:id], @caller_model)
|
|
161
|
+
when :update, nil, :disassociate
|
|
162
|
+
call_resource_method(:update, attributes, @caller_model)
|
|
163
|
+
else
|
|
164
|
+
call_resource_method(:create, attributes, @caller_model)
|
|
165
165
|
end
|
|
166
166
|
end
|
|
167
167
|
|
|
@@ -173,7 +173,7 @@ module Graphiti
|
|
|
173
173
|
def validate_link_for_sideload!(sideload)
|
|
174
174
|
return if sideload.resource.remote?
|
|
175
175
|
|
|
176
|
-
action = sideload.type == :belongs_to ? :show : :index
|
|
176
|
+
action = (sideload.type == :belongs_to) ? :show : :index
|
|
177
177
|
cache_key = :"#{@sideload.object_id}-#{action}"
|
|
178
178
|
return if self.class.validated_link_cache.include?(cache_key)
|
|
179
179
|
prc = Graphiti.config.context_for_endpoint
|
data/lib/graphiti/version.rb
CHANGED
data/lib/tasks/graphiti.rake
CHANGED