UNPKG

@rest-api/react-models

Version:

[![npm version](https://img.shields.io/npm/v/@rest-api/react-models)](https://www.npmjs.com/package/@rest-api/react-models) [![codecov](https://codecov.io/gh/hector7/rest-api-react-models/branch/master/graph/badge.svg)](https://codecov.io/gh/hector7/rest-

274 lines (273 loc) 13 kB
"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;