mirror of
				https://github.com/ClusterCockpit/cc-backend
				synced 2025-10-30 23:45:06 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			73 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			73 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| import { filter, map, merge, pipe, share, tap } from 'wonka';
 | |
| 
 | |
| /*
 | |
|  * Alternative to the default cacheExchange from urql (A GraphQL client).
 | |
|  * Mutations do not invalidate cached results, so in that regard, this
 | |
|  * implementation is inferior to the default one. Most people should probably
 | |
|  * use the standard cacheExchange and @urql/exchange-request-policy. This cache
 | |
|  * also ignores the 'network-and-cache' request policy.
 | |
|  *
 | |
|  * Options:
 | |
|  *    ttl: How long queries are allowed to be cached (in milliseconds)
 | |
|  *    maxSize: Max number of results cached. The oldest queries are removed first.
 | |
|  */
 | |
| export const expiringCacheExchange = ({ ttl, maxSize }) => ({ forward }) => {
 | |
|     const cache = new Map();
 | |
|     const isCached = (operation) => {
 | |
|         if (operation.kind !== 'query' || operation.context.requestPolicy === 'network-only')
 | |
|             return false;
 | |
| 
 | |
|         if (!cache.has(operation.key))
 | |
|             return false;
 | |
| 
 | |
|         let cacheEntry = cache.get(operation.key);
 | |
|         return Date.now() < cacheEntry.expiresAt;
 | |
|     };
 | |
| 
 | |
|     return operations => {
 | |
|         let shared = share(operations);
 | |
|         return merge([
 | |
|             pipe(
 | |
|                 shared,
 | |
|                 filter(operation => isCached(operation)),
 | |
|                 map(operation => cache.get(operation.key).response)
 | |
|             ),
 | |
|             pipe(
 | |
|                 shared,
 | |
|                 filter(operation => !isCached(operation)),
 | |
|                 forward,
 | |
|                 tap(response => {
 | |
|                     if (!response.operation || response.operation.kind !== 'query')
 | |
|                         return;
 | |
| 
 | |
|                     if (!response.data)
 | |
|                         return;
 | |
| 
 | |
|                     let now = Date.now();
 | |
|                     for (let cacheEntry of cache.values()) {
 | |
|                         if (cacheEntry.expiresAt < now) {
 | |
|                             cache.delete(cacheEntry.response.operation.key);
 | |
|                         }
 | |
|                     }
 | |
| 
 | |
|                     if (cache.size > maxSize) {
 | |
|                         let n = cache.size - maxSize + 1;
 | |
|                         for (let key of cache.keys()) {
 | |
|                             if (n-- == 0)
 | |
|                                 break;
 | |
| 
 | |
|                             cache.delete(key);
 | |
|                         }
 | |
|                     }
 | |
| 
 | |
|                     cache.set(response.operation.key, {
 | |
|                         expiresAt: now + ttl,
 | |
|                         response: response
 | |
|                     });
 | |
|                 })
 | |
|             )
 | |
|         ]);
 | |
|     };
 | |
| };
 | |
| 
 |