donmccurdy/property-graph

Create formal Ref/RefList/RefMap types

donmccurdy opened this issue · 5 comments

The current Ref, RefList, and RefMap concepts are loosely typed and detected at runtime. E.g. any empty object is assumed to be a RefMap. That holds up in my own implementation but is 'weird' as an API. Moreover, it would be useful to be able to remove things from a RefList in O(1) time (see donmccurdy/glTF-Transform#520 (reply in thread)) and so for that the implementation needs to be abstracted from the semantic meaning a bit, to implement a list-like API with a Set.

Testing in https://jsben.ch/o1OIh, performance seems pretty similar whether these are object literals or (small) class instances. Iteration speed will decrease a bit with a Set instead of an array.

// before
interface IPerson {
  name: string;
  age: number;
  friends: Person[];
  pet: Pet;
}

// after
interface IPerson {
  name: string;
  age: number;
  friends: RefList<Person>;
  pet: Ref<Pet>;
}

Relevant Set operations.

This change could also be made internally without changing the public API. More complicated and ultimately less ideal, but lets me delay a breaking API change for a while.

Unfortunately I think a breaking change is required to make this update properly. It's worth doing, but will be delayed a bit. Perhaps mid-2022.

Important note — Sets don't allow duplicates. For my purposes, that may be a problem.

Possible solution here would be to create distinct RefSet vs. RefList structures, probably with the same API. RefSet could be used for GLTF.IRoot and other property types that don't allow duplicates anyway.

Linked lists might also support everything needed from RefSet/RefList.

This could be implemented (at least for testing) without a breaking change. When addRef or removeRef are called and the list is not a RefList/RefSet, we'd just convert it as a one-time operation at that time. TypeScript definitions turn into a tangled mess, nope.