https://github.com/attack-monkey/store
Like normal javascript objects - but - with super powers
https://github.com/attack-monkey/store
immutable javascipt json query store
Last synced: about 1 month ago
JSON representation
Like normal javascript objects - but - with super powers
- Host: GitHub
- URL: https://github.com/attack-monkey/store
- Owner: attack-monkey
- License: mit
- Created: 2018-05-25T09:36:14.000Z (about 8 years ago)
- Default Branch: master
- Last Pushed: 2018-06-26T23:20:09.000Z (almost 8 years ago)
- Last Synced: 2025-01-25T08:43:43.656Z (over 1 year ago)
- Topics: immutable, javascipt, json, query, store
- Language: JavaScript
- Homepage:
- Size: 60.5 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
Store.js
========
Store is a local JSON store for javascript. It differs from a normal object in that it is dereferenced from any other object. Only specific methods can get, create, update, delete data. When `get` returns data, it is only a copy - keeping the original unchanged. Store also provides querying (sort, limit, filter), locking, and more...
_Normal objects..._
```javascript
var obj1 = {thing: 'apple'};
var obj2 = obj1;
obj2.thing = 'banana';
console.log(obj1.thing); // Oh no it's changed to banana!
```
_Store objects..._
```javascript
const obj1 = new Store({thing: 'apple'});
const obj2 = obj1.get();
obj2.thing = 'banana';
console.log(obj1.get('thing')); // Still apple baby!
```
## Features
- Holds a JSON object with no reference to other objects
- Is protected and can only be retrieved with `.get()` and updated with methods such as `set`, `push`, `unshift`, `update`, and `apply`
- `.get()` returns a copy of the object, keeping the original object unchanged
- When nodes are added, any missing parent nodes are added automatically
- When nodes are deleted, any redundent parent nodes are cleaned up automatically
- A Store can be locked and unlocked to aid in data not being accidentally changed
- Advanced querying with filters, limits, and multi-level sorting
## Install
### ES6 / Typescript
Use either store.ts or store.js from /src
```javascript
install { Store } from './src'
```
> Note: If not using ES6 style imports, use /src/index.js and modify the export style
### Run this example project
clone the repo
$ `https://github.com/attack-monkey/store`
install parcel.js globally. Required to run the project.
$ `npm install -g parcel-bundler`
Run the project which will automatically install typescript into the project
$ `npm start`
This will run the project locally on localhost:1234 by default
## Basics
```javascript
let store = new Store({});
store.set('lvl1/lvl2', 'hello') // Adds or updates the node and adds any parents if missing
store.set('lvl1/lvl2', undefined) // Deletes the node and cleans up any child-less parent nodes (undefined / null / [] / {}) all result in delete
store.get(); // gets the full contents of store
store.get('lvl1'); // gets the contents of store at a particular node
store.lock(); // Restricts any changes to the store
store.unlock(); // Removes the lock
```
## PushArrays
While you can get and set arrays, Store provides a more powerful solution in the form of pushArrays.
To create a pushArray just use .push() in place of set.
```javascript
store.push('lvl1', ['a', 'b', 'c']);
```
If you use push when there is already a pushArray present, then the new items are appended to the existing pushArray.
```javascript
store.push('lvl1', ['d', 'e']);
```
You can also push single values...
```javascript
store.push('lvl1', 'f');
```
**To push items to the front of the pushArray use `.unshift()` instead of `.push()`**
pushArrays are stored as an array of rows. A row is just an object with an id and value. `id` is a unique sequential ID and `value` is the value of the array item.
```javascript
{
lvl1: [
{id: 1, value: 'a'},
{id: 2, value: 'b'},
{id: 3, value: 'c'},
{id: 4, value: 'd'},
{id: 5, value: 'e'},
{id: 6, value: 'f'}
]
}
```
A pushArray can be retrieved in full with `store.get('lvl1')` which returns
```javascript
[
{id: 1, value: 'a'},
{id: 2, value: 'b'},
{id: 3, value: 'c'},
{id: 4, value: 'd'},
{id: 5, value: 'e'},
{id: 6, value: 'f'}
]
```
A pushArray row can be retrieved directly by `$` - eg.
`store.get('lvl1/$1')` which returns `{id: 1, value: 'a'}`.
### Stripping meta-data from the pushArray result
To strip the meta-data from an individual pushArray row, just get the value
`store.get('lvl1/$1/value')` which returns just the value 'a'.
To strip the meta data from a full pushArray result set, use
`store.get('lvl1', {})` - which returns `['a', 'b', 'c', 'd', 'e', 'f']`
The second argument in the above `.get()` is an a empty 'query options' object, which tells Store that it's querying a pushArray and expects an array (without meta-data) back.
### Queries
By passing a 'query options' object with `.get()`, powerful queries are possible.
A 'query options' object tells Store that it's querying a pushArray and expects an array (without meta-data) back.
You can still specify to have the result with meta-data by passing
`meta: true` ...
For example:
`store.get('lvl1', {meta: true})`
#### Filter
pushArrays can be filtered by passing in a filter function
For example, here we filter out any items that are not of type string...
`store.get('lvl1', {filter: row => typeof row.value === 'string'});`
A filter function passes each row into the filter and evaluates it to a boolean result.
If a filter function against a row equates to true, the row will be returned in the result set.
#### Sort and Limit
pushArrays can be sorted and limited ...
`store.get('lvl1', {sort: {by: 'value', dir: 'desc'}, limit: 3})` returns `['f', 'e', 'd']`
and multi value sorted...
`store.get('lvl1', {sort: [{by: 'value', dir: 'desc'}, {by: id', dir: 'asc'}], limit: 3})`
which sorts by value in descending order, then id in ascending order.
and sorted by child nodes...
`store.get('lvl1', {sort: {by: 'value/category', dir: 'desc'}, limit: 3})`
### Deleting pushArray rows
pushArray rows can be deleted with the normal set syntax...
`store.set('lvl1/$1', undefined); // delete`
### Updating pushArray rows
**The safest way to update a pushArray is with `.update()`, however `.set()` can also be used...**
Updating with `.set()` - eg.
`store.set('lvl1/$1/value', 'z'); // Update value of 'a' to 'z'`
or with `store.set('lvl1/$1', { id: 1, value: 'z'}); // Update value of 'a' to 'z'`
> Note: a pushArray row's id should not be updated -
`store.set('lvl1/$1/id', 99) // BAD!!!!`
`store.set('lvl1/$1/', { id: 99, value: 'z'}) // BAD!!!!`
The safest way to update pushArrays is with `.update()` ...
```javascript
store.update('lvl1', {id: 1, value: 'z'}); // Update value of 'a' to 'z'
```
`.update()` is also more powerful than using `.set()` because it allows multiple row updates at once...
```javascript
store.update('lvl1', [{id: 1, value: 'z'}, {id: 3, value: 'y'}]);
```
### Apply
pushArrays can also have any array.prototype function applied to them with `.apply()`
`store.apply('lvl1', pushArray => pushArray.pop()) // removes the last row of the pushArray`
`newResult = store.apply('lvl1', pushArray => pushArray.find(row => row.id === 1)) // returns the pushArray row where id is 1`
> Note: that some array.prototype functions (such as pop and shift) mutate the pushArray - that is they make actual changes.
Other array.prototype functions do not mutate, and instead can be used to generate a result.
> !!! Don't use `apply` + ( `unshift` or `push` ) as this will add items into the array without wrapping them with meta-data!
eg.
`store.apply('lvl1', pushArray => pushArray.push(something)) // BAD!!`
Instead use `store.push('lvl1', something)` or `store.unshift('lvl1', something)`