Usage & Examples
Basic Initialization (Issue #4)
TaggedKeyv can be initialized with or without a Keyv instance. If no Keyv instance is provided, it defaults to an in-memory store.
import { TaggedKeyv } from 'tagged-keyv-wrapper';
import Keyv from '@keyvhq/core';
import KeyvRedis from '@keyvhq/redis'; // Import the Redis adapter
// Using a custom Keyv instance (e.g., Redis, Memcached)
const redisStore = new KeyvRedis('redis://user:pass@localhost:6379');
const redisKeyv = new Keyv({ store: redisStore });
const cacheWithRedis = new TaggedKeyv(redisKeyv);
// Using the default in-memory Keyv store
const inMemoryCache = new TaggedKeyv();
// Example usage
await inMemoryCache.set('greeting', 'Hello, World!');
const greeting = await inMemoryCache.get('greeting');
console.log(greeting); // Output: Hello, World!
User Session Management
Manage multiple sessions for a single user and invalidate them all at once upon logout or a security event.
// Create sessions with tags
await cache.set('session:user1:web', { userId: 1, device: 'web' }, {
ttl: 3600000, // 1 hour in milliseconds
tags: ['user:1', 'device:web', 'sessions']
});
await cache.set('session:user1:mobile', { userId: 1, device: 'mobile' }, {
ttl: 3600000, // 1 hour in milliseconds
tags: ['user:1', 'device:mobile', 'sessions']
});
// Invalidate all sessions for user 1
await cache.invalidateTag('user:1');
Product Catalog Caching
Cache product data and group it by categories, allowing for efficient invalidation when a category is updated.
// Add products with category tags
await cache.setMany([
['product:1', { name: 'Laptop', price: 999 }, ['electronics', 'computers']],
['product:2', { name: 'Phone', price: 699 }, ['electronics', 'mobile']],
['product:3', { name: 'Shirt', price: 29 }, ['clothing', 'apparel']]
]);
// Clear all clothing items from the cache
await cache.invalidateTag('clothing');
Listing All Tags (Issue #5)
Retrieve a list of all unique tags currently in use across the cache.
// Assuming some keys have been set with tags
await cache.set('item:1', 'data1', { tags: ['tagA', 'tagB'] });
await cache.set('item:2', 'data2', { tags: ['tagB', 'tagC'] });
const allActiveTags = await cache.getAllTags();
console.log(allActiveTags); // Output: ['tagA', 'tagB', 'tagC'] (order may vary)
Paginated Tag Retrieval (Issue #6)
Retrieve key-value pairs associated with a tag using page and limit for efficient pagination.
// Populate cache with many items for a tag
for (let i = 1; i <= 105; i++) {
await cache.set(`user:${i}`, { name: `User ${i}` }, { tags: ['users'] });
}
// Get the first page (default limit is 50)
const firstPageUsers = await cache.getByTag('users', { page: 1 });
console.log(`First page has ${firstPageUsers.length} users.`); // Output: First page has 50 users.
// Get the second page with a custom limit
const secondPageUsers = await cache.getByTag('users', { page: 2, limit: 25 });
console.log(`Second page has ${secondPageUsers.length} users.`); // Output: Second page has 25 users.
console.log(secondPageUsers[0]); // Output: ['user:26', { name: 'User 26' }]
// Get the last page (page 3 with limit 25, or page 3 with default limit 50)
const lastPageUsers = await cache.getByTag('users', { page: 3, limit: 50 });
console.log(`Last page has ${lastPageUsers.length} users.`); // Output: Last page has 5 users.
Tag Introspection and Debugging
Inspect tags for specific keys to enable debugging, conditional operations, and permission checking.
// Set up some data with various tags
await cache.set('user:123', { name: 'Alice', role: 'admin' }, {
tags: ['users', 'role:admin', 'status:active', 'permissions:full']
});
await cache.set('session:abc', { userId: 123, device: 'desktop' }, {
tags: ['sessions', 'device:desktop', 'type:web']
});
// Inspect tags for a specific key
const userTags = await cache.getTagsForKey('user:123');
console.log('User tags:', userTags);
// Output: ['users', 'role:admin', 'status:active', 'permissions:full']
// Conditional operations based on tag presence
if (userTags.includes('role:admin')) {
console.log('User has admin privileges');
// Perform admin-only operations
}
// Check session type for routing decisions
const sessionTags = await cache.getTagsForKey('session:abc');
const isWebSession = sessionTags.includes('type:web');
const isMobileSession = sessionTags.includes('type:mobile');
if (isWebSession) {
console.log('Serving web-optimized content');
} else if (isMobileSession) {
console.log('Serving mobile-optimized content');
}
// Debug cache state by examining all tags and their usage
const allTags = await cache.getAllTags();
console.log('All active tags:', allTags);
for (const tag of allTags) {
const entries = await cache.getByTag(tag, { limit: 1 });
console.log(`Tag "${tag}" has entries (showing first):`, entries[0]);
}
// Audit specific keys for compliance
const auditKeys = ['user:123', 'session:abc'];
for (const key of auditKeys) {
const tags = await cache.getTagsForKey(key);
console.log(`${key} has tags:`, tags);
// Check for required compliance tags
const hasRequiredTags = tags.includes('audited') && tags.includes('compliant');
if (!hasRequiredTags) {
console.warn(`${key} missing compliance tags`);
}
}