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 answers

2
Shariati 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.