Redis-OM manager adapter for @storehouse/core. Provides seamless integration with Redis using the Redis-OM object mapping library.
npm install @storehouse/core redis redis-om @storehouse/redis-om
Create Redis-OM schemas to define your data structures:
schemas/movie.ts
import { Schema } from 'redis-om'
export const movieSchema = new Schema('movies', {
title: { type: 'string' },
director: { type: 'string' },
year: { type: 'number' },
rating: { type: 'number' },
genres: { type: 'string[]' }
})
index.ts
import { Storehouse } from '@storehouse/core';
import { RedisOMManager } from '@storehouse/redis-om';
import { movieSchema } from './schemas/movie';
// Register the manager
Storehouse.add({
redis: {
type: RedisOMManager,
config: {
// Redis client connection options
options: {
socket: {
host: 'localhost',
port: 6379
}
},
// Register your schemas
models: [movieSchema]
}
}
});
import { Storehouse } from '@storehouse/core';
import { RedisOMManager } from '@storehouse/redis-om';
import { Repository } from 'redis-om';
import { RedisClientType } from 'redis';
// Get the manager
const manager = Storehouse.getManager<RedisOMManager>('redis');
if (manager) {
// Connect to Redis
await manager.connect();
// Create search indexes (required for Repository#search)
await manager.createIndexes();
// Get a repository
const moviesRepo = manager.getModel('movies');
if (moviesRepo) {
// Create a new movie
const movie = await moviesRepo.save({
title: 'Inception',
director: 'Christopher Nolan',
year: 2010,
rating: 8.8,
genres: ['Sci-Fi', 'Thriller']
});
console.log('Created movie:', movie);
// Search for movies
const sciFiMovies = await moviesRepo
.search()
.where('genres').contains('Sci-Fi')
.return.all();
console.log('Sci-Fi movies:', sciFiMovies.length);
// Get total count
const count = await moviesRepo.search().return.count();
console.log('Total movies:', count);
}
}
The package provides helper functions that throw errors instead of returning undefined, making your code cleaner and safer.
getManager()Retrieves a RedisOMManager instance from the registry.
import { Storehouse } from '@storehouse/core';
import { getManager } from '@storehouse/redis-om';
const manager = getManager(Storehouse, 'redis');
await manager.connect();
Throws:
ManagerNotFoundError - If the manager doesn't existInvalidManagerConfigError - If the manager is not a RedisOMManager instancegetConnection()Retrieves the underlying Redis client connection.
import { Storehouse } from '@storehouse/core';
import { getConnection } from '@storehouse/redis-om';
const client = getConnection(Storehouse, 'redis');
// Use Redis client directly
await client.set('key', 'value');
const value = await client.get('key');
Throws:
ManagerNotFoundError - If the manager doesn't existgetModel()Retrieves a Redis-OM Repository by name.
import { Storehouse } from '@storehouse/core';
import { getModel } from '@storehouse/redis-om';
// Get model from default manager
const movies = getModel(Storehouse, 'movies');
// Get model from specific manager
const users = getModel(Storehouse, 'redis', 'users');
// Use the repository
await movies.createIndex();
const count = await movies.search().return.count();
Throws:
ModelNotFoundError - If the model doesn't existconnect(): Promise<this>Establishes connection to Redis.
await manager.connect();
close(): Promise<string>Closes the Redis connection gracefully using QUIT command.
await manager.close();
getConnection(): RedisClientTypeReturns the underlying Redis client instance.
const client = manager.getConnection();
await client.ping();
getModel<T>(name: string): Repository<T & Entity> | undefinedRetrieves a registered repository by schema name.
const moviesRepo = manager.getModel('movies');
createIndexes(): Promise<void>Creates search indexes for all registered repositories. Required for using Repository#search().
Requires: RediSearch and RedisJSON modules installed on Redis.
await manager.createIndexes();
dropIndexes(): Promise<void>Removes all existing indexes. Useful when schemas change.
Requires: RediSearch and RedisJSON modules installed on Redis.
await manager.dropIndexes();
await manager.createIndexes(); // Recreate with updated schemas
isConnected(): Promise<boolean>Checks if the connection is currently active.
const connected = await manager.isConnected();
if (connected) {
console.log('Redis is connected');
}
healthCheck(): Promise<RedisOMHealthCheckResult>Performs a comprehensive health check including ping test and latency measurement.
const health = await manager.healthCheck();
if (health.healthy) {
console.log(`✓ Redis is healthy`);
console.log(` Latency: ${health.details.latency}`);
console.log(` Models: ${health.details.models?.join(', ')}`);
console.log(` Ping: ${health.details.pingResponse}`);
} else {
console.error(`✗ Redis is unhealthy: ${health.message}`);
}
The health check returns a detailed result object with the following structure:
healthy: boolean - Overall health statusmessage: string - Descriptive message about the health statustimestamp: number - Timestamp when the health check was performedlatency?: number - Response time in millisecondsdetails: object - Detailed connection information
name: string - Manager nameisOpen: boolean - Connection open statusisReady: boolean - Connection ready statuspingResponse?: string | Buffer - Redis PING responsemodels?: string[] - Registered model nameslatency?: string - Response time in mserror?: string - Error details (if unhealthy)You can register multiple Redis connections:
Storehouse.add({
cache: {
type: RedisOMManager,
config: {
options: { url: 'redis://localhost:6379' },
models: [sessionSchema]
}
},
queue: {
type: RedisOMManager,
config: {
options: { url: 'redis://localhost:6380' },
models: [jobSchema]
}
}
});
// Access specific managers
const cacheManager = getManager(Storehouse, 'cache');
const queueManager = getManager(Storehouse, 'queue');
Set the manager type to simplify configuration and use string identifiers instead of class references:
import { Storehouse } from '@storehouse/core';
import { RedisOMManager } from '@storehouse/redis-om';
// Set default manager type
Storehouse.setManagerType(RedisOMManager);
// Now you can use type string instead of class
Storehouse.add({
redis: {
type: '@storehouse/redis-om',
config: {
options: { url: 'redis://localhost:6379' },
models: [movieSchema]
}
}
});
Access the Redis client directly for advanced operations beyond what Redis-OM provides:
const client = getConnection(Storehouse, 'redis');
// Use Redis commands directly
await client.hSet('user:1000', {
name: 'John',
email: 'john@example.com'
});
const user = await client.hGetAll('user:1000');
The manager automatically logs connection lifecycle events. These are logged using the @novice1/logger package and can be enabled with Debug mode:
import { Debug } from '@novice1/logger';
Debug.enable('@storehouse/redis-om*');
Events logged:
error - Connection errorsconnect - Connection initiatedready - Connection establishedend - Connection closedreconnecting - Reconnection attemptThe package is written in TypeScript and provides full type definitions for type-safe operations:
import { RedisClientType } from 'redis';
import { Repository } from 'redis-om';
import { RedisOMManager, RedisOMHealthCheckResult } from '@storehouse/redis-om';
// Typed manager
const manager = getManager<RedisOMManager>(Storehouse, 'redis');
// Typed connection
const client: RedisClientType = getConnection(Storehouse, 'redis');
// Typed model
const movies = getModel<{
title: string;
director: string;
year: number;
rating: number;
genres: string[]
}>(Storehouse, 'movies');
All helper functions throw specific errors for better error handling:
ManagerNotFoundError - When a manager is not found in the registryModelNotFoundError - When a model is not foundInvalidManagerConfigError - When a manager is not of the expected typeimport {
getManager,
getModel,
getConnection
} from '@storehouse/redis-om';
import {
ManagerNotFoundError,
ModelNotFoundError,
InvalidManagerConfigError
} from '@storehouse/core';
try {
const manager = getManager(Storehouse, 'nonexistent');
} catch (error) {
if (error instanceof ManagerNotFoundError) {
console.error('Manager not found:', error.message);
} else if (error instanceof InvalidManagerConfigError) {
console.error('Invalid manager type:', error.message);
}
}
try {
const model = getModel(Storehouse, 'nonexistent');
} catch (error) {
if (error instanceof ModelNotFoundError) {
console.error('Model not found:', error.message);
}
}
createIndexes() after connecting to enable search functionalityclose() when shutting down your applicationdropIndexes() then createIndexes() when updating schemasMIT