/*
Function that accept constraints in json format and will transform them into nano query for couchDB.
@constraints : json that contain some constraints.
@either : optional parameter. If true, change the request to a "or" request. At least one of contrainsts must match (not strict equality)
(1) : checking parts. Empty json, array or false value
(2) : if either variable is true, adding "$or" key to the query
(3) : query builder using a map function. "$and" and "$eq" are implicit here, we dont necessary need those operande to build the query.
(3.1) : If strict equality (either = false), we want to ckeck if a constraints with a value null exists in the doc. If not, the doc is
not returned.
(3.2) : When a constraints value is equal to an stringMap. 2 possibilities:
- If either, then adding a "$in" structure inside the "$or" array
- Else, simply add the "$in" structure inside the "elem" (constraints) key
If elem is not an stringMap type, we do the same thing without the "$in" structure
(4) : listener on testRequest function. This function accept the query builded with constraintsToQuery.
function constraintsToQuery(constraints, either = false) {
    let constEmitter = new EventEmitter;
    let query = { "selector": {} };
    let strConstr = JSON.stringify(constraints);
    let sel = query.selector;
    if (strConstr === JSON.stringify({}) || strConstr === JSON.stringify([])) {
        let error = 'Empty constraints json or array given';
        logger_1.logger.log('warn', error);
        constEmitter.emit('errorOnConstraints');
        return constEmitter;
    } // (1)
    if (!constraints) {
        let error = 'Constraints value is evaluated to false, maybe empty object or empty string';
        logger_1.logger.log('warn', error);
        constEmitter.emit('errorOnConstraints');
        return constEmitter;
    } // (1)
    if (either)
        sel["$or"] = []; // (2)
    Object.keys(constraints).map(elem => {
        if (constraints[elem] === null) {
            if (!either)
                sel[elem] = { "$exists": true }; // (3.1)
            return; // if constraints is null then we jump to the next iteration of the map => will return any value on this key
        }
        if (types.isStringMap(constraints[elem])) { // (3.2)
            either ? sel.$or.push({ [elem]: { "$in": [constraints[elem]] } }) : sel[elem] = { "$in": [constraints[elem]] };
        }
        else {
            either ? sel.$or.push({ [elem]: constraints[elem] }) : sel[elem] = constraints[elem];
        }
    });
    logger_1.logger.log('debug', 'query: ' + JSON.stringify(query));
    dbMod.testRequest(query, nameDB, accountDB, passwordDB, addressDB, portDB, proxyBool).on('requestDone', (data) => {
        if (!data.docs.length) {
            constEmitter.emit('noDocsFound', data);
        }
        else {
            constEmitter.emit('docsFound', data);
        }
    })
        .on('requestError', (err) => {
        constEmitter.emit('errorOnConstraints', err);
    });
    return constEmitter;
}