Initial commit
This commit is contained in:
157
services/cacheService.ts
Normal file
157
services/cacheService.ts
Normal file
@@ -0,0 +1,157 @@
|
||||
/**
|
||||
* 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;
|
||||
Reference in New Issue
Block a user