Skip to content

Custom field data storage model #1965

@hahn-kev

Description

@hahn-kev

Because custom fields are user defined they represent a difficult problem for type safety, JSON serialization and ease of use. Because we need to support custom fields on Entries, Senses, and Examples, it makes sense to have a single class which encapsulates all custom field data. Eg:

public class Entry {
  //existing properties...
  public CustomFields CustomFieldData {get;set;}
}

public class CustomFields {
  //... data here
}

In order to have good type safety and serialization handling each type of custom field will be stored in it's own dictionary. For example:

public class CustomFields {
  public Dictonary<CustomFieldId, DateTime> DateTimes {get; set;}
  public Dictonary<CustomFieldId, decimal> Numbers {get; set;}
}

This does introduce the potential for this:

var customFieldId = //get from somewhere
var customFieldData = entry.CustomFieldData;
customFieldData.DateTimes[customFieldId] = DateTime.Now;
customFieldData.Numbers[customFieldId] = 456;

I think this is acceptable and because all modifications go through Harmony changes I think we can prevent this with validation.

The last concern is for relations and deleting data. Harmony objects like Entries need to expose the Guids of objects they reference. All custom field data references the Custom Field Definition, and some custom field types reference option types, either one or many. If one of those options are deleted, then the reference needs to be removed from custom fields. This will be handled like this:

public class Entry {
  public Guid[] GetReferences()
    return CustomFieldData.GetReferences();
  }
}
public class CustomFields {
  public Guid[] GetReferences()
    return [
      ..DateTimes.Keys
//etc for all keys
      ..ObjectRefs.Values
      ..ObjectsRefs.Values.SelectMany()
    ]
  }
}

Similar for removing references, entry will also call CustomFields.RemoveReference which will then react accordingly. It may just remove object refs, it may also remove data in case a CustomField is actually deleted.

This does leave a potential problem, this is that a CustomFieldId is not be enough to determine where the data it wants is stored. Each dictonary of data would need to be checked unless the custom field type is also known. I'm not too concerned about this use case, but it is something worth considering when actually writing code.

It's also worth considering what changes might look like. One could be json patch that uses the path to the value and includes a reference to the custom field Id in the path. Another would be a dedicated Change type per Field Type, eg SetCustomDate(Guid entryId, CustomFieldId fieldId, DateTime value) this would probably be the simplest and make it easiest to reason about each change type.

Metadata

Metadata

Assignees

No one assigned

    Labels

    📖 MiniLcmissues related to miniLcm library code, includes fwdat bridge and lcmCrdt

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions