Source: search/SearchRequest.js

export { SearchRequest };

/**
 * A search request to be used with Search.
 * 
 * Note: Some methods expect an arbitrary number of arguments and are
 * always treated as arrays internally. >ou cannot pass arrays directly as arguments.
 * Please use the ...spread syntax if you try to pass arrays to the methods
 * 
 * @author rkoppe <roland.koppe@awi.de>
 * @author rhess <robin.hess@awi.de>
 * 
 * @memberof vef.search
 */
class SearchRequest {

    // initialize properties
    indices = [];
    types = [];
    facets = [];
    sorts = [];
    excludes = [];
    includes = [];
    offset = 0;
    hits = 10;
    query = '';
    queryFacets = {};
    queryGeometries = {};
    operator = "AND";

    /**
     * Initializes the SearchRequest for the given indices.
     * 
     * @param {...string} indices
     */
    constructor(...indices) {
        this.indices = indices;
    }

    /**
     * Sets the scrolling offset of returned search results.
     * 
     * @param {number} offset 
     * @returns {SearchRequest} instance of SearchRequest for chaining
     */
    setOffset(offset) {
        this.offset = offset;
        return this;
    }

    /**
     * Sets the maximum number of hits to be returned by the search result.
     * 
     * @param {number} hits
     * @returns {SearchRequest} instance of SearchRequest for chaining
     */
    setHits(hits) {
        this.hits = hits;
        return this;
    }

    /**
     * Adds the given field as facet to be calculated for the
     * search response.
     * 
     * @param {...string} field
     * @returns {SearchRequest} instance of SearchRequest for chaining
     */
    addFacet(...field) {
        this.facets = this.facets.concat(field);
        return this;
    }

    /**
     * Adds the given field/value pair as facet restriction to the query.
     * 
     * @param {string} field
     * @param {...string} value
     * @returns {SearchRequest} instance of SearchRequest for chaining
     */
    addQueryFacet(field, ...value) {
        let list = this.queryFacets[field] || [];
        list = list.concat(value);
        this.queryFacets[field] = list
        return this;
    }

    /**
     * Adds the given field/value pair as geometry restriction to the query.
     * 
     * @param {string} field
     * @param {...string} value value
     * @returns {SearchRequest} instance of SearchRequest for chaining
     */
    addQueryGeometry(field, ...value) {
        let list = this.queryGeometries[field] || [];
        list = list.concat(value);
        this.queryGeometries[field] = list;
        return this;
    }

    /**
     * Adds the given type for the search.
     * 
     * @param {...string} type
     * @returns {SearchRequest} instance of SearchRequest for chaining
     */
    addType(...type) {
        this.types = this.types.concat(type);
        return this;
    }

    /**
     * Adds the given query string to the request.
     * 
     * @param {string} query 
     * @returns {SearchRequest} instance of SearchRequest for chaining
     */
    addQuery(query) {
        this.query += query + ' ';
        return this;
    }

    /**
     * Adds the given term query defined by field and value to the request.
     * 
     * @param {string} field 
     * @param {...string} value 
     * @returns {SearchRequest} instance of SearchRequest for chaining
     */
    addTerm(field, ...value) {
        for (let i = 0; i < value.length; ++i) {
            this.query += field + ':' + value[i] + ' ';
        }
        return this;
    }

    /**
     * Adds a sort defined by the field and order asc}.
     * If asc is not defined sort will be executed asc.
     * 
     * @param {string} field 
     * @param {boolean} asc
     * @returns {SearchRequest} instance of SearchRequest for chaining
     */
    addSort(field, asc = true) {
        this.sorts.push(field + ":" + (asc && (asc != 'desc') ? 'asc' : 'desc'));
        return this;
    }

    /**
     * Add a field or array of fields to the list of excluded result fields.
     * 
     * @param {...string} exclude
     * @returns {SearchRequest} instance of SearchRequest for chaining
     */
    addExclude(...exclude) {
        this.excludes = this.excludes.concat(exclude);
        return this;
    }


    /**
     * Add a field or array of fields to the list of included result fields.
     * 
     * @param {...string} include
     * @returns {SearchRequest} instance of SearchRequest for chaining
     */
    addInclude(...include) {
        this.includes = this.includes.concat(include);
        return this;
    }

    /**
     * Adds a from/to range for the given field to the query.
     * And sets bounds as given by includeFrom and includeTo.
     * includeFrom and includeTo are optional and true by default.
     * 
     * @param {string} field 
     * @param {string} from 
     * @param {string} to 
     * @param {boolean} includeFrom 
     * @param {boolean} includeTo 
     * @returns {SearchRequest} instance of SearchRequest for chaining
     */
    addRange(field, from, to, includeFrom = true, includeTo = true) {
        this.query += field + ':'
            + (includeFrom ? '[' : '{') + (from != null ? from : '*')
            + ' TO '
            + (to != null ? to : '*') + (includeTo ? '] ' : '} ');
        return this;
    }

    /**
     * Wraps the given SearchRequests in an AND and adds it to the request.
     * 
     * @param  {...SearchRequest} requests
     * @returns {SearchRequest} instance of SearchRequest for chaining
     */
    and(...requests) {
        if (requests.length > 0) {
            this.query += '(' + requests.map(r => r.query).join(' AND ') + ') ';
        }
        return this;
    }

    /**
     * Wraps the given SearchRequests in an OR and adds it to the request.
     * 
     * @param  {...SearchRequest} requests 
     * @returns {SearchRequest} instance of SearchRequest for chaining
     */
    or(...requests) {
        if (requests.length > 0) {
            this.query += '(' + requests.map(r => r.query).join(' OR ') + ') ';
        }
        return this;
    }

    /**
     * Adds a NOT the the query.
     * 
     * @returns {SearchRequest} instance of SearchRequest for chaining
     */
    not() {
        this.query += 'NOT ';
        return this;
    }

}