sktwrx.store

0.8.0 • Public • Published

Store

Indexed, resource-based, evented data storage.

Somewhere between Backbone.Models/Collections and Redux reducers without ORM.

Flatten, index and subscribe to your data through a minimal interface.

Changes:

  • 0.8.0
    • remove Resource#create() and Resource#upsert() in favour of Resource#store()
    • remove Resource#_add() (private)
    • Resource#all() now provides all arguments from Array#map()
    • "create" event payload on a Resource is: [ instance, index ]

Quick start:

// create a data space for your app
const dataSpace = sktwrx_store.namespace('organisation.application');

// create a singleton resource collection with default Resouce#idAttribute 'id'
const users = dataSpace.resource('users');

// tell resource which keys to index on the instances to look up their positions
users.index('name', 'age');

/**
 * optional - tell the resource what namespace to use for indexing on an Instance
 * this is useful when an API returns something similar to this:
 * 
 * {
 *   href: '/ai/v1/users/5/',
 *   meta: {
 *     type: 'model',
 *     ...
 *   },
 *   body: {
 *     id: 5,
 *     name: 'bob',
 *     age: 5,
 *     ...
 *   }
 * }
 * 
 */
users.body('body');

// specifying default schema with values when creating an instance
users.defaults({
  name: '',
  age: 0,
  dickMoves: Array,
  ...
});

// store resource (collection) specific attributes - not indexed
users.set('limit', 20);
users.change({ page: 1, skip: 2 });

// store an instance
let bob = users.store({ id: 1, name: 'bob', age: 45 });

// update bill
bill.update({ age: 33 });
//or
users.update(bill, { age: 33 });

// reading properties from bill
bill.get('age'); // 33
// or get all props
bill.getProps(): 

// finding an item in the store - returns a Query
users.find('name', 'bill').first().getProps(); // { name: 'bill', ... }
// or return a query with instances that match 'name' or 'age' with their values.
users.query({ name: 'bill', age: 24 });

module

require('sktwrx.store'); or import { namespace, Resource, Instance } from 'sktwrx.store'; or window.sktwrx_store.

sktwrx_store.Namespace

Namespaces provide a way to group Resources into singleton data-spaces.

Creating and accessing a namespace:

import { namespace, Namespace } from 'sktwrx.store';

const myNS = namespace('myOrg.MyApp');
// or
const myOtherNS = new Namespace('myOrg.MyApp');

sktwrx_store.Resource

Resources store data items (Instances) in an ordered and linked fashion. It also contains the Index allow easy and fast data-access/lookup.

Creating and accessing a store via a namespace:

const Users = myNS.resource('users');

Creating and accessing a store globally:

import { resource } from 'sktwrx.store';

const Users = resource('users');

Resource indexing

By default the Resource will try to index an item by its Resource#idAttribute property which defaults to "id". This id attribute is used to determine if an item already exists or not. You can specify your own id field name when you create a resource:

import { resource } from 'sktwrx.store';

const Users = resource('users', '_id'); // MongoDB ObjectId

Or you can specify it on a Namespace to pass it as a default when creating a Resource within the namespace:

const { namespace } from 'sktwrx.store';
const NS = namespace('org.app');

NS.id('_id');

Once the Resource is created you can specify what attributes need indexing when storing/updating an item:

Add as many fields as you like, because if these fields are not specified the Resource will fall back to iterating through all items in the list which has major performance downsides on large-scale UIs (at least to my experience).

Users.index('name', 'age', 'dob', ...);

Or you can specify it on a Namespace to pass it as a default when creating a Resource within the namespace:

const { namespace } from 'sktwrx.store';
const NS = namespace('org.app');

NS.index('name', 'age', 'dob', ...);

You may find yourself in a situation where you are dealing with nested, more advanced data-structure containing metadata near your resource. You can specify which field (only one) to use as the resource item's body:

Users.body('body');

