Adapters IORedis
@tsed/adapters-ioredis provides ioredis-backed adapter implementations for Ts.ED.
Installation
sh
npm install --save @tsed/adapters-ioredis @tsed/ioredis ioredissh
yarn add @tsed/adapters-ioredis @tsed/ioredis ioredissh
pnpm add @tsed/adapters-ioredis @tsed/ioredis ioredissh
bun add @tsed/adapters-ioredis @tsed/ioredis ioredisAdapter Options
Common options used with Adapters.invokeAdapter(...):
connectionName: Redis connection name (default:default)useHash: store payload using hash strategy (used for OIDC consumable models)keyPrefix: prefix applied to all keys generated by the adapter (entity keys, index keys, OIDC keys)
typescript
import {Adapter, Adapters, AdapterModel} from "@tsed/adapters";
import {Injectable} from "@tsed/di";
import {OIRedisAdapter} from "@tsed/adapters-ioredis";
import {Property} from "@tsed/schema";
class Client implements AdapterModel {
@Property()
_id: string;
@Property()
name: string;
@Property()
secret: string;
}
@Injectable()
export class ClientsRepository {
private store: Adapter<Client>;
constructor(private adapters: Adapters) {
this.store = this.adapters.invokeAdapter<Client>({
adapter: OIRedisAdapter,
collectionName: "client",
model: Client,
keyPrefix: "tests:e2e:run-42"
});
}
async createClient(input: Pick<Client, "name" | "secret">) {
return this.store.create(input);
}
async getClients() {
return this.store.findAll();
}
async getClientById(id: string) {
return this.store.findById(id);
}
async updateClient(id: string, patch: Partial<Client>) {
const current = await this.store.findById(id);
if (!current) {
return undefined;
}
return this.store.update(id, {...current, ...patch});
}
async deleteClient(id: string) {
return this.store.deleteById(id);
}
}IORedis Module Configuration
@tsed/adapters-ioredis uses connections provided by @tsed/ioredis.
Single Connection
typescript
import {Configuration} from "@tsed/di";
import "@tsed/ioredis";
@Configuration({
ioredis: [
{
name: "default",
host: "localhost",
port: 6379
// or url, password, tls, db...
}
]
})
export class Server {}Cluster
typescript
import {Configuration} from "@tsed/di";
import "@tsed/ioredis";
@Configuration({
ioredis: [
{
name: "default",
nodes: ["redis://localhost:7000", "redis://localhost:7001", "redis://localhost:7002"]
// optional cluster options:
// scaleReads: "all",
// redisOptions: {...}
}
]
})
export class Server {}Sentinel
typescript
import {Configuration} from "@tsed/di";
import "@tsed/ioredis";
@Configuration({
ioredis: [
{
name: "default",
sentinelName: "mymaster",
sentinels: [
{host: "127.0.0.1", port: 26379},
{host: "127.0.0.1", port: 26380}
]
// optional redis/sentinel options:
// password: "...",
// redisOptions: {...}
}
]
})
export class Server {}Typical Use Case
Used for Redis-backed adapter flows requiring ioredis integration and OIDC-compatible adapter behavior.
typescript
import {OIRedisAdapter, OIDCIORedisAdapter} from "@tsed/adapters-ioredis";Test Isolation
When tests run in parallel, prefer keyPrefix isolation:
typescript
import {randomUUID} from "node:crypto";
import {Adapters} from "@tsed/adapters";
import {OIRedisAdapter} from "@tsed/adapters-ioredis";
import {DITest, inject} from "@tsed/di";
import {Property} from "@tsed/schema";
import {TestContainersRedis} from "@tsedio/testcontainers-redis";
import {beforeAll, beforeEach, afterAll, afterEach, describe, expect, it} from "vitest";
class AuthorizationCode {
@Property()
_id: string;
@Property()
uid: string;
}
describe("OIDC adapter isolation", () => {
let keyPrefix: string;
beforeAll(() => TestContainersRedis.startContainer());
beforeEach(() => {
keyPrefix = `test:${randomUUID()}`;
return DITest.create({
ioredis: [
{
name: "default",
...TestContainersRedis.getRedisOptions()
}
]
});
});
afterEach(() => DITest.reset());
afterAll(() => TestContainersRedis.stopContainer());
it("isolates data per test", async () => {
const adapter = inject(Adapters).invokeAdapter<AuthorizationCode>({
adapter: OIRedisAdapter,
collectionName: "AuthorizationCode",
model: AuthorizationCode,
keyPrefix
});
await adapter.create({uid: "u1"});
const items = await adapter.findAll();
const keys = await (adapter as any).db.keys(adapter.prefix("AuthorizationCode:*"));
expect(items.length).toBe(1);
expect(keys.length).toBe(1);
expect(keys[0]).toContain(adapter.prefix("AuthorizationCode:"));
});
});