Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/backtest-kit/backtest-kit-minio-s3-docker/llms.txt

Use this file to discover all available pages before exploring further.

BaseMap is a di-factory class that provides a namespaced, optionally TTL-bound key/value store backed by Redis. It is used directly by the three connection services — LogConnectionService, NotificationConnectionService, and StorageConnectionService — which extend it to add the time-ordered register / listNewest index on top of the base key/value primitives. Unlike BaseStorage (which targets durable, persistent S3 objects), BaseMap targets Redis and is optimised for fast writes, expiry-based cleanup, and cursor-based iteration over a namespaced keyspace.

Constructor

constructor(
  readonly connectionKey: string,
  readonly ttlExpireSeconds: number = DEFAULT_TTL_EXPIRE_SECONDS
)
connectionKey is the namespace for all Redis keys managed by this instance. Every key written by BaseMap is stored in Redis as ${connectionKey}:${key} — the colon separator is added by the internal _getItemKey helper. Choose a unique connectionKey per logical store (e.g. "log-items-connection") to prevent key collisions between different services sharing the same Redis database. ttlExpireSeconds defaults to DEFAULT_TTL_EXPIRE_SECONDS = 5 * 60 (300 seconds / 5 minutes). Pass -1 to disable expiry entirely, which is what all three connection services do — their time-ordered index entries are permanent until explicitly cleared.

TTL behaviour

const DEFAULT_TTL_EXPIRE_SECONDS = 5 * 60;
When ttlExpireSeconds is any positive integer, set() calls redis.expire(itemKey, ttlExpireSeconds) immediately after the redis.set(...) call, so each key automatically expires that many seconds after its last write. If the same key is written again before expiry, the TTL is reset.
All three connection services (LogConnectionService, NotificationConnectionService, StorageConnectionService) construct their BaseMap with ttlExpireSeconds = -1. This makes their index entries permanent — they survive Redis restarts (if persistence is configured) and are never evicted by TTL. The -1 sentinel skips the redis.expire call entirely.

_getItemKey()

_getItemKey(key: string): string {
  return `${this.connectionKey}:${key}`;
}
This helper is called internally by every method to translate a logical key into the namespaced Redis key. It is exposed as a non-private property (prefixed _ by convention) so that subclasses and tests can inspect or override key construction without duplicating the prefix logic.

Methods

set(key, value)
Promise<void>
Writes value to Redis under the namespaced key. If ttlExpireSeconds !== -1, a TTL is applied immediately after the write. Throws if key is an empty string.
async set(key: string, value: unknown): Promise<void>
get(key)
Promise<unknown | null>
Retrieves the value stored at the namespaced key. Returns null if key is null or if the key does not exist in Redis (ioredis returns null for missing keys).
async get(key: string | null): Promise<unknown | null>
delete(key)
Promise<void>
Removes the namespaced key from Redis using DEL. No-ops if key is null.
async delete(key: string): Promise<void>
has(key)
Promise<boolean>
Checks whether the namespaced key exists using Redis EXISTS. Returns true only when EXISTS returns 1. Returns false for null keys.
async has(key: string): Promise<boolean>
clear()
Promise<void>
Deletes all keys matching ${connectionKey}:* using a SCAN loop. Iterates the keyspace in batches of ITERATOR_BATCH_SIZE = 100 and issues a DEL for each non-empty batch until the cursor returns to 0.
async clear(): Promise<void>
toArray()
Promise<[string, unknown][]>
Collects all key/value pairs matching ${connectionKey}:* into an in-memory array. Uses SCAN + MGET per batch to minimize round-trips. The connectionKey: prefix is stripped from returned keys so callers see logical keys only.
async toArray(): Promise<[string, unknown][]>
iterate()
AsyncIterableIterator<readonly [string, unknown]>
Async generator that yields [key, value] tuples via SCAN + MGET batches. The generator holds the SCAN cursor state across yields so it does not need to complete the full scan before returning the first result. Logical keys are returned with the connectionKey: prefix stripped.
async *iterate(): AsyncIterableIterator<readonly [string, unknown]>
keys()
AsyncIterableIterator<string>
Async generator that yields logical key strings (prefix stripped) via SCAN batches. Does not fetch values, making it cheaper than iterate() when only key enumeration is needed.
async *keys(): AsyncIterableIterator<string>
values()
AsyncIterableIterator<unknown>
Async generator that yields raw Redis string values via SCAN + MGET batches. Skips entries whose value is not a string (null values from MGET are filtered out).
async *values(): AsyncIterableIterator<unknown>
size()
Promise<number>
Counts all keys matching ${connectionKey}:* by exhausting a SCAN loop and summing the lengths of each batch. No values are fetched.
async size(): Promise<number>

ITERATOR_BATCH_SIZE

const ITERATOR_BATCH_SIZE = 100;
All SCAN-based methods (clear, toArray, iterate, keys, values, size) pass COUNT 100 to the Redis SCAN command. This is a hint to Redis about how many keys to return per cursor step — Redis may return fewer or slightly more. A batch size of 100 balances the number of round-trips against the size of each response; increase it if you observe slow iteration over very large keyspaces and your Redis instance has headroom.
clear() uses SCAN to find matching keys before deleting them. On a Redis instance with a very large keyspace (millions of keys across many namespaces), SCAN can be slow because it must iterate the entire keyspace to find matches. In production, prefer scoped delete() calls on individual keys where possible rather than relying on clear() to clean up large namespaces.

Build docs developers (and LLMs) love