Module: GraphWeaver::ErrorFiltering
Overview
Shared filtering over a collection of GraphQLErrors, for surfacing field-level failures programmatically. Host must define #errors.
Instance Method Summary collapse
- #data ⇒ Object
- #each_error(&block) ⇒ Object
-
#entity_id(error) ⇒ Object
The id of the record an error points into, resolved by walking the error's path through the (partial) typed data: an error at ["people", 3, "email"] resolves to people.id.
-
#errors ⇒ Object
the host's interface, overridden by its attr_readers.
-
#errors_at(path) ⇒ Object
Errors touching a field path — "user.email" or ["user", "email"]; prefix match, so deeper errors count too.
-
#errors_by_field ⇒ Object
Errors grouped by the field they point at (index-stripped dotted path; nil key for global errors) — iterate with each_error:.
-
#report ⇒ Object
The user-facing rollup: errors keyed by field, with the ids of the actual records that failed inlined — "the 3 in people.3.email is useless to a user; people.email plus which people is the answer".
-
#schema_stale? ⇒ Boolean
True when any error looks like the server rejected the query's shape — the schema has likely changed since the module was generated.
Instance Method Details
#data ⇒ Object
170 171 172 |
# File 'lib/graph_weaver/errors.rb', line 170 def data raise NotImplementedError, "#{self.class} must define #data" end |
#each_error(&block) ⇒ Object
200 201 202 |
# File 'lib/graph_weaver/errors.rb', line 200 def each_error(&block) errors_by_field.each(&block) end |
#entity_id(error) ⇒ Object
The id of the record an error points into, resolved by walking the error's path through the (partial) typed data: an error at ["people", 3, "email"] resolves to people.id. nil when the data is missing, the path doesn't walk, or the record has no id field.
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 |
# File 'lib/graph_weaver/errors.rb', line 208 def entity_id(error) # untyped by nature: the walk traverses whatever structs this query # generated, reassigning across types at each step node = T.let(data, T.untyped) return unless node && error.path error.path[0..-2].each do |segment| node = if segment.is_a?(Integer) || segment.to_s.match?(/\A\d+\z/) node.is_a?(Array) ? node[segment.to_i] : nil else prop = GraphWeaver::Inflect.underscore(segment.to_s).to_sym node.respond_to?(prop) ? node.public_send(prop) : nil end return if node.nil? end node.respond_to?(:id) ? node.id : nil end |
#errors ⇒ Object
the host's interface, overridden by its attr_readers
166 167 168 |
# File 'lib/graph_weaver/errors.rb', line 166 def errors raise NotImplementedError, "#{self.class} must define #errors" end |
#errors_at(path) ⇒ Object
Errors touching a field path — "user.email" or ["user", "email"]; prefix match, so deeper errors count too. List indices appear as path segments ("people.0.email").
177 178 179 180 |
# File 'lib/graph_weaver/errors.rb', line 177 def errors_at(path) want = (path.is_a?(String) ? path.split(".") : path).map(&:to_s) errors.select { |error| error.path && error.path.map(&:to_s).first(want.size) == want } end |
#errors_by_field ⇒ Object
Errors grouped by the field they point at (index-stripped dotted path; nil key for global errors) — iterate with each_error:
response.each_error do |field, errors|
form.add_error(field, errors.map(&:message))
end
196 197 198 |
# File 'lib/graph_weaver/errors.rb', line 196 def errors_by_field errors.group_by(&:field) end |
#report ⇒ Object
The user-facing rollup: errors keyed by field, with the ids of the actual records that failed inlined — "the 3 in people.3.email is useless to a user; people.email plus which people is the answer".
{ "people.email" => { "messages" => [...], "codes" => [...],
"entity_ids" => ["7", "9"], "errors" => [full to_h...] } }
233 234 235 236 237 238 239 240 241 242 |
# File 'lib/graph_weaver/errors.rb', line 233 def report errors_by_field.to_h do |field, field_errors| [field, { "messages" => field_errors.map(&:message), "codes" => field_errors.filter_map(&:code).uniq, "entity_ids" => field_errors.filter_map { |e| entity_id(e) }.uniq, "errors" => field_errors.map(&:to_h), }] end end |
#schema_stale? ⇒ Boolean
True when any error looks like the server rejected the query's shape — the schema has likely changed since the module was generated. Refresh the schema dump and regenerate (rake graph_weaver:schema:refresh && rake graph_weaver:generate).
186 187 188 |
# File 'lib/graph_weaver/errors.rb', line 186 def schema_stale? errors.any?(&:validation?) end |