dataflux 1.2.1 → 1.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +82 -33
- package/dist/Model.js +66 -36
- package/dist/{StoreObject.js → Obj.js} +9 -6
- package/dist/ObserverStore.js +83 -39
- package/dist/PersistentStore.js +65 -30
- package/dist/Store.js +86 -45
- package/package.json +6 -3
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -30,23 +30,34 @@ Create your global store by creating a file (e.g., named `store.js`) containing
|
|
|
30
30
|
Consider the following hypothetical store/model declaration common to all the examples below:
|
|
31
31
|
|
|
32
32
|
```js
|
|
33
|
+
// Content of your store.js
|
|
33
34
|
import {Store, Model} from "dataflux";
|
|
34
35
|
|
|
36
|
+
// We create a new Store
|
|
35
37
|
const store = new Store();
|
|
36
|
-
const author = new Model("author", `https://rest.example.net/api/v1/authors`);
|
|
37
|
-
const book = new Model("book", `https://rest.example.net/api/v1/books`);
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
// We now create two models, "author" and "book".
|
|
40
|
+
// Both of them are auto generated based on the output of a REST API.
|
|
41
|
+
// The REST API does NOT need to provide a specific format.
|
|
42
|
+
// E.g., /books returns [{"title": "Hamlet", "year": 1600}, ...].
|
|
43
|
+
// See "REST API format" below for more info.
|
|
44
|
+
const book = new Model("book", `https://api.example.net/books`);
|
|
45
|
+
const author = new Model("author", `https://api.example.net/authors`);
|
|
46
|
+
|
|
47
|
+
// We add the models to the store
|
|
40
48
|
store.addModel(book);
|
|
49
|
+
store.addModel(author);
|
|
41
50
|
|
|
42
|
-
//
|
|
51
|
+
// Optionally, we can declare relations among models.
|
|
52
|
+
// E.g., we can declare that an author has one or more books.
|
|
43
53
|
author.addRelation(book, "id", "authorId");
|
|
54
|
+
// The relation will provide all the books where author.id = book.authorId
|
|
44
55
|
|
|
45
56
|
export default store;
|
|
46
57
|
```
|
|
47
58
|
|
|
48
59
|
|
|
49
|
-
The store can be initialized with [various options](#configuration). You need only one store for the entire application, that's why you should declare it in its own file and import it in multiple places.
|
|
60
|
+
The store can be initialized with [various options](#configuration). You need only one store for the entire application, that's why you should declare it in its own file (store.js in this case) and import it in multiple places.
|
|
50
61
|
|
|
51
62
|
The creation of a model requires at least a name and a url. GET, POST, PUT, and DELETE operations are going to be performed against the same url. [Models can be created with considerably more advanced options.](#models-creation)
|
|
52
63
|
|
|
@@ -55,28 +66,31 @@ A JS object is automatically created for each item returned by the API, for each
|
|
|
55
66
|
|
|
56
67
|
### Example 1
|
|
57
68
|
|
|
58
|
-
Retrieve and edit an author
|
|
69
|
+
Retrieve and edit an author by name and surname:
|
|
59
70
|
|
|
60
71
|
```js
|
|
61
|
-
import store from "./store";
|
|
72
|
+
import store from "./store"; // Import our store.js
|
|
62
73
|
|
|
63
74
|
// Find the author Dante Alighieri
|
|
64
75
|
store.find("author", ({name, surname}) => name == "Dante" && surname == "Alighieri")
|
|
65
76
|
.then(([author]) => {
|
|
77
|
+
|
|
78
|
+
// We got the author, let's now edit it
|
|
66
79
|
author.set("country", "Italy");
|
|
67
80
|
author.set("type", "poet");
|
|
68
|
-
// Nothing else to do, the store does a single PUT request to the model's API about the edited object
|
|
69
81
|
});
|
|
70
82
|
```
|
|
71
83
|
|
|
72
|
-
|
|
84
|
+
Nothing else to do! After your edit, the store will do a single PUT request to the model's API to save the edited object. This behavior can be disabled, see next example.
|
|
85
|
+
|
|
86
|
+
> You don't necessarily need to use `object.set` to edit an object attribute. You could do `author.country = "Italy"`. However, this approach has disadvantages, read [editing objects](#editing-objects) for more information
|
|
73
87
|
|
|
74
88
|
### Example 2
|
|
75
89
|
|
|
76
|
-
|
|
90
|
+
DataFlux automatically sends the edited objects back to the API to be saved. However, you can disable this behavior and manually instruct the store when to save.
|
|
77
91
|
|
|
78
92
|
```js
|
|
79
|
-
// To disable autoSave you must declare the store as follows
|
|
93
|
+
// To disable autoSave you must declare the store (in store.js) as follows
|
|
80
94
|
const store = new Store({autoSave: false});
|
|
81
95
|
```
|
|
82
96
|
|
|
@@ -86,11 +100,13 @@ The same example above now becomes:
|
|
|
86
100
|
// Find the author Dante Alighieri
|
|
87
101
|
store.find("author", ({name, surname}) => name == "Dante" && surname == "Alighieri")
|
|
88
102
|
.then(([author]) => {
|
|
89
|
-
|
|
103
|
+
|
|
104
|
+
// When autoSave is false, author.set("country", "Italy") and
|
|
105
|
+
// author.country = "Italy" are equivalent
|
|
90
106
|
author.country = "Italy"
|
|
91
107
|
author.type = "poet"
|
|
92
108
|
|
|
93
|
-
store.save(); //
|
|
109
|
+
store.save(); // Instruct the store to save
|
|
94
110
|
});
|
|
95
111
|
```
|
|
96
112
|
|
|
@@ -129,6 +145,7 @@ author.getRelation("book");
|
|
|
129
145
|
|
|
130
146
|
If you use `subscribe` instead of `find`, you can provide a callback to be invoked when data is ready or there is a change in the data.
|
|
131
147
|
|
|
148
|
+
_**DataFlux remembers your query and calls your callback every time any change is affecting the result of your query!**_
|
|
132
149
|
|
|
133
150
|
```js
|
|
134
151
|
const drawBooksCallback = (books) => {
|
|
@@ -139,7 +156,7 @@ const drawBooksCallback = (books) => {
|
|
|
139
156
|
store.subscribe("book", drawBooks, ({price}) => price < 20);
|
|
140
157
|
```
|
|
141
158
|
|
|
142
|
-
If now
|
|
159
|
+
If now a book is inserted/deleted/edited:
|
|
143
160
|
* if the book has `price < 20`, `drawBooksCallback` will be called again with the new dataset;
|
|
144
161
|
* if the book has `price > 20`, `drawBooksCallback` will NOT be called again (because the new book doesn't impact our selection).
|
|
145
162
|
|
|
@@ -151,14 +168,31 @@ const subKey = store.subscribe("book", drawBooks, ({price}) => price < 20); // S
|
|
|
151
168
|
store.unsubscribe(subKey); // Unsubscribe
|
|
152
169
|
```
|
|
153
170
|
|
|
171
|
+
You can also do multiple subscriptions at once:
|
|
172
|
+
|
|
173
|
+
```js
|
|
174
|
+
const subscriptions = [
|
|
175
|
+
["book", ({title}) => title === "The little prince"], // Model name and filter function
|
|
176
|
+
["author"], // No filter function, all objects returned
|
|
177
|
+
];
|
|
178
|
+
|
|
179
|
+
const callback = ([books, authors]) => {
|
|
180
|
+
// Objects are ready
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
const subKey = store.multipleSubscribe(requests, callback); // Subscribe
|
|
184
|
+
|
|
185
|
+
store.unsubscribe(subKey); // Unsubscribe
|
|
186
|
+
```
|
|
187
|
+
|
|
154
188
|
### Example 6 - Observability + React
|
|
155
189
|
|
|
156
190
|
The integration with React is offered transparently when using the store inside a `React.Component`.
|
|
157
|
-
You can use two methods: `findOne`, and `findAll
|
|
191
|
+
You can use two methods: `findOne`, and `findAll` (which are a react-specific syntactic sugar over `subscribe`).
|
|
158
192
|
|
|
159
|
-
|
|
193
|
+
**_Since the store is able to detect changes deep in a nested structure, you will not have to worry about the component not re-rendering. Also, the setState will be triggered ONLY when the next change of the dataset is impacting your selection._**
|
|
160
194
|
|
|
161
|
-
React Component example
|
|
195
|
+
React Component example:
|
|
162
196
|
```jsx
|
|
163
197
|
class MyComponent extends React.Component {
|
|
164
198
|
constructor(props) {
|
|
@@ -168,9 +202,9 @@ class MyComponent extends React.Component {
|
|
|
168
202
|
componentDidMount() {
|
|
169
203
|
// Get all books with a price < 20
|
|
170
204
|
store.findAll("book", "books", this, ({price}) => price < 20);
|
|
171
|
-
//
|
|
172
|
-
//
|
|
173
|
-
//
|
|
205
|
+
// An attribute "books" will be added/updated in the
|
|
206
|
+
// state (the rest of the state remains unchanged) every time
|
|
207
|
+
// a book in our selection is inserted/deleted/edited.
|
|
174
208
|
|
|
175
209
|
// findAll is a syntactic sugar for:
|
|
176
210
|
// const callback = (books) => {this.setState({...this.state, books})};
|
|
@@ -185,7 +219,7 @@ class MyComponent extends React.Component {
|
|
|
185
219
|
onTitleChange={(title) => book.set("title", title)}
|
|
186
220
|
// onTitleChange will alter the book and so the current
|
|
187
221
|
// state of "books" (a setState will be performed).
|
|
188
|
-
|
|
222
|
+
|
|
189
223
|
// Alternatively:
|
|
190
224
|
// onTitleChange={store.handleChange(book, "title")}
|
|
191
225
|
// is a syntactic sugar of the function above
|
|
@@ -194,9 +228,9 @@ class MyComponent extends React.Component {
|
|
|
194
228
|
}
|
|
195
229
|
```
|
|
196
230
|
|
|
197
|
-
The method `findAll` returns always an array. The method `findOne` returns a single object (if multiple objects satisfy the
|
|
231
|
+
The method `findAll` returns always an array. The method `findOne` returns a single object (if multiple objects satisfy the query, the first is returned).
|
|
198
232
|
|
|
199
|
-
When the component will unmount, the `findAll` subscription will be automatically terminated without the need to unsubscribe. Be aware, `store.findAll` injects the unsubscribe call inside `componentWillUnmount`. If your component already implements `componentWillUnmount()`, then you will have to use `store.subscribe` and `store.unsubscribe` instead of `store.findAll`, to avoid side effects when the component is unmounted.
|
|
233
|
+
When the component will unmount, the `findAll` subscription will be automatically terminated without the need to unsubscribe. Be aware, `store.findAll()` injects the unsubscribe call inside `componentWillUnmount()`. If your component already implements `componentWillUnmount()`, then you will have to use `store.subscribe()` and `store.unsubscribe()` instead of `store.findAll()`, to avoid side effects when the component is unmounted.
|
|
200
234
|
|
|
201
235
|
## Configuration
|
|
202
236
|
|
|
@@ -205,7 +239,7 @@ The store can be configured with the following options:
|
|
|
205
239
|
|
|
206
240
|
| Option | Description | Default |
|
|
207
241
|
|-----------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------|
|
|
208
|
-
| autoSave | It can be `true`, `false`, or an amount of milliseconds (integer). If `false`, you will have to perform `store.save()` manually. If `true`, the store will automatically perform `save()` when objects change. If an amount of milliseconds is provided, the objects are saved periodically AND when a change is detected. See [Editing objects](#editing-objects) for more information. |
|
|
242
|
+
| autoSave | It can be `true`, `false`, or an amount of milliseconds (integer). If `false`, you will have to perform `store.save()` manually. If `true`, the store will automatically perform `save()` when objects change. If an amount of milliseconds is provided, the objects are saved periodically AND when a change is detected. See [Editing objects](#editing-objects) for more information. | true |
|
|
209
243
|
| saveDelay | An amount of milliseconds used to defer synching operations with the server. It triggers `store.save()` milliseconds after the last change on the store's objects is detedect. This allows to bundle together multiple changes operated by an interacting user. See [Editing objects](#editing-objects) for more information. | 1000 |
|
|
210
244
|
| lazyLoad | A boolean. If set to `false`, the store is pre-populated with all the models' objects. If set to `true`, models' objects are loaded only on first usage (e.g., 'find', 'subscribe', 'getRelation'). LazyLoad operates per model, only the objects of the used models are loaded. | false |
|
|
211
245
|
|
|
@@ -216,7 +250,7 @@ The store can be configured with the following options:
|
|
|
216
250
|
A model can be simply created with:
|
|
217
251
|
|
|
218
252
|
```js
|
|
219
|
-
const book = new Model("book", `https://
|
|
253
|
+
const book = new Model("book", `https://api.example.net/books`);
|
|
220
254
|
```
|
|
221
255
|
|
|
222
256
|
However, sometimes you may want to define a more complex interaction with the API. In such cases you can pass options to perform more elaborated model's initializations.
|
|
@@ -418,14 +452,29 @@ author1.getRelation("book", (book) => book.price < 20)
|
|
|
418
452
|
|
|
419
453
|
The store has the following method.
|
|
420
454
|
|
|
421
|
-
| Method
|
|
422
|
-
|
|
423
|
-
|
|
|
424
|
-
|
|
|
425
|
-
|
|
|
426
|
-
|
|
|
427
|
-
| delete(
|
|
428
|
-
|
|
|
455
|
+
| Method | Description |
|
|
456
|
+
|--------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
457
|
+
| on(event, callback) | Method to subscribe to the events emitted by the store. See [events](#store-events) below. |
|
|
458
|
+
| addModel(model) | Introduce a new model to the store. If lazyLoad = false (default), the model is populated with the objects coming from the API. |
|
|
459
|
+
| get(type, id) | It allows to retrieve an object based on its type and store's ID (see `getId()` in [objects methods](#objects-methods). The type is the name of the model. |
|
|
460
|
+
| find(type, filterFunction) | The promise-oriented method to access objects given a type and a filter function. If the filter function is missing, all the objects are returned. See [example 1](#example-1). |
|
|
461
|
+
| delete(objects) | It deletes an array of objects. See [example 1](#example-3). |
|
|
462
|
+
| delete(type, filterFunction) | It deleted objects given an array and a filter function. See [example 1](#example-3). |
|
|
463
|
+
| insert(type, object) | It creates a new object of a given type and inserts it in the store. |
|
|
464
|
+
| subscribe(type, callback, filterFunction) | The callback-oriented method to access objects given a type and a filter function. It returns the key of the subscription, needed to unsubscribe. If the filter function is missing, all the objects are returned. **DataFlux remembers your query and calls the callback every time any change is affecting the result of your query.** See [example 5](#example-5---observability). |
|
|
465
|
+
| multipleSubscribe(subscriptions, callback) | A method to subscribe to multiple models. The first parameter is an array of models' names and filterFunctions, the second parameter is the callback to be called when the cumulative dataset is ready. E.g., `multipleSubscribe([["book", filterFunction1], ["author", filterFunction2]], callback)`. It returns the key of the subscription. See [example 5](#example-5---observability). |
|
|
466
|
+
| unsubscribe(key) | Method to terminate a subscription given a subscription key. See [example 5](#example-5---observability). |
|
|
467
|
+
| findOne(type, stateAttribute, context, filterFunction) | This method automatically injects and updates the React state with the requested data. If multiple objects satisfy the query, only the first is selected. The `stateAttribute` is the name of the attribute that will be added/updated in the state, the `context` is the React.Component. It automatically unsubscribe when the React.Component will unmount. See [example 6](#example-6---observability--react). |
|
|
468
|
+
| findAll(type, stateAttribute, context, filterFunction) | This method automatically injects and updates the React state with the requested data. The `stateAttribute` is the name of the attribute that will be added/updated in the state, the `context` is the React.Component. It automatically unsubscribe when the React.Component will unmount. If the filter function is missing, all the objects are returned. See [example 6](#example-6---observability--react). |
|
|
469
|
+
|
|
470
|
+
## Store events
|
|
471
|
+
The store emits the following events:
|
|
472
|
+
|
|
473
|
+
| Name | Description |
|
|
474
|
+
|---------|---------------------------------------------------------------------------------------------------------------------------------------|
|
|
475
|
+
| error | To listen the errors emitted by the store. |
|
|
476
|
+
| save | Possible emitted values are `start` and `end`. They are emitted when the store starts/finishes to persist the data (API interaction). |
|
|
477
|
+
| loading | The event is emitted while a new model is loaded. The value contains something like `{status: "start", model: "book"}` |
|
|
429
478
|
|
|
430
479
|
## Objects methods
|
|
431
480
|
Each object created is enriched with the following methods.
|
package/dist/Model.js
CHANGED
|
@@ -33,12 +33,16 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d
|
|
|
33
33
|
|
|
34
34
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
35
35
|
|
|
36
|
+
function _classPrivateMethodInitSpec(obj, privateSet) { _checkPrivateRedeclaration(obj, privateSet); privateSet.add(obj); }
|
|
37
|
+
|
|
36
38
|
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
37
39
|
|
|
38
40
|
function _classPrivateFieldInitSpec(obj, privateMap, value) { _checkPrivateRedeclaration(obj, privateMap); privateMap.set(obj, value); }
|
|
39
41
|
|
|
40
42
|
function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } }
|
|
41
43
|
|
|
44
|
+
function _classPrivateMethodGet(receiver, privateSet, fn) { if (!privateSet.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return fn; }
|
|
45
|
+
|
|
42
46
|
function _classPrivateFieldGet(receiver, privateMap) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "get"); return _classApplyDescriptorGet(receiver, descriptor); }
|
|
43
47
|
|
|
44
48
|
function _classApplyDescriptorGet(receiver, descriptor) { if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.value; }
|
|
@@ -49,6 +53,18 @@ function _classExtractFieldDescriptor(receiver, privateMap, action) { if (!priva
|
|
|
49
53
|
|
|
50
54
|
function _classApplyDescriptorSet(receiver, descriptor, value) { if (descriptor.set) { descriptor.set.call(receiver, value); } else { if (!descriptor.writable) { throw new TypeError("attempted to set read only private field"); } descriptor.value = value; } }
|
|
51
55
|
|
|
56
|
+
var applyData = function applyData(obj, data) {
|
|
57
|
+
for (var att in data) {
|
|
58
|
+
if (att !== "id" || obj.id === undefined || att === "id" && obj.id === data.id) {
|
|
59
|
+
obj[att] = data[att];
|
|
60
|
+
} else {
|
|
61
|
+
return Promise.reject("The loading function cannot change the id of the object.");
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return Promise.resolve(obj);
|
|
66
|
+
};
|
|
67
|
+
|
|
52
68
|
var _type = /*#__PURE__*/new WeakMap();
|
|
53
69
|
|
|
54
70
|
var _store = /*#__PURE__*/new WeakMap();
|
|
@@ -71,6 +87,8 @@ var _axios = /*#__PURE__*/new WeakMap();
|
|
|
71
87
|
|
|
72
88
|
var _loadFunction = /*#__PURE__*/new WeakMap();
|
|
73
89
|
|
|
90
|
+
var _error = /*#__PURE__*/new WeakSet();
|
|
91
|
+
|
|
74
92
|
var _addRelationByField = /*#__PURE__*/new WeakMap();
|
|
75
93
|
|
|
76
94
|
var _addRelationByFilter = /*#__PURE__*/new WeakMap();
|
|
@@ -92,6 +110,8 @@ var Model = /*#__PURE__*/_createClass(function Model(name) {
|
|
|
92
110
|
|
|
93
111
|
_classCallCheck(this, Model);
|
|
94
112
|
|
|
113
|
+
_classPrivateMethodInitSpec(this, _error);
|
|
114
|
+
|
|
95
115
|
_classPrivateFieldInitSpec(this, _type, {
|
|
96
116
|
writable: true,
|
|
97
117
|
value: void 0
|
|
@@ -160,35 +180,31 @@ var Model = /*#__PURE__*/_createClass(function Model(name) {
|
|
|
160
180
|
});
|
|
161
181
|
|
|
162
182
|
_defineProperty(this, "load", function (obj) {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
} else {
|
|
169
|
-
return Promise.reject("The loading function cannot change the id of the object.");
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
};
|
|
173
|
-
|
|
174
|
-
if (_classPrivateFieldGet(_this, _loadFunction)) {
|
|
175
|
-
var res = _classPrivateFieldGet(_this, _loadFunction).call(_this, obj.toJson());
|
|
183
|
+
if (_classPrivateFieldGet(_this, _loadFunction)) {
|
|
184
|
+
return _this.getStore().whenSaved(_this.getType())["catch"](function () {
|
|
185
|
+
throw new Error("You cannot perform load() on an unsaved object.");
|
|
186
|
+
}).then(function () {
|
|
187
|
+
var res = _classPrivateFieldGet(_this, _loadFunction).call(_this, obj.toJSON());
|
|
176
188
|
|
|
177
189
|
if (typeof res === "string") {
|
|
178
|
-
_classPrivateFieldGet(_this, _axios).call(_this, {
|
|
190
|
+
return _classPrivateFieldGet(_this, _axios).call(_this, {
|
|
179
191
|
method: "get",
|
|
180
192
|
url: res,
|
|
181
193
|
responseType: "json"
|
|
182
194
|
}).then(function (data) {
|
|
183
|
-
return
|
|
184
|
-
})
|
|
195
|
+
return data.data;
|
|
196
|
+
});
|
|
185
197
|
} else {
|
|
186
|
-
res
|
|
198
|
+
return res;
|
|
187
199
|
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
}
|
|
191
|
-
|
|
200
|
+
}).then(function (data) {
|
|
201
|
+
return applyData(obj, data);
|
|
202
|
+
})["catch"](function (error) {
|
|
203
|
+
return _classPrivateMethodGet(_this, _error, _error2).call(_this, error);
|
|
204
|
+
});
|
|
205
|
+
} else {
|
|
206
|
+
return _classPrivateMethodGet(_this, _error, _error2).call(_this, "You must define a loading function in the model to enable load().");
|
|
207
|
+
}
|
|
192
208
|
});
|
|
193
209
|
|
|
194
210
|
_defineProperty(this, "addRelation", function (model, param2, param3) {
|
|
@@ -216,17 +232,15 @@ var Model = /*#__PURE__*/_createClass(function Model(name) {
|
|
|
216
232
|
var filterRelation = _classPrivateFieldGet(_this, _includes)[includedType];
|
|
217
233
|
|
|
218
234
|
if (filterRelation) {
|
|
219
|
-
return
|
|
220
|
-
return
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
return data.filter(filterFunction);
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
return data;
|
|
235
|
+
return parentObject.load()["catch"](function () {}).then(function () {
|
|
236
|
+
return _this.getStore().find(includedType, function (item) {
|
|
237
|
+
return filterRelation(parentObject, item);
|
|
238
|
+
}).then(function (data) {
|
|
239
|
+
return filterFunction ? data.filter(filterFunction) : data;
|
|
240
|
+
});
|
|
227
241
|
});
|
|
228
242
|
} else {
|
|
229
|
-
return
|
|
243
|
+
return _classPrivateMethodGet(_this, _error, _error2).call(_this, "The relation doesn't exist");
|
|
230
244
|
}
|
|
231
245
|
});
|
|
232
246
|
|
|
@@ -235,7 +249,15 @@ var Model = /*#__PURE__*/_createClass(function Model(name) {
|
|
|
235
249
|
});
|
|
236
250
|
|
|
237
251
|
_defineProperty(this, "retrieveAll", function () {
|
|
238
|
-
return (0, _modelHooksUtils.executeHook)("retrieve", _classPrivateFieldGet(_this, _retrieveHook), null, _classPrivateFieldGet(_this, _axios)).then(
|
|
252
|
+
return (0, _modelHooksUtils.executeHook)("retrieve", _classPrivateFieldGet(_this, _retrieveHook), null, _classPrivateFieldGet(_this, _axios)).then(function (data) {
|
|
253
|
+
if (Array.isArray(data)) {
|
|
254
|
+
return data;
|
|
255
|
+
} else {
|
|
256
|
+
_classPrivateFieldSet(_this, _singleItemQuery, true);
|
|
257
|
+
|
|
258
|
+
return [data];
|
|
259
|
+
}
|
|
260
|
+
});
|
|
239
261
|
});
|
|
240
262
|
|
|
241
263
|
_defineProperty(this, "insertObjects", function (objects) {
|
|
@@ -275,9 +297,13 @@ var Model = /*#__PURE__*/_createClass(function Model(name) {
|
|
|
275
297
|
writable: true,
|
|
276
298
|
value: function value(objects, action) {
|
|
277
299
|
if (_classPrivateFieldGet(_this, _singleItemQuery)) {
|
|
278
|
-
return (0, _batchPromises["default"])(_classPrivateFieldGet(_this, _batchSize), objects
|
|
300
|
+
return (0, _batchPromises["default"])(_classPrivateFieldGet(_this, _batchSize), objects.map(function (i) {
|
|
301
|
+
return i.toJSON();
|
|
302
|
+
}), action);
|
|
279
303
|
} else {
|
|
280
|
-
return action(objects)
|
|
304
|
+
return action(objects.map(function (i) {
|
|
305
|
+
return i.toJSON();
|
|
306
|
+
}));
|
|
281
307
|
}
|
|
282
308
|
}
|
|
283
309
|
});
|
|
@@ -288,8 +314,6 @@ var Model = /*#__PURE__*/_createClass(function Model(name) {
|
|
|
288
314
|
if (Array.isArray(data)) {
|
|
289
315
|
return data;
|
|
290
316
|
} else {
|
|
291
|
-
_classPrivateFieldSet(_this, _singleItemQuery, true);
|
|
292
|
-
|
|
293
317
|
return [data];
|
|
294
318
|
}
|
|
295
319
|
}
|
|
@@ -356,4 +380,10 @@ var Model = /*#__PURE__*/_createClass(function Model(name) {
|
|
|
356
380
|
|
|
357
381
|
});
|
|
358
382
|
|
|
359
|
-
exports["default"] = Model;
|
|
383
|
+
exports["default"] = Model;
|
|
384
|
+
|
|
385
|
+
function _error2(error) {
|
|
386
|
+
error = error.message || error;
|
|
387
|
+
this.getStore().pubSub.publish("error", error);
|
|
388
|
+
return Promise.reject(error);
|
|
389
|
+
}
|
|
@@ -35,7 +35,7 @@ function _classApplyDescriptorGet(receiver, descriptor) { if (descriptor.get) {
|
|
|
35
35
|
|
|
36
36
|
var _loaded = /*#__PURE__*/new WeakMap();
|
|
37
37
|
|
|
38
|
-
var Obj = /*#__PURE__*/_createClass(function Obj(values,
|
|
38
|
+
var Obj = /*#__PURE__*/_createClass(function Obj(values, _model) {
|
|
39
39
|
var _this = this;
|
|
40
40
|
|
|
41
41
|
_classCallCheck(this, Obj);
|
|
@@ -49,11 +49,15 @@ var Obj = /*#__PURE__*/_createClass(function Obj(values, model) {
|
|
|
49
49
|
if (_classPrivateFieldGet(_this, _loaded)) {
|
|
50
50
|
return Promise.resolve(_this);
|
|
51
51
|
} else {
|
|
52
|
-
|
|
52
|
+
var model = _this.getModel();
|
|
53
|
+
|
|
54
|
+
return model.load(_this).then(function () {
|
|
53
55
|
_classPrivateFieldSet(_this, _loaded, true);
|
|
54
56
|
|
|
57
|
+
return model.getStore().update([_this], true); // Propagate update
|
|
58
|
+
}).then(function () {
|
|
55
59
|
return _this;
|
|
56
|
-
});
|
|
60
|
+
}); // return always this
|
|
57
61
|
}
|
|
58
62
|
});
|
|
59
63
|
|
|
@@ -75,8 +79,7 @@ var Obj = /*#__PURE__*/_createClass(function Obj(values, model) {
|
|
|
75
79
|
}
|
|
76
80
|
|
|
77
81
|
_this[attribute] = value;
|
|
78
|
-
|
|
79
|
-
_this.getModel().getStore().update([_this]);
|
|
82
|
+
return _this.getModel().getStore().update([_this]);
|
|
80
83
|
});
|
|
81
84
|
|
|
82
85
|
_defineProperty(this, "save", function () {
|
|
@@ -107,7 +110,7 @@ var Obj = /*#__PURE__*/_createClass(function Obj(values, model) {
|
|
|
107
110
|
});
|
|
108
111
|
|
|
109
112
|
this.getModel = function () {
|
|
110
|
-
return
|
|
113
|
+
return _model;
|
|
111
114
|
};
|
|
112
115
|
|
|
113
116
|
Object.keys(values).forEach(function (key) {
|
package/dist/ObserverStore.js
CHANGED
|
@@ -17,8 +17,16 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "d
|
|
|
17
17
|
|
|
18
18
|
function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
|
|
19
19
|
|
|
20
|
+
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
|
|
21
|
+
|
|
22
|
+
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
23
|
+
|
|
20
24
|
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
|
|
21
25
|
|
|
26
|
+
function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
|
|
27
|
+
|
|
28
|
+
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
|
|
29
|
+
|
|
22
30
|
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
|
|
23
31
|
|
|
24
32
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
@@ -83,6 +91,22 @@ var ObserverStore = /*#__PURE__*/function (_PersistentStore) {
|
|
|
83
91
|
|
|
84
92
|
_classPrivateMethodInitSpec(_assertThisInitialized(_this), _propagateInsertChange);
|
|
85
93
|
|
|
94
|
+
_defineProperty(_assertThisInitialized(_this), "multipleSubscribe", function (subscriptions, callback) {
|
|
95
|
+
return Promise.all(subscriptions.map(function (sub, index) {
|
|
96
|
+
var attrs = Array.from(Array(index + 1)).map(function () {
|
|
97
|
+
return null;
|
|
98
|
+
});
|
|
99
|
+
return _this.subscribe(sub[0], sub[1], function (data) {
|
|
100
|
+
attrs[index] = data;
|
|
101
|
+
return callback.apply(void 0, _toConsumableArray(attrs));
|
|
102
|
+
});
|
|
103
|
+
})).then(function (subKeys) {
|
|
104
|
+
var subKey = (0, _uuid.v4)();
|
|
105
|
+
_this._multipleSubscribed[subKey] = subKeys;
|
|
106
|
+
return subKey;
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
|
|
86
110
|
_defineProperty(_assertThisInitialized(_this), "subscribe", function (type, callback, filterFunction) {
|
|
87
111
|
var subKey = (0, _uuid.v4)();
|
|
88
112
|
|
|
@@ -104,14 +128,33 @@ var ObserverStore = /*#__PURE__*/function (_PersistentStore) {
|
|
|
104
128
|
});
|
|
105
129
|
|
|
106
130
|
_defineProperty(_assertThisInitialized(_this), "unsubscribe", function (key) {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
131
|
+
if (_this._multipleSubscribed[key]) {
|
|
132
|
+
var _iterator = _createForOfIteratorHelper(_this._multipleSubscribed[key]),
|
|
133
|
+
_step;
|
|
134
|
+
|
|
135
|
+
try {
|
|
136
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
137
|
+
var sub = _step.value;
|
|
112
138
|
|
|
113
|
-
|
|
114
|
-
|
|
139
|
+
_this.unsubscribe(sub);
|
|
140
|
+
}
|
|
141
|
+
} catch (err) {
|
|
142
|
+
_iterator.e(err);
|
|
143
|
+
} finally {
|
|
144
|
+
_iterator.f();
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
delete _this._multipleSubscribed[key];
|
|
148
|
+
} else {
|
|
149
|
+
for (var type in _this._subscribed) {
|
|
150
|
+
for (var id in _this._subscribed[type]) {
|
|
151
|
+
_this._subscribed[type][id] = _this._subscribed[type][id].filter(function (i) {
|
|
152
|
+
return i.subKey !== key;
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
if (_this._subscribed[type][id].length === 0) {
|
|
156
|
+
delete _this._subscribed[type][id];
|
|
157
|
+
}
|
|
115
158
|
}
|
|
116
159
|
}
|
|
117
160
|
}
|
|
@@ -122,34 +165,34 @@ var ObserverStore = /*#__PURE__*/function (_PersistentStore) {
|
|
|
122
165
|
value: function value(objects, type) {
|
|
123
166
|
var out = {};
|
|
124
167
|
|
|
125
|
-
var
|
|
126
|
-
|
|
168
|
+
var _iterator2 = _createForOfIteratorHelper(objects),
|
|
169
|
+
_step2;
|
|
127
170
|
|
|
128
171
|
try {
|
|
129
|
-
for (
|
|
130
|
-
var object =
|
|
172
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
173
|
+
var object = _step2.value;
|
|
131
174
|
var objectId = object.getId();
|
|
132
175
|
var typeChannel = _this._subscribed[type] || {};
|
|
133
176
|
var subscribedToObject = typeChannel[objectId] || [];
|
|
134
177
|
|
|
135
|
-
var
|
|
136
|
-
|
|
178
|
+
var _iterator3 = _createForOfIteratorHelper(subscribedToObject),
|
|
179
|
+
_step3;
|
|
137
180
|
|
|
138
181
|
try {
|
|
139
|
-
for (
|
|
140
|
-
var sub =
|
|
182
|
+
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
183
|
+
var sub = _step3.value;
|
|
141
184
|
out[sub.subKey] = out[sub.subKey] || sub;
|
|
142
185
|
}
|
|
143
186
|
} catch (err) {
|
|
144
|
-
|
|
187
|
+
_iterator3.e(err);
|
|
145
188
|
} finally {
|
|
146
|
-
|
|
189
|
+
_iterator3.f();
|
|
147
190
|
}
|
|
148
191
|
}
|
|
149
192
|
} catch (err) {
|
|
150
|
-
|
|
193
|
+
_iterator2.e(err);
|
|
151
194
|
} finally {
|
|
152
|
-
|
|
195
|
+
_iterator2.f();
|
|
153
196
|
}
|
|
154
197
|
|
|
155
198
|
return Object.values(out);
|
|
@@ -180,12 +223,12 @@ var ObserverStore = /*#__PURE__*/function (_PersistentStore) {
|
|
|
180
223
|
_classPrivateFieldInitSpec(_assertThisInitialized(_this), _subscribeToObjects, {
|
|
181
224
|
writable: true,
|
|
182
225
|
value: function value(type, objectsToSubscribe, item) {
|
|
183
|
-
var
|
|
184
|
-
|
|
226
|
+
var _iterator4 = _createForOfIteratorHelper(objectsToSubscribe),
|
|
227
|
+
_step4;
|
|
185
228
|
|
|
186
229
|
try {
|
|
187
|
-
for (
|
|
188
|
-
var object =
|
|
230
|
+
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
|
|
231
|
+
var object = _step4.value;
|
|
189
232
|
var id = object.getId();
|
|
190
233
|
|
|
191
234
|
if (!_this._subscribed[type][id]) {
|
|
@@ -195,21 +238,22 @@ var ObserverStore = /*#__PURE__*/function (_PersistentStore) {
|
|
|
195
238
|
_this._subscribed[type][id].push(item);
|
|
196
239
|
}
|
|
197
240
|
} catch (err) {
|
|
198
|
-
|
|
241
|
+
_iterator4.e(err);
|
|
199
242
|
} finally {
|
|
200
|
-
|
|
243
|
+
_iterator4.f();
|
|
201
244
|
}
|
|
202
245
|
}
|
|
203
246
|
});
|
|
204
247
|
|
|
205
248
|
_this._subscribed = {};
|
|
249
|
+
_this._multipleSubscribed = {};
|
|
206
250
|
return _this;
|
|
207
251
|
}
|
|
208
252
|
|
|
209
253
|
_createClass(ObserverStore, [{
|
|
210
254
|
key: "update",
|
|
211
|
-
value: function update(objects) {
|
|
212
|
-
return _get(_getPrototypeOf(ObserverStore.prototype), "update", this).call(this, objects).then(_classPrivateFieldGet(this, _propagateChange));
|
|
255
|
+
value: function update(objects, skipSave) {
|
|
256
|
+
return _get(_getPrototypeOf(ObserverStore.prototype), "update", this).call(this, objects, skipSave).then(_classPrivateFieldGet(this, _propagateChange));
|
|
213
257
|
}
|
|
214
258
|
}, {
|
|
215
259
|
key: "insert",
|
|
@@ -243,21 +287,21 @@ function _propagateInsertChange2(type, newObjects) {
|
|
|
243
287
|
for (var _i = 0, _objects = objects; _i < _objects.length; _i++) {
|
|
244
288
|
var object = _objects[_i];
|
|
245
289
|
|
|
246
|
-
var
|
|
247
|
-
|
|
290
|
+
var _iterator5 = _createForOfIteratorHelper(object),
|
|
291
|
+
_step5;
|
|
248
292
|
|
|
249
293
|
try {
|
|
250
|
-
for (
|
|
251
|
-
var sub =
|
|
294
|
+
for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
|
|
295
|
+
var sub = _step5.value;
|
|
252
296
|
|
|
253
297
|
if (!uniqueSubs[sub.subKey]) {
|
|
254
298
|
uniqueSubs[sub.subKey] = sub;
|
|
255
299
|
}
|
|
256
300
|
}
|
|
257
301
|
} catch (err) {
|
|
258
|
-
|
|
302
|
+
_iterator5.e(err);
|
|
259
303
|
} finally {
|
|
260
|
-
|
|
304
|
+
_iterator5.f();
|
|
261
305
|
}
|
|
262
306
|
}
|
|
263
307
|
|
|
@@ -272,12 +316,12 @@ function _propagateInsertChange2(type, newObjects) {
|
|
|
272
316
|
return _this3.find(type, filterFunction).then(function (data) {
|
|
273
317
|
var subKey;
|
|
274
318
|
|
|
275
|
-
var
|
|
276
|
-
|
|
319
|
+
var _iterator6 = _createForOfIteratorHelper(data),
|
|
320
|
+
_step6;
|
|
277
321
|
|
|
278
322
|
try {
|
|
279
|
-
for (
|
|
280
|
-
var d =
|
|
323
|
+
for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
|
|
324
|
+
var d = _step6.value;
|
|
281
325
|
|
|
282
326
|
var item = _this3._subscribed[d.getModel().getType()][d.getId()];
|
|
283
327
|
|
|
@@ -285,9 +329,9 @@ function _propagateInsertChange2(type, newObjects) {
|
|
|
285
329
|
if (subKey) break;
|
|
286
330
|
}
|
|
287
331
|
} catch (err) {
|
|
288
|
-
|
|
332
|
+
_iterator6.e(err);
|
|
289
333
|
} finally {
|
|
290
|
-
|
|
334
|
+
_iterator6.f();
|
|
291
335
|
}
|
|
292
336
|
|
|
293
337
|
_classPrivateFieldGet(_this3, _subscribeToObjects).call(_this3, type, objectsToSubscribe, {
|
package/dist/PersistentStore.js
CHANGED
|
@@ -49,11 +49,35 @@ var PersistentStore = /*#__PURE__*/function (_Store) {
|
|
|
49
49
|
|
|
50
50
|
_this = _super.call(this, options);
|
|
51
51
|
|
|
52
|
+
_defineProperty(_assertThisInitialized(_this), "whenSaved", function (type) {
|
|
53
|
+
return _this.getDiff(type).then(function (_ref) {
|
|
54
|
+
var inserted = _ref.inserted,
|
|
55
|
+
updated = _ref.updated,
|
|
56
|
+
deleted = _ref.deleted;
|
|
57
|
+
|
|
58
|
+
if (inserted.length === 0 && updated.length === 0 && deleted.length === 0) {
|
|
59
|
+
return true;
|
|
60
|
+
} else if (_this.options.autoSave) {
|
|
61
|
+
return _this._saveDiff(type, {
|
|
62
|
+
inserted: inserted,
|
|
63
|
+
updated: updated,
|
|
64
|
+
deleted: deleted
|
|
65
|
+
});
|
|
66
|
+
} else {
|
|
67
|
+
return Promise.reject("Save must be invoked manually");
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
52
72
|
_defineProperty(_assertThisInitialized(_this), "save", function () {
|
|
53
73
|
_this._busy = true;
|
|
54
74
|
|
|
55
75
|
_this.pubSub.publish("save", "start");
|
|
56
76
|
|
|
77
|
+
if (_this._delayedSaveTimer) {
|
|
78
|
+
clearTimeout(_this._delayedSaveTimer);
|
|
79
|
+
}
|
|
80
|
+
|
|
57
81
|
return Promise.all(Object.keys(_this.models).map(_this._saveByType)).then(function (data) {
|
|
58
82
|
_this._busy = false;
|
|
59
83
|
|
|
@@ -71,33 +95,43 @@ var PersistentStore = /*#__PURE__*/function (_Store) {
|
|
|
71
95
|
});
|
|
72
96
|
});
|
|
73
97
|
|
|
98
|
+
_defineProperty(_assertThisInitialized(_this), "_saveDiff", function (type, _ref2) {
|
|
99
|
+
var inserted = _ref2.inserted,
|
|
100
|
+
updated = _ref2.updated,
|
|
101
|
+
deleted = _ref2.deleted;
|
|
102
|
+
var model = _this.models[type].model; // Operations order:
|
|
103
|
+
// 1) insert
|
|
104
|
+
// 2) update
|
|
105
|
+
// 3) delete
|
|
106
|
+
|
|
107
|
+
return model.insertObjects(inserted.map(function (i) {
|
|
108
|
+
return i.object;
|
|
109
|
+
})).then(function () {
|
|
110
|
+
return _this.applyDiff({
|
|
111
|
+
inserted: inserted
|
|
112
|
+
}, type);
|
|
113
|
+
}).then(function () {
|
|
114
|
+
return model.updateObjects(updated.map(function (i) {
|
|
115
|
+
return i.object;
|
|
116
|
+
}));
|
|
117
|
+
}).then(function () {
|
|
118
|
+
return _this.applyDiff({
|
|
119
|
+
updated: updated
|
|
120
|
+
}, type);
|
|
121
|
+
}).then(function () {
|
|
122
|
+
return model.deleteObjects(deleted.map(function (i) {
|
|
123
|
+
return i.object;
|
|
124
|
+
}));
|
|
125
|
+
}).then(function () {
|
|
126
|
+
return _this.applyDiff({
|
|
127
|
+
deleted: deleted
|
|
128
|
+
}, type);
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
|
|
74
132
|
_defineProperty(_assertThisInitialized(_this), "_saveByType", function (type) {
|
|
75
|
-
return _this.getDiff(type).then(function (
|
|
76
|
-
|
|
77
|
-
updated = _ref.updated,
|
|
78
|
-
deleted = _ref.deleted;
|
|
79
|
-
var model = _this.models[type].model; // Operations order:
|
|
80
|
-
// 1) insert
|
|
81
|
-
// 2) update
|
|
82
|
-
// 3) delete
|
|
83
|
-
|
|
84
|
-
return model.insertObjects(inserted).then(function () {
|
|
85
|
-
return _this.applyDiff({
|
|
86
|
-
inserted: inserted
|
|
87
|
-
}, type);
|
|
88
|
-
}).then(function () {
|
|
89
|
-
return model.updateObjects(updated);
|
|
90
|
-
}).then(function () {
|
|
91
|
-
return _this.applyDiff({
|
|
92
|
-
updated: updated
|
|
93
|
-
}, type);
|
|
94
|
-
}).then(function () {
|
|
95
|
-
return model.deleteObjects(deleted);
|
|
96
|
-
}).then(function () {
|
|
97
|
-
return _this.applyDiff({
|
|
98
|
-
deleted: deleted
|
|
99
|
-
}, type);
|
|
100
|
-
});
|
|
133
|
+
return _this.getDiff(type).then(function (diff) {
|
|
134
|
+
return _this._saveDiff(type, diff);
|
|
101
135
|
});
|
|
102
136
|
});
|
|
103
137
|
|
|
@@ -131,8 +165,7 @@ var PersistentStore = /*#__PURE__*/function (_Store) {
|
|
|
131
165
|
var _this2 = this;
|
|
132
166
|
|
|
133
167
|
this._busy = true;
|
|
134
|
-
|
|
135
|
-
_get(_getPrototypeOf(PersistentStore.prototype), "addModel", this).call(this, model).then(function () {
|
|
168
|
+
return _get(_getPrototypeOf(PersistentStore.prototype), "addModel", this).call(this, model).then(function () {
|
|
136
169
|
_this2._busy = false;
|
|
137
170
|
});
|
|
138
171
|
}
|
|
@@ -160,11 +193,13 @@ var PersistentStore = /*#__PURE__*/function (_Store) {
|
|
|
160
193
|
}
|
|
161
194
|
}, {
|
|
162
195
|
key: "update",
|
|
163
|
-
value: function update(objects) {
|
|
196
|
+
value: function update(objects, skipSave) {
|
|
164
197
|
var _this5 = this;
|
|
165
198
|
|
|
166
199
|
return _get(_getPrototypeOf(PersistentStore.prototype), "update", this).call(this, objects).then(function (data) {
|
|
167
|
-
|
|
200
|
+
if (!skipSave) {
|
|
201
|
+
_this5.delayedSave();
|
|
202
|
+
}
|
|
168
203
|
|
|
169
204
|
return data;
|
|
170
205
|
});
|
package/dist/Store.js
CHANGED
|
@@ -5,7 +5,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports["default"] = void 0;
|
|
7
7
|
|
|
8
|
-
var
|
|
8
|
+
var _Obj = _interopRequireDefault(require("./Obj"));
|
|
9
9
|
|
|
10
10
|
var _PubSub = _interopRequireDefault(require("./PubSub"));
|
|
11
11
|
|
|
@@ -17,21 +17,29 @@ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o =
|
|
|
17
17
|
|
|
18
18
|
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
|
|
19
19
|
|
|
20
|
-
function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); }
|
|
21
|
-
|
|
22
20
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
23
21
|
|
|
24
22
|
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
|
|
25
23
|
|
|
26
24
|
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
|
|
27
25
|
|
|
26
|
+
function _classPrivateFieldInitSpec(obj, privateMap, value) { _checkPrivateRedeclaration(obj, privateMap); privateMap.set(obj, value); }
|
|
27
|
+
|
|
28
28
|
function _classPrivateMethodInitSpec(obj, privateSet) { _checkPrivateRedeclaration(obj, privateSet); privateSet.add(obj); }
|
|
29
29
|
|
|
30
30
|
function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } }
|
|
31
31
|
|
|
32
|
+
function _classPrivateFieldGet(receiver, privateMap) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "get"); return _classApplyDescriptorGet(receiver, descriptor); }
|
|
33
|
+
|
|
34
|
+
function _classExtractFieldDescriptor(receiver, privateMap, action) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to " + action + " private field on non-instance"); } return privateMap.get(receiver); }
|
|
35
|
+
|
|
36
|
+
function _classApplyDescriptorGet(receiver, descriptor) { if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.value; }
|
|
37
|
+
|
|
32
38
|
function _classPrivateMethodGet(receiver, privateSet, fn) { if (!privateSet.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return fn; }
|
|
33
39
|
|
|
34
|
-
var
|
|
40
|
+
var _error = /*#__PURE__*/new WeakSet();
|
|
41
|
+
|
|
42
|
+
var _deleteByObject = /*#__PURE__*/new WeakMap();
|
|
35
43
|
|
|
36
44
|
var _deleteByFilter = /*#__PURE__*/new WeakSet();
|
|
37
45
|
|
|
@@ -43,6 +51,8 @@ var _loadObjects = /*#__PURE__*/new WeakSet();
|
|
|
43
51
|
|
|
44
52
|
var Store = /*#__PURE__*/function () {
|
|
45
53
|
function Store() {
|
|
54
|
+
var _this = this;
|
|
55
|
+
|
|
46
56
|
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
47
57
|
|
|
48
58
|
_classCallCheck(this, Store);
|
|
@@ -55,10 +65,23 @@ var Store = /*#__PURE__*/function () {
|
|
|
55
65
|
|
|
56
66
|
_classPrivateMethodInitSpec(this, _deleteByFilter);
|
|
57
67
|
|
|
58
|
-
_classPrivateMethodInitSpec(this,
|
|
68
|
+
_classPrivateMethodInitSpec(this, _error);
|
|
69
|
+
|
|
70
|
+
_classPrivateFieldInitSpec(this, _deleteByObject, {
|
|
71
|
+
writable: true,
|
|
72
|
+
value: function value(object) {
|
|
73
|
+
var id = object.getId();
|
|
74
|
+
|
|
75
|
+
var filterFunction = function filterFunction(item) {
|
|
76
|
+
return id === item.getId();
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
return _classPrivateMethodGet(_this, _deleteByFilter, _deleteByFilter2).call(_this, object.getModel().getType(), filterFunction);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
59
82
|
|
|
60
83
|
this.options = {
|
|
61
|
-
autoSave: options.autoSave !== undefined ? options.autoSave :
|
|
84
|
+
autoSave: options.autoSave !== undefined ? options.autoSave : true,
|
|
62
85
|
saveDelay: options.saveDelay || 1000,
|
|
63
86
|
lazyLoad: options.lazyLoad || false
|
|
64
87
|
};
|
|
@@ -83,65 +106,75 @@ var Store = /*#__PURE__*/function () {
|
|
|
83
106
|
}, {
|
|
84
107
|
key: "addModel",
|
|
85
108
|
value: function addModel(model) {
|
|
86
|
-
var
|
|
109
|
+
var _this2 = this;
|
|
87
110
|
|
|
88
111
|
return new Promise(function (resolve, reject) {
|
|
89
|
-
|
|
112
|
+
_this2.validateModel(model);
|
|
90
113
|
|
|
91
114
|
var type = model.getType();
|
|
92
115
|
|
|
93
|
-
if (!
|
|
94
|
-
|
|
116
|
+
if (!_this2.models[type]) {
|
|
117
|
+
_this2.models[type] = {
|
|
95
118
|
model: model,
|
|
96
119
|
storedObjects: {}
|
|
97
120
|
};
|
|
98
|
-
model.setStore(
|
|
121
|
+
model.setStore(_this2);
|
|
99
122
|
|
|
100
|
-
if (!
|
|
101
|
-
resolve(_classPrivateMethodGet(
|
|
123
|
+
if (!_this2.options.lazyLoad) {
|
|
124
|
+
resolve(_classPrivateMethodGet(_this2, _loadObjects, _loadObjects2).call(_this2, type));
|
|
102
125
|
} else {
|
|
103
126
|
resolve();
|
|
104
127
|
}
|
|
105
128
|
} else {
|
|
106
|
-
|
|
129
|
+
var error = "The model already exists";
|
|
130
|
+
|
|
131
|
+
_this2.pubSub.publish("error", error);
|
|
132
|
+
|
|
133
|
+
reject(error);
|
|
107
134
|
}
|
|
108
135
|
});
|
|
109
136
|
}
|
|
110
137
|
}, {
|
|
111
138
|
key: "update",
|
|
112
139
|
value: function update(objects) {
|
|
113
|
-
return Promise.resolve(); // Nothing to do at this level
|
|
140
|
+
return Promise.resolve(objects); // Nothing to do at this level
|
|
114
141
|
}
|
|
115
142
|
}, {
|
|
116
143
|
key: "delete",
|
|
117
144
|
value: function _delete(typeOrObjects, filterFunction) {
|
|
118
145
|
if (typeof typeOrObjects === "string" && typeof filterFunction === "function") {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
146
|
+
var type = typeOrObjects;
|
|
147
|
+
return _classPrivateMethodGet(this, _deleteByFilter, _deleteByFilter2).call(this, type, filterFunction);
|
|
148
|
+
} else if (Array.isArray(typeOrObjects) && typeOrObjects.length && !filterFunction) {
|
|
149
|
+
var objects = typeOrObjects;
|
|
150
|
+
return Promise.all(objects.map(_classPrivateFieldGet(this, _deleteByObject))).then(function (data) {
|
|
151
|
+
return data.flat();
|
|
152
|
+
});
|
|
122
153
|
} else {
|
|
123
|
-
|
|
154
|
+
var error = "Invalid delete request. You have to provide a list of objects or a type and a filter function";
|
|
155
|
+
this.pubSub.publish("error", error);
|
|
156
|
+
return Promise.reject(error);
|
|
124
157
|
}
|
|
125
158
|
}
|
|
126
159
|
}, {
|
|
127
160
|
key: "insert",
|
|
128
161
|
value: function insert(type, objects) {
|
|
129
|
-
var
|
|
162
|
+
var _this3 = this;
|
|
130
163
|
|
|
131
164
|
return _classPrivateMethodGet(this, _getPromise, _getPromise2).call(this, type).then(function () {
|
|
132
165
|
return objects.map(function (object) {
|
|
133
|
-
return _classPrivateMethodGet(
|
|
166
|
+
return _classPrivateMethodGet(_this3, _insertObject, _insertObject2).call(_this3, type, object, true);
|
|
134
167
|
});
|
|
135
168
|
});
|
|
136
169
|
}
|
|
137
170
|
}, {
|
|
138
171
|
key: "get",
|
|
139
172
|
value: function get(type, id) {
|
|
140
|
-
var
|
|
173
|
+
var _this4 = this;
|
|
141
174
|
|
|
142
175
|
return _classPrivateMethodGet(this, _getPromise, _getPromise2).call(this, type).then(function () {
|
|
143
176
|
try {
|
|
144
|
-
return
|
|
177
|
+
return _this4.models[type].storedObjects[id].object;
|
|
145
178
|
} catch (error) {
|
|
146
179
|
return Promise.reject("Object not found");
|
|
147
180
|
}
|
|
@@ -150,17 +183,17 @@ var Store = /*#__PURE__*/function () {
|
|
|
150
183
|
}, {
|
|
151
184
|
key: "find",
|
|
152
185
|
value: function find(type, filterFunction) {
|
|
153
|
-
var
|
|
186
|
+
var _this5 = this;
|
|
154
187
|
|
|
155
188
|
return _classPrivateMethodGet(this, _getPromise, _getPromise2).call(this, type).then(function () {
|
|
156
|
-
var all = Object.values(
|
|
189
|
+
var all = Object.values(_this5.models[type].storedObjects).filter(function (i) {
|
|
157
190
|
return i.status !== "deleted";
|
|
158
191
|
}).map(function (i) {
|
|
159
192
|
return i.object;
|
|
160
193
|
});
|
|
161
194
|
return filterFunction ? all.filter(filterFunction) : all;
|
|
162
195
|
})["catch"](function (error) {
|
|
163
|
-
|
|
196
|
+
_this5.pubSub.publish("error", error);
|
|
164
197
|
|
|
165
198
|
return Promise.reject(error);
|
|
166
199
|
});
|
|
@@ -168,7 +201,7 @@ var Store = /*#__PURE__*/function () {
|
|
|
168
201
|
}, {
|
|
169
202
|
key: "applyDiff",
|
|
170
203
|
value: function applyDiff(_ref, type) {
|
|
171
|
-
var
|
|
204
|
+
var _this6 = this;
|
|
172
205
|
|
|
173
206
|
var _ref$inserted = _ref.inserted,
|
|
174
207
|
inserted = _ref$inserted === void 0 ? [] : _ref$inserted,
|
|
@@ -185,7 +218,7 @@ var Store = /*#__PURE__*/function () {
|
|
|
185
218
|
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
186
219
|
var object = _step.value;
|
|
187
220
|
|
|
188
|
-
var item =
|
|
221
|
+
var item = _this6.models[type || object.object.getModel().getType()].storedObjects[object.id];
|
|
189
222
|
|
|
190
223
|
item.fingerprint = object.object.getFingerprint();
|
|
191
224
|
item.status = "old";
|
|
@@ -202,7 +235,7 @@ var Store = /*#__PURE__*/function () {
|
|
|
202
235
|
try {
|
|
203
236
|
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
204
237
|
var _object = _step2.value;
|
|
205
|
-
delete
|
|
238
|
+
delete _this6.models[type || _object.object.getModel().getType()].storedObjects[_object.id];
|
|
206
239
|
}
|
|
207
240
|
} catch (err) {
|
|
208
241
|
_iterator2.e(err);
|
|
@@ -216,13 +249,19 @@ var Store = /*#__PURE__*/function () {
|
|
|
216
249
|
}
|
|
217
250
|
});
|
|
218
251
|
}
|
|
252
|
+
}, {
|
|
253
|
+
key: "hasChanged",
|
|
254
|
+
value: function hasChanged(type, object) {
|
|
255
|
+
var obj = this.models[type].storedObjects[object.getId()];
|
|
256
|
+
return obj.fingerprint !== obj.object.getFingerprint();
|
|
257
|
+
}
|
|
219
258
|
}, {
|
|
220
259
|
key: "getDiff",
|
|
221
260
|
value: function getDiff(type) {
|
|
222
|
-
var
|
|
261
|
+
var _this7 = this;
|
|
223
262
|
|
|
224
263
|
return _classPrivateMethodGet(this, _getPromise, _getPromise2).call(this, type).then(function () {
|
|
225
|
-
var objects = Object.values(
|
|
264
|
+
var objects = Object.values(_this7.models[type].storedObjects);
|
|
226
265
|
var inserted = [];
|
|
227
266
|
var updated = [];
|
|
228
267
|
var deleted = [];
|
|
@@ -234,7 +273,7 @@ var Store = /*#__PURE__*/function () {
|
|
|
234
273
|
inserted.push(object);
|
|
235
274
|
} else if (object.status === "deleted") {
|
|
236
275
|
deleted.push(object);
|
|
237
|
-
} else if (
|
|
276
|
+
} else if (_this7.hasChanged(type, object.object)) {
|
|
238
277
|
updated.push(object);
|
|
239
278
|
}
|
|
240
279
|
}
|
|
@@ -253,17 +292,17 @@ var Store = /*#__PURE__*/function () {
|
|
|
253
292
|
|
|
254
293
|
exports["default"] = Store;
|
|
255
294
|
|
|
256
|
-
function
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
295
|
+
function _error2(error) {
|
|
296
|
+
error = error.message || error;
|
|
297
|
+
this.pubSub.publish("error", error);
|
|
298
|
+
return Promise.reject(error);
|
|
260
299
|
}
|
|
261
300
|
|
|
262
301
|
function _deleteByFilter2(type, filterFunction) {
|
|
263
|
-
var
|
|
302
|
+
var _this8 = this;
|
|
264
303
|
|
|
265
304
|
return _classPrivateMethodGet(this, _getPromise, _getPromise2).call(this, type).then(function () {
|
|
266
|
-
var deleted = Object.values(
|
|
305
|
+
var deleted = Object.values(_this8.models[type].storedObjects).filter(function (i) {
|
|
267
306
|
return filterFunction(i.object);
|
|
268
307
|
});
|
|
269
308
|
|
|
@@ -281,12 +320,14 @@ function _deleteByFilter2(type, filterFunction) {
|
|
|
281
320
|
_iterator3.f();
|
|
282
321
|
}
|
|
283
322
|
|
|
284
|
-
return
|
|
323
|
+
return deleted.map(function (i) {
|
|
324
|
+
return i.object;
|
|
325
|
+
});
|
|
285
326
|
});
|
|
286
327
|
}
|
|
287
328
|
|
|
288
329
|
function _getPromise2(type) {
|
|
289
|
-
var
|
|
330
|
+
var _this9 = this;
|
|
290
331
|
|
|
291
332
|
if (!this.models[type]) {
|
|
292
333
|
return Promise.reject("The model doesn't exist");
|
|
@@ -294,7 +335,7 @@ function _getPromise2(type) {
|
|
|
294
335
|
return Promise.reject("The model is not loaded");
|
|
295
336
|
} else if (!this.models[type].promise && this.options.lazyLoad) {
|
|
296
337
|
return _classPrivateMethodGet(this, _loadObjects, _loadObjects2).call(this, type).then(function () {
|
|
297
|
-
return
|
|
338
|
+
return _this9.models[type].promise;
|
|
298
339
|
});
|
|
299
340
|
} else {
|
|
300
341
|
return this.models[type].promise;
|
|
@@ -304,7 +345,7 @@ function _getPromise2(type) {
|
|
|
304
345
|
function _insertObject2(type, item) {
|
|
305
346
|
var markAsNew = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
|
|
306
347
|
var model = this.models[type].model;
|
|
307
|
-
var wrapper = new
|
|
348
|
+
var wrapper = new _Obj["default"](item, model);
|
|
308
349
|
var id = wrapper.getId();
|
|
309
350
|
|
|
310
351
|
if (this.models[type].storedObjects[id]) {
|
|
@@ -321,7 +362,7 @@ function _insertObject2(type, item) {
|
|
|
321
362
|
}
|
|
322
363
|
|
|
323
364
|
function _loadObjects2(type) {
|
|
324
|
-
var
|
|
365
|
+
var _this10 = this;
|
|
325
366
|
|
|
326
367
|
var item = this.models[type];
|
|
327
368
|
this.pubSub.publish("loading", {
|
|
@@ -336,7 +377,7 @@ function _loadObjects2(type) {
|
|
|
336
377
|
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
|
|
337
378
|
var _item = _step4.value;
|
|
338
379
|
|
|
339
|
-
_classPrivateMethodGet(
|
|
380
|
+
_classPrivateMethodGet(_this10, _insertObject, _insertObject2).call(_this10, type, _item, false);
|
|
340
381
|
}
|
|
341
382
|
} catch (err) {
|
|
342
383
|
_iterator4.e(err);
|
|
@@ -344,7 +385,7 @@ function _loadObjects2(type) {
|
|
|
344
385
|
_iterator4.f();
|
|
345
386
|
}
|
|
346
387
|
|
|
347
|
-
|
|
388
|
+
_this10.pubSub.publish("loading", {
|
|
348
389
|
status: "end",
|
|
349
390
|
model: type
|
|
350
391
|
});
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dataflux",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.5",
|
|
4
4
|
"description": "DataFlux, automatically interfaces with your REST APIs to create a 2-way-synced local data store. Transparently manages data propagation in the React state.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": "dist/index.js",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"babel": "node_modules/.bin/babel",
|
|
9
|
-
"test": "./node_modules/.bin/mocha tests --require @babel/register",
|
|
9
|
+
"test": "./node_modules/.bin/mocha tests/*.test.js --require @babel/register --exit",
|
|
10
10
|
"compile": "rm -rf dist/ && ./node_modules/.bin/babel src -d dist",
|
|
11
11
|
"release": "dotenv release-it"
|
|
12
12
|
},
|
|
@@ -86,8 +86,11 @@
|
|
|
86
86
|
"@babel/plugin-transform-runtime": "^7.16.10",
|
|
87
87
|
"@babel/preset-env": "^7.16.11",
|
|
88
88
|
"@babel/preset-react": "^7.16.7",
|
|
89
|
+
"chai": "^4.3.4",
|
|
90
|
+
"chai-subset": "^1.6.0",
|
|
89
91
|
"dotenv-cli": "^4.1.1",
|
|
90
|
-
"
|
|
92
|
+
"mocha": "^9.2.0",
|
|
93
|
+
"release-it": "^14.12.4"
|
|
91
94
|
},
|
|
92
95
|
"dependencies": {
|
|
93
96
|
"axios": "^0.25.0",
|