dataflux 1.7.5 → 1.9.1
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/README.md +139 -25
- package/dist/BasicObj.js +53 -6
- package/dist/Model.js +145 -38
- package/dist/ObserverStore.js +21 -8
- package/dist/PersistentStore.js +51 -22
- package/dist/Store.js +202 -64
- package/dist/dataflux.min.js +1 -1
- package/dist/dataflux.min.js.map +1 -1
- package/dist/modelHooksUtils.js +50 -19
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -258,11 +258,12 @@ function MyComponent() {
|
|
|
258
258
|
The store can be configured with the following options:
|
|
259
259
|
|
|
260
260
|
|
|
261
|
-
| Option
|
|
262
|
-
|
|
263
|
-
| autoSave
|
|
264
|
-
| saveDelay
|
|
265
|
-
| lazyLoad
|
|
261
|
+
| Option | Description | Default |
|
|
262
|
+
|-------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------|
|
|
263
|
+
| 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 `store.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 |
|
|
264
|
+
| 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 |
|
|
265
|
+
| 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 |
|
|
266
|
+
| autoRefresh | It can be `true`, `false`, or an amount of milliseconds (integer). If `false`, you will have to perform `store.refresh()` manually. If `true`, the store will automatically perform `store.refresh()` every 2 minutes. If an amount of milliseconds is provided, the `store.refresh()` is performed periodically. See [store methods](#store-methods) for more information. | false |
|
|
266
267
|
|
|
267
268
|
|
|
268
269
|
|
|
@@ -296,6 +297,7 @@ All the possible options for a model creation are (they are all optional):
|
|
|
296
297
|
| hiddenFields | An array of attribute names that will never be sent back to the API. E.g., if you set `hiddenFields: ["pages"]`, a book object can contain an attribute `pages` locally, but this will be stripped out in PUT/POST requests. |
|
|
297
298
|
| deep | A boolean defining if nested objects should be enriched with the object methods. | true |
|
|
298
299
|
| lazyLoad | A boolean defining if the model should be lazy loaded on the first use. This takes precedence over the lazyLoad declared during store initialization. | false |
|
|
300
|
+
| validate | A dictionary containing functions to validate the objects of this model. See [objects validation](#objects-validation) | no validation |
|
|
299
301
|
|
|
300
302
|
### Operations
|
|
301
303
|
As described in the table above, there are four possible operations: **retrieve, insert, update,** and **delete**. An operation can be defined as an operation object or a function.
|
|
@@ -308,10 +310,23 @@ An operation object is an object like follows:
|
|
|
308
310
|
{
|
|
309
311
|
"method": "get",
|
|
310
312
|
"url": "https://api.example.com",
|
|
311
|
-
"headers": {
|
|
313
|
+
"headers": {
|
|
314
|
+
"Authorization": "bearer XXXX"
|
|
315
|
+
},
|
|
316
|
+
"batch": false
|
|
312
317
|
}
|
|
313
318
|
```
|
|
314
319
|
|
|
320
|
+
Possible parameters are:
|
|
321
|
+
|
|
322
|
+
| Parameter | Description | Default |
|
|
323
|
+
|-----------|--------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------|
|
|
324
|
+
| method | HTTP method, accepted are get,post,put, and delete | "get" for retrieve, "post" for insert, "put" for update, and "delete" for delete |
|
|
325
|
+
| url | The url of the api | |
|
|
326
|
+
| headers | Headers for the HTTP request ([list](https://en.wikipedia.org/wiki/List_of_HTTP_header_fields)). |
|
|
327
|
+
| batch | A boolean declaring if the API is able to receive an array of objects or an object at a time. This is not applicable for `retrieve`. | false |
|
|
328
|
+
|
|
329
|
+
|
|
315
330
|
Usage example:
|
|
316
331
|
|
|
317
332
|
```js
|
|
@@ -540,41 +555,73 @@ The store has the following method.
|
|
|
540
555
|
| 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). |
|
|
541
556
|
| delete(objects) | It deletes an array of objects. See [example 1](#example-3). |
|
|
542
557
|
| delete(type, filterFunction) | It deleted objects given an array and a filter function. See [example 1](#example-3). |
|
|
543
|
-
| insert(type, object) | It creates a new object of a given type and inserts it in the store.
|
|
558
|
+
| insert(type, object) | It creates a new object of a given type and inserts it in the store. The object inserted MUST be ready to be persisted, read `mock()` below. |
|
|
559
|
+
| mock(type, object) | It creates a mock object of a given type and inserts it in the store. The mock object behaves exactly like a real object, except that it is not persisted (sent to the API) as long as you don't call `object.insert()`. This is useful when you want to create an object but you need to be able to change some properties before to send it to the API. Read [insert vs. mock](#insert-vs-mock). |
|
|
544
560
|
| 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). |
|
|
545
561
|
| 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). |
|
|
546
562
|
| unsubscribe(key) | Method to terminate a subscription given a subscription key. See [example 5](#example-5---observability). |
|
|
547
563
|
| 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). |
|
|
548
564
|
| 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). |
|
|
549
565
|
| preload(type) | This method allows to preLoad all objects of a given model. If you initialize the store with `lazyLoad:true`, the objects of a model are retrieved from the API at the first query performed on that model (e.g., at the first `.find()`). However, sometimes you may want to speed up the first query by pre loading the objects of a specific model while keeping `lazyLoad:true` on the store; in such a case you can use `store.preload(type)`. |
|
|
566
|
+
| save() | Persist the changes. Edited local objects will be sent to the REST APIs (insert/update/delete). See also [editing objects](#editing-objects). |
|
|
567
|
+
| save() | Persist the changes (`local -> remote`). Edited local objects will be sent to the REST APIs (insert/update/delete). See also [editing objects](#editing-objects). |
|
|
568
|
+
| refresh() | This method syncs all the objects in the store with the remote version offered by the REST APIs (`remote -> local`). Remote changes are applied locally, including adding/removing objects. Objects edited locally but not yet persisted are preserved locally (tip: you can also create a store with the `autoRefresh` option). |
|
|
569
|
+
### Insert vs. Mock
|
|
570
|
+
|
|
571
|
+
If you do:
|
|
572
|
+
```js
|
|
573
|
+
store.insert("book", {title: "The little prince"});
|
|
574
|
+
```
|
|
575
|
+
when the store will try to save, the object `{title: "The little prince"}` will be sent to the API in a post request. However, the API may require an attribute "price" for each book object, hence the post request will fail.
|
|
576
|
+
Of course, you can add the attribute directly in the `.insert()` call; however, the value of this attribute may not be known at that time. For example, the user may need to input the price in a text field.
|
|
577
|
+
|
|
578
|
+
You may think to delay the `.insert()` up to when all the required attributes are available; however, **this is a bad idea**, because as long as the object is not in the store, you will not benefit from the observability provided by DataFlux. _E.g., your React state will not update automatically and you will need to handle the changes triggered by the input fields yourself_ ([reinventing the wheel](https://en.wikipedia.org/wiki/Reinventing_the_wheel)).
|
|
579
|
+
|
|
580
|
+
Solution, use `.mock()` to create a mock object:
|
|
581
|
+
|
|
582
|
+
```js
|
|
583
|
+
store.mock("book", {title: "The little prince"});
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
The mock object behaves exactly like a normal object: you can retrieve it with `.find`/`.findAll`/`.findOne`/`.subscribe`.
|
|
587
|
+
|
|
588
|
+
However, the mock object is not sent to the API as long as you don't call `.insert()` on the object itself. When you call `.insert()`, the mock object is promoted to real object.
|
|
589
|
+
|
|
590
|
+
> Warning: to promote a mock object, you need to call `object.insert()` on the object itself (you must first retrieve it) and NOT `store.insert()`.
|
|
591
|
+
|
|
550
592
|
|
|
551
593
|
## Store events
|
|
552
594
|
The store emits the following events:
|
|
553
595
|
|
|
554
|
-
| Name
|
|
555
|
-
|
|
556
|
-
| error
|
|
557
|
-
| save
|
|
558
|
-
| loading
|
|
596
|
+
| Name | Description |
|
|
597
|
+
|------------|---------------------------------------------------------------------------------------------------------------------------------------|
|
|
598
|
+
| error | To listen the errors emitted by the store. |
|
|
599
|
+
| save | Possible emitted values are `start` and `end`. They are emitted when the store starts/finishes to persist the data (API interaction). |
|
|
600
|
+
| loading | The event is emitted while a new model is loaded. The value contains something like `{status: "start", model: "book"}` |
|
|
601
|
+
| refreshing | The event is emitted while a model is refreshed. The value contains something like `{status: "start", model: "book"}` |
|
|
559
602
|
|
|
560
603
|
## Objects methods
|
|
561
604
|
Each object created is enriched with the following methods.
|
|
562
605
|
|
|
563
606
|
|
|
564
|
-
| Method | Description
|
|
565
|
-
|
|
566
|
-
| getId() | It returns a unique ID used by the store to identify the object. The ID is unique inside a single model. Be aware, `object.id` and `objet.getId()` may return different values, since store's IDs can be different from the one of the REST API.
|
|
567
|
-
| set(attribute, value, hidden) | A method to set an attribute to the object. It provides some advantages compared to doing `object.attribute = value`, these are discussed in [below](#editing-objects). The third parameter is optional, and when set to true will set the attribute as hidden (see [hiddenFields](#models-creation)).
|
|
568
|
-
| setConstant(attribute, value) | A method to set an unmodifiable hidden attribute on the object. Setting the attribute as a constant will not propagate an update.
|
|
607
|
+
| Method | Description |
|
|
608
|
+
|------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
609
|
+
| getId() | It returns a unique ID used by the store to identify the object. The ID is unique inside a single model. Be aware, `object.id` and `objet.getId()` may return different values, since store's IDs can be different from the one of the REST API. |
|
|
610
|
+
| set(attribute, value, hidden) | A method to set an attribute to the object. It provides some advantages compared to doing `object.attribute = value`, these are discussed in [below](#editing-objects). The third parameter is optional, and when set to true will set the attribute as hidden (see [hiddenFields](#models-creation)). |
|
|
611
|
+
| setConstant(attribute, value) | A method to set an unmodifiable hidden attribute on the object. Setting the attribute as a constant will not propagate an update. |
|
|
569
612
|
| get(attribute, defaultValue) | Method to retrieve the value of an attribute. It does not provide any advantage compared to accessing directly the attribute (e.g., `author.name`); except for hidden fields and constants, which can be retrieved only with the `.get` method. Additionally, you can provide a default value as a second parameter in case the object doesn't have that attribute. |
|
|
570
|
-
| getRelation(model, filterFunction) | To get all the objects respecting a specific relation with this object (see [model relations](#model-relations)).
|
|
571
|
-
| save() | Method to save the object. You can do `store.save()` instead.
|
|
572
|
-
| destroy() | Method to delete the object. You can do `store.delete()` instead.
|
|
573
|
-
| toJSON() | It returns a pure JSON representation of the object.
|
|
574
|
-
| toString() | It returns a string representation of the object.
|
|
575
|
-
| getFingerprint() | It returns a hash of the object. The hash changes at every change of the object or of any nested object. Useful to detect object changes.
|
|
576
|
-
| getModel() | It returns the model of this object. Mostly useful to do `object.getModel().getType()` and obtain a string defining the type of the object.
|
|
577
|
-
|
|
613
|
+
| getRelation(model, filterFunction) | To get all the objects respecting a specific relation with this object (see [model relations](#model-relations)). |
|
|
614
|
+
| save() | Method to save the object. You can do `store.save()` instead. |
|
|
615
|
+
| destroy() | Method to delete the object. You can do `store.delete()` instead. |
|
|
616
|
+
| toJSON() | It returns a pure JSON representation of the object. |
|
|
617
|
+
| toString() | It returns a string representation of the object. |
|
|
618
|
+
| getFingerprint() | It returns a hash of the object. The hash changes at every change of the object or of any nested object. Useful to detect object changes. |
|
|
619
|
+
| getModel() | It returns the model of this object. Mostly useful to do `object.getModel().getType()` and obtain a string defining the type of the object. |
|
|
620
|
+
| getError() | If an operation on an object triggers an error, this error can be retrieved with `getError()`. This allows to observe specific objects' errors, instead of the generic `store.on("error", ...)`. |
|
|
621
|
+
| getError(attributeName) | This method allows you to check if the specificed attribute generated any error according to the validation property specified in the model. See [objects validation](#objects-validation). |
|
|
622
|
+
| setError(error) | Additionally to DataFlux's errors, you can trigger your own errors with this method. Other components observing this objet's error will be notified. |
|
|
623
|
+
|
|
624
|
+
### Deep Objects
|
|
578
625
|
When a model is declared with the option `deep: true` (default, see [model creation](#models-creation)), all the sub objects will also offer many of the methods above.
|
|
579
626
|
|
|
580
627
|
Imagine the API returns:
|
|
@@ -611,8 +658,75 @@ store.find("book")
|
|
|
611
658
|
});
|
|
612
659
|
```
|
|
613
660
|
|
|
661
|
+
### Objects validation
|
|
662
|
+
|
|
663
|
+
DataFlux supports automatic validation of the objects. This is important for two reasons:
|
|
664
|
+
* Objects that contain invalid attributes' values are not sent back to the API;
|
|
665
|
+
* Validation errors can be used to automatically suggest errors in the UI.
|
|
666
|
+
|
|
667
|
+
To specify the validation of the objects for a specific model, you need to add a `validate` dictionary during model creation.
|
|
668
|
+
|
|
669
|
+
```js
|
|
670
|
+
const book = new Model("book", {
|
|
671
|
+
retrieve: {
|
|
672
|
+
url: "https://rest.example.net/api/v1/books/"
|
|
673
|
+
},
|
|
674
|
+
validate: {
|
|
675
|
+
isbn: ({isbn}) => {
|
|
676
|
+
if (typeof(isbn) !== "number") {
|
|
677
|
+
throw new Error("The isbn must be a number");
|
|
678
|
+
}
|
|
679
|
+
},
|
|
680
|
+
title: ({title}) => {
|
|
681
|
+
if (!title) {
|
|
682
|
+
throw new Error("The title is mandatory");
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
});
|
|
687
|
+
```
|
|
688
|
+
|
|
689
|
+
Each key of the `validate` dictionary is an attribute of the object (a field name), each value is a function receiving in input the object and throwing an error in case the field is not valid.
|
|
690
|
+
|
|
691
|
+
> Be aware: A validation function cannot return a boolean, you have to throw an error.
|
|
692
|
+
|
|
693
|
+
To validate a specific attribute of an object, you can do `object.getError(attributeName)` (e.g., `book.getError(isbn)`). In case of error, a string describing the error is returned, `false` otherwise.
|
|
694
|
+
|
|
695
|
+
Example of usage in a React component.
|
|
696
|
+
|
|
697
|
+
```js
|
|
698
|
+
class MyComponent extends React.Component {
|
|
699
|
+
constructor(props) {
|
|
700
|
+
super(props);
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
render(){
|
|
704
|
+
const {book} = this.state;
|
|
705
|
+
|
|
706
|
+
// A textfield to edit the title of a book
|
|
707
|
+
return <TextField
|
|
708
|
+
value={book.title}
|
|
709
|
+
onChange={store.handleChange(book, "title")}
|
|
710
|
+
error={object.getError("title")}
|
|
711
|
+
// E.g., in material UI the test field will be red in case of errors
|
|
712
|
+
/>;
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
```
|
|
716
|
+
|
|
717
|
+
> Be aware: if you do `object.getError()` without specifying any attribute, you will receive object errors not associated with any field, such as API errors. This is similar to `store.on("error")`
|
|
718
|
+
|
|
614
719
|
|
|
615
720
|
## Editing objects
|
|
721
|
+
|
|
722
|
+
The preferred method to edit objects is using the `.set()` method that each object has, instead of editing directly the attributes. However, there are a few notions to keep in mind.
|
|
723
|
+
|
|
724
|
+
#### Client-side object validaion will not work when editing attributes directly.
|
|
725
|
+
|
|
726
|
+
You will be able to validate objects only if you use `.set()`. If you edit directly the attribute (e.g., `book.title = "test"`) errors will be discovered only by the API.
|
|
727
|
+
|
|
728
|
+
#### Auto save may not work when editing attributes directly.
|
|
729
|
+
|
|
616
730
|
The option `autoSave` can be `true`, `false`, or a number (milliseconds).
|
|
617
731
|
|
|
618
732
|
* When `autoSave` is set to `false`, the following operations are equivalent:
|
package/dist/BasicObj.js
CHANGED
|
@@ -24,20 +24,21 @@ function _classPrivateFieldInitSpec(obj, privateMap, value) { _checkPrivateRedec
|
|
|
24
24
|
|
|
25
25
|
function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } }
|
|
26
26
|
|
|
27
|
-
function
|
|
27
|
+
function _classPrivateFieldGet(receiver, privateMap) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "get"); return _classApplyDescriptorGet(receiver, descriptor); }
|
|
28
28
|
|
|
29
|
-
function
|
|
29
|
+
function _classApplyDescriptorGet(receiver, descriptor) { if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.value; }
|
|
30
30
|
|
|
31
|
-
function
|
|
31
|
+
function _classPrivateFieldSet(receiver, privateMap, value) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "set"); _classApplyDescriptorSet(receiver, descriptor, value); return value; }
|
|
32
32
|
|
|
33
33
|
function _classExtractFieldDescriptor(receiver, privateMap, action) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to " + action + " private field on non-instance"); } return privateMap.get(receiver); }
|
|
34
34
|
|
|
35
|
-
function
|
|
35
|
+
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; } }
|
|
36
36
|
|
|
37
37
|
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); }
|
|
38
38
|
|
|
39
39
|
var dateRegex = new RegExp("^[0-9][0-9][0-9][0-9]-[0-9].*T[0-9].*Z$");
|
|
40
40
|
exports.dateRegex = dateRegex;
|
|
41
|
+
var globalError = "_object";
|
|
41
42
|
|
|
42
43
|
function setValues(values, model, SubObj, parent, context) {
|
|
43
44
|
Object.keys(values).forEach(function (key) {
|
|
@@ -64,6 +65,10 @@ var _setHidden = /*#__PURE__*/new WeakMap();
|
|
|
64
65
|
|
|
65
66
|
var _id = /*#__PURE__*/new WeakMap();
|
|
66
67
|
|
|
68
|
+
var _error = /*#__PURE__*/new WeakMap();
|
|
69
|
+
|
|
70
|
+
var _model = /*#__PURE__*/new WeakMap();
|
|
71
|
+
|
|
67
72
|
var BasicObj = /*#__PURE__*/_createClass(function BasicObj(values, model) {
|
|
68
73
|
var _this = this;
|
|
69
74
|
|
|
@@ -79,10 +84,26 @@ var BasicObj = /*#__PURE__*/_createClass(function BasicObj(values, model) {
|
|
|
79
84
|
value: null
|
|
80
85
|
});
|
|
81
86
|
|
|
87
|
+
_classPrivateFieldInitSpec(this, _error, {
|
|
88
|
+
writable: true,
|
|
89
|
+
value: {}
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
_classPrivateFieldInitSpec(this, _model, {
|
|
93
|
+
writable: true,
|
|
94
|
+
value: void 0
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
_defineProperty(this, "setId", function (id) {
|
|
98
|
+
_classPrivateFieldSet(_this, _id, id);
|
|
99
|
+
});
|
|
100
|
+
|
|
82
101
|
_defineProperty(this, "getId", function () {
|
|
83
102
|
if (!_classPrivateFieldGet(_this, _id)) {
|
|
84
103
|
if (_this.id && (typeof _this.id === "string" || typeof _this.id === "number")) {
|
|
85
104
|
_classPrivateFieldSet(_this, _id, _this.id.toString());
|
|
105
|
+
|
|
106
|
+
delete _this.setId;
|
|
86
107
|
} else {
|
|
87
108
|
_classPrivateFieldSet(_this, _id, (0, _uuid.v4)());
|
|
88
109
|
}
|
|
@@ -106,15 +127,39 @@ var BasicObj = /*#__PURE__*/_createClass(function BasicObj(values, model) {
|
|
|
106
127
|
}
|
|
107
128
|
|
|
108
129
|
_this[attribute] = value;
|
|
130
|
+
|
|
131
|
+
_classPrivateFieldGet(_this, _model).validateObjectAttribute(_this, attribute);
|
|
109
132
|
}
|
|
110
133
|
|
|
111
134
|
return _this.update();
|
|
112
135
|
});
|
|
113
136
|
|
|
114
|
-
_defineProperty(this, "
|
|
137
|
+
_defineProperty(this, "getError", function () {
|
|
115
138
|
var _classPrivateFieldGet3;
|
|
116
139
|
|
|
117
|
-
|
|
140
|
+
var attribute = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
|
|
141
|
+
var key = attribute ? attribute : globalError;
|
|
142
|
+
return (_classPrivateFieldGet3 = _classPrivateFieldGet(_this, _error)[key]) !== null && _classPrivateFieldGet3 !== void 0 ? _classPrivateFieldGet3 : false;
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
_defineProperty(this, "setError", function (error) {
|
|
146
|
+
var attribute = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
|
|
147
|
+
|
|
148
|
+
if (error && attribute) {
|
|
149
|
+
_classPrivateFieldGet(_this, _error)[attribute] = error;
|
|
150
|
+
} else if (error && !attribute) {
|
|
151
|
+
_classPrivateFieldGet(_this, _error)[globalError] = error;
|
|
152
|
+
} else if (!error && attribute) {
|
|
153
|
+
delete _classPrivateFieldGet(_this, _error)[attribute];
|
|
154
|
+
} else {
|
|
155
|
+
_classPrivateFieldSet(_this, _error, {});
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
_defineProperty(this, "setConstant", function (attribute, value) {
|
|
160
|
+
var _classPrivateFieldGet4;
|
|
161
|
+
|
|
162
|
+
_classPrivateFieldGet(_this, _setHidden)[attribute] = (_classPrivateFieldGet4 = _classPrivateFieldGet(_this, _setHidden)[attribute]) !== null && _classPrivateFieldGet4 !== void 0 ? _classPrivateFieldGet4 : value;
|
|
118
163
|
});
|
|
119
164
|
|
|
120
165
|
_defineProperty(this, "toJSON", function () {
|
|
@@ -153,6 +198,8 @@ var BasicObj = /*#__PURE__*/_createClass(function BasicObj(values, model) {
|
|
|
153
198
|
_defineProperty(this, "update", function () {
|
|
154
199
|
return Promise.resolve();
|
|
155
200
|
});
|
|
201
|
+
|
|
202
|
+
_classPrivateFieldSet(this, _model, model);
|
|
156
203
|
});
|
|
157
204
|
|
|
158
205
|
exports.BasicObj = BasicObj;
|
package/dist/Model.js
CHANGED
|
@@ -7,8 +7,6 @@ exports["default"] = void 0;
|
|
|
7
7
|
|
|
8
8
|
var _modelHooksUtils = require("./modelHooksUtils");
|
|
9
9
|
|
|
10
|
-
var _batchPromises = _interopRequireDefault(require("batch-promises"));
|
|
11
|
-
|
|
12
10
|
var _axios2 = _interopRequireDefault(require("axios"));
|
|
13
11
|
|
|
14
12
|
var _BasicObj = require("./BasicObj");
|
|
@@ -95,22 +93,29 @@ var _addRelationByFilter = /*#__PURE__*/new WeakMap();
|
|
|
95
93
|
|
|
96
94
|
var _removeHiddenFields = /*#__PURE__*/new WeakMap();
|
|
97
95
|
|
|
98
|
-
var _bulkOperation = /*#__PURE__*/new WeakMap();
|
|
99
|
-
|
|
100
96
|
var _toArray = /*#__PURE__*/new WeakMap();
|
|
101
97
|
|
|
102
98
|
var _unWrap = /*#__PURE__*/new WeakMap();
|
|
103
99
|
|
|
104
100
|
var _insertObjects = /*#__PURE__*/new WeakMap();
|
|
105
101
|
|
|
102
|
+
var _assignId = /*#__PURE__*/new WeakMap();
|
|
103
|
+
|
|
106
104
|
var _updateObjects = /*#__PURE__*/new WeakMap();
|
|
107
105
|
|
|
108
106
|
var _deleteObjects = /*#__PURE__*/new WeakMap();
|
|
109
107
|
|
|
108
|
+
var _hanldeApiError = /*#__PURE__*/new WeakMap();
|
|
109
|
+
|
|
110
|
+
var _cleanApiError = /*#__PURE__*/new WeakMap();
|
|
111
|
+
|
|
112
|
+
var _removeFromStoreSilentlyAfterFailure = /*#__PURE__*/new WeakMap();
|
|
113
|
+
|
|
110
114
|
var Model = /*#__PURE__*/_createClass(function Model(name) {
|
|
111
115
|
var _this = this,
|
|
112
116
|
_options$deep,
|
|
113
|
-
_options$parseMoment
|
|
117
|
+
_options$parseMoment,
|
|
118
|
+
_options$validate;
|
|
114
119
|
|
|
115
120
|
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
116
121
|
|
|
@@ -178,6 +183,31 @@ var Model = /*#__PURE__*/_createClass(function Model(name) {
|
|
|
178
183
|
value: void 0
|
|
179
184
|
});
|
|
180
185
|
|
|
186
|
+
_defineProperty(this, "validateObjectAttribute", function (object, key) {
|
|
187
|
+
var validate = _this.options.validate;
|
|
188
|
+
|
|
189
|
+
if (validate && validate[key]) {
|
|
190
|
+
try {
|
|
191
|
+
validate[key](object);
|
|
192
|
+
object.setError(false, key);
|
|
193
|
+
} catch (error) {
|
|
194
|
+
object.setError(error.message, key);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
_defineProperty(this, "isObjectValid", function (object) {
|
|
200
|
+
for (var key in object) {
|
|
201
|
+
if (typeof object[key] !== "function") {
|
|
202
|
+
if (object.getError(key)) {
|
|
203
|
+
return false;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return true;
|
|
209
|
+
});
|
|
210
|
+
|
|
181
211
|
_defineProperty(this, "getStore", function () {
|
|
182
212
|
return _classPrivateFieldGet(_this, _store);
|
|
183
213
|
});
|
|
@@ -272,15 +302,15 @@ var Model = /*#__PURE__*/_createClass(function Model(name) {
|
|
|
272
302
|
});
|
|
273
303
|
|
|
274
304
|
_defineProperty(this, "insertObjects", function (objects) {
|
|
275
|
-
return objects.length ? _classPrivateFieldGet(_this,
|
|
305
|
+
return objects.length ? _classPrivateFieldGet(_this, _insertObjects).call(_this, objects) : Promise.resolve();
|
|
276
306
|
});
|
|
277
307
|
|
|
278
308
|
_defineProperty(this, "updateObjects", function (objects) {
|
|
279
|
-
return objects.length ? _classPrivateFieldGet(_this,
|
|
309
|
+
return objects.length ? _classPrivateFieldGet(_this, _updateObjects).call(_this, objects) : Promise.resolve();
|
|
280
310
|
});
|
|
281
311
|
|
|
282
312
|
_defineProperty(this, "deleteObjects", function (objects) {
|
|
283
|
-
return objects.length ? _classPrivateFieldGet(_this,
|
|
313
|
+
return objects.length ? _classPrivateFieldGet(_this, _deleteObjects).call(_this, objects) : Promise.resolve();
|
|
284
314
|
});
|
|
285
315
|
|
|
286
316
|
_defineProperty(this, "factory", function (params) {
|
|
@@ -339,26 +369,11 @@ var Model = /*#__PURE__*/_createClass(function Model(name) {
|
|
|
339
369
|
}
|
|
340
370
|
});
|
|
341
371
|
|
|
342
|
-
_classPrivateFieldInitSpec(this, _bulkOperation, {
|
|
343
|
-
writable: true,
|
|
344
|
-
value: function value(objects, action) {
|
|
345
|
-
if (_classPrivateFieldGet(_this, _singleItemQuery)) {
|
|
346
|
-
return (0, _batchPromises["default"])(_classPrivateFieldGet(_this, _batchSize), objects.map(function (i) {
|
|
347
|
-
return _classPrivateFieldGet(_this, _removeHiddenFields).call(_this, i.toJSON());
|
|
348
|
-
}), action);
|
|
349
|
-
} else {
|
|
350
|
-
return action(objects.map(function (i) {
|
|
351
|
-
return _classPrivateFieldGet(_this, _removeHiddenFields).call(_this, i.toJSON());
|
|
352
|
-
}));
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
});
|
|
356
|
-
|
|
357
372
|
_classPrivateFieldInitSpec(this, _toArray, {
|
|
358
373
|
writable: true,
|
|
359
374
|
value: function value(data) {
|
|
360
375
|
if (Array.isArray(data)) {
|
|
361
|
-
if (data.every(function (str) {
|
|
376
|
+
if (data.length && data.every(function (str) {
|
|
362
377
|
return ["string", "number"].includes(_typeof(str));
|
|
363
378
|
})) {
|
|
364
379
|
return [{
|
|
@@ -381,7 +396,11 @@ var Model = /*#__PURE__*/_createClass(function Model(name) {
|
|
|
381
396
|
|
|
382
397
|
_classPrivateFieldInitSpec(this, _unWrap, {
|
|
383
398
|
writable: true,
|
|
384
|
-
value: function value(
|
|
399
|
+
value: function value(objects) {
|
|
400
|
+
var data = Object.values(objects).map(function (object) {
|
|
401
|
+
return _classPrivateFieldGet(_this, _removeHiddenFields).call(_this, object.toJSON());
|
|
402
|
+
});
|
|
403
|
+
|
|
385
404
|
if (data.value != null && Object.keys(data).length === 1) {
|
|
386
405
|
return data.value;
|
|
387
406
|
} else if (Array.isArray(data) && data.length === 1 && data[0].value != null && Object.keys(data[0]).length === 1) {
|
|
@@ -394,22 +413,109 @@ var Model = /*#__PURE__*/_createClass(function Model(name) {
|
|
|
394
413
|
|
|
395
414
|
_classPrivateFieldInitSpec(this, _insertObjects, {
|
|
396
415
|
writable: true,
|
|
397
|
-
value: function value(
|
|
398
|
-
|
|
416
|
+
value: function value(objects) {
|
|
417
|
+
var operation = "insert";
|
|
418
|
+
return (0, _modelHooksUtils.executeHook)(operation, _classPrivateFieldGet(_this, _insertHook), _classPrivateFieldGet(_this, _unWrap).call(_this, objects), _classPrivateFieldGet(_this, _axios)).then(function (data) {
|
|
419
|
+
if (data) _classPrivateFieldGet(_this, _assignId).call(_this, data, objects);
|
|
420
|
+
|
|
421
|
+
_classPrivateFieldGet(_this, _cleanApiError).call(_this, objects);
|
|
422
|
+
|
|
423
|
+
return data;
|
|
424
|
+
}).then(_classPrivateFieldGet(_this, _toArray))["catch"](function (error) {
|
|
425
|
+
_classPrivateFieldGet(_this, _removeFromStoreSilentlyAfterFailure).call(_this, objects);
|
|
426
|
+
|
|
427
|
+
return _classPrivateFieldGet(_this, _hanldeApiError).call(_this, error, objects, operation);
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
_classPrivateFieldInitSpec(this, _assignId, {
|
|
433
|
+
writable: true,
|
|
434
|
+
value: function value(data, objects) {
|
|
435
|
+
if (data.length === 1) {
|
|
436
|
+
var newId = data[0].id;
|
|
437
|
+
objects[0].setId(newId);
|
|
438
|
+
delete objects[0].setId;
|
|
439
|
+
}
|
|
399
440
|
}
|
|
400
441
|
});
|
|
401
442
|
|
|
402
443
|
_classPrivateFieldInitSpec(this, _updateObjects, {
|
|
403
444
|
writable: true,
|
|
404
|
-
value: function value(
|
|
405
|
-
|
|
445
|
+
value: function value(objects) {
|
|
446
|
+
var operation = "update";
|
|
447
|
+
return (0, _modelHooksUtils.executeHook)(operation, _classPrivateFieldGet(_this, _updateHook), _classPrivateFieldGet(_this, _unWrap).call(_this, objects), _classPrivateFieldGet(_this, _axios)).then(function (data) {
|
|
448
|
+
_classPrivateFieldGet(_this, _cleanApiError).call(_this, objects);
|
|
449
|
+
|
|
450
|
+
return data;
|
|
451
|
+
}).then(_classPrivateFieldGet(_this, _toArray))["catch"](function (error) {
|
|
452
|
+
return _classPrivateFieldGet(_this, _hanldeApiError).call(_this, error, objects, operation);
|
|
453
|
+
});
|
|
406
454
|
}
|
|
407
455
|
});
|
|
408
456
|
|
|
409
457
|
_classPrivateFieldInitSpec(this, _deleteObjects, {
|
|
410
458
|
writable: true,
|
|
411
|
-
value: function value(
|
|
412
|
-
|
|
459
|
+
value: function value(objects) {
|
|
460
|
+
var operation = "delete";
|
|
461
|
+
return (0, _modelHooksUtils.executeHook)(operation, _classPrivateFieldGet(_this, _deleteHook), _classPrivateFieldGet(_this, _unWrap).call(_this, objects), _classPrivateFieldGet(_this, _axios)).then(function (data) {
|
|
462
|
+
_classPrivateFieldGet(_this, _cleanApiError).call(_this, objects);
|
|
463
|
+
|
|
464
|
+
return data;
|
|
465
|
+
}).then(_classPrivateFieldGet(_this, _toArray))["catch"](function (error) {
|
|
466
|
+
return _classPrivateFieldGet(_this, _hanldeApiError).call(_this, error, objects, operation);
|
|
467
|
+
});
|
|
468
|
+
}
|
|
469
|
+
});
|
|
470
|
+
|
|
471
|
+
_classPrivateFieldInitSpec(this, _hanldeApiError, {
|
|
472
|
+
writable: true,
|
|
473
|
+
value: function value(error, objects, operation) {
|
|
474
|
+
var _error$response$data, _error3, _error3$response, _ref, _error$message, _error4, _error5;
|
|
475
|
+
|
|
476
|
+
error = (_error$response$data = (_error3 = error) === null || _error3 === void 0 ? void 0 : (_error3$response = _error3.response) === null || _error3$response === void 0 ? void 0 : _error3$response.data) !== null && _error$response$data !== void 0 ? _error$response$data : error;
|
|
477
|
+
var targets = objects.map(function (object) {
|
|
478
|
+
return object.getId();
|
|
479
|
+
}); // Set errors
|
|
480
|
+
|
|
481
|
+
var strError = (_ref = (_error$message = (_error4 = error) === null || _error4 === void 0 ? void 0 : _error4.message) !== null && _error$message !== void 0 ? _error$message : (_error5 = error) === null || _error5 === void 0 ? void 0 : _error5.error) !== null && _ref !== void 0 ? _ref : error;
|
|
482
|
+
Object.values(objects).map(function (object) {
|
|
483
|
+
return object.setError(strError);
|
|
484
|
+
});
|
|
485
|
+
return Promise.reject(_objectSpread(_objectSpread({}, error), {}, {
|
|
486
|
+
targets: targets,
|
|
487
|
+
operation: operation
|
|
488
|
+
}));
|
|
489
|
+
}
|
|
490
|
+
});
|
|
491
|
+
|
|
492
|
+
_classPrivateFieldInitSpec(this, _cleanApiError, {
|
|
493
|
+
writable: true,
|
|
494
|
+
value: function value(objects) {
|
|
495
|
+
Object.values(objects).map(function (object) {
|
|
496
|
+
return object.setError(false);
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
});
|
|
500
|
+
|
|
501
|
+
_classPrivateFieldInitSpec(this, _removeFromStoreSilentlyAfterFailure, {
|
|
502
|
+
writable: true,
|
|
503
|
+
value: function value(objects) {
|
|
504
|
+
var _iterator2 = _createForOfIteratorHelper(objects.map(function (object) {
|
|
505
|
+
return object.getId();
|
|
506
|
+
})),
|
|
507
|
+
_step2;
|
|
508
|
+
|
|
509
|
+
try {
|
|
510
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
511
|
+
var target = _step2.value;
|
|
512
|
+
delete _this.getStore().models[_this.getType()].storedObjects[target];
|
|
513
|
+
}
|
|
514
|
+
} catch (err) {
|
|
515
|
+
_iterator2.e(err);
|
|
516
|
+
} finally {
|
|
517
|
+
_iterator2.f();
|
|
518
|
+
}
|
|
413
519
|
}
|
|
414
520
|
});
|
|
415
521
|
|
|
@@ -418,7 +524,8 @@ var Model = /*#__PURE__*/_createClass(function Model(name) {
|
|
|
418
524
|
this.options = _objectSpread(_objectSpread({}, options), {}, {
|
|
419
525
|
deep: (_options$deep = options.deep) !== null && _options$deep !== void 0 ? _options$deep : true,
|
|
420
526
|
parseMoment: (_options$parseMoment = options.parseMoment) !== null && _options$parseMoment !== void 0 ? _options$parseMoment : false,
|
|
421
|
-
lazyLoad: options.lazyLoad
|
|
527
|
+
lazyLoad: options.lazyLoad,
|
|
528
|
+
validate: (_options$validate = options.validate) !== null && _options$validate !== void 0 ? _options$validate : {}
|
|
422
529
|
});
|
|
423
530
|
|
|
424
531
|
_classPrivateFieldSet(this, _store, null);
|
|
@@ -439,12 +546,12 @@ var Model = /*#__PURE__*/_createClass(function Model(name) {
|
|
|
439
546
|
throw new Error("The load option must be a function");
|
|
440
547
|
}
|
|
441
548
|
|
|
442
|
-
var
|
|
443
|
-
|
|
444
|
-
retrieveHook =
|
|
445
|
-
insertHook =
|
|
446
|
-
updateHook =
|
|
447
|
-
deleteHook =
|
|
549
|
+
var _ref2 = _typeof(options) === "object" ? (0, _modelHooksUtils.getHooksFromOptions)(options) : (0, _modelHooksUtils.getHooksFromUrl)(options),
|
|
550
|
+
_ref3 = _slicedToArray(_ref2, 4),
|
|
551
|
+
retrieveHook = _ref3[0],
|
|
552
|
+
insertHook = _ref3[1],
|
|
553
|
+
updateHook = _ref3[2],
|
|
554
|
+
deleteHook = _ref3[3];
|
|
448
555
|
|
|
449
556
|
_classPrivateFieldSet(this, _retrieveHook, retrieveHook);
|
|
450
557
|
|