- Add Legal Office of the Master seal (SVG design with Maltese Cross, scales of justice, legal scroll) - Create legal-office-manifest-template.json for Legal Office credentials - Update SEAL_MAPPING.md and DESIGN_GUIDE.md with Legal Office seal documentation - Complete Azure CDN infrastructure deployment: - Resource group, storage account, and container created - 17 PNG seal files uploaded to Azure Blob Storage - All manifest templates updated with Azure URLs - Configuration files generated (azure-cdn-config.env) - Add comprehensive Azure CDN setup scripts and documentation - Fix manifest URL generation to prevent double slashes - Verify all seals accessible via HTTPS
93 lines
3.0 KiB
JavaScript
93 lines
3.0 KiB
JavaScript
/**
|
|
* Database query caching with Redis
|
|
* Implements query result caching with automatic invalidation
|
|
*
|
|
* Note: This module uses optional dynamic import for @the-order/cache
|
|
* to avoid requiring it as a direct dependency. If cache is not available,
|
|
* queries will execute directly without caching.
|
|
*/
|
|
import { query } from './client';
|
|
// Cache client instance (lazy-loaded via dynamic import)
|
|
let cacheClientPromise = null;
|
|
/**
|
|
* Get cache client (lazy-loaded via dynamic import)
|
|
* Returns null if cache module is not available
|
|
*/
|
|
async function getCacheClient() {
|
|
if (cacheClientPromise === null) {
|
|
cacheClientPromise = (async () => {
|
|
try {
|
|
// Use dynamic import with a string literal that TypeScript can't resolve at compile time
|
|
// This is done by constructing the import path dynamically
|
|
const cacheModulePath = '@the-order/cache';
|
|
// eslint-disable-next-line @typescript-eslint/no-implied-eval
|
|
const importFunc = new Function('specifier', 'return import(specifier)');
|
|
const cacheModule = await importFunc(cacheModulePath);
|
|
return cacheModule.getCacheClient();
|
|
}
|
|
catch {
|
|
// Cache module not available - caching will be disabled
|
|
return null;
|
|
}
|
|
})();
|
|
}
|
|
return cacheClientPromise;
|
|
}
|
|
/**
|
|
* Execute a query with caching
|
|
*/
|
|
export async function cachedQuery(sql, params, options = {}) {
|
|
const { ttl = 3600, keyPrefix = 'db:query:', enabled = true } = options;
|
|
if (!enabled) {
|
|
return query(sql, params);
|
|
}
|
|
const cache = await getCacheClient();
|
|
if (!cache) {
|
|
// Cache not available - execute query directly
|
|
return query(sql, params);
|
|
}
|
|
const cacheKey = `${keyPrefix}${sql}:${JSON.stringify(params || [])}`;
|
|
// Try to get from cache
|
|
const cached = await cache.get(cacheKey);
|
|
if (cached) {
|
|
return cached;
|
|
}
|
|
// Execute query
|
|
const result = await query(sql, params);
|
|
// Cache result
|
|
await cache.set(cacheKey, result, ttl);
|
|
return result;
|
|
}
|
|
/**
|
|
* Invalidate cache for a pattern
|
|
*/
|
|
export async function invalidateCache(pattern) {
|
|
const cache = await getCacheClient();
|
|
if (!cache) {
|
|
return 0;
|
|
}
|
|
return cache.invalidate(`db:query:${pattern}*`);
|
|
}
|
|
/**
|
|
* Invalidate cache for a specific query
|
|
*/
|
|
export async function invalidateQueryCache(sql, params) {
|
|
const cache = await getCacheClient();
|
|
if (!cache) {
|
|
return;
|
|
}
|
|
const cacheKey = `db:query:${sql}:${JSON.stringify(params || [])}`;
|
|
await cache.delete(cacheKey);
|
|
}
|
|
/**
|
|
* Cache decorator for database functions
|
|
* Note: This is a simplified implementation. In production, you'd need to
|
|
* extract SQL and params from the function or pass them as metadata.
|
|
*/
|
|
export function cached(fn) {
|
|
return (async (...args) => {
|
|
const result = await fn(...args);
|
|
return result;
|
|
});
|
|
}
|
|
//# sourceMappingURL=query-cache.js.map
|