graphiti 1.2.35 → 1.2.40

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5aaea1da30c8eb6b86abc1be0df8fba47d2df8f55be42f6141f78976a2c02dea
4
- data.tar.gz: c4611d1226bc10b04a755e29943bc131831cb9df23cb55480ab3daa3cfa8d4b5
3
+ metadata.gz: d10b110934848ed53d75bb0b8595f73c50524833818d39dc53f3859c393d342b
4
+ data.tar.gz: a28ab64e8453486628ee93d131914479c24d60ade77e8dd201030bbe68dd055c
5
5
  SHA512:
6
- metadata.gz: 20c0ca9615484a566e528c5851702dfff7436c37e3ccf7774ef37611699397870bb74be19f633b1dfc9eca9c315642a29777412c66823550290bca8406e6a254
7
- data.tar.gz: 1edb1ae4364f3b348fa74dffc6c8a794b0e54d39289144614e0c9e605e0dc3df6f850ea72b7117f99a72725ffc9cf536cda93a9694ee3a39a7cc21748405973b
6
+ metadata.gz: 1d1d78896c8079cfbc4e74f3f6b754047a5c597adfe87023340adae7c56029ef60873c5cfe91fd099d7aac7965db7048dfb45e10efa8d29a39e4cdbfc19d99e3
7
+ data.tar.gz: f563f24c252c72e49a8bc8ba52ac8a6c5ab814d7699817fce981adee68dc74edc6e3dc82f2a5fdc5986e1b07411fbad776df5bba7099baeae930b305a03e0b92
@@ -74,19 +74,22 @@ module Graphiti
74
74
  name_chain << k unless name_chain.last == k
75
75
 
76
76
  unless remote_resource? && serializers.nil?
77
- attrs[name.to_sym] = if serializers.is_a?(Array)
78
- serializers.map do |rr|
77
+ payload = if serializers.is_a?(Array)
78
+ data = serializers.map { |rr|
79
79
  rr.to_hash(fields: fields, include: nested_include, graphql: graphql, name_chain: name_chain)
80
- end
80
+ }
81
+ graphql ? {nodes: data} : data
81
82
  elsif serializers.nil?
82
83
  if @resource.class.respond_to?(:sideload)
83
84
  if @resource.class.sideload(k).type.to_s.include?("_many")
84
- []
85
+ graphql ? {nodes: []} : []
85
86
  end
86
87
  end
87
88
  else
88
89
  serializers.to_hash(fields: fields, include: nested_include, graphql: graphql, name_chain: name_chain)
89
90
  end
91
+
92
+ attrs[name.to_sym] = payload
90
93
  end
91
94
  end
92
95
 
@@ -133,29 +136,58 @@ module Graphiti
133
136
  serializers = options[:data]
134
137
  opts = options.slice(:fields, :include)
135
138
  opts[:graphql] = @graphql
136
- to_hash(serializers, opts).tap do |hash|
137
- hash.merge!(options.slice(:meta)) unless options[:meta].empty?
138
- end
139
+ top_level_key = get_top_level_key(@resource, serializers.is_a?(Array))
140
+
141
+ hash = {top_level_key => {}}
142
+ nodes = get_nodes(serializers, opts)
143
+ add_nodes(hash, top_level_key, options, nodes, @graphql)
144
+ add_stats(hash, top_level_key, options, @graphql)
145
+ hash
139
146
  end
140
147
 
141
148
  private
142
149
 
143
- def to_hash(serializers, opts)
144
- {}.tap do |hash|
145
- top_level_key = :data
146
- if @graphql
147
- top_level_key = @resource.graphql_entrypoint
148
- unless serializers.is_a?(Array)
149
- top_level_key = top_level_key.to_s.singularize.to_sym
150
- end
150
+ def get_top_level_key(resource, is_many)
151
+ key = :data
152
+
153
+ if @graphql
154
+ key = @resource.graphql_entrypoint
155
+ key = key.to_s.singularize.to_sym unless is_many
156
+ end
157
+
158
+ key
159
+ end
160
+
161
+ def get_nodes(serializers, opts)
162
+ if serializers.is_a?(Array)
163
+ serializers.map do |s|
164
+ s.to_hash(**opts)
151
165
  end
166
+ else
167
+ serializers.to_hash(**opts)
168
+ end
169
+ end
170
+
171
+ def add_nodes(hash, top_level_key, opts, nodes, graphql)
172
+ payload = nodes
173
+ if graphql && nodes.is_a?(Array)
174
+ payload = {nodes: nodes}
175
+ end
152
176
 
153
- hash[top_level_key] = if serializers.is_a?(Array)
154
- serializers.map do |s|
155
- s.to_hash(**opts)
177
+ # Don't render nodes if we only requested stats
178
+ unless graphql && opts[:fields].values == [[:stats]]
179
+ hash[top_level_key] = payload
180
+ end
181
+ end
182
+
183
+ def add_stats(hash, top_level_key, options, graphql)
184
+ if options[:meta] && !options[:meta].empty?
185
+ if @graphql
186
+ if (stats = options[:meta][:stats])
187
+ hash[top_level_key][:stats] = stats
156
188
  end
