NestJS - how to call Service method in Module options

5k Views Asked by At

I'm trying out a event sourced NestJS application. I'm stuck at the following point: In my GamesModule I'm setting up the Eventstore connection to my stream. In these options there are write and read functions which are called by the library to update/ read the stream's last checkpoint position. I'd like to call my service methods that write and read to/from the database from these functions.

I've tried injecting the service in the constructor, but because the register function is and has to be a static method, I don't have access to whatever is injected in the constructor.

Is it possible to use a service or repository in the Dynamic module's options?

Service writing to and reading from DB:

@Injectable()
export class EventStoreStateService {
  private readonly logger = new Logger(EventStoreStateService.name);
  constructor(
    @InjectRepository(EventStoreState)
    private eventStoreStateRepository: Repository<EventStoreState>,
  ) {}
  updateCheckpoint(stream: string, position: number) {
    const updated = this.eventStoreStateRepository.update(
      { lastCheckpoint: position },
      { streamName: stream },
    );
    this.logger.log({ updated });

    return updated;
  }

  getLastCheckpoint(stream: string) {
    const last = this.eventStoreStateRepository.findOne({
      where: { streamName: stream },
    });
    this.logger.log({ last });
    return last;
  }
}

The module where I setup the event-store connection. In the useFactory store.write(key: string, value: number) I'd like to call my service methods

@Module({
  imports: [EventStoreStateModule],
})
export class GamesModule {
  constructor(
    // no access to this service in the static method
    //
    @Inject(EventStoreStateService)
    private readonly eventStoreStateService: EventStoreStateService,
  ) {}
  static register(): // updateCheckpoint: (key: string, value: number) => Promise<number>,
  // getLastCheckpoint: (key: string) => Promise<number>,
  DynamicModule {
    return {
      module: GamesModule,
      imports: [
        CqrsModule,
        EventStoreModule.registerFeatureAsync({
          type: 'event-store',
          useFactory: async (...args) => {
            console.log({ args });
            return {
              featureStreamName: '$ce-game',
              type: 'event-store',
              subscriptions: [
                {
                  type: EventStoreSubscriptionType.CatchUp, // research various types
                  stream: '$ce-game',
                  resolveLinkTos: true,
                },
              ],
              eventHandlers: EventStoreInstanciators,
              store: {
                storeKey: 'game',
                write: async (key: string, value: number) => {
                  // TODO: on every new event for stream x this function
                  // is called with the last position number
                  // problem: we need access to the service that connects
                  // to ORM, but it's a static method so no access to whatever
                  // is injected in the constructor
                  //
                },
                read: async (key: string) => {
                  // same as write function
                  //
                },
                clear: () => null,
              },
            };
          },
        }),
        TypeOrmModule.forFeature([GameProjection]),
      ],
      controllers: [GamesController],
      providers: [
        GamesResolver,
        GamesService,
        GamesRepository,
        ...CommandHandlers,
        ...EventHandlers,
      ],
    };
  }
}

Using this library for event-store connection: https://github.com/juicycleff/nestjs-event-store.

1

There are 1 best solutions below

2
On

Key things to know in NestJs.

  1. If you want to access service within the same module, make sure you inject service in your constructor like constructor( private readonly eventStoreStateService: EventStoreStateService){}
  2. If you want to access service from another module then you have to export the service in .module.ts exports: [EventStoreStateService] and then also inject in service or controller where you want to use it.