States

You can use states to store user data

What are states?

States allow you to store user data (for example, a newly entered nickname in a scope). The states also store data about the current scopes (state.__currentScope). The data is stored locally until the project is reloaded, but you can also use your state getter to persist the data in your database

Using states

To use state in the controller/scope, use @GetState property decorator. The state type is your own object, so you can use interfaces to describe the state type. Then you can use this.state expression in your handlers to get/set current user state

app.controller.ts
import { Controller, GetState, OnCommand } from 'nestgram';
import { AppService } from './app.service';

export interface IMyState {
  counter?: number;
}

@Controller()
export class AppController {
  @GetState() state: IMyState;
  constructor(private readonly appService?: AppService) {}

  @OnCommand('start')
  start(): string {
    this.state.counter = (this.state.counter || 0) + 1;
    return 'Hello!';
  }

  @OnCommand('stats')
  stats(): string {
    return `You entered /start ${this.state.counter || 0} times`;
  }
}

Default state value

You can set a default state value per user if it has no state. In the main.ts file, call the .setDefaultValue stateStore method

.setDefaultValue method takes argument: default value (object)

main.ts
import { NestGram, stateStore } from 'nestgram';
import { AppModule } from './app.module';
import * as config from 'config';

async function bootstrap(): Promise<void> {
  const bot: NestGram = new NestGram(config.get<string>('botToken'), AppModule);

  stateStore.setDefaultValue({
    count: 0,
  });

  await bot.start();
}

bootstrap();

Custom state getter

You can set your own state getter (e.g. with database work). In the main.ts file, call the .setCustomGetter stateStore method and pass your custom method as argument. It's a function (it can be async) that takes some arguments (below hint). This function is called when a handler is processing an update and state is required in its controller

.setCustomGetter method takes argument: your custom getter (method) you want to set. It takes these arguments. This function should return a state (object)

Your custom method can take arguments:

ArgumentDescription
1

User ID

2

Params from the handler

3

Default value

main.ts
import { NestGram, stateStore } from 'nestgram';
import { AppModule } from './app.module';
import * as config from 'config';

async function bootstrap(): Promise<void> {
  const bot: NestGram = new NestGram(config.get<string>('botToken'), AppModule);

  stateStore.setCustomGetter(
    async <T = any>(userId: number, params?: any, defaultValue?: any): Promise<T> => {
      let state: T = {} as T;
      // ... (your code to get state)
      return state;
    }
  );

  await bot.start();
}

bootstrap();

Custom state setter

You can set your own state getter (e.g. to save the new state to the db). In the main.ts file, call the .setCustomSetter stateStore method and pass your custom method as argument. It's a function (it can be async) that takes some arguments (below hint). This function is called when the state changes

.setCustomSetter method takes argument: your custom setter (method) you want to set. It takes these arguments

Your custom method can take arguments:

ArgumentDescription
1

User ID

2

The name of the changed state property

3

The value of the changed state property

4

Params from the handler

main.ts
import { NestGram, stateStore } from 'nestgram';
import { AppModule } from './app.module';
import * as config from 'config';

async function bootstrap(): Promise<void> {
  const bot: NestGram = new NestGram(config.get<string>('botToken'), AppModule);

  stateStore.setCustomSetter(
    async (userId: number, name: string, value: string, params?: any): Promise<any> => {
      // save new state to db ...
    }
  );

  await bot.start();
}

bootstrap();

Last updated