Creating a personalized Cache Module in Nest JS involves implementing a custom caching mechanism tailored to

I need help with implementing a custom CacheModule in NestJS. The guide only shows how to connect the cache directly to the main module of the AppModule application. What is the correct way to define and implement a custom cache module?

My attempt at creating a custom cache module has not been successful. When I try to add it as a dependency to the test module, the tests do not run because they cannot access the custom cache module.

This is my custom.cache.module.ts file:

@Module({})
export class CustomCacheModule {
  static forRoot(): DynamicModule {
    return {
      imports: [CacheModule.register({ isGlobal: true })],
      module: CustomCacheModule,
      providers: [
        { useClass: CacheService, provide: CACHE_SERVICE },
        { useClass: CalculatorService, provide: CALCULATOR_SERVICE },
        {
          useClass: ExpressionCounterService,
          provide: EXPRESSION_COUNTER_SERVICE,
        },
        {
          useClass: RegExCreatorService,
          provide: REGEXP_CREATOR_SERVICE_INTERFACE,
        },
      ],
      exports: [CustomCacheModule],
    };
  }
}

The import statement in my AppModule requires me to call the forRoot method, which I find inconvenient but necessary based on existing implementations.

Here is an excerpt from my app.module.ts file:

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
    }),
    CustomCacheModule.forRoot(),
    DBModule,
    HistoryModule,
    CalculatorModule,
  ],
})
export class AppModule {}

In an effort to follow best practices, I have included my spec file below. Despite setting up all dependencies, the code in the spec file does not work. Can you spot any errors or suggest improvements?

This is my calculator.controller.spec.ts file:

let calculatorController: CalculatorController;
let calculatorService: CalculatorService;

afterAll((done) => {
  mongoose.connection.close();
  done();
});

beforeEach(async () => {
  const moduleRef = await Test.createTestingModule({
    imports: [HistoryModule, CustomCacheModule],
    controllers: [CalculatorController],
    providers: [
      CalculatorService,
      {
        provide: CacheService,
        useValue: {
          checkInCache: jest.fn().mockReturnValue(Promise<null>),
          setToCache: jest.fn().mockReturnValue(Promise),
        },
      },
    ],
  })
    .useMocker(() => createMock())
    .compile();
  calculatorController =
    moduleRef.get<CalculatorController>(CalculatorController);
  calculatorService = moduleRef.get<CalculatorService>(CalculatorService);
  jest.clearAllMocks();
});

describe('Calculator Controller', () => {
  it('should be defined', () => {
    expect(calculatorController).toBeDefined();
  });
  it('should have all methods', () => {
    expect(calculatorController.getResult).toBeDefined();
    expect(calculatorController.getResult(calculatorStub().request)).toBe(
      typeof Promise,
    );
  });
});

Answer №1

Uncertain if this is what you desire.

I have developed a new Cache Module structured as follows:

./src/cache/cache.module.ts

import {  Module } from '@nestjs/common';
import { CacheModule as NestJsCacheModule } from '@nestjs/cache-manager'
import { ConfigModule } from '@nestjs/config';
import { redisStore } from 'cache-manager-redis-store';
import type { RedisClientOptions } from 'redis';

import config from '../common/configs/config';
import { ConfigService } from '@nestjs/config';
import {CacheManagerService} from './cache-manager.service';


@Module({
  imports: [
    ConfigModule.forFeature(config),
  
    NestJsCacheModule.registerAsync<Promise<RedisClientOptions>>({
      imports: [ConfigModule],
      isGlobal: true,
      useFactory: async (configService: ConfigService) => ({
        store: redisStore,
        url: configService.get('REDIS_URL'),
      }),
      inject: [ConfigService],
    }),

  ],
  providers: [CacheManagerService],
  exports: [CacheManagerService],
})
export class CacheModule {}

./src/cache/cache-manager.service

import { Inject, Injectable } from '@nestjs/common';
import { CACHE_MANAGER } from '@nestjs/cache-manager'
import { Cache } from 'cache-manager';

@Injectable()
export class CacheManagerService {
  constructor(@Inject(CACHE_MANAGER) private cacheManager: Cache) {}

  public async get(key: string): Promise<string> {
    return this.cacheManager.get(key);
  }

  /**
   * Sets a value in the cache.
   *
   * @param {string} key - The key under which to store the value.
   * @param {any} value - The value to store.
   * @param {number} [ttl] - The time-to-live in milliseconds for the cache entry. Optional.
   *
   * @returns {Promise<void>} A promise that resolves when the value has been set in the cache.
   */
  public async set(key: string, value: any, ttl?: number): Promise<void> {
    return this.cacheManager.set(key, value, ttl);
  }

  /**
   * Deletes a value from the cache.
   *
   * @param {string} key - The key under which the value is stored.
   *
   * @returns {Promise<void>} A promise that resolves when the value has been deleted from the cache.
   */
  public async del(key: string): Promise<void> {
    return this.cacheManager.del(key);
  }
}

Next, import the CacheModule into app.module.ts and utilize the cache-manager-service across the entire Application

import { CacheManagerService } from '../cache/cache-manager.service';

package.json

    "@nestjs/cache-manager": "^2.1.1",
    "@nestjs/common": "10.1.0",
    "@nestjs/config": "3.0.0",
    "@nestjs/core": "10.1.0",
    "cache-manager": "^5.3.2",
    "cache-manager-redis-store": "^3.0.1",

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Issues with Angular 2 loading properly on Internet Explorer 11

