sillsdev / sillsdev/languageforge-lexbox

Custom field data storage model

Open
#1,965 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

📖 MiniLcm
Dominant language
C#
Stars
9
Forks
8
Avg merge
2d 13h
Merged PRs (30d)
49

Description

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.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the proposed Entry and CustomFields classes in the issue, focusing on typed dictionaries, reference collection and removal, and how custom-field changes should be represented. Done requires an agreed and implemented storage model that supports Entries, Senses, and Examples, serialization, validation, reference cleanup, and change handling.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp
Domain
backend
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.