158 lines
3.4 KiB
TypeScript
Executable File
158 lines
3.4 KiB
TypeScript
Executable File
/**
|
|
* Service de cache pour optimiser les performances
|
|
*/
|
|
|
|
export interface CacheEntry<T> {
|
|
data: T;
|
|
timestamp: number;
|
|
ttl: number; // Time to live en millisecondes
|
|
}
|
|
|
|
export class CacheService {
|
|
private static cache = new Map<string, CacheEntry<any>>();
|
|
private static readonly DEFAULT_TTL = 5 * 60 * 1000; // 5 minutes par défaut
|
|
|
|
/**
|
|
* Stocke une valeur dans le cache
|
|
*/
|
|
static set<T>(key: string, data: T, ttl: number = this.DEFAULT_TTL): void {
|
|
const entry: CacheEntry<T> = {
|
|
data,
|
|
timestamp: Date.now(),
|
|
ttl
|
|
};
|
|
this.cache.set(key, entry);
|
|
}
|
|
|
|
/**
|
|
* Récupère une valeur du cache
|
|
*/
|
|
static get<T>(key: string): T | null {
|
|
const entry = this.cache.get(key);
|
|
|
|
if (!entry) {
|
|
return null;
|
|
}
|
|
|
|
// Vérifier si l'entrée a expiré
|
|
if (Date.now() - entry.timestamp > entry.ttl) {
|
|
this.cache.delete(key);
|
|
return null;
|
|
}
|
|
|
|
return entry.data as T;
|
|
}
|
|
|
|
/**
|
|
* Supprime une entrée du cache
|
|
*/
|
|
static delete(key: string): boolean {
|
|
return this.cache.delete(key);
|
|
}
|
|
|
|
/**
|
|
* Vide tout le cache
|
|
*/
|
|
static clear(): void {
|
|
this.cache.clear();
|
|
}
|
|
|
|
/**
|
|
* Nettoie les entrées expirées
|
|
*/
|
|
static cleanup(): void {
|
|
const now = Date.now();
|
|
for (const [key, entry] of this.cache.entries()) {
|
|
if (now - entry.timestamp > entry.ttl) {
|
|
this.cache.delete(key);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Récupère ou exécute une fonction avec mise en cache
|
|
*/
|
|
static async getOrSet<T>(
|
|
key: string,
|
|
fetchFunction: () => Promise<T>,
|
|
ttl: number = this.DEFAULT_TTL
|
|
): Promise<T> {
|
|
// Essayer de récupérer depuis le cache
|
|
const cached = this.get<T>(key);
|
|
if (cached !== null) {
|
|
return cached;
|
|
}
|
|
|
|
// Exécuter la fonction et mettre en cache
|
|
try {
|
|
const data = await fetchFunction();
|
|
this.set(key, data, ttl);
|
|
return data;
|
|
} catch (error) {
|
|
// Ne pas mettre en cache les erreurs
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Invalide le cache pour un pattern de clés
|
|
*/
|
|
static invalidatePattern(pattern: string): void {
|
|
const regex = new RegExp(pattern);
|
|
for (const key of this.cache.keys()) {
|
|
if (regex.test(key)) {
|
|
this.cache.delete(key);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Obtient les statistiques du cache
|
|
*/
|
|
static getStats(): {
|
|
size: number;
|
|
keys: string[];
|
|
expired: number;
|
|
} {
|
|
const now = Date.now();
|
|
let expired = 0;
|
|
|
|
for (const [key, entry] of this.cache.entries()) {
|
|
if (now - entry.timestamp > entry.ttl) {
|
|
expired++;
|
|
}
|
|
}
|
|
|
|
return {
|
|
size: this.cache.size,
|
|
keys: Array.from(this.cache.keys()),
|
|
expired
|
|
};
|
|
}
|
|
}
|
|
|
|
// Nettoyage automatique toutes les 10 minutes
|
|
if (typeof window !== 'undefined') {
|
|
setInterval(() => {
|
|
CacheService.cleanup();
|
|
}, 10 * 60 * 1000);
|
|
}
|
|
|
|
// Clés de cache prédéfinies
|
|
export const CacheKeys = {
|
|
CLIENTS: 'clients',
|
|
CHANTIERS: 'chantiers',
|
|
DEVIS: 'devis',
|
|
FACTURES: 'factures',
|
|
DASHBOARD_STATS: 'dashboard_stats',
|
|
USER_PROFILE: 'user_profile',
|
|
|
|
// Fonctions utilitaires pour générer des clés
|
|
clientById: (id: string) => `client_${id}`,
|
|
chantierId: (id: string) => `chantier_${id}`,
|
|
devisById: (id: string) => `devis_${id}`,
|
|
factureById: (id: string) => `facture_${id}`,
|
|
devisByClient: (clientId: string) => `devis_client_${clientId}`,
|
|
facturesByClient: (clientId: string) => `factures_client_${clientId}`,
|
|
} as const;
|