Home Manual Reference Source Test Repository

src/searching/BaseSearch.js

'use strict';

import q from 'q';

const LIMIT_SIZE_DEF_VALUE = 1000;

/** 
 * This is a abstract class, it must be extended to another class that defined the specific search.
 * This class is responsible to manage execute request to OpenGate North API
 */
export default class BaseSearch {
    /**
     * Constructor
     * @param {!InternalOpenGateAPI} ogapi - this is ogapi instance
     * @param {!string} resource - this is a base url resource
     * @param {!number} [timeout] - timeout on request
     * @param {string} serviceBaseURL - base of the uri petition
     */
    constructor(ogapi, resource, timeout, serviceBaseURL) {
        if (this.constructor === BaseSearch) {
            throw new Error("Cannot construct Abstract instances directly");
        }
        if (typeof this._filter !== "function") {
            throw new Error("Must override method: filter");
        }
        if (typeof timeout !== 'number') {
            this._timeout = ogapi.Napi._options.timeout;
        } else {
            this._timeout = timeout;
        }
        this._ogapi = ogapi;
        this._resource = resource;
        this._headers = undefined;
        this._urlParameters = undefined;
        this._serviceBaseURL = serviceBaseURL
    }

    _getExtraHeaders() {
        return this._headers;
    }

    _setExtraHeaders(headers) {
        if (this._headers) {
            var keys = Object.keys(headers);
            for (var i = 0; i < keys.length; i++) {
                var key = keys[i];
                this._headers[key] = headers[key];
            }
        } else {
            this._headers = headers;
        }
    }

    _getUrlParameters() {
        return this._urlParameters;
    }

    _setUrlParameters(parameters) {
        if (this._urlParameters) {
            var keys = Object.keys(parameters);
            for (var i = 0; i < keys.length; i++) {
                var key = keys[i];
                this._urlParameters[key] = parameters[key];
            }
        } else {
            this._urlParameters = parameters;
        }
    }

    /**
     * This invoke a request to OpenGate North API and the callback is managed by promises
     * @return {Promise}
     * @property {function (result:object, statusCode:number)} then - When request it is OK
     * @property {function (error:string)} catch - When request it is NOK
     */
    execute() {
        var defered = q.defer();
        var promise = defered.promise;
        this._ogapi.Napi
            .post(this._resource, this._filter(), this._timeout, this._getExtraHeaders(), this._getUrlParameters(), this._getServiceBaseURL())
            .then((response) => {
                let resultQuery = response.body;
                let statusCode = response.statusCode;
                defered.resolve({
                    data: resultQuery,
                    statusCode: statusCode
                });
            })
            .catch((error) => {
                defered.reject(error);
            });
        return promise;
    }

    /** TODO: no implementado todavía. Ver tarea OUW-3577
     * This invoke a request to OpenGate North API and the callback is managed by promises
     * @return {Promise}
     * @property {function (result:object, statusCode:number)} then - When request it is OK
     * @property {function (error:string)} catch - When request it is NOK
     
    delete() {
        var defered = q.defer();
        var promise = defered.promise;
        this._ogapi.Napi
            .delete(this._resource, this._timeout, this._getExtraHeaders(), this._getUrlParameters(), this._filter(),)
            .then((response) => {
                if (response.statusCode === 200) {
                    defered.resolve({
                        statusCode: response.statusCode
                    });
                } else {
                    defered.reject({
                        errors: response.errors,
                        statusCode: response.statusCode
                    });
                }
            })
            .catch((error) => {
                defered.reject(error);
            });
        return promise;
    }*/

