Class: Ecoportal::API::Common::GraphQL::Model::Diffable::LeafDiffService
- Inherits:
-
DiffService
- Object
- ClassicDiffService
- DiffService
- Ecoportal::API::Common::GraphQL::Model::Diffable::LeafDiffService
- Defined in:
- lib/ecoportal/api/common/graphql/model/diffable/leaf_diff_service.rb
Overview
Diff strategy for models whose array attributes are leaf DATA, not nested
GraphQL::Model children.
Array attributes declared with passarray (tag lists, id lists, config lists)
— and embeds_many id-collections written as a whole set (e.g. page locations)
— are registered as cascaded attributes. The default DiffService:
1. strips cascaded keys from the flat classic diff
(`doc_with_non_cascaded_attributes`), on the assumption that a later
`diff_reduce` pass re-adds them by cascading into nested `GraphQL::Model`
children; and
2. in `diff_reduce`, deletes the flat placeholder for every cascaded key and
only re-adds it when the child object `is_a?(GraphQL::Model)`.
A passarray is wrapped as a v2 ArrayModel and a whole-set embeds_many as a
CollectionModel — neither is a GraphQL::Model, so the re-add never happens and
the array change becomes invisible to as_update (scalar passthrough fields
are unaffected). This is the systemic "array/leaf fields don't diff" root cause
(see .ai-assistance/code/model_input_mapping/SYNTHESIS.md §3.1).
This service fixes it for leaf models by:
1. keeping cascaded keys in the flat classic diff (`doc_with_non_cascaded_attributes`
is a no-op), and
2. overriding `diff_reduce` so the flat-diff placeholder for a NON-model leaf
child is preserved (only real `GraphQL::Model` children are cascade-diffed;
`root!` children are still dropped as independent entities), and
3. treating a leaf array as an OPAQUE value: a change replaces the whole array
(a full-set replace), rather than the id-keyed nested update/delete/create
patch-ops the default array diff would emit. This matches how the write inputs
consume these arrays (`PageInput.otherTags`, `PageInput.locations = [{ id: }]`,
register `filterTags`, PresetView `fieldConfigurations`).
A model can either behave as a full leaf (call dirty?/as_update with
flat: true, as Base::Page::DataField does — it has no nested GraphQL::Model
children at all) or as a mixed model with both leaf arrays and real nested model
children (page / register / preset view — the default cascaded as_update still
recurses into the model children while the leaf arrays now diff inline).
Constant Summary
Constants included from HashDiffNesting
HashDiffNesting::META_KEYS, HashDiffNesting::NO_CHANGES
Instance Attribute Summary
Attributes inherited from ClassicDiffService
Method Summary
Methods inherited from DiffService
Methods included from HashHelpers
Methods included from HashHelpers::InstanceMethods
#deep_dup, #except_keys, #keys_to_s_deep, #keys_to_sym_deep, #remove_nil_keys_deep
Methods included from HashDiffNesting
Methods inherited from ClassicDiffService
Constructor Details
This class inherits a constructor from Ecoportal::API::Common::GraphQL::Model::Diffable::DiffService