Skip to content
This repository was archived by the owner on Dec 6, 2022. It is now read-only.

Repository files navigation

VersionedValueMap

CircleCI

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.

Installation

$ npm install --save versioned-value-map

Basic usage

Importing

import{VersionedValueMap}from"versioned-value-map";

Add values

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.

Add value with timestamp

The 3rd argument is reserved for timestamp.

constnewMap=map.$add("propName01","foobar","2018-03-02T18:56:00.222Z");

Get values

Current values

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);

Get Item

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;

Remove values

Create a new map with newest value removed from it:

constnewMap=map.$removeNewest("propName01");

You can see that map is unchanged.

Remove the specific value with timestamp

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");

Serialization

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: {
...
}}}

Integration with Redux

Understanding UpdateOperation

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.

sp2

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.

example

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.

TypeScript support

You can write more robust codes with TypeScript.

Put type map for better inference

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}

API Documentation

TBD

LICENSE

Apache License 2.0

About

Immutable container of time-series data

Resources

Stars

4 stars

Watchers

9 watching

Forks

Releases

Packages

Used by

Contributors

Languages