Consider Adding an API to DataField to allow Custom Handling for Differential Updates #11978
Description
Context: Important parts of the API like actor.update
all eventually defer to DataField.#updateField
(the .#
to indicate a static-side private field).
In it there are special cases for the core "container" data models:
static #updateField(name, field, source, value, options) {
const {dryRun, fallback, recursive, restoreDelta, _collections, _singletons, _diff, _backup} = options;
let current = source?.[name]; // The current value may be null or undefined
// Special Case: Update Embedded Collection
if ( field instanceof EmbeddedCollectionField ) {
_backup[name] = current;
if ( !dryRun ) _collections[name].update(value, {fallback, recursive, restoreDelta});
return;
}
// Special Case: Update Embedded Document
if ( (field instanceof EmbeddedDocumentField) && _singletons[name] ) {
_diff[name] = _singletons[name].updateSource(value ?? {}, {dryRun, fallback, recursive, restoreDelta});
if ( isEmpty(_diff[name]) ) delete _diff[name];
return;
}
[...]
}
Specifically EmbeddedCollectionField
, EmbeddedDocumentField
, SchemaField
, EmbeddedDataField
, TypeDataField
, and ObjectField
all have special cases here.
However this leads to a footgun if you do something like this:
class RecordField extends DataField { ... }
In this case RecordField
is quite similar to ObjectField
but notably because it does not extend ObjectField
it does not receive differential updates. I've seen implementations like this before because the author simply didn't want it to get lumped in with instanceof ObjectField
checks or just not thinking of it etc.
This is quickly going to dive into hypotheticals but I can also see other use cases for this:
- Wanting to have a
SetField
that absorbs new elements (adds to the set) rather than overriding. - Adding something like a
PackField
/CompendiumField
or something else to operate on that. Sort of likeForeignDocumentField
but handling other things.
One way to allow this would be adding an abstract method DataField#_differentialUpdate
. I have no strong feelings on the name, this proposed name is a bit long, but such an API could help drive these behaviors.
I'll admit this is a fairly minor complaint and I see that the refactor could be a bit painful but I figured I'd raise an issue in case it was useful.
Metadata
Assignees
Type
Projects
Status
Done