Skip to main content

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(),
});
info

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.