Source: ressource/serviceCacheRessource.js


'use strict'

module.exports = function (component) {
  component.service('$cacheRessource', function ($cache, $settings, EntityRessource) {
    /**
     * Ne fait rien
     * @private
     */
    function dummy () {}

    /**
     * retourne la clé de cache (ressource_oid cache des ressources, ressourceBy_xxx des oid)
     * @private
     * @param {string} id oid ou clé
     * @param {string} [origine] origine (id est idOrigine) ou 'cle' (id est la clé), ignoré si id est un rid
     * @return {string}
     */
    function getKey (id, origine) {
      if (!id) {
        log.error(new Error('getKey veut un id'))
        return 'undefined'
      }
      if (origine) return `ressourceBy_${origine}_${id}`
      return `ressource_${id}`
    }

    const ttl = $settings.get('components.ressource.cacheTTL', 3600)

    if ($settings.get('noCache', false)) {
      return {
        get: dummy,
        getByCle: dummy,
        getByOrigine: dummy,
        set: dummy,
        delete: dummy,
        deleteByOrigine: dummy
      }
    }

    /**
     * Service de gestion du cache des ressources (helper de $ressourceRepository)
     * @service $cacheRessource
     * @requires $cache
     * @requires $settings
     */
    const $cacheRessource = {}

    /**
     * Envoie une ressource du cache (format Entity) à next
     * @param {Number}         oid   Id de la ressource
     * @param {RessourceCallback} next Callback
     * @memberOf $cacheRessource
     */
    $cacheRessource.get = function (oid, next) {
      $cache.get(getKey(oid), function (error, ressourceCached) {
        // on ne bloque pas si le cache est en erreur
        if (error) {
          log.error(error)
          return next()
        }
        if (ressourceCached) return next(null, EntityRessource.create(ressourceCached))
        next()
      })
    }

    /**
     * Envoie une ressource du cache (format Entity) à next
     * @param {string}         cle
     * @param {RessourceCallback} next
     * @memberOf $cacheRessource
     */
    $cacheRessource.getByCle = function (cle, next) {
      $cache.get(getKey(cle, 'cle'), function (error, oid) {
        if (error) {
          log.error(error)
          return next()
        }
        if (!oid) return next()
        $cache.get(getKey(oid), function (error, ressourceCached) {
          if (error) {
            log.error(error)
            return next()
          }
          if (ressourceCached) return next(null, EntityRessource.create(ressourceCached))
          next()
        })
      })
    }

    /**
     * Envoie une ressource du cache (format Entity) à next
     * @param {string}         origine
     * @param {string}         idOrigine
     * @param {RessourceCallback} next
     * @memberOf $cacheRessource
     */
    $cacheRessource.getByOrigine = function (origine, idOrigine, next) {
      $cache.get(getKey(idOrigine, origine), function (error, oid) {
        if (error) {
          log.error(error)
          return next()
        }
        if (!oid) return next()
        $cache.get(getKey(oid), function (error, ressourceCached) {
          if (error) {
            log.error(error)
            return next()
          }
          if (ressourceCached) return next(null, EntityRessource.create(ressourceCached))
          next()
        })
      })
    }

    /**
     * Met en cache une ressource
     * @param {EntityRessource}      ressource
     * @param {errorCallback} [next] en cas d'erreur du cache, elle sera logguée et next appelé avec la ressource reçue
     * @memberOf $cacheRessource
     */
    $cacheRessource.set = function (ressource, next = dummy) {
      if (!ressource.oid) return next(new Error('cacheSet sur une ressource sans oid'))
      // on utilise Entity.values(), pour stocker la même chose que ce qui aurait été mis en bdd
      if (typeof ressource.values !== 'function') return next(Error('$cache.set veut une Entity'))
      const values = ressource.values()
      const { oid, aliasOf, origine, idOrigine, cle } = values
      // next appelé seulement sur le set principal (le dernier)
      if (origine && idOrigine) $cache.set(getKey(idOrigine, origine), oid, ttl, log.ifError)
      if (cle) $cache.set(getKey(cle, 'cle'), oid, ttl, log.ifError)
      if (aliasOf) $cache.set(getKey(aliasOf, 'aliasOf'), oid, ttl, log.ifError)
      $cache.set(getKey(oid), values, ttl, function (error, ress) {
        if (error) {
          // on log mais on plante pas
          if (error.message && /^The length of the value is greater/.test(error.message)) {
            log.dataError(`ressource ${oid} trop grosse pour le cache (${error.message})`)
          } else {
            log.error(error)
          }
          return next(null, values)
        }
        next(null, ress)
      })
    }

    /**
     * Efface une ressource du cache
     * @param {Number}         oid
     * @param {SimpleCallback} [next]
     * @memberOf $cacheRessource
     */
    $cacheRessource.delete = function (oid, next = dummy) {
      // faut aller le chercher en cache pour effacer l'entrée par origine
      $cache.get(getKey(oid), function (error, ressource) {
        if (error) {
          log.error(error)
          return next()
        }
        if (ressource) {
          $cache.delete(getKey(ressource.idOrigine, ressource.origine), log.ifError)
          $cache.delete(getKey(oid), function (error) {
            if (error) log.error(error)
            next()
          })
        }
      })
    }

    /**
     * Efface une ressource du cache d'après idOrigine
     * @param {string} origine
     * @param {string} idOrigine
     * @param {errorCallback} [next]
     * @memberOf $cacheRessource
     */
    $cacheRessource.deleteByOrigine = function (origine, idOrigine, next = dummy) {
      $cacheRessource.getByOrigine(origine, idOrigine, function (error, oid) {
        if (error) {
          log.error(error)
          return next()
        }
        if (!oid) return next()
        $cache.delete(getKey(idOrigine, origine), log.ifError)
        $cache.delete(getKey(oid), function (error) {
          if (error) log.error(error)
          next()
        })
      })
    }

    return $cacheRessource
  })
}