@transitive-sdk/datacache
v0.14.1
Published
A class for storing data in a JSON object with change detection and change notifications. Ideal for building data-syncs.
Readme
DataCache
A class for storing data in a JSON object with change detection and change notifications. Ideal for building data-syncs and for triggering reactive updates in React (or similar front-end framework) when this synced data is changed on the back-end.
> const {DataCache} = require('@transitive-sdk/datacache')
> d = new DataCache()
> d.subscribe((change) => console.log('d has changed', change));
> d.subscribeTopic('/+first/c', (value, path, match) => console.log('/+first/c has changed to', value, `with first being ${match.first}`));
> d.update(['a','b'], 1234)
d has changed { '/a/b': 1234 }
> d.update(['a','c'], 123)
d has changed { '/a/c': 123 }
/+first/c has changed to 123 with first being a
> d.get()
{ a: { b: 1234, c: 123 } }With this it is terribly easy to implement a data-sync over any connection that allows you to send strings:
const data = new DataCache();
const client = new SomeCommunicationProtocol();
client.connect('...to some peer over some protocol');
// parse messages we receive from peer, apply to local DataCache
client.on('message', (message) => {
const change = JSON.parse(message.toString());
if (change) {
_.forEach(change, (value, key) =>
data.update(key, value, {external: true}));
}
});
// subscribe to local changes and publish them to the peer
data.subscribe((change, tags) => {
if (tags?.external)
// this is a change that we've received from another party, don't re-publish
return;
// notify the peer of these changes
client.send(JSON.stringify(change));
});Documentation
Table of Contents
- DataCache
- dropWildcardIds
- forMatchIterator
- isPrefixOf
- isSubTopicOf
- pathToTopic
- selectFromObject
- setFromPath
- toFlatObject
- topicMatch
- topicToPath
- unset
- updateObject
DataCache
A class implementing a local data cache, used as a local data store with deduplication detection and update events. While this class is very handy you probably won't need to create instances of it directly. Instead use the mqttSync.data instance which holds the locally stored data subscribed/published from/to MQTTSync. For example on the robot:
// update/publish our status:
mqttSync.data.update('status', {changed: Date.now(), msg: 'OK'});
// subscribe to new user requests (e.g., from UI):
mqttSync.data.subscribePath('+user/request', (request, key, {user}) => {
log.debug(`user ${user} made request`, request);
});In the cloud or in a web component you would need to use the full topic including org, device, scope, cap-name, and version.
Parameters
data(optional, default{})
filter
Filter the object using path with wildcards
Parameters
path
filterByTopic
Filter the object using topic with wildcards
Parameters
topic
forMatch
For each topic match, invoke the callback with the value, path, and match just like subscribePath, but on the current data rather than future changes.
Parameters
topiccallback
forPathMatch
For each path match, invoke the callback with the value, path, and match just like subscribePath
Parameters
pathcallback
get
Get sub-value at path, or entire object if none given
Parameters
path(optional, default[])
getByTopic
Get sub-value specified by topic
Parameters
topic
subscribe
Add a callback for all change events.
Parameters
callback
subscribePath
Subscribe to a specific path (array) only. Callback receives
value, key, matched, tags.
Parameters
pathcallback
subscribePathFlat
Same as subscribePath but always get all changes in flat form
Parameters
topiccallback
subscribeTopic
Subscribe to a specific topic only. Callback receives
value, key, matched, tags.
Parameters
topiccallback
unsubscribe
Remove a callback previously registered using subscribe.
Parameters
callback
update
Update the value at the given path (array or dot separated string)
Parameters
pathvaluetags
updateFromArray
Update the object with the given value at the given path, remove empty;
return the flat changes (see toFlatObject). Add tags to updates to mark
them somehow based on the context, e.g., so that some subscriptions can choose
to ignore updates with a certain tag.
Parameters
pathvaluetags(optional, default{})
updateFromModifier
Update data from a modifier object where keys are topic names to be interpreted as paths, and values are the values to set
Parameters
modifiertags
updateFromTopic
Set value from the given topic (with or without leading or trailing slash)
Parameters
topicvaluetags
dropWildcardIds
reduce wildcards with Ids, such as +sessionId, to just +
Parameters
x
forMatchIterator
Iterate through the object and invoke callback for each match of path (with named wildcards)
Parameters
objpathcallbackpathSoFar(optional, default[])matchSoFar(optional, default{})
isPrefixOf
prefixArray is a prefix of the array
Parameters
prefixArrayarray
isSubTopicOf
sub is a strict sub-topic of parent, and in particular not equal
Parameters
subparent
pathToTopic
convert a path array to mqtt topic; reduces +id identifiers to +
Parameters
pathArray
selectFromObject
Given an object and a path with wildcards (* and +), modify the object
to only contain elements matched by the path, e.g.,
{a: {b: 1, c: 2}, d: 2} and ['a','+'] would give {a: {b: 1, c: 2}}
Parameters
objobject The object to select frompatharray An array specifying the path to select, potentially containing mqtt wildcards ('+').
setFromPath
Like _.set but without arrays. This allows using numbers as keys.
Parameters
objpathvalue
toFlatObject
Given an object, return a new flat object of topic+value pairs, e.g.:
{a: {b: 1, c: 2}, d: 3} → {'/a/b': 1, '/a/c': 2, '/d': 3}Note: not idempotent!
{'/a/b': 1, '/a/c': 2, d: 3} → {'%2Fa%2Fb': 1, '%2Fa%2Fc': 2, '/d': 3}Parameters
objprefix(optional, default[])rtv(optional, default{})
topicMatch
Match a slash-separated topic or path array with a selector using +XYZ for (named) wildcards. Return the matching result.
Parameters
selectortopic
topicToPath
convert topic to path array
Parameters
topic
unset
Unset the topic in that obj, and clean up parent if empty, recursively. Return the path to the removed node.
Parameters
objpath
updateObject
Given a modifier {"a/b/c": "xyz"} update the object obj such that
obj.a.b.c = "xyz".
Parameters
objmodifier