157
189
  else
158
- serializers.to_hash(**opts)
190
+ hash.merge!(options.slice(:meta))
159
191
  end
160
192
  end
161
193
  end
@@ -25,7 +25,7 @@ module Graphiti
25
25
  end
26
26
  end
27
27
 
28
- typecast_attributes(resource, deserialized_payload.attributes, deserialized_payload.meta[:payload_path])
28
+ typecast_attributes(resource, deserialized_payload.attributes, @action, deserialized_payload.meta[:payload_path])
29
29
  process_relationships(resource, deserialized_payload.relationships, deserialized_payload.meta[:payload_path])
30
30
  else
31
31
  errors.add(:"data.type", :missing)
@@ -65,15 +65,20 @@ module Graphiti
65
65
  next
66
66
  end
67
67
 
68
- typecast_attributes(x[:resource], x[:attributes], x[:meta][:payload_path])
69
- process_relationships(x[:resource], x[:relationships], x[:meta][:payload_path])
68
+ resource = x[:resource]
69
+ attributes = x[:attributes]
70
+ relationships = x[:relationships]
71
+ payload_path = x[:meta][:payload_path]
72
+ action = x[:meta][:method]
73
+ typecast_attributes(resource, attributes, action, payload_path)
74
+ process_relationships(resource, relationships, payload_path)
70
75
  end
71
76
  end
72
77
 
73
- def typecast_attributes(resource, attributes, payload_path)
78
+ def typecast_attributes(resource, attributes, action, payload_path)
74
79
  attributes.each_pair do |key, value|
75
80
  # Only validate id if create action, otherwise it's only used for lookup
76
- next if @action != :create &&
81
+ next if action != :create &&
77
82
  key == :id &&
78
83
  resource.class.config[:attributes][:id][:writable] == false
79
84
 
@@ -96,9 +96,14 @@ module Graphiti
96
96
  extra_attributes: extra_attributes(r),
97
97
  sorts: sorts(r),
98
98
  filters: filters(r),
99
- relationships: relationships(r)
99
+ relationships: relationships(r),
100
+ stats: stats(r)
100
101
  }
101
102
 
103
+ if r.grouped_filters.any?
104
+ config[:filter_group] = r.grouped_filters
105
+ end
106
+
102
107
  if r.default_sort
