@alwian/cache
TypeScript icon, indicating that this package has built-in type declarations

1.0.0 • Public • Published

Cache

Cache is a type safe way to store data with ttls. Event listneners are also available for different operations, see Events.

Contents

Getting Started

Installation

Run npm install @alwian/cache to install the latest version.

Basic Usage

import Cache from "@alwian/cache";

// Create a cache using the default config and no initial data, you must call .init() before you can use a cache.
const cache = new Cache().init();

// Create a cache with some custom config and initial data
const cacheWithConfig = new Cache().init({
  initialData: [{ key: "myKey", value: "myValue" }],
  defaultTtl: 10,
  ...
})

API


Types

Type Safety

This package has been built with type safety in mind. It allows you to define what keys are allowed to be stored in a cache, and what type of value each key corresponds too. For example -

type ItemMap = {
  key1: string;
  key2: number;
  key3: string;
};

// Create cache using predefined key value pairs in ItemMap
const cache = new Cache<ItemMap>().init();

// Won't compile as key4 is not a permitted key
cache.set({ key: "key4", value: "value4" });

// Won't compile as key1 should correspond to a string
cache.set({ key: "key1", value: 10 });

// Will compile as key2 is a valid key and the type of value is correct
cache.set({ key: "key2", value: 10 });

Each method available has been written to be type safe -

  • When you use a method which requires you to enter keys, it will restrict the available keys to those provided.
  • When you need to enter key/value pairs, it will ensure the type of value is correct based on the key provided.

To omit type safety and allow any keys/values, just create the cache without providing ItemMap.

CacheConfig

This type represents the config used by the cache.

Field Type Default Value Description
interval number 1 How frequently to check if items have expired (in seconds). Set to 0 to stop checking.
defaultTtl number 0 The default number a seconds before an item should expire once it is added to the cache, 0 mean don't expire.
removeOnExpire boolean true Whether expired items should be removed from the cache.
expireOnce boolean true Whether an expired item should only trigger a single expire event, even if it is not removed from the cache and is still expired the next time the cache checks for expired items.
capacity number Infinity The maximum number of items that can be in the cache.
errorOnFull boolean false Whether to throw an error when attemtpting to add items which would result in capacity being exceeded.
errorOnMiss boolean false Whether to throw and error when attempting to retrieve a non existent item.
errorOnDuplicate boolean false Whether to throw an error when adding an item with a key that is already in use.

CacheItem

This type represents an item to add to the cache.

Field Type Description
key string The key used to access the item.
value any The value of the item.
ttl? number How long before the item should expire after it is added to the cache (in seconds).

ItemStats

This type represents the stats that are stored about an item.

Field Type Description
accesses number How many times the item has been accessed.

Methods

set(...items: CacheItem[]): void

Use this to add items to the cache. If the key being used already exists, by default the existing item will be replaced.

const cache = new DataCache().init();

cache.set({ key: "key1", value: "key2" }, { key: "key2", value: "value2" });

Has the potential to throw an error if -

  • capacity is set, errorOnFull is true and the number of items being added would exceed capacity. In this case no items will be added before the error is thrown.
  • errorOnDuplicate is true and an item is being added with a key that already exists in the cache.

get(...keys: string[]): unknown | Record<string,unknown>

Use this to retrieve items from the cache.

There are 3 potential ways this method can return -

  • If no keys are provided then all items will be returned in an object containing each key/value pair.
  • If a single key is provided then the corresponding value will be returned on it's own.
  • If multiple keys are provided an object containing each key/value pair will be returned.
const cache = new DataCache().init({
  initialData: [
    { key: "key1", value: "key2" },
    { key: "key2", value: "value2" },
    { key: "key3", value: "value3" }
  ]
});

cache.get("key1"); // "key2"
cache.get("key1", "key2"); // { key1: "value1", key2: "value2" }
cache.get(); // { key1: "value1", key2: "value2", key3: "value3" }
cache.get("key4"); // undefined

Has the potential to throw an error if -

  • errorOnMiss is true and a key is requested that doesn't exist.

pop(...keys: string[]): unknown | Record<string, unknown>

Use this to retrieve items whilst simultaneousely removing them from the cache.

There are 3 potential ways this method can return -

  • If no keys are provided then all items will be returned in an object containing each key/value pair.
  • If a single key is provided then the corresponding value will be returned on it's own.
  • If multiple keys are provided an object containing each key/value pair will be returned.
const cache = new DataCache({
  initialData: [
    { key: "key1", value: "key2" },
    { key: "key2", value: "value2" },
    { key: "key3", value: "value3" }
  ]
});

cache.pop("key1"); // "key2"
cache.pop("key1", "key2"); // { key1: "value1", key2: "value2" }
cache.pop(); // { key1: "value1", key2: "value2", key3: "value3" }

