Source: services/entities-cli/_helpers.js

'use strict'
const flow = require('an-flow')
const anLog = require('an-log')('lassi-cli')
const log = (...args) => anLog('entities-cli', ...args)

/**
 * Parse une string json et retourne le résultat ou undefined si le parsing a planté
 * @private
 * @param {string} json
 */
function parse (json) {
  try {
    return JSON.parse(json)
  } catch (error) {
    if (lassi.debug) {
      log.error('Error de parsing json sur ' + json)
      log.error(error)
    }
  }
}

/**
 * Traduit l'objet wheres en requête lassi sur Entity
 * @param {Entity} Entity
 * @param {string} wheres un objet json (cf help pour la syntaxe)
 * @return {EntityQuery}
 */
function addConditions (Entity, wheres) {
  let query = Entity
  if (wheres) {
    const filters = parse(wheres)
    if (!filters || !Array.isArray(filters)) throw new Error('le 3e arguments where doit être un tableau (string JSON) dont chaque élément est un tableau [champ, condition, valeur]')
    filters.forEach(([field, condition, value]) => {
      if (!field) throw new Error('filtre invalide')
      if (condition === 'isNull') {
        query = query.match(field).isNull()
      } else if (condition === 'isNotNull') {
        query = query.match(field).isNotNull()
      } else {
        if (!value) throw new Error(`condition invalide (valeur manquante pour le champ ${field} et la condition ${condition})`)
        if (typeof value !== 'string') throw new Error(`condition invalide (valeur non string pour le champ ${field} et la condition ${condition})`)
        if (condition === '=') query = query.match(field).equals(value)
        else if (condition === '>') query = query.match(field).greaterThan(value)
        else if (condition === '>=') query = query.match(field).greaterThanOrEquals(value)
        else if (condition === '<') query = query.match(field).lowerThan(value)
        else if (condition === '<=') query = query.match(field).lowerThanOrEquals(value)
        else if (condition === '<>' || condition === '><') query = query.match(field).notIn([value])
        else if (condition === 'in' || condition === 'notIn') {
          // value doit être une liste avec la virgule en séparateur
          const values = value.split(',')
          if (condition === 'in') query = query.match(field).in(values)
          else query = query.match(field).notIn(values)
        } else throw new Error(`Condition ${condition} non gérée`)
      }
    })
  } else {
    query = query.match()
  }

  return query
}

/**
 * Helper pour lancer la récupération d'entité par paquets de limit
 * @private
 * @param {EntityQuery} query
 * @param {number} limit
 * @param {function} eachCb Callback appelée avec chaque entité remontée
 * @param options
 * @param done
 */
function grab (query, limit, eachCb, options, done) {
  function nextGrab () {
    let nb
    flow()
      .seq(function () {
        nb = 0
        query.grab({ limit: limit, offset: offset }, this)
      })
      .seqEach(function (entity) {
        nb++
        eachCb(entity, this)
      })
      .seq(function () {
        if (options.groupCb) options.groupCb(offset, nb)
        if (nb === limit) {
          offset += limit
          setTimeout(nextGrab, 0)
        } else {
          done()
        }
      })
      .catch(done)
  }
  let offset = 0
  if (typeof options === 'function') {
    done = options
    options = {}
  }
  nextGrab()
}

module.exports = {
  addConditions,
  grab
}