react-backend
Version:
A framework which help fetch data from backends and provide them to React.js components.
239 lines (191 loc) • 7.06 kB
JavaScript
Object.defineProperty(exports, "__esModule", {
value: true
});
var _createClass = function () { 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); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
/**
* Base class for your DataProvider objects.
*/
var DataProvider = function () {
/**
* Constructor
* At client side, will retrieve the preloaded data from window.data
* so that there is no need to fetch data from backend
* @returns {DataProvider}
*/
/**
* This will hold a cache of the created promise objects,
* in the form [ string => promise object ]
*/
/** Resolved values of the promises. Use getData() to access it */
function DataProvider() {
var _this = this;
_classCallCheck(this, DataProvider);
this.values = {};
this.errors = {};
this.promises = {};
this._shouldReload = false;
this.when = this.getPromise;
this.pushNeeds = function (needs) {
if (typeof needs === 'string') needs = [needs];
needs.forEach(function (promiseFuncName) {
_this.getPromise(promiseFuncName);
});
};
this.getData = function (need) {
return _this.values[need];
};
this.getError = function (need) {
return _this.errors[need];
};
this.hasErrors = function () {
return Object.values(_this.errors).length > 0;
};
if (typeof window !== 'undefined' && window.data) {
Object.keys(window.data).forEach(function (key) {
var value = window.data[key];
_this.promises[key] = Promise.resolve(value);
_this.values[key] = value;
});
}
}
/**
* Builder and accessor function to get the promises managed by the DataProvider
* @param {String} promiseName - name of the dataProvider function, such as "getUserComments"
* @returns {Promise} - the associated promise
*/
/** will be true when some data need to be fetched from the backend */
/** Resolved errors of the promises. Use hasErrors() and getError() to access it */
_createClass(DataProvider, [{
key: 'getPromise',
value: function getPromise(promiseName) {
var promise = this.promises[promiseName];
if (!promise) {
promise = this[promiseName]();
this.promises[promiseName] = promise;
this._shouldReload = true;
}
return promise;
}
/**
* Use the when() function to express dependencies between your data.
* If several promises share the same dependency, it will be cached and
* called only one time.
* Example :
* getUserComments() { this.when("getUserId").then(id => db.fetchComments(id)) }
*/
/**
* This is used internall by the NeedsData component.
* @param {String or Object} needs - can be either the name of a function of your
* dataProvider instance, or an array of names.
* @returns {undefined}
*/
}, {
key: 'resolveNeeds',
/**
* This will resolved all the promises, and populate the values and errors fields.
* @returns {Promise} A promise resolving all the data needs.
*/
value: function resolveNeeds() {
var self = this;
// we store all the promises in the resolvers array
// in such a way that they will always resolve (never reject)
var resolvers = [];
Object.values(this.promises).forEach(function (promise) {
resolvers.push(promise.then(function (value) {
promise.value = value;
}, function (error) {
promise.error = error;
}));
});
// and we resolve the array of promises
return Promise.all(resolvers).then(function () {
var values = {};
var errors = {};
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = Object.keys(self.promises)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var funcName = _step.value;
var p = self.promises[funcName];
if (p.value) values[funcName] = p.value;
if (p.error) errors[funcName] = p.error;
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
self.values = values;
self.errors = errors;
self._shouldReload = false;
});
}
/**
* Will force the data to be fetched again from the backend during the next
* UI refresh
* @param {String or Object} needs - can be either the name of a function of your
* dataProvider instance, or an array of names.
* @returns {undefined}
*/
}, {
key: 'invalidate',
value: function invalidate(needs) {
if (typeof needs === 'string') needs = [needs];
var self = this;
needs.forEach(function (need) {
delete self.promises[need];
delete self.values[need];
delete self.errors[need];
});
}
/**
* Will invalidate all the data, in order to force reload during the next UI
* refresh
* @returns {undefined}
*/
}, {
key: 'invalidateAll',
value: function invalidateAll() {
this.promises = {};
this.values = {};
this.errors = {};
this._shouldReload = false;
}
/**
* @returns {bool} - will return true when there are unresolved needs which must be
* fetched from the backend
*/
}, {
key: 'shouldReload',
value: function shouldReload() {
return this._shouldReload;
}
/**
* Use this to get the values of the data
* @param {String} need - the name of the dataProvider function
* @returns {DataProvider.values} - will return undefined if there was errors
*/
/**
* Use this to get the error triggered when retrieving data
* @param {String} need - the name of the dataProvider function
* @returns {DataProvider.errors} - will return undefined if there was no error
*/
/**
* @returns {Boolean} true if there are some errors
*/
}]);
return DataProvider;
}();
exports.default = DataProvider;
;