cache.get("key1"); // undefined (key was removed with the initial pop call)

Has the potential to throw an error if -

  • errorOnMiss is true and a key is requested that doesn't exist. In this case no items will have been removed.

remove(...keys: string[]): void

Remove items from the cache.

There are 2 possible uses for this method -

  • Passing 1 or more keys will remove those items from the cache.
  • When no keys are specified then all items are removed. This gives the same affect as calling clear().
const cache = new DataCache().init({
  initialData: [
    { key: "key1", value: "key2" },
    { key: "key2", value: "value2" },
    { key: "key3", value: "value3" }
  ]
});

cache.remove("key1", "key2");
cache.get("key1", "key2"); // { key1: undefined, key2: undefined }

cache.remove();
cache.get(); // { key1: undefined, key2: undefined, key3: undefined }

Has the potential to throw an error if -

  • errorOnMiss is true and a key is passed that doesn't exist. In this case no items will have been removed.

clear(): void

Remove all items from the cache.

const cache = new DataCache().init({
  initialData: [
    { key: "key1", value: "value1" },
    { key: "key2", value: "value2" },
    { key: "key3", value: "value3" }
  ]
});

cache.clear();

cache.get(); // {}

has(key: string): boolean

Check whether a key exists in the cache.

const cache = new DataCache().init({
  initialData: [{ key: "key1", value: "value1" }]
});

cache.has("key1"); // true
cache.has("key2"); // false

keys(): string[]

Get each key stored in the cache.

const cache = new DataCache().init({
  initialData: [
    { key: "key1", value: "value1" },
    { key: "key2", value: "value2" },
    { key: "key3", value: "value3" }
  ]
});

cache.keys(); // ["key1", "key2", "key3"]

stats(...keys: string[]): ItemStats | Record<string, ItemStats>

Get the stats of items in the cache.

There are 3 possible uses for this method -

  • Passing a single key will return an ItemStats object containing the stats for that key.
  • Passing multiple keys will return an object containing key/ItemStats pairs.
  • Passing in no keys will result in the stats for all items being returned in an object of containing key/ItemStats pairs.
const cache = new DataCache().init({
  initialData: [
    { key: "key1", value: "value1" },
    { key: "key2", value: "value2" },
    { key: "key3", value: "value3" }
  ]
});

cache.stats("key1"); // { accesses: 0 }
cache.stats("key1", "key2"); // { key1: { accesses: 0 }, keys2: { accesses: 0 }}
cache.stats(); // { key1: { accesses: 0 }, keys2: { accesses: 0 }, key3: { accesses: 0 }}

Has the potential to throw an error if -

  • errorOnMiss is true and a key is passed that doesn't exist.

clearStats(...keys: string[]): void

Reset the stats of items in the cache.

There are 2 possible uses for this method -

  • Passing 1 or more keys will reset the stats for the specified keys.
  • If no keys are passed then the stats for all items will be reset.
const cache = new DataCache().init({
  initialData: [
    { key: "key1", value: "value1" },
    { key: "key2", value: "value2" }
  ]
});

cache.get("key1");
cache.stats("key1"); // { accesses: 1 }

cache.clearStats("key1");
cache.stats("key1"); // { accesses: 0 }

cache.get("key1", "key2");
cache.stats(); // { key1: { accesses: 1 }, key2: { accesses: 1 } }

cache.clearStats();
cache.stats(); // { key1: { accesses: 0 }, key2: { accesses: 0 } }

Has the potential to throw an error if -

  • errorOnMiss is true and a key is passed that doesn't exist. In this case no items will have been modified.

config(config: Partial<Omit<CacheConfig, "initialData">>): void

Update the config being used by the cache.

const cache = new DataCache().init();

cache.config({
  errorOnMiss: true,
  errorOnDuplicate: true
});

ttl(ttl: number, ...keys: string[]): void

Update the ttl of items in the cache.

There are 2 ways to use this method -

  • Passing in 1 or more keys will update the ttl for the specified keys.
  • If no keys are specified then all items will have their ttl updated.
const cache = new DataCache().init({
  initialData: [
    { key: "key1", value: "value1" },
    { key: "key2", value: "value2" }
  ]
});

cache.ttl(10, "key1"); // key1 will now expire 10 seconds after it was added.
cache.ttl(15); // key1 and key2 will now expire 15 seconds after they were added.

Has the potential to throw an error if -

  • errorOnMiss is true and a key is passed that doesn't exist. In this case no items will have been modified.

purge(): void

Remove expired items from the cache.

