graphiti 1.2.16 → 1.2.17
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/.travis.yml +43 -14
- data/Appraisals +37 -5
- data/Guardfile +4 -4
- data/deprecated_generators/graphiti/resource_generator.rb +1 -1
- data/gemfiles/rails_5_0.gemfile +18 -0
- data/gemfiles/rails_5_0_graphiti_rails.gemfile +20 -0
- data/gemfiles/rails_5_1.gemfile +18 -0
- data/gemfiles/rails_5_1_graphiti_rails.gemfile +20 -0
- data/gemfiles/{rails_5.gemfile → rails_5_2.gemfile} +0 -0
- data/gemfiles/{rails_5_graphiti_rails.gemfile → rails_5_2_graphiti_rails.gemfile} +0 -0
- data/gemfiles/rails_6.gemfile +1 -1
- data/gemfiles/rails_6_graphiti_rails.gemfile +1 -1
- data/graphiti.gemspec +10 -10
- data/lib/graphiti.rb +3 -3
- data/lib/graphiti/adapters/abstract.rb +3 -3
- data/lib/graphiti/adapters/active_record.rb +64 -35
- data/lib/graphiti/configuration.rb +1 -1
- data/lib/graphiti/debugger.rb +4 -4
- data/lib/graphiti/delegates/pagination.rb +3 -3
- data/lib/graphiti/deserializer.rb +3 -3
- data/lib/graphiti/errors.rb +24 -4
- data/lib/graphiti/query.rb +4 -4
- data/lib/graphiti/railtie.rb +1 -1
- data/lib/graphiti/request_validator.rb +4 -4
- data/lib/graphiti/request_validators/update_validator.rb +1 -2
- data/lib/graphiti/request_validators/validator.rb +2 -2
- data/lib/graphiti/resource/configuration.rb +6 -4
- data/lib/graphiti/resource/dsl.rb +5 -4
- data/lib/graphiti/resource/links.rb +3 -3
- data/lib/graphiti/resource/persistence.rb +2 -1
- data/lib/graphiti/resource/polymorphism.rb +2 -1
- data/lib/graphiti/resource/remote.rb +1 -1
- data/lib/graphiti/runner.rb +1 -1
- data/lib/graphiti/schema.rb +6 -6
- data/lib/graphiti/scope.rb +5 -5
- data/lib/graphiti/scoping/base.rb +3 -3
- data/lib/graphiti/scoping/filter.rb +17 -7
- data/lib/graphiti/scoping/sort.rb +1 -1
- data/lib/graphiti/sideload.rb +26 -22
- data/lib/graphiti/sideload/belongs_to.rb +1 -1
- data/lib/graphiti/stats/payload.rb +4 -4
- data/lib/graphiti/types.rb +15 -15
- data/lib/graphiti/util/link.rb +5 -1
- data/lib/graphiti/util/persistence.rb +16 -10
- data/lib/graphiti/util/relationship_payload.rb +4 -4
- data/lib/graphiti/util/simple_errors.rb +1 -1
- data/lib/graphiti/util/transaction_hooks_recorder.rb +1 -1
- data/lib/graphiti/version.rb +1 -1
- metadata +8 -4
data/lib/graphiti/debugger.rb
CHANGED
@@ -59,10 +59,10 @@ module Graphiti
|
|
59
59
|
add_chunk(payload[:resource], payload[:parent]) do |logs, json|
|
60
60
|
logs << [" \\_ #{sideload.name}", :yellow, true]
|
61
61
|
json[:name] = sideload.name
|
62
|
-
if sideload.class.scope_proc
|
63
|
-
|
62
|
+
query = if sideload.class.scope_proc
|
63
|
+
"#{payload[:resource].class.name}: Manual sideload via .scope"
|
64
64
|
else
|
65
|
-
|
65
|
+
"#{payload[:resource].class.name}.all(#{params.inspect})"
|
66
66
|
end
|
67
67
|
logs << [" #{query}", :cyan, true]
|
68
68
|
json[:query] = query
|
@@ -148,7 +148,7 @@ module Graphiti
|
|
148
148
|
parent: parent,
|
149
149
|
logs: logs,
|
150
150
|
json: json,
|
151
|
-
children: []
|
151
|
+
children: []
|
152
152
|
}
|
153
153
|
end
|
154
154
|
|
@@ -15,7 +15,7 @@ module Graphiti
|
|
15
15
|
links[:last] = pagination_link(last_page)
|
16
16
|
links[:prev] = pagination_link(current_page - 1) unless current_page == 1
|
17
17
|
links[:next] = pagination_link(current_page + 1) unless current_page == last_page
|
18
|
-
end.select {|k, v| !v.nil? }
|
18
|
+
end.select { |k, v| !v.nil? }
|
19
19
|
end
|
20
20
|
|
21
21
|
private
|
@@ -29,8 +29,8 @@ module Graphiti
|
|
29
29
|
uri.query = @proxy.query.hash.merge({
|
30
30
|
page: {
|
31
31
|
number: page,
|
32
|
-
size: page_size
|
33
|
-
}
|
32
|
+
size: page_size
|
33
|
+
}
|
34
34
|
}).to_query
|
35
35
|
uri.to_s
|
36
36
|
end
|
@@ -87,7 +87,7 @@ class Graphiti::Deserializer
|
|
87
87
|
type: data[:type],
|
88
88
|
temp_id: data[:'temp-id'],
|
89
89
|
method: action,
|
90
|
-
payload_path: ["data"]
|
90
|
+
payload_path: ["data"]
|
91
91
|
}
|
92
92
|
end
|
93
93
|
|
@@ -185,10 +185,10 @@ class Graphiti::Deserializer
|
|
185
185
|
jsonapi_type: datum[:type],
|
186
186
|
temp_id: temp_id,
|
187
187
|
method: method,
|
188
|
-
payload_path: ["included", included_idx]
|
188
|
+
payload_path: ["included", included_idx]
|
189
189
|
},
|
190
190
|
attributes: attributes,
|
191
|
-
relationships: relationships
|
191
|
+
relationships: relationships
|
192
192
|
}
|
193
193
|
end
|
194
194
|
|
data/lib/graphiti/errors.rb
CHANGED
@@ -143,8 +143,13 @@ module Graphiti
|
|
143
143
|
def message
|
144
144
|
allow = @filter.values[0][:allow]
|
145
145
|
deny = @filter.values[0][:deny]
|
146
|
+
value_string = if @value == "(empty)"
|
147
|
+
"empty value"
|
148
|
+
else
|
149
|
+
"value #{@value.inspect}"
|
150
|
+
end
|
146
151
|
msg = <<-MSG
|
147
|
-
#{@resource.class.name}: tried to filter on #{@filter.keys[0].inspect}, but passed invalid
|
152
|
+
#{@resource.class.name}: tried to filter on #{@filter.keys[0].inspect}, but passed invalid #{value_string}.
|
148
153
|
MSG
|
149
154
|
msg << "\nAllowlist: #{allow.inspect}" if allow
|
150
155
|
msg << "\nDenylist: #{deny.inspect}" if deny
|
@@ -189,7 +194,7 @@ module Graphiti
|
|
189
194
|
|
190
195
|
Make sure the endpoint "#{@sideload.resource.endpoint[:full_path]}" exists with action #{@action.inspect}, or customize the endpoint for #{@sideload.resource.class.name}.
|
191
196
|
|
192
|
-
If you do not wish to generate a link, pass link: false or set self.
|
197
|
+
If you do not wish to generate a link, pass link: false or set self.autolink = false.
|
193
198
|
MSG
|
194
199
|
end
|
195
200
|
end
|
@@ -316,14 +321,14 @@ module Graphiti
|
|
316
321
|
sortable: "sort on",
|
317
322
|
filterable: "filter on",
|
318
323
|
readable: "read",
|
319
|
-
writable: "write"
|
324
|
+
writable: "write"
|
320
325
|
}[@flag]
|
321
326
|
else
|
322
327
|
{
|
323
328
|
sortable: "add sort",
|
324
329
|
filterable: "add filter",
|
325
330
|
readable: "read",
|
326
|
-
writable: "write"
|
331
|
+
writable: "write"
|
327
332
|
}[@flag]
|
328
333
|
end
|
329
334
|
end
|
@@ -722,6 +727,21 @@ module Graphiti
|
|
722
727
|
end
|
723
728
|
|
724
729
|
class RecordNotFound < Base
|
730
|
+
def initialize(resource = nil, id = nil, path = nil)
|
731
|
+
@resource = resource
|
732
|
+
@id = id
|
733
|
+
@path = path
|
734
|
+
end
|
735
|
+
|
736
|
+
def message
|
737
|
+
if !@resource.nil? && !@id.nil?
|
738
|
+
"The referenced resource '#{@resource}' with id '#{@id}' could not be found.".tap do |msg|
|
739
|
+
msg << " Referenced at '#{@path}'" unless @path.nil?
|
740
|
+
end
|
741
|
+
else
|
742
|
+
"Specified Record Not Found"
|
743
|
+
end
|
744
|
+
end
|
725
745
|
end
|
726
746
|
|
727
747
|
class RequiredFilter < Base
|
data/lib/graphiti/query.rb
CHANGED
@@ -232,7 +232,7 @@ module Graphiti
|
|
232
232
|
return true if @resource.remote?
|
233
233
|
|
234
234
|
if (att = @resource.get_attr(name, flag, request: true))
|
235
|
-
|
235
|
+
att
|
236
236
|
else
|
237
237
|
not_associated_name = !@resource.class.association_names.include?(name)
|
238
238
|
not_associated_type = !@resource.class.association_types.include?(name)
|
@@ -262,8 +262,8 @@ module Graphiti
|
|
262
262
|
def parse_fieldset(fieldset)
|
263
263
|
{}.tap do |hash|
|
264
264
|
fieldset.each_pair do |type, fields|
|
265
|
-
type
|
266
|
-
fields
|
265
|
+
type = type.to_sym
|
266
|
+
fields = fields.split(",") unless fields.is_a?(Array)
|
267
267
|
hash[type] = fields.map(&:to_sym)
|
268
268
|
end
|
269
269
|
end
|
@@ -282,7 +282,7 @@ module Graphiti
|
|
282
282
|
|
283
283
|
def sort_hash(attr)
|
284
284
|
value = attr[0] == "-" ? :desc : :asc
|
285
|
-
key
|
285
|
+
key = attr.sub("-", "").to_sym
|
286
286
|
|
287
287
|
{key => value}
|
288
288
|
end
|
data/lib/graphiti/railtie.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
module Graphiti
|
2
2
|
class RequestValidator
|
3
3
|
delegate :validate,
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
:validate!,
|
5
|
+
:errors,
|
6
|
+
:deserialized_payload,
|
7
|
+
to: :@validator
|
8
8
|
|
9
9
|
def initialize(root_resource, raw_params)
|
10
10
|
@validator = ValidatorFactory.create(root_resource, raw_params)
|
@@ -5,7 +5,7 @@ module Graphiti
|
|
5
5
|
if required_payload? && payload_matches_endpoint?
|
6
6
|
super
|
7
7
|
else
|
8
|
-
|
8
|
+
false
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
@@ -36,7 +36,6 @@ module Graphiti
|
|
36
36
|
attribute_mismatch([:data, :id])
|
37
37
|
end
|
38
38
|
|
39
|
-
|
40
39
|
meta_type = @raw_params.dig(:data, :type)
|
41
40
|
|
42
41
|
# NOTE: calling #to_s and comparing 2 strings is slower than
|
@@ -25,7 +25,7 @@ module Graphiti
|
|
25
25
|
|
26
26
|
def validate!
|
27
27
|
unless validate
|
28
|
-
raise @error_class || Graphiti::Errors::InvalidRequest,
|
28
|
+
raise @error_class || Graphiti::Errors::InvalidRequest, errors
|
29
29
|
end
|
30
30
|
|
31
31
|
true
|
@@ -47,7 +47,7 @@ module Graphiti
|
|
47
47
|
def process_relationships(resource, relationships, payload_path)
|
48
48
|
opts = {
|
49
49
|
resource: resource,
|
50
|
-
relationships: relationships
|
50
|
+
relationships: relationships
|
51
51
|
}
|
52
52
|
|
53
53
|
Graphiti::Util::RelationshipPayload.iterate(opts) do |x|
|
@@ -22,7 +22,7 @@ module Graphiti
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def type=(val)
|
25
|
-
val = val
|
25
|
+
val = val&.to_sym
|
26
26
|
if (val = super)
|
27
27
|
serializer.type(val)
|
28
28
|
end
|
@@ -42,7 +42,7 @@ module Graphiti
|
|
42
42
|
path: val,
|
43
43
|
full_path: val,
|
44
44
|
url: val,
|
45
|
-
actions: [:index, :show]
|
45
|
+
actions: [:index, :show]
|
46
46
|
}
|
47
47
|
end
|
48
48
|
|
@@ -82,7 +82,8 @@ module Graphiti
|
|
82
82
|
:attributes_schema_by_default,
|
83
83
|
:relationships_readable_by_default,
|
84
84
|
:relationships_writable_by_default,
|
85
|
-
:filters_accept_nil_by_default
|
85
|
+
:filters_accept_nil_by_default,
|
86
|
+
:filters_deny_empty_by_default
|
86
87
|
|
87
88
|
class << self
|
88
89
|
prepend Overrides
|
@@ -104,6 +105,7 @@ module Graphiti
|
|
104
105
|
default(klass, :relationships_readable_by_default, true)
|
105
106
|
default(klass, :relationships_writable_by_default, true)
|
106
107
|
default(klass, :filters_accept_nil_by_default, false)
|
108
|
+
default(klass, :filters_deny_empty_by_default, false)
|
107
109
|
|
108
110
|
unless klass.config[:attributes][:id]
|
109
111
|
klass.attribute :id, :integer_id
|
@@ -197,7 +199,7 @@ module Graphiti
|
|
197
199
|
attributes: {},
|
198
200
|
extra_attributes: {},
|
199
201
|
sideloads: {},
|
200
|
-
callbacks: {}
|
202
|
+
callbacks: {}
|
201
203
|
}
|
202
204
|
end
|
203
205
|
|
@@ -32,7 +32,8 @@ module Graphiti
|
|
32
32
|
dependencies: opts[:dependent],
|
33
33
|
required: required,
|
34
34
|
operators: operators.to_hash,
|
35
|
-
allow_nil: opts.fetch(:allow_nil, filters_accept_nil_by_default)
|
35
|
+
allow_nil: opts.fetch(:allow_nil, filters_accept_nil_by_default),
|
36
|
+
deny_empty: opts.fetch(:deny_empty, filters_deny_empty_by_default)
|
36
37
|
}
|
37
38
|
elsif (type = args[0])
|
38
39
|
attribute name, type, only: [:filterable], allow: opts[:allow]
|
@@ -55,7 +56,7 @@ module Graphiti
|
|
55
56
|
|
56
57
|
if get_attr(name, :sortable, raise_error: :only_unsupported)
|
57
58
|
config[:sorts][name] = {
|
58
|
-
proc: blk
|
59
|
+
proc: blk
|
59
60
|
}.merge(opts.slice(:only))
|
60
61
|
elsif (type = args[0])
|
61
62
|
attribute name, type, only: [:sortable]
|
@@ -78,7 +79,7 @@ module Graphiti
|
|
78
79
|
def default_filter(name = nil, &blk)
|
79
80
|
name ||= :__default
|
80
81
|
config[:default_filters][name.to_sym] = {
|
81
|
-
filter: blk
|
82
|
+
filter: blk
|
82
83
|
}
|
83
84
|
end
|
84
85
|
|
@@ -131,7 +132,7 @@ module Graphiti
|
|
131
132
|
readable: true,
|
132
133
|
writable: false,
|
133
134
|
sortable: false,
|
134
|
-
filterable: false
|
135
|
+
filterable: false
|
135
136
|
}
|
136
137
|
options = defaults.merge(options)
|
137
138
|
config[:extra_attributes][name] = options
|
@@ -39,7 +39,7 @@ module Graphiti
|
|
39
39
|
path: path,
|
40
40
|
full_path: full_path_for(path),
|
41
41
|
url: url_for(path),
|
42
|
-
actions: DEFAULT_ACTIONS.dup
|
42
|
+
actions: DEFAULT_ACTIONS.dup
|
43
43
|
}
|
44
44
|
end
|
45
45
|
|
@@ -49,7 +49,7 @@ module Graphiti
|
|
49
49
|
path: path,
|
50
50
|
full_path: full_path_for(path),
|
51
51
|
url: url_for(path),
|
52
|
-
actions: actions
|
52
|
+
actions: actions
|
53
53
|
}
|
54
54
|
end
|
55
55
|
|
@@ -60,7 +60,7 @@ module Graphiti
|
|
60
60
|
path: path,
|
61
61
|
full_path: full_path_for(path),
|
62
62
|
url: url_for(path),
|
63
|
-
actions: actions
|
63
|
+
actions: actions
|
64
64
|
}]
|
65
65
|
end
|
66
66
|
|
@@ -89,7 +89,8 @@ module Graphiti
|
|
89
89
|
|
90
90
|
def update(update_params, meta = nil)
|
91
91
|
model_instance = nil
|
92
|
-
id = update_params
|
92
|
+
id = update_params[:id]
|
93
|
+
update_params = update_params.except(:id)
|
93
94
|
|
94
95
|
run_callbacks :persistence, :update, update_params, meta do
|
95
96
|
run_callbacks :attributes, :update, update_params, meta do |params|
|
@@ -67,7 +67,8 @@ module Graphiti
|
|
67
67
|
end
|
68
68
|
|
69
69
|
def resource_for_model(model)
|
70
|
-
resource = children.find { |c| model.
|
70
|
+
resource = children.find { |c| model.class == c.model } ||
|
71
|
+
children.find { |c| model.is_a?(c.model) }
|
71
72
|
if resource.nil?
|
72
73
|
raise Errors::PolymorphicResourceChildNotFound.new(self, model: model)
|
73
74
|
else
|
data/lib/graphiti/runner.rb
CHANGED
data/lib/graphiti/schema.rb
CHANGED
@@ -33,7 +33,7 @@ module Graphiti
|
|
33
33
|
{
|
34
34
|
resources: generate_resources,
|
35
35
|
endpoints: generate_endpoints,
|
36
|
-
types: generate_types
|
36
|
+
types: generate_types
|
37
37
|
}
|
38
38
|
end
|
39
39
|
|
@@ -94,7 +94,7 @@ module Graphiti
|
|
94
94
|
extra_attributes: extra_attributes(r),
|
95
95
|
sorts: sorts(r),
|
96
96
|
filters: filters(r),
|
97
|
-
relationships: relationships(r)
|
97
|
+
relationships: relationships(r)
|
98
98
|
}
|
99
99
|
|
100
100
|
if r.default_sort
|
@@ -121,7 +121,7 @@ module Graphiti
|
|
121
121
|
name: r.name,
|
122
122
|
description: r.description,
|
123
123
|
remote: r.remote_url,
|
124
|
-
relationships: relationships(r)
|
124
|
+
relationships: relationships(r)
|
125
125
|
}
|
126
126
|
}
|
127
127
|
|
@@ -136,7 +136,7 @@ module Graphiti
|
|
136
136
|
type: config[:type].to_s,
|
137
137
|
readable: flag(config[:readable]),
|
138
138
|
writable: flag(config[:writable]),
|
139
|
-
description: resource.attribute_description(name)
|
139
|
+
description: resource.attribute_description(name)
|
140
140
|
}
|
141
141
|
end
|
142
142
|
end
|
@@ -149,7 +149,7 @@ module Graphiti
|
|
149
149
|
attrs[name] = {
|
150
150
|
type: config[:type].to_s,
|
151
151
|
readable: flag(config[:readable]),
|
152
|
-
description: resource.attribute_description(name)
|
152
|
+
description: resource.attribute_description(name)
|
153
153
|
}
|
154
154
|
end
|
155
155
|
end
|
@@ -186,7 +186,7 @@ module Graphiti
|
|
186
186
|
|
187
187
|
config = {
|
188
188
|
type: filter[:type].to_s,
|
189
|
-
operators: filter[:operators].keys.map(&:to_s)
|
189
|
+
operators: filter[:operators].keys.map(&:to_s)
|
190
190
|
}
|
191
191
|
|
192
192
|
config[:single] = true if filter[:single]
|
data/lib/graphiti/scope.rb
CHANGED
@@ -3,10 +3,10 @@ module Graphiti
|
|
3
3
|
attr_accessor :object, :unpaginated_object
|
4
4
|
attr_reader :pagination
|
5
5
|
def initialize(object, resource, query, opts = {})
|
6
|
-
@object
|
7
|
-
@resource
|
8
|
-
@query
|
9
|
-
@opts
|
6
|
+
@object = object
|
7
|
+
@resource = resource
|
8
|
+
@query = query
|
9
|
+
@opts = opts
|
10
10
|
|
11
11
|
@object = @resource.around_scoping(@object, @query.hash) { |scope|
|
12
12
|
apply_scoping(scope, opts)
|
@@ -75,7 +75,7 @@ module Graphiti
|
|
75
75
|
resource: @resource,
|
76
76
|
params: @opts[:params],
|
77
77
|
sideload: @opts[:sideload],
|
78
|
-
parent: @opts[:parent]
|
78
|
+
parent: @opts[:parent]
|
79
79
|
# Set once data is resolved within block
|
80
80
|
# results: ...
|
81
81
|
}
|