Module: reverse-map-query

System-internal reverse maps are used to search backwards (upwards) in the ONE object tree. It is easy to follow the links in objects to find a leaf node, but to go the other way and find which higher level objects link to a (given) lower-level one is made possible by these maps. Each time a ONE object is written that links to another object the reverse map belonging to the linked (targeted) object is updated.

There is a reverse map

  1. for each unversioned object, or for each ID object of a versioned object, and
  2. for each type of object that links to the object.

The second point leads to having a variable number of reverse maps for each object, it is an optimization that assumes that there may be quite a lot of entries and that the most common use case probably is to look for links to a given object only from a certain type of object, so that having to sift through all links from all types of objects each time is unnecessary effort.

For example, if we have an app that stores the contents of a user's IMAP folder in ONE we may have ONE objects for Email and Mailbox. It is easy to find which Emails are in any given Mailbox object because the Email objects are directly linked from there. However, when given an Email object, to find out which Mailbox objects link to it - after all, any email is found in several IMAP mailboxes - we need to consult the reverse map for the given Email object which contains the map of Mailbox objects linking to it. It was updated each time a(ny) Mailbox object was written that contained a link to this Email object. There will be other reverse map files for other types of objects linking to the Email object.

Map name pattern:

${id-hash}.${type}

The "H" (for "Hash") indicates that this is a map for an unversioned (single) object, the "I" (for "ID hash") shows it is for a versioned object (with many objects).

We could of course find out if a given hash is the hash of a concrete object (unversioned) or of an ID-object (versioned object), but this requires additional effort (both I/O and CPU). By having this one letter as part of the name, and at a fixed position, we can use that information much more easily if we need it.

Similar for the type string at the end of the filename. We could read the hash we found in the map and find the type, but this comes at a cost. By having it in the name we can select the appropriate reverse map using this simple naming pattern without any effort.

Format:

targetObjHash,referencingObjIdHash,referencingObjHash
targetObjHash,referencingObjIdHash,referencingObjHash
targetObjHash,referencingObjIdHash,referencingObjHash
...
Source:

Methods

(async, static) getOnlyLatestReferencingObjsHashAndId(targetHash, typeOfReferencingObj, createdAfteropt) → {Promise.<Array.<HashAndIdHashAndTimestamp>>}

Parameters:
Name Type Attributes Description
targetHash SHA256Hash | SHA256IdHash

Object owning the reverse map to query. For versioned objects this must be an ID hash.

typeOfReferencingObj OneVersionedObjectTypeNames

The specific reverse map from fromHash back to any object of this type with a hash link to idHash or one of the concrete versions

createdAfter number <optional>

Optional timestamp: The most current object is included into the final result only if it has a version map timestamp after this time

Frontend to getAllEntries which only returns entries that point to the most current version of a referencing object.

This function is only useful if the reverse map is for referencing objects that are versioned. If it is called for an unversioned referencing object type, where the reverse map has no entries for ID hashes (the 2nd hash is empty), it throws an Error.

The function takes the results returned by reverse-map-query.getAllEntries and uses the referencing object ID hashes (2nd reverse map column) to load the version maps for those objects. It then checks if any of the concrete version hashes for each ID hash is the most current version of that object. It returns only those concrete object hashes for which this is the case.

The original use case for this function is checking access rights: Both Access and Group objects are versioned, and both only grant access through the latest version. If a Person once was member of a group but is not a member in the latest version of the group they should not get access. Similar for Access objects which revoke previously granted access to a ONE object.

Source:
Throws:

Throws an error if the given 2nd parameter toType is not a versioned object type (only versioned objects can have a "most current" version)

Type: Error

Returns:

Returns an array of triples of hash, ID hash and timestamp of the latest version of versioned objects referencing the object the reverse map is for. Note that this function guarantees that there always are ID hashes, since it throws an Error if invoked for unversioned object type reverse maps.

Type: Promise.<Array.<HashAndIdHashAndTimestamp>>

(async, static) getOnlyLatestReferencingObjsHash(targetHash, typeOfReferencingObj, createdAfteropt) → {Promise.<Array.<SHA256Hash>>}

Parameters:
Name Type Attributes Description
targetHash SHA256Hash | SHA256IdHash

Object owning the reverse map to query. For versioned objects this must be an ID hash.

typeOfReferencingObj OneVersionedObjectTypeNames

The specific reverse map from fromHash back to any object of this type with a hash link to idHash or one of the concrete versions

createdAfter number <optional>

Optional timestamp: The most current object is included into the final result only if it has a version map timestamp after this time

Same as getOnlyLatestReferencingObjsHashAndId but only returns the hashes and not the ID hashes and timestamps.

Source:
Throws:

Throws an error if the given 2nd parameter toType is not a versioned object type (only versioned objects can have a "most current" version)

Type: Error

Returns:

Returns an array of triples of hash, ID hash and timestamp of the latest version of versioned objects referencing the object the reverse map is for. Note that this function guarantees that there always are ID hashes, since it throws an Error if invoked for unversioned object type reverse maps.

Type: Promise.<Array.<SHA256Hash>>

(async, static) getAllEntries(targetHash, typeOfReferencingObj) → {Promise.<Array.<ReverseMapEntry>>}

Parameters:
Name Type Description
targetHash SHA256Hash | SHA256IdHash

Object owning the reverse map to query. For versioned objects this must be an ID hash.

typeOfReferencingObj OneVersionedObjectTypeNames

The specific reverse map from idHash back to any object of this type with a hash link to idHash or one of the concrete versions

Reads the given reverse map and returns the data in a 1:N hash => hashes form.

A non-existent map file is not an error, it simply means no object references the one the given reverse map is for.

The given reverse map filename is checked against the expected pattern for these files, which is Hash-of-object-the-map-is-for.Object.ReferencingOneObjectTypeName and an Error is thrown if the pattern does not fit.

Source:
Returns:

Type: Promise.<Array.<ReverseMapEntry>>

(async, static) getAllIdObjectEntries(targetHash, typeOfReferencingObj) → {Promise.<Array.<ReverseMapEntry>>}

Parameters:
Name Type Description
targetHash SHA256Hash | SHA256IdHash

Object owning the reverse map to query. For versioned objects this must be an ID hash.

typeOfReferencingObj OneVersionedObjectTypeNames

The specific reverse map from idHash back to any object of this type with a hash link to idHash or one of the concrete versions

Obtains the hashes of all IdObjects that reference the targetHash.

A non-existent map file is not an error, it simply means no object references the one the given reverse map is for.

The given reverse map filename is checked against the expected pattern for these files, which is Hash-of-object-the-map-is-for.IdObject.ReferencingOneObjectTypeName and an Error is thrown if the pattern does not fit.

Source:
Returns:

Type: Promise.<Array.<ReverseMapEntry>>