@rest-api/react-models
Version:
[](https://www.npmjs.com/package/@rest-api/react-models) [](https://codecov.io/gh/hector7/rest-
274 lines (273 loc) • 13 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const __1 = require("../..");
const index_1 = require("./index");
const utils_1 = require("../reducers/utils");
class ComplexIdActions {
constructor(restModel) {
this.actions = {
fetchByIdIfNeeded: (opt, id) => index_1.idActions.fetchByIdIfNeeded(this.restModel.model.name, this.restModel._id, id),
invalidateAll: () => index_1.idActions.invalidateAll(this.restModel.model.name),
invalidateOpt: (opt) => index_1.idActions.invalidateAll(this.restModel.model.name),
failedById: (opt, id, error) => index_1.idActions.failedById(this.restModel.model.name, this.restModel._id, id, error),
invalidateById: (opt, id) => index_1.idActions.invalidateById(this.restModel.model.name, this.restModel._id, id),
receiveById: (opt, data) => index_1.idActions.receiveById(this.restModel.model.name, data),
removeById: (opt, data) => index_1.idActions.removeById(this.restModel.model.name, this.restModel._id, data),
};
this.idQueue = {};
this.restModel = restModel;
}
getIdRequest(getState, id) {
const reducer = (getState()[this.restModel.model.name]);
return utils_1.getIdRequest(reducer, this.restModel._id, id);
}
getUri(opts) {
return this.restModel.trailingSlash ? `${this.restModel.getUrl(opts)}/` : `${this.restModel.getUrl(opts)}`;
}
getIdUri(opts, id) {
return this.restModel.trailingSlash ? `${this.restModel.getUrl(opts)}/${id}/` : `${this.restModel.getUrl(opts)}/${id}`;
}
getById(opts, id, callback) {
const actions = this.actions;
return (dispatch, getState) => {
const optKey = this.getUri(opts);
if (callback)
this.idQueue[optKey][id].push(callback);
dispatch(actions.fetchByIdIfNeeded(opts, id));
const xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = () => {
if (xhttp.readyState === 4 && (xhttp.status === 200 || xhttp.status === 201)) {
try {
const res = JSON.parse(xhttp.responseText);
if (this.restModel.validateItem(res)) {
dispatch(actions.receiveById(opts, this.restModel.model.schema._useUpdatedSteps(getState(), res)));
let cb;
while ((cb = this.idQueue[optKey][id].shift()) !== undefined) {
cb(null, res);
}
}
else {
console.error(this.restModel.model.schema.getValidateErrorPretty(res));
throw (new Error(`Response text from "${this.getIdUri(opts, id)}" is not valid (Schema definition is invalid or bad implementation).
Check console for details.`));
}
}
catch (err) {
const error = new __1.HttpError(500, err.message);
dispatch(actions.failedById(opts, id, error));
let cb;
while ((cb = this.idQueue[optKey][id].shift()) !== undefined) {
cb(error);
}
}
}
else if (xhttp.readyState === 4) {
if (index_1.IGNORED_STATUS.indexOf(xhttp.status) > -1) {
return dispatch(this.getById(opts, id, callback));
}
const error = new __1.HttpError(xhttp.status, xhttp.responseText);
dispatch(actions.failedById(opts, id, error));
let cb;
while ((cb = this.idQueue[optKey][id].shift()) !== undefined) {
cb(error);
}
}
};
xhttp.open('GET', this.getIdUri(opts, id), true);
Object.keys(this.restModel.headers).forEach(key => {
xhttp.setRequestHeader(key, this.restModel.headers[key]);
});
xhttp.setRequestHeader('Content-Type', 'application/json');
xhttp.send();
};
}
invalidateById(opts, id) {
if (typeof id !== 'string' && typeof id !== 'number')
throw (new Error(`${JSON.stringify(id)} is not string or number. is type ${typeof id}`));
return this.actions.invalidateById(opts, id);
}
fetchByIdIfNeeded(opts, id, callback) {
const actions = this.actions;
return (dispatch, getState) => {
const optKey = this.getUri(opts);
if (typeof id !== 'string' && typeof id !== 'number')
throw (new Error(`${JSON.stringify(id)} is not string or number. is type ${typeof id}`));
if (!this.idQueue.hasOwnProperty(optKey))
this.idQueue[optKey] = {};
if (!this.idQueue[optKey].hasOwnProperty(id))
this.idQueue[optKey][id] = [];
const req = this.getIdRequest(getState, id);
if (index_1.shouldFetch(req)) {
return dispatch(this.getById(opts, id, callback));
}
const promiseCb = (err, res) => {
if (err) {
if (callback)
callback(err);
return;
}
if (callback)
callback(null, res);
};
if (utils_1.isFetching(req)) {
this.idQueue[optKey][id].push(promiseCb);
}
else {
const error = utils_1.getError(req);
if (error)
return promiseCb(error);
promiseCb(null, utils_1.getResult(req));
}
};
}
fetchByIdPopulatedIfNeeded(opts, id) {
const actions = this.actions;
return (dispatch, getState) => {
dispatch(this.fetchByIdIfNeeded(opts, id));
const req = this.getIdRequest(getState, id);
if (req.result) {
this.restModel.model.schema._getModelValuesToPopulate(req.result, (model, id) => dispatch(model._actions.fetchByIdPopulatedIfNeeded(id)));
}
//TODO Return promise
};
}
post(opts, item, callback) {
const actions = this.actions;
return (dispatch) => {
const xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = () => {
if (xhttp.readyState === 4 && (xhttp.status === 200 || xhttp.status === 201)) {
try {
const item = JSON.parse(xhttp.responseText);
dispatch(this.actions.invalidateAll());
dispatch(actions.receiveById(opts, item));
callback(null, item);
}
catch (err) {
callback(new __1.HttpError(500, err.message));
}
}
else if (xhttp.readyState === 4) {
if (index_1.IGNORED_STATUS.indexOf(xhttp.status) > -1) {
return dispatch(this.post(opts, item, callback));
}
callback(new __1.HttpError(xhttp.status, xhttp.responseText));
}
};
xhttp.open('POST', this.getUri(opts), true);
Object.keys(this.restModel.headers).forEach(key => {
xhttp.setRequestHeader(key, this.restModel.headers[key]);
});
if (item.__proto__ === FormData)
xhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
else
xhttp.setRequestHeader('Content-Type', 'application/json');
xhttp.send(item.__proto__ === FormData ? item : JSON.stringify(item));
};
}
put(opts, id, item, callback) {
const actions = this.actions;
return (dispatch) => {
if (typeof id !== 'string' && typeof id !== 'number')
throw (new Error(`${JSON.stringify(id)} is not string or number. is type ${typeof id}`));
const xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = () => {
if (xhttp.readyState === 4 && xhttp.status === 200) {
try {
const item = JSON.parse(xhttp.responseText);
dispatch(this.actions.invalidateAll());
dispatch(actions.receiveById(opts, item));
callback(null, item);
}
catch (err) {
callback(new __1.HttpError(500, err.message));
}
}
else if (xhttp.readyState === 4) {
if (index_1.IGNORED_STATUS.indexOf(xhttp.status) > -1) {
return dispatch(this.put(opts, id, item, callback));
}
callback(new __1.HttpError(xhttp.status, xhttp.responseText));
}
};
xhttp.open('PUT', this.getIdUri(opts, id), true);
Object.keys(this.restModel.headers).forEach(key => {
xhttp.setRequestHeader(key, this.restModel.headers[key]);
});
if (item.__proto__ === FormData)
xhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
else
xhttp.setRequestHeader('Content-Type', 'application/json');
xhttp.send(item.__proto__ === FormData ? item : JSON.stringify(item));
};
}
invalidateAll() {
return this.actions.invalidateAll();
}
patch(opts, id, item, callback) {
const actions = this.actions;
return (dispatch) => {
if (typeof id !== 'string' && typeof id !== 'number')
throw (new Error(`${JSON.stringify(id)} is not string or number. is type ${typeof id}`));
const xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = () => {
if (xhttp.readyState === 4 && xhttp.status === 200) {
try {
const item = JSON.parse(xhttp.responseText);
dispatch(this.actions.invalidateAll());
dispatch(actions.receiveById(opts, item));
callback(null, item);
}
catch (err) {
callback(new __1.HttpError(500, err.message));
}
}
else if (xhttp.readyState === 4) {
if (index_1.IGNORED_STATUS.indexOf(xhttp.status) > -1) {
return dispatch(this.patch(opts, id, item, callback));
}
callback(new __1.HttpError(xhttp.status, xhttp.responseText));
}
};
xhttp.open('PATCH', this.getIdUri(opts, id), true);
Object.keys(this.restModel.headers).forEach(key => {
xhttp.setRequestHeader(key, this.restModel.headers[key]);
});
if (item.__proto__ === FormData)
xhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
else
xhttp.setRequestHeader('Content-Type', 'application/json');
xhttp.send(item.__proto__ === FormData ? item : JSON.stringify(item));
};
}
delete(opts, item, callback) {
const actions = this.actions;
return (dispatch) => {
const xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = () => {
if (xhttp.readyState === 4 && (xhttp.status === 200 || xhttp.status === 204)) {
try {
dispatch(this.actions.invalidateAll());
dispatch(actions.removeById(opts, item));
callback(null);
}
catch (err) {
callback(new __1.HttpError(500, err.message));
}
}
else if (xhttp.readyState === 4) {
if (index_1.IGNORED_STATUS.indexOf(xhttp.status) > -1) {
return dispatch(this.delete(opts, item, callback));
}
callback(new __1.HttpError(xhttp.status, xhttp.responseText));
}
};
xhttp.open('DELETE', this.getIdUri(opts, item[this.restModel._id]), true);
Object.keys(this.restModel.headers).forEach(key => {
xhttp.setRequestHeader(key, this.restModel.headers[key]);
});
xhttp.send();
};
}
}
exports.default = ComplexIdActions;