103
108
  default_sort = r.default_sort.map { |s|
104
109
  {s.keys.first.to_s => s.values.first.to_s}
@@ -165,6 +170,14 @@ module Graphiti
165
170
  end
166
171
  end
167
172
 
173
+ def stats(resource)
174
+ {}.tap do |stats|
175
+ resource.stats.each_pair do |name, config|
176
+ stats[name] = config.calculations.keys
177
+ end
178
+ end
179
+ end
180
+
168
181
  def sorts(resource)
169
182
  {}.tap do |s|
170
183
  resource.sorts.each_pair do |name, sort|
@@ -212,6 +225,10 @@ module Graphiti
212
225
  end
213
226
  end
214
227
 
228
+ def filter_group(resource)
229
+ resource.config[:grouped_filters]
230
+ end
231
+
215
232
  def relationships(resource)
216
233
  {}.tap do |r|
217
234
  resource.sideloads.each_pair do |name, config|
@@ -1,8 +1,8 @@
1
1
  module Graphiti
2
2
  class SchemaDiff
3
3
  def initialize(old, new)
4
- @old = old.deep_symbolize_keys
5
- @new = new.deep_symbolize_keys
4
+ @old = JSON.parse(old.to_json).deep_symbolize_keys
5
+ @new = JSON.parse(new.to_json).deep_symbolize_keys
6
6
  @errors = []
7
7
  end
8
8
 
@@ -30,6 +30,8 @@ module Graphiti
30
30
  compare_extra_attributes(r, new_resource)
31
31
  compare_sorts(r, new_resource)
32
32
  compare_filters(r, new_resource)
33
+ compare_filter_group(r, new_resource)
34
+ compare_stats(r, new_resource)
33
35
  compare_relationships(r, new_resource)
34
36
  end
35
37
  end
@@ -133,12 +135,12 @@ module Graphiti
133
135
  end
134
136
 
135
137
  if new_sort[:only] && !old_sort[:only]
136
- @errors << "#{old_resource[:name]}: sort #{name.inspect} now limited to only #{new_sort[:only].inspect}."
138
+ @errors << "#{old_resource[:name]}: sort #{name.inspect} now limited to only #{new_sort[:only].to_sym.inspect}."
137
139
  end
138
140
 
139
141
  if new_sort[:only] && old_sort[:only]
140
142
  if new_sort[:only] != old_sort[:only]
141
- @errors << "#{old_resource[:name]}: sort #{name.inspect} was limited to only #{old_sort[:only].inspect}, now limited to only #{new_sort[:only].inspect}."
143
+ @errors << "#{old_resource[:name]}: sort #{name.inspect} was limited to only #{old_sort[:only].to_sym.inspect}, now limited to only #{new_sort[:only].to_sym.inspect}."
142
144
  end
143
145
  end
144
146
  end
@@ -204,6 +206,44 @@ module Graphiti
204
206
  end
205
207
  end
206
208
 
209
+ def compare_filter_group(old_resource, new_resource)
210
+ if new_resource[:filter_group]
211
+ if old_resource[:filter_group]
212
+ new_names = new_resource[:filter_group][:names]
213
+ old_names = old_resource[:filter_group][:names]
214
+ diff = new_names - old_names
215
+ if !diff.empty? && new_resource[:filter_group][:required] == "all"
216
+ @errors << "#{old_resource[:name]}: all required filter group #{old_names.map(&:to_sym).inspect} added #{"member".pluralize(diff.length)} #{diff.map(&:to_sym).inspect}."
217
+ end
218
+
219
+ old_required = old_resource[:filter_group][:required]
220
+ new_required = new_resource[:filter_group][:required]
221
+ if old_required == "any" && new_required == "all"
222
+ @errors << "#{old_resource[:name]}: filter group #{old_names.map(&:to_sym).inspect} moved from required: :any to required: :all"
223
+ end
224
+ else
225
+ @errors << "#{old_resource[:name]}: filter group #{new_resource[:filter_group][:names].map(&:to_sym).inspect} was added."
226
+ end
227
+ end
228
+ end
229
+
230
+ def compare_stats(old_resource, new_resource)
231
+ return unless old_resource.key?(:stats)
232
+
233
+ old_resource[:stats].each_pair do |name, old_calculations|
234
+ new_calculations = new_resource[:stats][name]
235
+ if new_calculations
236
+ old_calculations.each do |calc|
237
+ unless new_calculations.include?(calc)
238
+ @errors << "#{old_resource[:name]}: calculation #{calc.to_sym.inspect} was removed from stat #{name.inspect}."
239
+ end
240
+ end
241
+ else
242
+ @errors << "#{old_resource[:name]}: stat #{name.inspect} was removed."
243
+ end
244
+ end
245
+ end
246
+
207
247
  def compare_endpoints
208
248
  @old[:endpoints].each_pair do |path, old_endpoint|
209
249
  unless (new_endpoint = @new[:endpoints][path])
@@ -137,11 +137,16 @@ module Graphiti
137
137
  end
138
138
 
139
139
  def link_extra_fields
140
+ return unless context&.respond_to?(:params)
141
+
140
142
  extra_fields_name = [association_name, resource.type].find { |param|
141
143
  context.params.dig(:extra_fields, param)
142
144
  }
143
145
 
144
- {resource.type => context.params.dig(:extra_fields, extra_fields_name)} if extra_fields_name
146
+ if extra_fields_name
147
+ extra_fields = context.params.dig(:extra_fields, extra_fields_name)
148
+ {resource.type => extra_fields}
149
+ end
145
150
  end
146
151
 
147
152
  # The parent resource is a remote,
@@ -16,13 +16,11 @@ module Graphiti
16
16
 
17
17
  if @name == :id
18
18
  @serializer.id(&proc)
19
- elsif @attr[:proc]
19
+ elsif @attr[:proc] ||
20
+ !previously_applied? ||
21
+ previously_applied_via_resource?
20
22
  @serializer.send(_method, @name, serializer_options, &proc)
21
- elsif @serializer.attribute_blocks[@name].nil?
22
- @serializer.send(_method, @name, serializer_options, &proc)
23
- elsif @serializer.send(applied_method).include?(@name)
24
- @serializer.field_condition_blocks[@name] = guard if guard?
25
- else
23
+ else # Previously applied via explicit serializer, so wrap it
26
24
  inner = @serializer.attribute_blocks.delete(@name)
27
25
  wrapped = wrap_proc(inner)
28
26
  @serializer.send(_method, @name, serializer_options, &wrapped)
@@ -34,6 +32,14 @@ module Graphiti
34
32
 
35
33
  private
36
34
 
35
+ def previously_applied?
36
+ @serializer.attribute_blocks[@name].present?
37
+ end
38
+
39
+ def previously_applied_via_resource?
40
+ @serializer.send(applied_method).include?(@name)
41
+ end
42
+
37
43
  def previously_guarded?
38
44
  @serializer.field_condition_blocks[@name]
39
45
  end
@@ -1,3 +1,3 @@
1
1
  module Graphiti
2
- VERSION = "1.2.35"
2
+ VERSION = "1.2.40"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphiti
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.35
4
+ version: 1.2.40
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lee Richmond
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-03-18 00:00:00.000000000 Z
11
+ date: 2021-04-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: jsonapi-serializable