We are currently running an Asp.net MVC 5 web application integrated with Angular 2. The application functions smoothly on Chrome, Firefox, and Edge browsers, but encounters loading issues on IE 11, displaying the error illustrated in the image below: ht ...

Sending selected IDs from the JSON data

In my project, there is a JSON file named "workers" which contains information about all the workers. I have created a select component to display the names of the workers like this: https://i.sstatic.net/0Glyf.png Currently, I am selecting some workers ...

Can you explain the functionality of `property IN array` in the TypeORM query builder?

I'm looking to filter a list of entity ids using query builder in an efficient way. Here's the code snippet I have: await this._productRepo .createQueryBuilder('Product') .where('Product.id IN (:...ids)', { ids: [1, 2, 3, 4] ...

Switching the checkbox state by clicking a button in a React component

Is there a way to update checkbox values not just by clicking on the checkbox itself, but also when clicking on the entire button that contains both the input and span elements? const options = ["Option A", "Option B", "Option C"]; const [check ...

Fulfill the promise to retrieve the value contained within

Is there a way to use TypeScript to call the Wikipedia API for retrieving a random page title and save it in a variable for later use? I am struggling with resolving promises as I keep getting ZoneAwarePromise returned. I'm new to both promises and Ty ...

Why isn't the constraint satisfied by this recursive map type in Typescript?

type CustomRecursiveMap< X extends Record<string, unknown>, Y extends Record<string, unknown> > = { [M in keyof X]: M extends keyof Y ? X[M] extends Record<string, unknown> ? Y[M] extends Record<st ...

What is the most efficient approach to handle the next state after calling setState in react with immer?

Using Typescript, React, and Immer, I have set up a state management system to save profiles with multiple options. My goal is to ensure that the active profile has the correct option data before saving it. const { updateProfileList, getProfile } = useProf ...

Encountering syntax errors with CommonJS Rollup plugin when attempting to import third-party libraries, particularly those involving the 'process' module

I have been developing a personalized rollup configuration that involves React projects and inlines the JS and CSS in index.html. When attempting to import third-party React libraries (such as material-ui-color), I encountered an issue with CommonJS repo ...

Mastering TypeScript in Router Configuration

I am currently working with a standard router setup. type Routes = '/' | '/achievements' | ... ; This helps in identifying the routers present in the project. However, I am faced with a new challenge of creating an array that includes ...

Unable to associate a model with an additional attribute in objection because of a TypeScript issue

I'm attempting to establish a connection between two models while adding an additional property called "url": if (typeof session.id === "number") { const sessionUser = await Session.relatedQuery("users") .for(session.id) .relate({ id: ...

The Next.js template generated using "npx create-react-app ..." is unable to start on Netlify

My project consists solely of the "npx create-react-app ..." output. To recreate it, simply run "npx create-react-app [project name]" in your terminal, replacing [project name] with your desired project name. Attempting to deploy it on Netlify Sites like ...

Using Next.js and Tailwind CSS to apply a consistent pseudo-random color class both on the server and client side

I am faced with a challenge on my website where I need to implement different background colors for various components throughout the site. The website is generated statically using Next.js and styled using Tailwind. Simply selecting a color using Math.ra ...

The Radio Button's value appears in a distinct way on Ionic Angular

I am currently working with the Ionic framework and I am trying to display data values on radio buttons. However, I am facing difficulties in retrieving the correct value and setting it appropriately. index.html <td> <label>{{learn ...

The API endpoint code functions perfectly in Express, but encounters an error when integrated into Next.js

Express Code: app.get('/', async (req, res) => { const devices = await gsmarena.catalog.getBrand("apple-phones-48"); const name = devices.map((device) => device.name); res.json(name); }) Nextjs Code: import {gsmarena} ...

Using JSDoc with "T extending Component"

get_matching_components<T extends Component>(component_type_to_return: { new (doodad: Doodad): T }): T[] { return this.components.filter(component => component instanceof component_type_to_return) } In TypeScript, I created a method to retrie ...

Drizzle ORM retrieve unique string that is not a database column

I'm working with a SQL query that looks like this: SELECT * FROM ( SELECT 'car' AS type, model FROM car UNION SELECT 'truck' AS type, model FROM trucks ) vehicles; In Drizzle, I'm trying to replicate the 'car ...

Creating dynamic and engaging videos using Angular with the ability to make multiple requests

I am facing an issue while working with videos in Angular. I am fetching the video URLs from an API to embed them in my application using the sanitazer.bypassSecurityTrustResourceUrl function provided by Angular. The videos are being displayed correctly wi ...

Using TypeORM with a timestamp type column set to default null can lead to an endless loop of migrations being

In my NestJs project using TypeORM, I have the following column definition in an entity: @CreateDateColumn({ nullable: true, type: 'timestamp', default: () => 'NULL', }) public succeededAt?: Date; A migration is gene ...

The Express server automatically shuts down following the completion of 5 GET requests

The functionality of this code is as expected, however, after the fifth GET request, it successfully executes the backend operation (storing data in the database) but does not log anything on the server and there are no frontend changes (ReactJS). const ex ...

Compiling Vue with TypeScript: Troubleshooting common errors

Using Vue Components with Templates Multiple Times in TypeScript I am working on utilizing a component with a template multiple times within another component. The code is split between a .html file and a .ts file. The .html file structure is as follows: ...