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

Utilizing TypeScript's conditional return type with an object as a parameter, and incorporating default values

Is it possible to create a function where the return type is determined by a string, with some additional complexities involved? I'm looking to achieve the following: The parameter is contained within an object The parameter is optional The object it ...

Implementing a GIF loader in your webpack configuration for a Typescript/React/Next.js application

Upon inserting a .gif file in my Typescript React app, an error message has surfaced. ./src/gif/moving.gif 1:6 Module parse failed: Unexpected token (1:6) You may need an appropriate loader to handle this file type, currently no loaders are configured to p ...

Is it possible to selectively export certain interfaces within a .d.ts file?

// configuration.d.ts export interface Configuration { MENU_STRUCTURE: Node[]; } interface Node { name: string; } Looking at the snippet above, I am aiming to only export Configuration. However, I noticed that I can also import Node from an ext ...

How can I seamlessly combine CoffeeScript and TypeScript files within a single Node.js project?

When working on a server-side node project utilizing the standard package.json structure, what is the best way to incorporate both Coffeescript and Typescript files? It's crucial that we maintain the availability of npm install, npm test, and npm sta ...

Tips for accessing the 'index' variable in *ngFor directive and making modifications (restriction on deleting only one item at a time from a list)

Here is the code snippet I'm working with: HTML: <ion-item-sliding *ngFor="let object of objectList; let idx = index"> <ion-item> <ion-input type="text" text-left [(ngModel)]="objectList[idx].name" placeholder="Nam ...

Transform a 3D text rotation JavaScript file into an Angular component tailored TypeScript file

I have a javascript file that rotates text in 3D format, and I need help converting it into an Angular component specific TypeScript file. You can find the codepen for the original JavaScript code here. Below are my Angular files: index.html <!doctyp ...

Best practices for managing backend errors with Next.js 14

Currently, I am developing a project in Next.js 14 and I have set up my API requests using fetch within a handler.tsx file as shown below: async function getPositions() { const response = await fetch( process.env.BASE_API_URL + "/positions?enabl ...

Tips for setting a new key and value for an existing object in TypeScript

As I transition from JavaScript to TypeScript, I am currently working on creating a Discord bot using TypeScript to familiarize myself with the environment. However, I encountered an error when attempting to add new keys to an object that was previously cr ...

Using TypeScript to Verify the Existence of Words in a String

Is there a way in typescript to find specific words within a given string? For example: If we have a list: ['Mr', 'Mrs', 'FM.', 'Sir'] and a string named 'Sir FM. Sam Manekshaw'. The words 'Sir' ...

Enhancing Angular input validators with updates

Working on a project with Angular 6, I have set up an input field using mat-input from the Angular Material framework and assigned it an id for FormGroup validation. However, when I initialize my TypeScript class and update the input value, the validator d ...

The Angular-slickgrid is encountering an issue where it is unable to access the property "hostView" as it

Hey there developers, I've been experimenting with the angular slickgrid library and attempting to incorporate the rowDetailView feature it offers. The issue I'm facing is that while I can expand the view by clicking on it, I'm unable to c ...

Substitute the specific class title with the present class

Here is a sample class (supposed to be immutable): class A { normalMethod1(): A{ const instance = this.staticMethod1(); return instance; } static staticMethod1: A(){ return new this(); } } The code above works fine, but how can I re ...

tips for utilizing a variable for inferring an object in typescript

In my current code, I have the following working implementation: type ParamType = { a: string, b: string } | { c: string } if ('a' in params) { doSomethingA(params) } else { doSomethingC(params) } The functions doSomethingA and doSomething ...

Creating JPEG images with specified dimensions. How can you add W x H sizing to an image?

I have been searching for a Deno/TypeScript code snippet that can create basic images with dimensions embedded on them. I have provided an example of the code below, which generates images in JPEG format, base64, and dataURL. The code works by adding RGB ...

Enhancing DOM Elements in a React Application Using TypeScript and Styled-Components with Click Event

I've been working on an app using React, Typescript, and styled components (still a beginner with typescript and styled components). I'm trying to create a simple click event that toggles between which of the two child components is visible insid ...

`What exactly do auth.guard.ts and the AuthenticationService do in Angular 8?`

import { Injectable } from '@angular/core'; import { AuthenticationService } from './_services'; import { Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; @Injectable({ providedIn: & ...

Extending parent context in dependencies through OOP/Typescript as an alternative to using "extends"

Introducing a custom class called EventBus has been a game-changer for me. This class allows for easy attachment of on/off/once methods to any class that extends it, enabling the creation of an array of events that can be listened to. Currently, I find my ...

Exploring Ngu-Carousel in Angular 7: Importing JSON data for a dynamic display

After attempting to import data from JSON and display it using ngu-carousel, I encountered an error. The error shows "length of undefined" Subsequently, when I try to click on the previous/next button, another error appears. This error states "innerHTML ...

Errors encountered when using TypeScript with destructured variables and props not being recognized

I have a function that returns data. The object is structured with properties such as headerMenu, page, content, and footer. These properties are defined in DataProps interface. When I try to destructure the data object using the line: const { headerMenu, ...

Tips for troubleshooting a React Native project built with Expo and utilizing TypeScript

I started a new Expo project with TypeScript integration. After launching the app using expo start, I noticed that the Chrome debugger only displays .js files at http://localhost:19001/debugger-ui/: https://i.stack.imgur.com/cmyy9.png How can I make sur ...