@brainbytes/immutable-store

0.4.0 • Public • Published

@brainbytes/immutable-store

ES6 Flux-based immutable data store with Immutable.js

Store

import Store, {MessageTypes} from 'immutable-store'
import schema from './my-schema.json'

// Store **requires** a schema to be constructed
let myStore = new Store(schema);

myStore.handleMessage({
  type: MessageTypes.Write,
  payload: {
    table: 'user',
    row: {
      id: '2361',
      username: 'someguy37'
    }
  },
  promise: myApi.updateUser()
});

Methods

Currently the store has a single method, handleMessage, which is used to update the store's internal state.

handleMessage

handleMessage(message)

handleMessage accepts a single parameter, message which contains a type, and a payload. Each message type has it's own format for the payload

Message Types

When creating a message, it should have a type field which is exported on the MessageType object. The value of the type field determines the expected shape of the message.payload

MessageType.Write

Writing implies an 'additive' operation, including but not limitied to creating and updating records.

{
  table: 'someTable',
  row: {
    id: 'someId'
    field1: 'value1',
    field2: 'value2'
  }
}

table required

the name of the collection which you want to perform the operation on

row required

the actual data you want to write. id is required on the row, and all other fields are optional. Any fields omitted in the row object which are on the referenced record will remain unchanged, and all other fields in the record will be set to their corresponding value on row.

rows optional

rows can be provided instead of row, as an array of row objects. Any invariants that hold for row or operations involving row should also hold for every object in the rows p

MessageType.Replace

Replace operations work mostly the same as write operations, but instead of being 'additive', they will fully replace the record being written. The message format is exactly the same, the exception of the semantics of row and rows being that any fields not in row will be removed from the record during the update.

Any records not in the rows array will be unmodified. If you wish to replace the contents of an entire collection, see MessageType.ReplaceAll

MessageType.Delete

Delete operations are for removing one or more records from a collection. To delete a single record the syntax is as follows:

{
  table: 'someTable',
  row: 'someId'
}

For deleting multiple records, you can use rows instead, and provide an array of ids to delete.

{
  table: 'someTable',
  rows: ['id1', 'id2', 'id3']
}

Lastly, you can omit row and rows to delete the entire collection

{
  table: 'someTable'
}

MessageType.ReplaceAll

Replace all as an operation works similar to Replace but applied to the level of the collection.

{
  table: 'someTable',
  rows: [{
    id: 'id1'
    field1: 'value1',
    field2: 'value2'
  }, {
    id: 'id2',
    field1: 'otherValue'
  }],
  promise: myApi.writeLots()
}

The collection someTable will now contain exactly two records, regardless of how many it had before the operation.

Unlike Replace, the row field cannot be supplied.

MessageType.DeleteAll

This message type does not require a payload, because it simply deletes everything in the store. This is useful for clearing the store when a user logs out or otherwise wants to 'forget' all data.

Store instance properties

The store instance has a few read-only properties once it is constructed.

data

This is the current state of all the collections represented as an immutable collection.

messages

This is a total history of all the messages which have been passed to the store since it was constructed. messages is an immutable list.

schema

This is an immutable representation of the schema passed into the store that it uses to create/maintain the store's representation of data.

Message.Promise

Optimistic by default

immutable-store is capable of handling all operations optimistically, simply by including a promise field an operation will be committed or rolled back when the promise is resolved or rejected.

What this means in practice is that if you perform some effect-ful operation on the server via a web request, and if you have a promise representing that action you can send that along with the message to immutable-store, and it will watch the promise for resolution.

Semantics

Internally, immutable-store keeps an ordered list of all messages it receives, and any message without a promise is considered 'final' by default. The most recent 'final' message not preceeded by some pending operation is the HEAD message. The HEAD message is stored, alongside the state the store was in after the HEAD message has been applied.

Any message with a promise that is resolved will be marked as final.

Any time a message is marked as final, HEAD will be recomputed.

Any message with a promise that is rejected will be removed from the queue and placed in a special 'failed' queue, which retains the ordering from the message queue.

Any time a promise is rejected, after the message is removed from the queue, the state of the store is then reset to the HEAD and each message after HEAD is re-applied to the store's state, until all the messages have been applied.

install

npm install @brainbytes/immutable-store

Testing

In order for Karma to test on all browsers make sure Google Chrome and Firefox are both installed. (IE and Safari will be loaded depending on your platform)

If Karma is unable to find one of the browsers it is trying to launch, it will not run the tests. If you cannot install the necessary browsers, edit the karma.config.js file, and remove the appropriate entry from browsers.

First, make sure Karma is installed

npm install -g karma-cli

Install dependencies

npm install

Finally,

npm test

license

MIT

Package Sidebar

Install

npm i @brainbytes/immutable-store

Weekly Downloads

3

Version

0.4.0

License

MIT

Last publish

Collaborators

  • nicktennies
  • codeseer
  • syynth
  • brainbytes