j-Store
Use the localStorage like a small database.
This package was created for me to use in my own projects, but i thought that will be useful for others to use
See this simple Todo App that uses jStore.
Some warnings
- This project is still in development, so pardon for any bugs.
- I'm from brazil and my english is not so great, so if you see an english error in this documentation, i'm sorry.
- Please, consider using a real database if you want to hold sensitive information.
Instalation
npm i --save @j-theta/j-store
Usage
import jStore from '@j-theta/j-store';
// will save the object passed in the localStorage
// if there are already an object in the localStorage with the key
// __JSTORE__, then this object will be ignored
// and the object in the localStorage will be loaded instead
const store = new jStore({
users: {
"45": { age: 37, name: "Dorothy Nelson" },
"59": { age: 40, name: "Randy Floyd" },
"57": { age: 31, name: "Lillian Russell" },
"28": { age: 37, name: "Ray Adkins" },
"42": { age: 21, name: "Jonathan Hernandez" },
},
cities: [
'Medufpuh',
'Oguagwon',
'Wuhaful',
'Pitburi',
'Mimekiras',
'Suvvakpo',
]
});
// get the users
store.get('/users')
/*
[
{ age: 37, name: "Dorothy Nelson" },
{ age: 40, name: "Randy Floyd" },
{ age: 31, name: "Lillian Russell" },
{ age: 37, name: "Ray Adkins" },
{ age: 21, name: "Jonathan Hernandez" },
]
*/
store.get('/users/28') // { age: 37, name: "Ray Adkins" }
// get the cities
store.get('/cities')
/*
[
'Medufpuh',
'Oguagwon',
'Wuhaful',
'Pitburi',
'Mimekiras',
'Suvvakpo',
]
*/
// if you want an item from an array with specific index
store.get('/cities/0') // 'Medufpuh'
// adding an item in the storage
store.post('/hello', 'world!')
store.get('/hello') // 'world!'
// remove an item from the storage
store.remove('/hello')
store.get('/hello') // undefined
The jStore class constructor
constructor(data: object, listeners?: Partial<Listeners>)
Properties
-
store - Get the current
store
data
Methods
-
get - Get data from store with the given
path
public get(path?: string, options?: options): any;
-
set - Set new data in the given
path
public set(path: string, data: any): void;
-
post - Like the
set
method, this method add new data in thestore
, but only if the path does not already exists. This is useful when you want to add new data without accidentaly override the data of an path that already exists.
public post(path: string, data: any): void;
-
reset - Reset the
store
to its default state.
public reset(): void;
-
remove - Remove a path from the
store
.
public remove(path: string): void;
-
add - Add new items to an array in the
store
.
public add(path: string, value: any, index?: number): void;
-
exists - Test if a path exists in the
store
public exists(path: string): void;
-
on - Add a
event listener
to the store.
public on(method: Method, handler: (...args: any[]) => void) : void
Options to get
interface options {
/** A function to filter the results */
where?: (value: any, index: number) => boolean;
/** a string property to order the results */
orderBy?: string;
/** Determine if the result order will be `descending` */
desc?: boolean;
/** Determine if the result order will be 'ascending' */
asc?: boolean;
/** an integer to limit the results */
limit?: number;
}
Filtering the results
Using the store from the previous example
store.get('/cities', {
where: citie => citie.startsWith('M')
}) // ['Medufpuh', 'Mimekiras']
Ordering the results
Order ascending will be the default
store.get('/users', { orderBy: 'age' })
/*
[
{ age: 21, name: "Jonathan Hernandez" },
{ age: 31, name: "Lillian Russell"},
{ age: 37, name: "Ray Adkins"},
{ age: 37, name: "Dorothy Nelson"},
{ age: 40, name: "Randy Floyd"},
]
*/
But, you can order the results descending if you want
store.get('/users', { orderBy: 'age', desc: true })
/*
[
{ age: 40, name: "Randy Floyd"},
{ age: 37, name: "Dorothy Nelson"},
{ age: 37, name: "Ray Adkins"},
{ age: 31, name: "Lillian Russell"},
{ age: 21, name: "Jonathan Hernandez"},
]
*/
Limiting the results
store.get('/users', { limit: 2 })
/*
[
{ age: 37, name: "Dorothy Nelson"},
{ age: 40, name: "Randy Floyd"},
]
*/
Events
You can add some event listeners to control how your store is manipulated.
store.on(method: Method, handler);
type Method = 'get' | 'set' | 'post' | 'remove' | 'reset' | 'add';
Examples:
- Get logs
store.on('get', path => console.log(`The path ${path} has been accessed`))
store.get('/users') // logs: The path /users has been accessed
- Data validation
If you return a value in the callback passed in the on method, then the post method will return that value before sending the data to the store. This is useful when you want to validate new data.
store.on('post', (path, data) => {
if (path.startsWith('/user')) {
const { name, age } = data;
if (name.trim() === '') return new Error('The user name must be valid')
if (age < 18) return new Error('The user must be adult')
}
})
- Simulate a protected route
You can use examples like this to protect some paths to be accessed.
store.on('get', path => {
if (path === '/protected-route') {
return new Error("Can't access a protected route")
}
})
The Listener interface
interface Listeners {
/**
* This function is called every time the `set` method is called.
* @param path the path passed to `set`.
* @param data the data passed to `set`.
* @param store the store instance.
*/
onset(path?: string, data?: any, store?: jStore): void | any;
/**
* This function is called every time the `post` method is called.
* @param path the path passed to `post`.
* @param data the data passed to `post`.
* @param store the store instance.
*/
onpost(path?: string, data?: any, store?: jStore): void | any;
/**
* This function is called every time the `get` method is called.
* @param path the path passed to `get`.
* @param store the store instance.
*/
onget(path?: string, store?: jStore): void | any;
/**
* This function is called every time the `reset` method is called.
* @param store the store instance.
*/
onreset(store?: jStore): void | any;
/**
* This function is called every time the `remove` method is called.
* @param path the path passed to `remove`.
* @param store the store instance.
*/
onremove(path?: string, store?: jStore): void | any;
/**
* This function is called every time the `add` method is called.
* @param path the path passed to `add`.
* @param value the value passed to `add`.
* @param index the index passed to `add`.
* @param store the store instance.
*/
onadd(path?: string, value?: any, index?: number, store?: jStore): void | any;
}
The jStoreAsync class
This class is useful when you want to simulate real requests to a dabatase, to see how your UI handle promises.
All methods of this class behave exactly like the jStore class, except that each method returns a promise.
constructor(data: object, delay: number = 1000)
The delay
argument is the time in milliseconds that each promise takes to resolve.
Examples
import { jStoreAsync } from '@j-theta/j-store'
const initialState = {
cities: [
'Imozumop',
'Hiducuv',
'Gowoju',
'Retona',
'Pirovo',
'Uwlaji',
'Emefetil',
],
emails: [
'kogrefenu@leezu.bn',
'et@ravral.ly',
'rul@tecot.us',
'goga@biuka.bo',
'ugwedtuj@idoubcef.nc',
]
}
const store = new jStoreAsync(initialState, 1200);
store.get('/cities')
.then(res => console.log(res))
/*
[
'Imozumop',
'Hiducuv',
'Gowoju',
'Retona',
'Pirovo',
'Uwlaji',
'Emefetil',
]
*/
store.post('/cities', 'foo')
.catch(e => console.log(e))
// Error: "The path /cities is already been used"