Skip to content

Consider Adding an API to DataField to allow Custom Handling for Differential Updates #11978

Closed
@LukeAbby

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 like ForeignDocumentField 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

Labels

apiIssues related to the API used by Mod Devsdata-modelsIssues related to data models and schema changes

Type

No type

Projects

Relationships

None yet

Development

No branches or pull requests

Issue actions