dataflux 1.14.9 → 1.15.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 CHANGED
@@ -302,7 +302,9 @@ All the possible options for a model creation are (they are all optional):
302
302
  | 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 |
303
303
  | validate | A dictionary containing functions to validate the objects of this model. See [objects validation](#objects-validation) | no validation |
304
304
  | autoRefresh | Set auto refresh for the specific model. See `autoRefresh` in the [store config](#configuration). | |
305
- |autoSave| It allows to specify `autoSave` at model level. If store.autoSave is true, `autoSave: false` at model level will allow to disable autoSave only for the specific model. |
305
+ | autoSave | It allows to specify `autoSave` at model level. If store.autoSave is true, `autoSave: false` at model level will allow to disable autoSave only for the specific model. |
306
+ | pre | A function that is executed for every object retrieved, before creating the collection in the store. It is useful for pre-processing every data item received from the API. |
307
+ | post | A function that is executed for every object retrieved before delete, update, and insert operations. It is useful for post-processing every data item before sending them back to the API. |
306
308
 
307
309
  ### Operations
308
310
  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.
@@ -573,6 +575,7 @@ The store has the following method.
573
575
  | refresh(type) | 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). If a model type is passed, only objects of that type will be refreshed. |
574
576
  | reset(type) | 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 reverted to the corresponding remote object. If a model type is passed, only objects of that type will be reset. |
575
577
  | findSync(type, filterFunction) | This method returns the objects in a synchronous way (no Promise). However, *it works only if you already performed an async operation (e.g., like refresh, load, find, subscribe) or if you set lazyLoad to false and the store had enough time to load.* |
578
+ | hasChanged(type, object) | This method receives in input a model type and an object (optional). It returns a boolean, `true` if the object is dirty (it changed but it has not yet being persisted). If the object is not passed, the method checks if any of the objects of the specified model type has changed. |
576
579
 
577
580
  ### Insert vs. Mock
578
581
 
@@ -612,22 +615,22 @@ The store emits the following events:
612
615
  Each object created is enriched with the following methods.
613
616
 
614
617
 
615
- | Method | Description |
616
- |------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
617
- | 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. |
618
- | 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)). |
619
- | 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. |
618
+ | Method | Description |
619
+ |------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
620
+ | 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. |
621
+ | 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)). |
622
+ | 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. |
620
623
  | 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. |
