An immutable, portable, serializable, restorable, and extensible container of time-series data. You can add/remove values and new instance will be created. It can be easily integrated with Redux, sp2, and Phenyl.
$ npm install --save versioned-value-mapimport{VersionedValueMap}from"versioned-value-map";constmap=newVersionedValueMap();constnewMap=map.$add("propName01","foobar");map is unchanged. newMap forms the following structure.
{items: {propName01: {name: 'propName01',records: [{value: 'foobar',at: '2018-03-02T18:56:00.222Z'},],},bar: {
...
}}}You can see that the timestamp is automatically added into the records.
The 3rd argument is reserved for timestamp.
constnewMap=map.$add("propName01","foobar","2018-03-02T18:56:00.222Z");Call map.get(name) to get the current value of the Value Map.
constmap=newVersionedValueMap().$add("propName01","foobar");constcurrentValue=map.get("propName01");assert(currentValue==="foobar");Trying to get non-registered value will return null.
constcurrentValue=map.get("abc");assert(currentValue==null);constitem=map.getItem("propName01");item is an instance of VersionedValue that forms the following structure:
{name: 'propName01',records: [{value: 'foobar',at: '2018-03-02T18:56:00.222Z'}]}All these properties are public and it can be accessed like the following:
constcreatedAt=map.getItem("propName01").records[0].at;Create a new map with newest value removed from it:
constnewMap=map.$removeNewest("propName01");You can see that map is unchanged.
You can use map.$remove(name, at) to remove a specific value at specific timestamp.
constnewMap=map.$remove("propName01","2018-03-02T18:56:00.222Z");VersionedValueMap is Restorable.
That means it can be re-created by passing its JSON object to the class constructor.
In the following case, map is deeply equal to newMap.
constplainMap=JSON.parse(JSON.stringify(map));constnewMap=newVersionedValueMap(plainMap);The plain map's structure is as follows.
{items: {foo: {name: 'foo',records: [{value: 1,at: '2018-03-02T18:56:00.222Z'},{value: 7,at: '2018-03-04T03:11:23.524Z'},],},bar: {
...
}}}constmap=newVersionedValueMap();constoperation=map.add("propName01","foobar");Unlike $add() which directly creates a new map, add() creates an UpdateOperation instead.
operation here contains the operation to update map as data.
{$set: {'items.propName01': {name: 'propName01',records: [{value: 'foobar',at: '2018-03-02T18:56:00.222Z'}]}}}This format is almost the same as MongoDB's Update Operators. See sp2 Documentation for more detailed information.
UpdateOperation can be parsed by a simple library called sp2.
Pass the operation generated above to update() to create a new object.
import{update}from"@sp2/updater";constnewPlainMap=update(oldMap,operation);// NewMap = OldMap + UpdateOperationconstnewMap=newVersionedValueMap(newPlainMap);Since update() returns a plain object, you will need to call constructor afterwards to create a new VersionValueMap.
Alternatively, you can call updateAndRestore() to automatically create a new VersionValueMap.
import{updateAndRestore}from"@sp2/updater";constnewMap=updateAndRestore(oldMap,operation);Writing these code in Reducer function will let you handle the state of VersionedValueMap with Redux.
First, let's define the reducer.
import{updateProp}from'@sp2/udpater'functionreducer(state,action){if(!state){return{map: {}}// expect plain VersionedValueMap}if(action.type==='update-map'){constupdateOperation=action.payload// This immutably updates the update operation to "map"returnupdateProp(state,'map',updateOperation)}
...
}updateProp() is like update() but it updates not to the state but to state.map.
Action can be dispatched like this:
conststate=store.getState();constmap=newVersionedValueMap(state.map);constupdateOperation=map.add("propName01","foobar");constaction={type: "update-map",payload: updateOperation};dispatch(action);Make sure that state contains a plain map object and every time reducer is called the map is constructed by new VersionedValueMap(state.map).
We've benchmarked the performance and found that a map with 5000 items containing 10 datapoints will be constructed within 1msec (in Node.js v8).
That means we can ignore the construction cost in modern JS environments.
You can write more robust codes with TypeScript.
Put type map in initializing instances as below:
import{VersionedValueMap}from"versioned-value-map/jsnext";constmap: VersionedValueMap<{foo: string,bar: number}>=newVersionedValueMap();Then, TypeScript can get its types.
conststr=map.get("foo");if(str!=null){// here, str is regarded as string}constnum=map.get("bar");if(num!=null){// here, num is regarded as number}TBD
Apache License 2.0