    /**
     * This invoke a request to OpenGate North API and the callback is managed by promises
     * @return {Promise} - Promise with data with format csv
     * @property {function (result:object, statusCode:number)} then - When request it is OK
     * @property {function (error:string)} catch - When request it is NOK
     */
    downloadCsv() {
        var defered = q.defer();
        var promise = defered.promise;
        var filter = this._filter();

        if (filter && filter.limit) {
            delete filter.limit;
        }
        this._setExtraHeaders({
            'Accept': 'text/plain'
        });

        this._ogapi.Napi.post(this._resource, filter, this._timeout, this._getExtraHeaders(), this._getUrlParameters(), this._getServiceBaseURL())
            .then((response) => {
                let resultQuery = response;
                let statusCode = response.statusCode;
                defered.resolve({
                    data: resultQuery,
                    statusCode: statusCode
                });
            })
            .catch((error) => {
                defered.reject(error);
            });
        return promise;
    }

    //Se debera fijar simpre un objeto limit en la paginacion asincrona
    //Si no existiera el objeto limit se creara uno por defecto
    //Si tuviera se modficara para que siempre comience en la primera pagina
    _asyncPagingFilter() {
        var filter = this._filter();

        if (!filter.limit || !filter.limit.size) {
            filter.limit = {
                size: LIMIT_SIZE_DEF_VALUE,
                start: 1
            };
        } else {
            filter.limit.start = 1;
        }
        return filter;
    }

    cancelAsyncPaging(message) {
        if (typeof message === 'string' && message.length > 0) {
            this.cancel = message;
        } else
            this.cancel = true;
    }

    _loadData(resource) {
        let _this = this;
        let defered = q.defer();
        let filter = _this._asyncPagingFilter();
        let paging = false;
        //Funcion que realizara la llamada al search paginado y, de forma recursiva, llamara a todas las paginas
        function loadAll() {
            if (_this.cancel || typeof _this.cancel === 'string') {
                var message = typeof _this.cancel === 'string' ? _this.cancel : 'Cancel process';
                defered.reject({
                    data: message,
                    statusCode: 403
                });
            } else {
                _this._ogapi.Napi
                    .post(_this._resource, filter, _this._timeout, _this._getExtraHeaders(), _this._getUrlParameters(), _this._getServiceBaseURL())
                    .then((response) => {
                        let statusCode = response.statusCode;
                        let body = response.body;
                        if (!body && response.text) {
                            try {
                                let parsedResult = JSON.parse(response.text);

                                if (parsedResult) {
                                    body = parsedResult;
                                }
                            } catch (ignoreError) {
                                console.error("Impossible to parse text from response");
                            }
                        }

                        if (statusCode === 200 || statusCode === 200) {
                            paging = true;
                            let result = body.data ? body.data[resource] : body[resource];
                            defered.notify(result);
                            //Se permite devolver un boolean o un string que reemplazará el mensaje por defecto
                            if (result.length === filter.limit.size) {
                                filter.limit.start += 1;
                                loadAll();
                            } else {
                                defered.resolve({
                                    data: 'DONE',
                                    statusCode: 200
                                });
                            }
                        } else {
                            if (paging) {
                                defered.resolve({
                                    data: 'DONE',
                                    statusCode: 200
                                });
                            } else
                                defered.reject({
                                    data: body,
                                    statusCode: statusCode
                                });
                        }
                    })
                    .catch((error) => {
                        defered.reject(error);
                    });
            }
        }
        loadAll();
        return defered.promise;
    }

    /**
     * This invokes a request for asynchronous paging to the OpenGate North API and the return of the pages is managed by promises and its notify object
     * To cancel the process in the notify method return false or string with custom message for response
     * In case of canceling the process, the response will be 403: Forbidden -> {data: 'Cancel process'|| custom_message, statusCode: 403}
     * @param {string} resource - resource to find.
     * @return {Promise}
     * @property {function (), null, function ()} then - When request it is OK
     * @property {function (error:string)} catch - When request it is NOK
     */
    executeWithAsyncPaging(resource) {
        let defered = q.defer();
        let promise = defered.promise;
        //Comenzamos con la carga asincrona
        this._loadData(resource)
            .then(
                (response) => {
                    defered.resolve(response);
                }, null,
                (notify) => {
                    defered.notify(notify);
                })
            .catch((error) => {
                defered.reject(error);
            });


        return promise;
    }

    _getServiceBaseURL() {
        return this._serviceBaseURL
    }
}