621
- | getRelation(model, filterFunction) | To get all the objects respecting a specific relation with this object (see [model relations](#model-relations)). |
622
- | save() | Method to save the object. You can do `store.save()` instead. |
623
- | destroy() | Method to delete the object. You can do `store.delete()` instead. |
624
- | toJSON() | It returns a pure JSON representation of the object. |
625
- | toString() | It returns a string representation of the object. |
626
- | 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. |
627
- | 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. |
628
- | 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", ...)`. |
629
- | 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). |
630
- | 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. |
624
+ | getRelation(model, filterFunction) | To get all the objects respecting a specific relation with this object (see [model relations](#model-relations)). |
625
+ | save() | Method to save the object. You can do `store.save()` instead. |
626
+ | destroy() | Method to delete the object. You can do `store.delete()` instead. |
627
+ | toJSON() | It returns a pure JSON representation of the object. |
628
+ | toString() | It returns a string representation of the object. |
629
+ | 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. |
630
+ | 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. |
631
+ | 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", ...)`. |
632
+ | 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). |
633
+ | 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. |
631
634
 
632
635
  ### Deep Objects
633
636
  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.
@@ -680,12 +683,12 @@ const book = new Model("book", {
680
683
  url: "https://rest.example.net/api/v1/books/"
681
684
  },
682
685
  validate: {
683
- isbn: ({isbn}) => {
686
+ isbn: ({isbn}, store) => {
684
687
  if (typeof(isbn) !== "number") {
685
688
  throw new Error("The isbn must be a number");
686
689
  }
687
690
  },
688
- title: ({title}) => {
691
+ title: ({title}, store) => {
689
692
  if (!title) {
690
693
  throw new Error("The title is mandatory");
691
694
  }
@@ -694,7 +697,7 @@ const book = new Model("book", {
694
697
  });
695
698
  ```
696
699
 
697
- 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.
700
+ 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 the store, and throwing an error in case the field is not valid.
698
701
 
699
702
  > Be aware: A validation function cannot return a boolean, you have to throw an error.
700
703
 
package/dist/Model.js CHANGED
@@ -90,7 +90,11 @@ var Model = exports["default"] = /*#__PURE__*/_createClass(function Model(name)
90
90
  _ref5,
91
91
  _options$autoSave,
92
92
  _ref6,
93
- _options$autoRefresh;
93
+ _options$autoRefresh,
94
+ _ref7,
95
+ _options$pre,
96
+ _ref8,
97
+ _options$post;
94
98
  var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
95
99
  var defaults = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
96
100
  _classCallCheck(this, Model);
@@ -219,6 +223,9 @@ var Model = exports["default"] = /*#__PURE__*/_createClass(function Model(name)
219
223
  _classPrivateFieldSet(_singleItemQuery, _this, true);
220
224
  }
221
225
  return _classPrivateFieldGet(_toArray, _this).call(_this, data);
226
+ }).then(function (data) {
227
+ var _this$options;
228
+ return (_this$options = _this.options) !== null && _this$options !== void 0 && _this$options.pre ? data.map(_this.options.pre) : data;
222
229
  });
223
230
  });
224
231
  _defineProperty(this, "insertObjects", function (objects) {
@@ -292,6 +299,9 @@ var Model = exports["default"] = /*#__PURE__*/_createClass(function Model(name)
292
299
  _classPrivateFieldInitSpec(this, _unWrap, function (objects) {
293
300
  var data = Object.values(objects).map(function (object) {
294
301
  return _classPrivateFieldGet(_removeHiddenFields, _this).call(_this, object.toJSON());
302
+ }).map(function (object) {
303
+ var _this$options2;
304
+ return (_this$options2 = _this.options) !== null && _this$options2 !== void 0 && _this$options2.post ? _this.options.post(object) : object;
295
305
  });
296
306
  if (data.value != null && Object.keys(data).length === 1) {
297
307
  return data.value;
@@ -386,7 +396,9 @@ var Model = exports["default"] = /*#__PURE__*/_createClass(function Model(name)
386
396
  lazyLoad: (_options$lazyLoad = options.lazyLoad) !== null && _options$lazyLoad !== void 0 ? _options$lazyLoad : defaults.lazyLoad,
387
397
  validate: (_ref4 = (_options$validate = options.validate) !== null && _options$validate !== void 0 ? _options$validate : defaults.validate) !== null && _ref4 !== void 0 ? _ref4 : {},
388
398
  autoSave: (_ref5 = (_options$autoSave = options.autoSave) !== null && _options$autoSave !== void 0 ? _options$autoSave : defaults.autoSave) !== null && _ref5 !== void 0 ? _ref5 : null,
389
- autoRefresh: (_ref6 = (_options$autoRefresh = options.autoRefresh) !== null && _options$autoRefresh !== void 0 ? _options$autoRefresh : defaults.autoRefresh) !== null && _ref6 !== void 0 ? _ref6 : false
399
+ autoRefresh: (_ref6 = (_options$autoRefresh = options.autoRefresh) !== null && _options$autoRefresh !== void 0 ? _options$autoRefresh : defaults.autoRefresh) !== null && _ref6 !== void 0 ? _ref6 : false,
400
+ pre: (_ref7 = (_options$pre = options.pre) !== null && _options$pre !== void 0 ? _options$pre : defaults.pre) !== null && _ref7 !== void 0 ? _ref7 : null,
401
+ post: (_ref8 = (_options$post = options.post) !== null && _options$post !== void 0 ? _options$post : defaults.post) !== null && _ref8 !== void 0 ? _ref8 : null
390
402
  });
391
403
  _classPrivateFieldSet(_store, this, null);
392
404
  _classPrivateFieldSet(_includes, this, {});
@@ -399,12 +411,12 @@ var Model = exports["default"] = /*#__PURE__*/_createClass(function Model(name)
399
411
  if (_classPrivateFieldGet(_loadFunction, this) && typeof _classPrivateFieldGet(_loadFunction, this) !== "function") {
400
412
  throw new Error("The load option must be a function");
401
413
  }
402
- var _ref7 = _typeof(options) === "object" ? (0, _modelHooksUtils.getHooksFromOptions)(options) : (0, _modelHooksUtils.getHooksFromUrl)(options),
403
- _ref8 = _slicedToArray(_ref7, 4),
404
- retrieveHook = _ref8[0],
405
- insertHook = _ref8[1],
406
- updateHook = _ref8[2],
407
- deleteHook = _ref8[3];
414
+ var _ref9 = _typeof(options) === "object" ? (0, _modelHooksUtils.getHooksFromOptions)(options) : (0, _modelHooksUtils.getHooksFromUrl)(options),
415
+ _ref10 = _slicedToArray(_ref9, 4),
416
+ retrieveHook = _ref10[0],
417
+ insertHook = _ref10[1],
418
+ updateHook = _ref10[2],
419
+ deleteHook = _ref10[3];
408
420
  _classPrivateFieldSet(_retrieveHook, this, retrieveHook);
409
421
  _classPrivateFieldSet(_updateHook, this, updateHook);
410
422
  _classPrivateFieldSet(_insertHook, this, insertHook);
package/dist/Store.js CHANGED
@@ -358,8 +358,18 @@ var Store = exports["default"] = /*#__PURE__*/function () {
358
358
  }, {
359
359
  key: "hasChanged",
360
360
  value: function hasChanged(type, object) {
361
- var obj = this.models[type].storedObjects[object.getId()];
362
- return !obj || obj.fingerprint !== obj.object.getFingerprint();
361
+ var _this8 = this;
362
+ var _hasChanged = function _hasChanged(type, object) {
363
+ var obj = _this8.models[type].storedObjects[object.getId()];
364
+ return !obj || obj.fingerprint !== obj.object.getFingerprint();
365
+ };
366
+ if (object) {
367
+ return _hasChanged(type, object);
368
+ } else {
369
+ return Object.values(this.models[type].storedObjects).some(function (i) {
370
+ return _hasChanged(type, i);
371
+ });
372
+ }
363
373
  }
364
374
  }, {
365
375
  key: "preload",
@@ -369,9 +379,9 @@ var Store = exports["default"] = /*#__PURE__*/function () {
369
379
  }, {
370
380
  key: "getDiff",
371
381
  value: function getDiff(type, ifLoaded) {
372
- var _this8 = this;
382
+ var _this9 = this;
373
383
  return this._getPromise(type, ifLoaded).then(function () {
374
- var objects = Object.values(_this8.models[type].storedObjects);
384
+ var objects = Object.values(_this9.models[type].storedObjects);
375
385
  var inserted = [];
376
386
  var updated = [];
377
387
  var deleted = [];
@@ -381,7 +391,7 @@ var Store = exports["default"] = /*#__PURE__*/function () {
381
391
  inserted.push(object);
382
392
  } else if (object.status === "deleted") {
383
393
  deleted.push(object);
384
- } else if (object.status === "old" && _this8.hasChanged(type, object.object)) {
394
+ } else if (object.status === "old" && _this9.hasChanged(type, object.object)) {
385
395
  updated.push(object);
386
396
  } // Nothing for mock objects
387
397
  }
@@ -395,7 +405,7 @@ var Store = exports["default"] = /*#__PURE__*/function () {
395
405
  }, {
396
406
  key: "factory",
397
407
  value: function factory(type, params) {
398
- var _this9 = this;
408
+ var _this10 = this;
399
409
  var item = this.models[type];
400
410
  this.pubSub.publish("loading", {
401
411
  status: "start",
@@ -407,14 +417,14 @@ var Store = exports["default"] = /*#__PURE__*/function () {
407
417
  try {
408
418
  for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
409
419
  var _item = _step4.value;
410
- _classPrivateFieldGet(_insertObject, _this9).call(_this9, type, _item, "old");
420
+ _classPrivateFieldGet(_insertObject, _this10).call(_this10, type, _item, "old");
411
421
  }
412
422
  } catch (err) {
413
423
  _iterator4.e(err);
414
424
  } finally {
415
425
  _iterator4.f();
416
426
  }
417
- _this9.pubSub.publish("loading", {
427
+ _this10.pubSub.publish("loading", {
418
428
  status: "end",
419
429
  model: type
420
430
  });
@@ -424,7 +434,7 @@ var Store = exports["default"] = /*#__PURE__*/function () {
424
434
  }, {
425
435
  key: "_getPromise",
426
436
  value: function _getPromise(type) {
427
- var _this10 = this;
437
+ var _this11 = this;
428
438
  var ifLoaded = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
429
439
  if (!this.models[type]) {
430
440
  return Promise.reject("The model doesn't exist");
@@ -432,7 +442,7 @@ var Store = exports["default"] = /*#__PURE__*/function () {
432
442
  return Promise.reject("The model is not loaded");
433
443
  } else if (!this.models[type].promise && this.options.lazyLoad && !ifLoaded) {
434
444
  return _assertClassBrand(_Store_brand, this, _loadObjects).call(this, type).then(function () {
435
- return _this10.models[type].promise;
445
+ return _this11.models[type].promise;
436
446
  });
437
447
  } else if (!this.models[type].promise && this.options.lazyLoad && ifLoaded) {
438
448
  return Promise.resolve();
@@ -448,9 +458,9 @@ function _error(error) {
448
458
  return Promise.reject(error);
449
459
  }
450
460
  function _deleteByFilter(type, filterFunction) {
451
- var _this11 = this;
461
+ var _this12 = this;
452
462
  return this._getPromise(type).then(function () {
453
- var deleted = Object.values(_this11.models[type].storedObjects).filter(function (i) {
463
+ var deleted = Object.values(_this12.models[type].storedObjects).filter(function (i) {
454
464
  return filterFunction(i.object);
455
465
  });
456
466
  var _iterator5 = _createForOfIteratorHelper(deleted),
@@ -471,7 +481,7 @@ function _deleteByFilter(type, filterFunction) {
471
481
  });
472
482
  }
473
483
  function _loadObjects(type) {
474
- var _this12 = this;
484
+ var _this13 = this;
475
485
  var item = this.models[type];
476
486
  this.pubSub.publish("loading", {
477
487
  status: "start",
@@ -483,14 +493,14 @@ function _loadObjects(type) {
483
493
  try {
484
494
  for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
485
495
  var _item2 = _step6.value;
486
- _classPrivateFieldGet(_insertObject, _this12).call(_this12, type, _item2, "old");
496
+ _classPrivateFieldGet(_insertObject, _this13).call(_this13, type, _item2, "old");
487
497
  }
488
498
  } catch (err) {
489
499
  _iterator6.e(err);
490
500
  } finally {
491
501
  _iterator6.f();
492
502
  }
493
- _this12.pubSub.publish("loading", {
503
+ _this13.pubSub.publish("loading", {
494
504
  status: "end",
495
505
  model: type
496
506
  });