Or you can specify it on a Namespace to pass it as a default when creating a Resource within the namespace:

const { namespace } from 'sktwrx.store';
const NS = namespace('org.app');

NS.body('body');

Additionally, you can specify default values when storing an item

Users.defaults({ name: '', age: 0, friends: Array, ... });

Storing resource instances

Storing (creating) an item will add it to the end of the list:

const keira = Users.store({ name: 'keira' });

You can store instances at a specified position:

const bob = Users.store({ id: 3, name: 'bob' }, 2); // insert as the 3rd element

Creating an Instance will publish the create event on the Resource.

Inserting before/after an instance

Users.store([
  { id: 0, name: 'bill' },
  { id: 1, name: 'bob' },
  { id: 2, name: 'betty' },
]);

const bob = Users.at(1);
const amelia = Users.before(bob, { id: 3, name: 'amelia' });
const anastasia = Users.after(bob, { id: 4, name: 'anastasia' });
Users.all(i => console.log(i.get('name')); // [ 'bill', 'amelia', 'bob', 'anastasia', 'betty' ];

Getting the position(s) of a key and value

You can return the position(s) if you want to find where to insert new items:

Users.position('name', 'bob'); // [3, 7, ...]

Updating resource instances

When updating an item, the index will be rebuilt around the item.

bob.update({ age: 33 });
// or
Users.update(bob, { age: 33 });

Updating an Instance will publish the update event on the Instance first and then on the Resource.

Removing resource instances

bob.remove();
// or
Users.remove(bob);

Updating an Instance will publish the remove event on the Resource.

Querying the Resource

There are 2 ways of finding resource items: find or query.

Find works for only one key - value combination:

// return all resource instances that have the name 'bob'
Users.find('name', 'bob');

Query will look up based on the provided object:

// return items that have either the name 'bob' or the age 45 
Users.query({
  name: 'bob',
  age: 45
});

Additionally, you might want to be able to query the Resource for the available values first (for example available categories of a Resource)

import { resource } from 'sktwrx.store';

const Books = resource('books');
Books.index('category');

Books.store({ id: 0, category: 'scary' });
Books.store({ id: 1, category: 'romantic' });
Books.store({ id: 2, category: 'drama' });
Books.store({ id: 3, category: 'drama' });
Books.store({ id: 4, category: 'scary' });

Books.values('category'); // [ 'scary', 'romantic', 'drama' ]

Resetting the Resource

Cleans up the Resource, removes resource instances and destructs the Resource index.

Users.reset();

Resetting the Resource will publish the reset event on the Resource.

Storing list specific data

Resources might have other data describing them, such as paging or page size. You can store these keys and values on the Resource:

Users.set('page', 5);
// or
Users.change({ page: 5, limit: 20 });

Setting/changing on a Resource will publish the change event on the Resource.

sktwrx_store.Instance

Instances are evented resource items

const bob = Users.store({ id: 0, name: 'bob', age: 45 });

Changing an Instance

There are 2 ways of modifying an Instance: changing it or updating it.

Change is registering the key-values in a different lookup but doesn't change the underlying data source.

bob.set('age', 25);
// or
bob.change({ age: 25 });

Update will take all changes from before and merge it together with the given updates then merge it onto the underlying data source.

bob.update({ age: 33 });

Events

Resource: create, change, update, remove, reset

Instance: change, update

Event constants:

import { events } from 'sktwrx.store;

events.CREATE // 'create'
events.CHANGE // 'change'
events.UPDATE // 'update'
events.REMOVE // 'remove'
events.RESET // 'reset'

Subscribing to events: bob.subscribe('update', ... );

Unsubscribe from events: Users.unsubscribe('update', ... );

Readme

Keywords

none

Package Sidebar

Install

npm i sktwrx.store

Weekly Downloads

0

Version

0.8.0

License

MIT

Last publish

Collaborators

  • benqus