Cache usage
The eridu-tech/cache component provides a way for storing key-value pairs with expiration independent of data storage
Initial configuration
To begin using the Cache class, you'll need to create and configure an instance:
import { TimeSpan } from "eridu-tech/time-span";
import { MemoryCacheAdapter } from "eridu-tech/cache/memory-cache-adapter";
import { Cache } from "eridu-tech/cache";
const cache = new Cache({
// You can provide default TTL value
// If you set it to null it means keys will be stored forever.
defaultTtl: TimeSpan.fromSeconds(2),
// You can choose the adapter to use
adapter: new MemoryCacheAdapter(),
});
Here is a complete list of settings for the Cache class.
Cache basics
Adding keys
You can add a key with a optional TTL to overide the default:
await cache.add("a", "value", TimeSpan.fromSeconds(1));
The method returns true if the key does not exists.
Retrieving keys
You can retrieve the key:
await cache.get("a");
Checking key existence
You can check if the key exists:
await cache.exists("a");
You can check if the key is missing:
await cache.missing("a");
Updating keys
You can update a key and true will be returned if the key exists and was updated:
await cache.update("a", 2);
You can increment the a key and true will be returned if the key exists and was updated. If the key is not a number an error will be thrown:
await cache.increment("a", 2);
You can decrement the a key and true will be returned if the key exists and was updated. If the key is not a number an error will be thrown,:
await cache.decrement("a", 1);
You can perform an upsert that replaces the ttl when updated. True will be returned if the key was updated otherwise false is returned:
await cache.put("a", 2);
await cache.put("a", 4, TimeSpan.fromSeconds(3));
Removing keys
You can remove a key and true will be returned if the key was found and removed:
await cache.remove("a");
You can remove multiple keys and true will be returned if one of the keys exists and where removed:
await cache.removeMany(["a", "b"]);
You can clear all the keys of the given namespace:
await cache.clear();
Patterns
Compile time type safety
You can enforce compile time type safety by setting the cache value type:
import { MemoryCacheAdapter } from "eridu-tech/cache/memory-cache-adapter";
import { Cache } from "eridu-tech/cache";
type IUser = {
name: string;
email: string;
age: number;
};
const cache = new Cache<IUser>({
adapter: new MemoryCacheAdapter(),
});
// A typescript error will occur because the type is not matching.
await cache.add("a", "asd");
If you have multiple types you can use algeberical enums:
import { MemoryCacheAdapter } from "eridu-tech/cache/memory-cache-adapter";
import { Cache } from "eridu-tech/cache";
type IUser = {
type: "USER";
name: string;
email: string;
age: number;
};
type IProduct = {
type: "PRODUCT";
name: string;
price: number;
};
type CacheValue = IUser | IProduct;
const cache = new Cache<CacheValue>({
adapter: new MemoryCacheAdapter(),
});
const cacheValue = await cache.get("user1");
// You need to check the type is "USER" inorder to access IUser fields.
if (cacheValue.type === "USER") {
console.log(cacheValue.name, cacheValue.age);
}
// You need to check the type is "PRODUCT" inorder to access IProduct fields.
if (cacheValue.type === "PRODUCT") {
console.log(cacheValue.name, cacheValue.price);
}
Alternatively you can use different Cache classes with different namespaces:
import { MemoryCacheAdapter } from "eridu-tech/cache/memory-cache-adapter";
import { Cache } from "eridu-tech/cache";
const cacheAdapter = new MemoryCacheAdapter();
type IUser = {
name: string;
email: string;
age: number;
};
const userCache = new Cache<IUser>({
adapter: cacheAdapter,
});
type IProduct = {
name: string;
price: number;
};
const productCache = new Cache<IProduct>({
adapter: cacheAdapter,
});
Additional methods
You can retrieve the key and if it does not exist an error will be thrown:
await cache.getOrFail("ab");
You can retrieve the key and if it does not exist you can return a default value:
await cache.getOr("ab", 1);
You can retrieve the key and if it does not exist you can insert a default value that will aslo be returned:
await cache.getOrAdd("ab", 1);
You can retrieve the key and afterwards remove it:
await cache.getAndRemove("ab");
You can add key and if it does exist an error will be thrown:
await cache.addOrFail("ab", 1);
You can update the key and if it does not exist an error will be thrown:
await cache.updateOrFail("ab", 1);
You can increment the key and if it does not exist an error will be thrown:
await cache.incrementOrFail("ab", 1);
You can decrement the key and if it does not exist an error will be thrown:
await cache.decrementOrFail("ab", 1);
You can remove the key and if it does not exist an error will be thrown:
await cache.removeOrFail("ab");
Separating cache reading from manipulation
The library includes 2 additional contracts:
-
IReadableCache- Allows only for reading cache. -
ICache- Allows for both reading and manipulating the cache.
This separation makes it easy to visually distinguish the two contracts, making it immediately obvious that they serve different purposes.
import type { ICache, IReadableCache } from "eridu-tech/cache/contracts";
import { Cache } from "eridu-tech/cache";
import { MemoryCacheAdapter } from "eridu-tech/cache/memory-cache-adapter";
async function readingFunc(cache: IReadableCache): Promise<void> {
// You cannot access write methods like put, add and update
// You will get typescript error if you try
console.log("reading only:", await cache.get("a"));
}
async function manipulatingFunc(cache: ICache): Promise<void> {
// You will get typescript error if you try
await cache.add("a", 1);
console.log("writing and reading:", await cache.get("a"));
}
const cache = new Cache({
adapter: new MemoryCacheAdapter(),
});
await manipulatingFunc(cache);
await readingFunc(cache);
Further information
For further information refer to eridu-tech/cache API docs.