UNPKG

9.88 kBMarkdownView Raw
1![One logo](https://lh3.googleusercontent.com/5CBS5xCZm0BQQ9GaE8SfDnomFNWkr5jU-ZPRi_Cdptj7__GSyRPCeQbQA1OBxt0OZ3LNs-a_eGiyBSCtOM4=s100 "One logo")
2
3# **ONE** #
4
5```One``` is a browser side application cache. It guarantees entity uniqueness across the entire cache.
6
7[![Npm Status](https://badge.fury.io/js/one.svg)](https://npmjs.com/package/one-typescript) [![Build Status](https://travis-ci.org/maierson/one.svg)](https://travis-ci.org/maierson/one) [![Coverage Status](https://coveralls.io/repos/github/maierson/one/badge.svg?branch=master)](https://coveralls.io/github/maierson/one?branch=master)
8
9Each entity tracked for uniqueness must have a unique id. There is precisely ONE distinct entity in the cache
10for each unique id. Entities that do not have a unique id are still cached but not tracked for uniqueness.
11
12- [Changes](#changes)
13- [Api](#api)
14- [Usage](#usage)
15- [Immutable](#immutable)
16- [Configuration](#configuration)
17- [Motivation](#motivation)
18- [Performance](#performance-considerations)
19- [Data shape](#data-shape)
20
21### __Changes__
221. Complete rewrite in typescript.
232. Fix some subtle bugs related to object structure (ie modifiying arrays would sometimes behave unpredictably based on the parent's structure).
243. Remove the need for ```babel-polyfill```
254. __Breaking api changes:__ Simplified minimal api. You really only need the commands in the table below. There are a couple of other options mostly for debugging (see the Api section for the development api list).
26
27| Command | Action |
28| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
29| __getCache__ | Create or access a specific version of the cache. There can be multiple concurrent versions of the cache in case distinct versions of the same entity are needed (for example if display and edit data need to be different until a user commits changes). ```One.getCache('edit') ``` would create a cache dedicated to edit operations. |
30| __put__ | Add an entity to the cache and make it immutable. |
31| __get__ | Retrieve an entity from the cache. This is a fast hash map locator. |
32| __getEdit__ | Get a shallow editable version of the entity from the cache. Inner nested entities are still immutable. This is in order to make efficient use of trie structures. |
33| __evict__ | Remove an entity from the cache. Evicts it from all parents as well. |
34
35
36### __Api__
37In addition to the 5 production api commands there are 4 options intended for development:
38
39| Command | Action |
40| ---------- | :--------------------------------------------------------------------------------------------------------------------------------------------- |
41| __reset__ | Resets the cache to empty. Useful for testing. |
42| __length__ | Number of nodes in the current cache. Each node contains one atomic change to the cache so moving between nodes gives you time travelling. |
43| __size__ | Number of entities cached on the current node (the size of the node). |
44| __print__ | Provides a printable representation of the entire cache that can be passed on to a logger. Slow. For debugging only. Do not use in production. |
45
46
47### __Usage__
48
49```js
50npm install one --save
51```
52or
53```js
54yarn add one
55```
56Use it
57```js
58import * as One from 'one'
59
60// get a hold of an instance
61let one = One.getCache()
62
63// you can then use the instance to cache items
64one.put(item)
65
66// One.getCache() is a singleton so you can also do this
67One.getCache().put(item)
68
69// or if you are only using the default instance of the cache
70One.put(item)
71```
72
73Or simply put ```one.min.js``` on your page to access the ```One``` global variable from anywhere. In this case the instance is created for you and you can access it directly.
74
75
76```js
77One.put(item)
78```
79
80Some code
81
82```js
83let item1 = { uid:1 }
84let item2 = { uid:2, ref:item1 }
85
86One.put(item2)
87
88// puts all items with uid separately in the cache
89
90One.get(item1) === undefined // false (item1 is added from item2)
91item1 === One.get(item1) // true (same object)
92item2.ref === One.get(1) // true
93```
94
95### __Immutable__
96All data is immutable. Once an item enters the cache it freezes and cannot change. This is to enable quick identity checks against immutable entities (ie React / Redux identity check).
97
98```js
99let item = { uid:1 }
100Object.isFrozen(item) // false
101
102One.put(item);
103Object.isFrozen(item) // true
104
105let result = One.get(item)
106result === item // true
107```
108
109If you later want to edit a reference of the object you can get an editable copy from the cache. This gives you a separate clone of the object that is now editable:
110
111```js
112let item = { uid:1 }
113One.put(item)
114
115let editable = One.getEdit(1) // or cuid.getEditable(item1);
116Object.isFrozen(editable) // false
117item === editable // false
118
119editable.text = "test"
120One.put(editable)
121
122let edited = One.get(1)
123edited.text = "text" // true
124Object.isFrozen(edited) // true
125```
126__Important__ Edit clones are shallow. If you want to edit a nested child that also has a uid you must get an editable copy of the child.
127
128```js
129const item1 = { uid:1 } // uid item cached separately
130const item2 = { value: 'test' } // item has no uid - it will be cloned for edit
131const item = {
132 uid: 1,
133 item1,
134 item2
135}
136
137one.put(item)
138
139const editable = one.getEdit(item)
140
141Object.isFrozen(editable.item1) // true - item1 has a uid - not cloned
142item1 === editable.item1 // true
143
144Object.isFrozen(editable.item2) // false item2 has no uid - it will be cloned
145item2 === editable.item2 // false
146```
147
148Editing an item changes all its instances in the cache:
149
150```js
151let item = { uid:1 }
152let item2 = { uid:2, child:item }
153
154One.put(item2)
155
156One.get(1) === item // true
157One.get(2) === item2 // true
158
159// Let's do some editing
160let editable = One.getEdit(1);
161editable.text = "test"
162One.put(editable) // also updates item2 reference to item
163
164let result = One.get(2)
165console.log(JSON.stringify(result.item)) // {uid:1, text:"test"}
166```
167### __Configuration__
168
169For existing code bases the name of the `uid` property can be configured via a config object passed as a second argument to the `.getCache()` method. In order for this to work correctly the values held by the configured property must be unique across all instances.
170
171```js
172const one = One.getCache('test', { uidName:'id' })
173
174const item = { id:'unique_id_value' }
175
176one.put(item)
177
178one.get('unique_id_value') !== undefined // true (works)
179```
180
181### __Motivation__
182More an more applications are giving users the ability to edit data in the browser.
183With a normalized data model various instances of an entity can exist at the same time in different locations. This depends on how data is received from the server and added to the local model / store.
184
185This is inconvenient because:
186* Keeping all the instances in sync can be a daunting task.
187* It can make debugging hard.
188* It requires tracking each instance and makes reasoning about data complicated.
189* It can make the application structure needlessly complex.
190
191[Redux](https://github.com/reactjs/redux) brings a great breakthrough by putting the entire application state in one place and mutating it only via dispatched actions. But it doesn't enforce entity uniqueness. ```One``` aims to take the concept a step further by making each entity unique and immutable in a single store (cache).
192
193### __Performance considerations__
194
195* __Read optimized__: Yes there is a performance cost in analyzing each entity deeply to track its dependencies. ```One``` mitigates this by being read optimized. The penalty is incurred on write operations only. These happen a lot less frequently than read ops. Read ops are super fast (a simple key lookup).
196* __Trie structures__: Data is stored in a trie like structure. This way all entities are referenced (not copied) and minimal changes are performed on every put or getEdit operation.
197
198### __Data shape__
199This is not currently designed to work with cyclical data. It is best for non-cyclical objects received from the server in the form of json (or other non-cyclical fomats).
200It might happen later if there's a need.
\No newline at end of file