graphiti 2.0.0.beta.8 → 2.0.0.beta.10
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 +1 -1
- data/.github/workflows/docs.yml +9 -6
- data/.github/workflows/release.yml +1 -1
- data/CHANGELOG.md +43 -0
- data/Rakefile +28 -0
- data/UPGRADING.md +1 -1
- data/lib/generators/graphiti/generator_mixin.rb +24 -0
- data/lib/generators/graphiti/templates/application_resource.rb.erb +9 -16
- data/lib/graphiti/configuration.rb +66 -28
- data/lib/graphiti/debugger.rb +18 -6
- data/lib/graphiti/delegates/pagination.rb +2 -2
- data/lib/graphiti/error_serializers/deprecated_constants.rb +23 -0
- data/lib/graphiti/error_serializers/invalid_request.rb +6 -0
- data/lib/graphiti/errors.rb +51 -3
- data/lib/graphiti/query.rb +36 -14
- data/lib/graphiti/rails/controller.rb +26 -6
- data/lib/graphiti/rails/rake_helpers.rb +17 -0
- data/lib/graphiti/rails.rb +14 -0
- data/lib/graphiti/railtie.rb +8 -0
- data/lib/graphiti/request_validators/update_validator.rb +1 -1
- data/lib/graphiti/request_validators/validator.rb +9 -0
- data/lib/graphiti/resource/configuration.rb +138 -40
- data/lib/graphiti/resource/dsl.rb +21 -2
- data/lib/graphiti/resource/interface.rb +1 -1
- data/lib/graphiti/resource/links.rb +36 -5
- data/lib/graphiti/resource/remote.rb +2 -1
- data/lib/graphiti/resource/sideloading.rb +2 -2
- data/lib/graphiti/schema.rb +2 -2
- data/lib/graphiti/scope.rb +115 -23
- data/lib/graphiti/scoping/filter.rb +4 -4
- data/lib/graphiti/scoping/paginate.rb +3 -3
- data/lib/graphiti/serializer.rb +12 -6
- data/lib/graphiti/sideload/polymorphic_belongs_to.rb +11 -4
- data/lib/graphiti/sideload.rb +22 -14
- data/lib/graphiti/spec_helpers/matchers.rb +2 -2
- data/lib/graphiti/spec_helpers/rspec.rb +6 -3
- data/lib/graphiti/util/link.rb +1 -1
- data/lib/graphiti/util/serializer_attributes.rb +5 -3
- data/lib/graphiti/util/serializer_relationships.rb +26 -16
- data/lib/graphiti/version.rb +1 -1
- data/lib/graphiti.rb +6 -1
- data/lib/tasks/graphiti.rake +4 -0
- data/package-lock.json +114 -0
- data/package.json +16 -3
- metadata +3 -2
|
@@ -30,14 +30,34 @@ module Graphiti
|
|
|
30
30
|
|
|
31
31
|
register_exception Graphiti::Errors::InvalidRequest,
|
|
32
32
|
status: 400, handler: Graphiti::Rails::InvalidRequestHandler
|
|
33
|
-
register_exception Graphiti::Errors::ConflictRequest,
|
|
34
|
-
status: 409, handler: Graphiti::Rails::ConflictRequestHandler
|
|
35
|
-
register_exception Graphiti::Errors::RecordNotFound,
|
|
36
|
-
status: 404, handler: Graphiti::Rails::ExceptionHandler
|
|
37
33
|
register_exception Graphiti::Errors::RemoteWrite,
|
|
38
|
-
status: 400, handler: Graphiti::Rails::ExceptionHandler
|
|
34
|
+
status: 400, detail: :exception, handler: Graphiti::Rails::ExceptionHandler
|
|
39
35
|
register_exception Graphiti::Errors::SingularSideload,
|
|
40
|
-
status: 400, handler: Graphiti::Rails::ExceptionHandler
|
|
36
|
+
status: 400, detail: :exception, handler: Graphiti::Rails::ExceptionHandler
|
|
37
|
+
register_exception Graphiti::Errors::InvalidInclude,
|
|
38
|
+
status: 400, detail: :exception, handler: Graphiti::Rails::ExceptionHandler
|
|
39
|
+
register_exception Graphiti::Errors::UnsupportedSort,
|
|
40
|
+
status: 400, detail: :exception, handler: Graphiti::Rails::ExceptionHandler
|
|
41
|
+
register_exception Graphiti::Errors::UnsupportedOperator,
|
|
42
|
+
status: 400, detail: :exception, handler: Graphiti::Rails::ExceptionHandler
|
|
43
|
+
register_exception Graphiti::Errors::InvalidFilterValue,
|
|
44
|
+
status: 400, detail: :exception, handler: Graphiti::Rails::ExceptionHandler
|
|
45
|
+
register_exception Graphiti::Errors::RequiredFilter,
|
|
46
|
+
status: 400, detail: :exception, handler: Graphiti::Rails::ExceptionHandler
|
|
47
|
+
register_exception Graphiti::Errors::UnsupportedPageSize,
|
|
48
|
+
status: 400, detail: :exception, handler: Graphiti::Rails::ExceptionHandler
|
|
49
|
+
register_exception Graphiti::Errors::UnsupportedBeforeCursor,
|
|
50
|
+
status: 400, detail: :exception, handler: Graphiti::Rails::ExceptionHandler
|
|
51
|
+
register_exception Graphiti::Errors::UnsupportedPagination,
|
|
52
|
+
status: 400, detail: :exception, handler: Graphiti::Rails::ExceptionHandler
|
|
53
|
+
register_exception Graphiti::Errors::FilterGroupMissingRequiredFilters,
|
|
54
|
+
status: 400, detail: :exception, handler: Graphiti::Rails::ExceptionHandler
|
|
55
|
+
|
|
56
|
+
register_exception Graphiti::Errors::RecordNotFound,
|
|
57
|
+
status: 404, detail: :exception, handler: Graphiti::Rails::ExceptionHandler
|
|
58
|
+
|
|
59
|
+
register_exception Graphiti::Errors::ConflictRequest,
|
|
60
|
+
status: 409, handler: Graphiti::Rails::ConflictRequestHandler
|
|
41
61
|
end
|
|
42
62
|
end
|
|
43
63
|
end
|
|
@@ -21,6 +21,23 @@ module Graphiti
|
|
|
21
21
|
::Rails.application.config.action_controller.perform_caching = false
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
+
# The pool and RAILS_MAX_THREADS are read from this environment, and production may size both differently.
|
|
25
|
+
def connection_pool_advisory
|
|
26
|
+
return unless defined?(ActiveRecord::Base)
|
|
27
|
+
|
|
28
|
+
pool = ActiveRecord::Base.connection_db_config.pool
|
|
29
|
+
threads = ENV.fetch("RAILS_MAX_THREADS", 5).to_i
|
|
30
|
+
sideload_threads = Graphiti.config.concurrency_max_threads
|
|
31
|
+
needed = threads + sideload_threads + 1
|
|
32
|
+
return if pool.nil? || pool >= needed
|
|
33
|
+
|
|
34
|
+
"WARNING database.yml pool is #{pool} in this environment. With concurrency on (the production default), " \
|
|
35
|
+
"each sideload holds its own connection, so pool should be at least " \
|
|
36
|
+
"web threads (#{threads}) + concurrency_max_threads (#{sideload_threads}) + 1 = #{needed}. " \
|
|
37
|
+
"If production sizes these differently, check the numbers there. " \
|
|
38
|
+
"See graphiti.dev/concepts/resources#concurrency-pool-sizing."
|
|
39
|
+
end
|
|
40
|
+
|
|
24
41
|
def make_request(path, debug = false)
|
|
25
42
|
if path.split("/").length == 2
|
|
26
43
|
path = "#{ApplicationResource.endpoint_namespace}#{path}"
|
data/lib/graphiti/rails.rb
CHANGED
|
@@ -31,6 +31,13 @@ module Graphiti
|
|
|
31
31
|
autoload :Responders, "graphiti/rails/responders"
|
|
32
32
|
autoload :TestHelpers, "graphiti/rails/test_helpers"
|
|
33
33
|
|
|
34
|
+
# Deprecated. Backed graphiti-rails' enable!/disable! spec toggles. Remove in 3.0.
|
|
35
|
+
GraphitiErrorsTesting = ActiveSupport::Deprecation::DeprecatedConstantProxy.new(
|
|
36
|
+
"Graphiti::Rails::GraphitiErrorsTesting",
|
|
37
|
+
"Graphiti::Rails::TestHelpers",
|
|
38
|
+
DEPRECATOR
|
|
39
|
+
)
|
|
40
|
+
|
|
34
41
|
# @!attribute self.handled_exception_formats
|
|
35
42
|
# A list of formats as symbols whose exceptions will be handled by Graphiti. See {Railtie}.
|
|
36
43
|
cattr_accessor :handled_exception_formats, default: []
|
|
@@ -47,6 +54,13 @@ module Graphiti
|
|
|
47
54
|
"Graphiti::Rails::Responders",
|
|
48
55
|
DEPRECATOR
|
|
49
56
|
)
|
|
57
|
+
|
|
58
|
+
# Deprecated. Core's railtie merged into graphiti-rails'. Remove in 3.0.
|
|
59
|
+
Railtie = ActiveSupport::Deprecation::DeprecatedConstantProxy.new(
|
|
60
|
+
"Graphiti::Railtie",
|
|
61
|
+
"Graphiti::Rails::Railtie",
|
|
62
|
+
DEPRECATOR
|
|
63
|
+
)
|
|
50
64
|
end
|
|
51
65
|
|
|
52
66
|
ActiveSupport.on_load(:active_record) do
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# Deprecated require path, kept so a leftover 1.x require does not raise.
|
|
2
|
+
# The railtie lives in Graphiti::Rails as of 2.0. Remove in 3.0.
|
|
3
|
+
require "graphiti"
|
|
4
|
+
|
|
5
|
+
Graphiti::DEPRECATOR.warn(
|
|
6
|
+
'require "graphiti/railtie" is no longer needed. The railtie is part of the Rails ' \
|
|
7
|
+
"integration as of 2.0, and loads with graphiti when Rails is present."
|
|
8
|
+
)
|
|
@@ -17,6 +17,7 @@ module Graphiti
|
|
|
17
17
|
# In the future these should have their own validation logic, but
|
|
18
18
|
# for now we can just bypass
|
|
19
19
|
return errors.blank? unless @params.has_key?(:data)
|
|
20
|
+
return false unless validate_data_shape
|
|
20
21
|
|
|
21
22
|
resource = @root_resource
|
|
22
23
|
if @params[:data].has_key?(:type)
|
|
@@ -56,6 +57,14 @@ module Graphiti
|
|
|
56
57
|
@errors.add(:page, :invalid, message: "must be an object")
|
|
57
58
|
end
|
|
58
59
|
|
|
60
|
+
def validate_data_shape
|
|
61
|
+
data = @params[:data]
|
|
62
|
+
return true if data.nil? || data.respond_to?(:each_pair)
|
|
63
|
+
|
|
64
|
+
@errors.add(:data, :invalid, message: "must be an object")
|
|
65
|
+
false
|
|
66
|
+
end
|
|
67
|
+
|
|
59
68
|
def process_relationships(resource, relationships, payload_path)
|
|
60
69
|
relationships.each_key do |name|
|
|
61
70
|
unless resource.class.sideload(name.to_sym)
|
|
@@ -4,16 +4,75 @@ module Graphiti
|
|
|
4
4
|
extend ActiveSupport::Concern
|
|
5
5
|
|
|
6
6
|
DEFAULT_MAX_PAGE_SIZE = 1_000
|
|
7
|
+
LINK_MODES = [true, false, :on_demand].freeze
|
|
8
|
+
BELONGS_TO_RESOURCE_IDS_MODES = [:foreign_key, :always, :never].freeze
|
|
9
|
+
BLANK_MODES = [:as_literal, :as_nil, :reject].freeze
|
|
10
|
+
|
|
11
|
+
# Grouped for the ApplicationResource the install generator writes.
|
|
12
|
+
SETTING_GROUPS = { # :nodoc:
|
|
13
|
+
attributes: {
|
|
14
|
+
attributes_readable_by_default: {default: true},
|
|
15
|
+
attributes_writable_by_default: {default: true},
|
|
16
|
+
attributes_sortable_by_default: {default: true},
|
|
17
|
+
attributes_filterable_by_default: {default: true},
|
|
18
|
+
attributes_schema_by_default: {default: true},
|
|
19
|
+
typecast_reads: {default: true}
|
|
20
|
+
},
|
|
21
|
+
relationships: {
|
|
22
|
+
relationships_readable_by_default: {default: true},
|
|
23
|
+
relationships_writable_by_default: {default: true},
|
|
24
|
+
belongs_to_resource_ids_by_default: {
|
|
25
|
+
default: :foreign_key,
|
|
26
|
+
values: BELONGS_TO_RESOURCE_IDS_MODES,
|
|
27
|
+
invalid: ->(klass, value) { Errors::InvalidBelongsToResourceIds.new(klass, value) }
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
filters: {
|
|
31
|
+
filters_blanks_by_default: {
|
|
32
|
+
default: :as_literal,
|
|
33
|
+
values: BLANK_MODES,
|
|
34
|
+
invalid: ->(klass, value) { Errors::InvalidFilterBlanks.new(klass, :filters_blanks_by_default, value) }
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
sorting: {
|
|
38
|
+
default_sort: {default: nil, note: "per resource, e.g. [{id: :desc}]"}
|
|
39
|
+
},
|
|
40
|
+
pagination: {
|
|
41
|
+
page_default_size: {default: nil, note: "unset falls back to 20"},
|
|
42
|
+
page_max_size: {default: DEFAULT_MAX_PAGE_SIZE, format: "1_000"},
|
|
43
|
+
page_cursors: {default: false, note: "render cursors for pagination"},
|
|
44
|
+
page_links: {
|
|
45
|
+
default: false,
|
|
46
|
+
values: LINK_MODES,
|
|
47
|
+
invalid: ->(klass, value) { Errors::InvalidLinkRendering.new(klass, :page_links, value) }
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
endpoints: {
|
|
51
|
+
validate_requests: {default: true, note: "refuse requests to undeclared endpoints"}
|
|
52
|
+
},
|
|
53
|
+
links: {
|
|
54
|
+
relationship_links: {
|
|
55
|
+
default: true,
|
|
56
|
+
values: LINK_MODES,
|
|
57
|
+
invalid: ->(klass, value) { Errors::InvalidLinkRendering.new(klass, :relationship_links, value) }
|
|
58
|
+
},
|
|
59
|
+
validate_links: {default: true, note: "refuse to render links to unroutable endpoints"}
|
|
60
|
+
}
|
|
61
|
+
}.freeze
|
|
62
|
+
|
|
63
|
+
SETTINGS = SETTING_GROUPS.values.reduce(:merge).freeze # :nodoc:
|
|
7
64
|
|
|
8
65
|
module Overrides
|
|
9
|
-
|
|
66
|
+
SETTINGS.each_pair do |name, setting|
|
|
67
|
+
next unless setting[:values]
|
|
10
68
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
69
|
+
define_method(:"#{name}=") do |val|
|
|
70
|
+
unless setting[:values].include?(val)
|
|
71
|
+
raise setting[:invalid].call(self, val)
|
|
72
|
+
end
|
|
15
73
|
|
|
16
|
-
|
|
74
|
+
super(val)
|
|
75
|
+
end
|
|
17
76
|
end
|
|
18
77
|
|
|
19
78
|
def serializer=(val)
|
|
@@ -95,51 +154,37 @@ module Graphiti
|
|
|
95
154
|
:polymorphic,
|
|
96
155
|
:polymorphic_child,
|
|
97
156
|
:serializer,
|
|
98
|
-
:default_page_size,
|
|
99
|
-
:default_sort,
|
|
100
|
-
:max_page_size,
|
|
101
|
-
:attributes_readable_by_default,
|
|
102
|
-
:attributes_writable_by_default,
|
|
103
|
-
:attributes_sortable_by_default,
|
|
104
|
-
:attributes_filterable_by_default,
|
|
105
|
-
:attributes_schema_by_default,
|
|
106
|
-
:relationships_readable_by_default,
|
|
107
|
-
:relationships_writable_by_default,
|
|
108
|
-
:belongs_to_resource_ids_by_default,
|
|
109
|
-
:filters_accept_nil_by_default,
|
|
110
|
-
:filters_deny_empty_by_default,
|
|
111
157
|
:graphql_entrypoint,
|
|
112
|
-
|
|
158
|
+
*SETTINGS.keys
|
|
113
159
|
|
|
114
160
|
class << self
|
|
115
161
|
prepend Overrides
|
|
116
162
|
end
|
|
117
163
|
|
|
164
|
+
SETTINGS.each_pair do |name, setting|
|
|
165
|
+
public_send(:"#{name}=", setting[:default])
|
|
166
|
+
end
|
|
167
|
+
|
|
118
168
|
def self.inherited(klass)
|
|
119
169
|
super
|
|
120
170
|
klass.config = Util::Hash.deep_dup(config)
|
|
121
171
|
klass.adapter ||= Adapters::Abstract
|
|
122
|
-
klass.max_page_size ||= DEFAULT_MAX_PAGE_SIZE
|
|
123
172
|
# re-assigning causes a new Class.new
|
|
124
173
|
klass.serializer = (klass.serializer || klass.infer_serializer_superclass)
|
|
125
174
|
klass.type ||= klass.infer_type
|
|
126
175
|
klass.graphql_entrypoint = klass.type.to_s.pluralize.to_sym
|
|
127
|
-
default(klass, :attributes_readable_by_default, true)
|
|
128
|
-
default(klass, :attributes_writable_by_default, true)
|
|
129
|
-
default(klass, :attributes_sortable_by_default, true)
|
|
130
|
-
default(klass, :attributes_filterable_by_default, true)
|
|
131
|
-
default(klass, :attributes_schema_by_default, true)
|
|
132
|
-
default(klass, :relationships_readable_by_default, true)
|
|
133
|
-
default(klass, :relationships_writable_by_default, true)
|
|
134
|
-
default(klass, :belongs_to_resource_ids_by_default, :foreign_key)
|
|
135
|
-
default(klass, :filters_accept_nil_by_default, false)
|
|
136
|
-
default(klass, :filters_deny_empty_by_default, false)
|
|
137
|
-
|
|
138
176
|
unless klass.config[:attributes][:id]
|
|
139
177
|
klass.attribute :id, :integer_id
|
|
140
178
|
end
|
|
141
179
|
klass.stat total: [:count]
|
|
142
180
|
|
|
181
|
+
# An abstract parent has no serializer for its sideloads, so the subclass applies them here.
|
|
182
|
+
if abstract_class?
|
|
183
|
+
klass.config[:sideloads].each_pair do |name, sideload|
|
|
184
|
+
klass.apply_sideload_to_serializer(name) if klass.eagerly_apply_sideload?(sideload)
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
|
|
143
188
|
if defined?(::Rails) && ::Rails.env.development?
|
|
144
189
|
# Avoid adding dupe resources when re-autoloading
|
|
145
190
|
Graphiti.resources.reject! { |r| r.name == klass.name }
|
|
@@ -149,6 +194,52 @@ module Graphiti
|
|
|
149
194
|
end
|
|
150
195
|
|
|
151
196
|
class_methods do
|
|
197
|
+
# Deprecated. Both folded into filters_blanks_by_default. Remove in 3.0.
|
|
198
|
+
def filters_accept_nil_by_default
|
|
199
|
+
filters_blanks_by_default == :as_nil
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
def filters_accept_nil_by_default=(val)
|
|
203
|
+
self.filters_blanks_by_default = val ? :as_nil : :as_literal
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def filters_deny_empty_by_default
|
|
207
|
+
filters_blanks_by_default == :reject
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
def filters_deny_empty_by_default=(val)
|
|
211
|
+
self.filters_blanks_by_default = val ? :reject : :as_literal
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# Deprecated. Renamed to the page_ family. Remove in 3.0.
|
|
215
|
+
def default_page_size
|
|
216
|
+
page_default_size
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
def default_page_size=(val)
|
|
220
|
+
self.page_default_size = val
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
def max_page_size
|
|
224
|
+
page_max_size
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
def max_page_size=(val)
|
|
228
|
+
self.page_max_size = val
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
def cursor_paginatable
|
|
232
|
+
page_cursors
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
def cursor_paginatable=(val)
|
|
236
|
+
self.page_cursors = val
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
def cursor_paginatable?
|
|
240
|
+
!!page_cursors
|
|
241
|
+
end
|
|
242
|
+
|
|
152
243
|
def get_attr!(name, flag, opts = {})
|
|
153
244
|
opts[:raise_error] = true
|
|
154
245
|
get_attr(name, flag, opts)
|
|
@@ -205,14 +296,6 @@ module Graphiti
|
|
|
205
296
|
serializer_class
|
|
206
297
|
end
|
|
207
298
|
|
|
208
|
-
def default(object, attr, value)
|
|
209
|
-
prior = object.send(attr)
|
|
210
|
-
unless prior || prior == false
|
|
211
|
-
object.send(:"#{attr}=", value)
|
|
212
|
-
end
|
|
213
|
-
end
|
|
214
|
-
private :default
|
|
215
|
-
|
|
216
299
|
def config
|
|
217
300
|
@config ||=
|
|
218
301
|
{
|
|
@@ -332,5 +415,20 @@ module Graphiti
|
|
|
332
415
|
self.class.default_filters
|
|
333
416
|
end
|
|
334
417
|
end
|
|
418
|
+
|
|
419
|
+
blanks_msg = "Use `self.filters_blanks_by_default` (:as_literal, :as_nil, or :reject)"
|
|
420
|
+
page_msg = "Use `self.page_default_size`, `self.page_max_size` and `self.page_cursors`"
|
|
421
|
+
DEPRECATOR.deprecate_methods(Configuration::ClassMethods,
|
|
422
|
+
filters_accept_nil_by_default: blanks_msg,
|
|
423
|
+
"filters_accept_nil_by_default=": blanks_msg,
|
|
424
|
+
filters_deny_empty_by_default: blanks_msg,
|
|
425
|
+
"filters_deny_empty_by_default=": blanks_msg,
|
|
426
|
+
default_page_size: page_msg,
|
|
427
|
+
"default_page_size=": page_msg,
|
|
428
|
+
max_page_size: page_msg,
|
|
429
|
+
"max_page_size=": page_msg,
|
|
430
|
+
cursor_paginatable: page_msg,
|
|
431
|
+
"cursor_paginatable=": page_msg,
|
|
432
|
+
cursor_paginatable?: page_msg)
|
|
335
433
|
end
|
|
336
434
|
end
|
|
@@ -40,8 +40,7 @@ module Graphiti
|
|
|
40
40
|
required: required,
|
|
41
41
|
schema: schema,
|
|
42
42
|
operators: operators.to_hash,
|
|
43
|
-
|
|
44
|
-
deny_empty: opts.fetch(:deny_empty, filters_deny_empty_by_default)
|
|
43
|
+
blanks: blanks_for(name, opts)
|
|
45
44
|
}
|
|
46
45
|
elsif (type = args[0])
|
|
47
46
|
attribute name, type, only: [:filterable], allow: opts[:allow]
|
|
@@ -206,6 +205,26 @@ module Graphiti
|
|
|
206
205
|
end
|
|
207
206
|
end
|
|
208
207
|
private :relationship_option
|
|
208
|
+
|
|
209
|
+
def blanks_for(name, opts)
|
|
210
|
+
if opts.key?(:deny_empty)
|
|
211
|
+
DEPRECATOR.warn("The deny_empty: filter option is deprecated. Use blanks: :reject.")
|
|
212
|
+
return :reject if opts[:deny_empty]
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
if opts.key?(:allow_nil)
|
|
216
|
+
DEPRECATOR.warn("The allow_nil: filter option is deprecated. Use blanks: :as_nil.")
|
|
217
|
+
return opts[:allow_nil] ? :as_nil : :as_literal
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
blanks = opts.fetch(:blanks, filters_blanks_by_default)
|
|
221
|
+
unless Resource::BLANK_MODES.include?(blanks)
|
|
222
|
+
raise Errors::InvalidFilterBlanks.new(self, name, blanks)
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
blanks
|
|
226
|
+
end
|
|
227
|
+
private :blanks_for
|
|
209
228
|
end
|
|
210
229
|
end
|
|
211
230
|
end
|
|
@@ -80,7 +80,7 @@ module Graphiti
|
|
|
80
80
|
end
|
|
81
81
|
|
|
82
82
|
def validate_request!(params)
|
|
83
|
-
return if Graphiti.context[:graphql] || !
|
|
83
|
+
return if Graphiti.context[:graphql] || !validate_requests?
|
|
84
84
|
|
|
85
85
|
if context&.respond_to?(:request)
|
|
86
86
|
path = context.request.env["PATH_INFO"]
|
|
@@ -25,12 +25,8 @@ module Graphiti
|
|
|
25
25
|
class_attribute :endpoint,
|
|
26
26
|
:base_url,
|
|
27
27
|
:endpoint_namespace,
|
|
28
|
-
:secondary_endpoints
|
|
29
|
-
:autolink,
|
|
30
|
-
:validate_endpoints
|
|
28
|
+
:secondary_endpoints
|
|
31
29
|
self.secondary_endpoints = []
|
|
32
|
-
self.autolink = true
|
|
33
|
-
self.validate_endpoints = true
|
|
34
30
|
|
|
35
31
|
class << self
|
|
36
32
|
prepend Overrides
|
|
@@ -38,6 +34,33 @@ module Graphiti
|
|
|
38
34
|
end
|
|
39
35
|
|
|
40
36
|
class_methods do
|
|
37
|
+
# Deprecated. Folded into relationship_links. Remove in 3.0.
|
|
38
|
+
def autolink
|
|
39
|
+
relationship_links != false
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def autolink=(val)
|
|
43
|
+
self.relationship_links = val ? true : false
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def autolink?
|
|
47
|
+
autolink
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Deprecated. Split into validate_requests and validate_links. Remove in 3.0.
|
|
51
|
+
def validate_endpoints
|
|
52
|
+
validate_requests && validate_links
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def validate_endpoints=(val)
|
|
56
|
+
self.validate_requests = val
|
|
57
|
+
self.validate_links = val
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def validate_endpoints?
|
|
61
|
+
validate_endpoints
|
|
62
|
+
end
|
|
63
|
+
|
|
41
64
|
def infer_endpoint
|
|
42
65
|
return unless name
|
|
43
66
|
|
|
@@ -101,4 +124,12 @@ module Graphiti
|
|
|
101
124
|
end
|
|
102
125
|
end
|
|
103
126
|
end
|
|
127
|
+
|
|
128
|
+
msg = "Use `self.relationship_links` (true, false, or :on_demand)"
|
|
129
|
+
endpoints_msg = "Use `self.validate_requests` for inbound requests, `self.validate_links` for rendered links"
|
|
130
|
+
DEPRECATOR.deprecate_methods(Links::ClassMethods,
|
|
131
|
+
autolink: msg, "autolink=": msg, autolink?: msg,
|
|
132
|
+
validate_endpoints: endpoints_msg,
|
|
133
|
+
"validate_endpoints=": endpoints_msg,
|
|
134
|
+
validate_endpoints?: endpoints_msg)
|
|
104
135
|
end
|
|
@@ -126,11 +126,11 @@ module Graphiti
|
|
|
126
126
|
end
|
|
127
127
|
|
|
128
128
|
# If eager loading, ensure routes are loaded first, then apply
|
|
129
|
-
# This happens in Railtie
|
|
129
|
+
# This happens in Railtie. Setup runs once, so classes redefined by a reload apply at definition.
|
|
130
130
|
def eagerly_apply_sideload?(sideload)
|
|
131
131
|
# TODO: Maybe handle this in the Rails integration
|
|
132
132
|
if defined?(::Rails) && (app = ::Rails.application)
|
|
133
|
-
app.config.eager_load ?
|
|
133
|
+
app.config.eager_load ? Graphiti.setup? : true
|
|
134
134
|
else
|
|
135
135
|
sideload.resource_class_loaded?
|
|
136
136
|
end
|
data/lib/graphiti/schema.rb
CHANGED
|
@@ -111,8 +111,8 @@ module Graphiti
|
|
|
111
111
|
config[:default_sort] = default_sort
|
|
112
112
|
end
|
|
113
113
|
|
|
114
|
-
if r.
|
|
115
|
-
config[:default_page_size] = r.
|
|
114
|
+
if r.page_default_size
|
|
115
|
+
config[:default_page_size] = r.page_default_size
|
|
116
116
|
end
|
|
117
117
|
|
|
118
118
|
if r.polymorphic? && !r.polymorphic_child?
|