const cache = new DataCache().init({
  config: {
    defaultTtl: 10, // Items expire after 10 seconds by default
    removeOnExpire: false
  },
  initialData: [
    { key: "key1", value: "value1" },
    { key: "key2", value: "value2" },
    { key: "key3", value: "value3", ttl: 15 } // Item will expire after 15 seconds
  ]
});

// 10 seconds later
cache.purge();
cache.get(); // "value3"

resetExpiry(...keys: string[]): void

Reset the expiry counter for items in the cache.

This method resets the time at which an item was added to the cache, restarting the countdown to it's expiry. If an item has already expired, it's will no longer be expired.

There are 2 ways to use this method -

  • Passing in 1 or more keys will reset the expiry for the specified keys.
  • If no keys are passed in then all items are reset.
const cache = new DataCache().init({
  config: {
    defaultTtl: 10, // Items expire after 10 seconds by default
    removeOnExpire: false
  },
  initialData: [
    { key: "key1", value: "value1" },
    { key: "key2", value: "value2" },
    { key: "key3", value: "value3", ttl: 15 } // Item will expire after 15 seconds
  ]
});

// 10 Seconds later key1 and key2 are expired

cache.resetExpiry("key1"); // key1 no longer expired and will expire in 10 seconds
cache.resetExpiry(); // All keys have been reset and will expire in the relevant number of seconds

Has the potential to throw an error if -

  • errorOnMiss is true and a key is passed that doesn't exist. In this case no items will have been modified.

values(): unknown[]

Get each value stored in the cache.

const cache = new DataCache().init({
  initialData: [
    { key: "key1", value: "value1" },
    { key: "key2", value: "value2" },
    { key: "key3", value: "value3" }
  ]
});

cache.values(); // ["value1", "value2", "value3"]

entries(): [string, unknown][]

Get each key/value pair stored in the cache.

const cache = new DataCache().init({
  initialData: [
    { key: "key1", value: "value1" },
    { key: "key2", value: "value2" },
    { key: "key3", value: "value3" }
  ]
});

cache.entries(); // [["key1", "value1"], ["key2", "value2"], ["key3", "value3"]]

size(): number

Get the number of items stored in the cache.

const cache = new DataCache().init({
  initialData: [
    { key: "key1", value: "value1" },
    { key: "key2", value: "value2" },
    { key: "key3", value: "value3" }
  ]
});

cache.size(); // 3

Events

set

This event is triggered for each item that is added to the cache using set.

const cache = new DataCache().init();

cache.on("set", (key: string, value: unknown) => {
  console.log(`${key} + ${value as string}`);
});

cache.set({ key: "key1", value: "value1" }, { key: "key2", value: "value2" });

// console.log: key1 + value1
// console.log: key2 + value2

get

This is event is triggered for each item that is retrieved using get.

const cache = new DataCache().init({
  initialData: [
    { key: "key1", value: "value1" },
    { key: "key2", value: "value2" }
  ]
});

cache.on("get", (key: string, value: unknown) => {
  console.log(`${key} + ${value as string}`);
});

cache.get();

// console.log: key1 + value1
// console.log: key2 + value2

pop

This is event is triggered for each item that is retrieved using pop.

const cache = new DataCache().init({
  initialData: [
    { key: "key1", value: "value1" },
    { key: "key2", value: "value2" }
  ]
});

cache.on("pop", (key: string, value: unknown) => {
  console.log(`${key} + ${value as string}`);
});

cache.pop();

// console.log: key1 + value1
// console.log: key2 + value2

remove

This event is triggered for each item that is removed using remove.

const cache = new DataCache().init({
  initialData: [
    { key: "key1", value: "value1" },
    { key: "key2", value: "value2" }
  ]
});

cache.on("remove", (key: string, value: unknown) => {
  console.log(`${key} + ${value as string}`);
});

cache.remove();

// console.log: key1 + value1
// console.log: key2 + value2

clear

This is event is triggered when the cache is cleared using clear.

const cache = new DataCache().init({
  initialData: [
    { key: "key1", value: "value1" },
    { key: "key2", value: "value2" }
  ]
});

cache.on("pop", () => {
  console.log("Cache cleared");
});

cache.clear();

// console.log: Cache cleared

Release History

Version Date Description
1.0.0 31/05/2023 This release introduces type safety throughout Cache. Can be used to predefine keys that can be used and the type of value they correspond to, this also makes it possible to narrow down the return types of various methods.
0.0.2 28/05/2023 Initial release (I messed up 0.0.1 so had to skip). This release contains the initial version of Cache with all of the standard functionality I thought should be included.

Readme

Keywords

Package Sidebar

Install

npm i @alwian/cache

Weekly Downloads

2

Version

1.0.0

License

MIT

Unpacked Size

51.2 kB

Total Files

33

Last publish

Collaborators

  • alwian