'use strict'
const flow = require('an-flow')
const { getNormalizedName } = require('../lib/normalize')
module.exports = function (component) {
component.service('$cacheGroupe', function ($cache, $settings) {
// on peut pas le mettre en dépendance car il nous utilise
let EntityGroupe
/**
* TTL du cache des groupes, mis idem personne si c'est en conf, 20min par défaut
* @type number
*/
const ttl = $settings.get('components.personne.cacheTTL', 20 * 60)
const prefix = 'groupe_'
/**
* Retourne la clé de cache d'un groupe, construite d'après son nom
* (nom normalisé sans espace)
* @private
* @param {string|Groupe} groupe
* @returns {string}
*/
const getKey = (groupe) => {
let key
// si on tombait un jour sur une clé sortie de sanitizeHashKey qui plaisait pas à memcache,
// utiliser un md5 du nom, mais c'est bcp plus gourmand
// key = crypto.createHash('md5').update(data).digest('hex')
// key = prefix + tools.sanitizeHashKey(nom)
if (groupe) {
let nom = typeof groupe === 'string' ? groupe : groupe.nom
if (nom) {
nom = getNormalizedName(nom).replace(' ', '')
if (nom) return nom
}
}
return key
}
/**
* Enrobe next pour passer le groupe retourné du cache par EntityGroupe.create
* @private
* @param {groupeCallback} next
* @return {groupeCallback}
*/
const getWrapper = (next) => {
if (!EntityGroupe) EntityGroupe = lassi.service('EntityGroupe')
return (error, groupe) => {
if (error) return next(error)
if (!groupe) return next()
next(null, EntityGroupe.create(groupe))
}
}
/**
* Récupère un groupe dans le cache, d'après son oid
* @param {string} oid
* @param {groupeCallback} next
* @memberOf $cacheGroupe
*/
function get (oid, next) {
$cache.get(prefix + oid, getWrapper(next))
}
/**
* Récupère un groupe dans le cache, d'après son nom
* @param {string} nom Le nom, normalisé ou pas
* @param {groupeCallback} next
* @memberOf $cacheGroupe
*/
function getByNom (nom, next) {
const key = getKey(nom)
if (!key) return next(Error('Nom manquant'))
$cache.get(key, getWrapper(next))
}
/**
* Met un groupe en cache
* @param {Groupe} groupe
* @param {errorCallback} [next]
* @memberOf $cacheGroupe
*/
function set (groupe, next = log.ifError) {
if (typeof groupe.values !== 'function') return next(Error('$cacheGroupe.set veut une Entity'))
const key = getKey(groupe)
if (key) {
const values = groupe.values()
const { oid } = groupe
flow().seq(function () {
$cache.set(key, values, ttl, this)
if (oid) $cache.set(prefix + oid, values, ttl, log.ifError)
}).seq(function () {
next()
}).catch(function (error) {
log.error(`le $cache.set a planté avec la clé ${key}`, error)
// pb de clé, tant pis, ça sera pas en cache via le nom
// (pas de risque d'avoir une ancienne version foireuse au get)
next()
})
} else {
next(Error('Groupe invalide'))
}
}
/**
* Efface un groupe du cache
* @param {string|Groupe} groupe (l'objet ou son nom)
* @param {errorCallback} [next]
* @memberOf $cacheGroupe
*/
function deleteGroupe (groupe, next = log.ifError) {
const key = getKey(groupe)
if (key) {
if (groupe.oid) {
$cache.delete(key, next)
$cache.delete(prefix + groupe.oid, next)
} else {
// faut aller le chercher en cache pour récupérer l'oid
$cache.get(key, (error, groupe) => {
if (error) return next(error)
if (!groupe) return next()
$cache.delete(key, next)
$cache.delete(prefix + groupe.oid, next)
})
}
} else {
next(new Error('groupe invalide'))
}
}
// on ajoute une possibilité noCache en conf
if ($settings.get('noCache', false)) {
log('$cacheRessource désactivé')
const dummy = (arg, next) => next()
return {
delete: dummy,
get: dummy,
getByNom: dummy,
set: dummy
}
}
/**
* Service helper de $personneRepository
* Chaque groupe est mis en cache deux fois, par son nom et son oid
* @service $cacheGroupe
*/
const $cacheGroupe = {
delete: deleteGroupe,
get,
getByNom,
set
}
return $cacheGroupe
})
}