node.js - Nestjs: κλήση συναρτήσεων υπηρεσίας από Μοντέλο/Οντότητα με hooks του sequelize


Στο NestJS, πρέπει να χρησιμοποιήσω μια υπηρεσία module μέσα σε ένα entity/model για να γεμίσω δεδομένα στον elastic-search δείκτη. Η λογική για τη γεμισμα του elastic search δείκτη είναι γραμμένη στο Job.service.ts.

Θέλω να καλέσω αυτήν τη μέθοδο onCreate από το Job.service.ts από τα hooks του sequelize που υπάρχουν στα μοντέλα.

Εδώ είναι ο κώδικας για το μοντέλο/οντότητα Job.ts -

import { Table, Model, Column, AutoIncrement, PrimaryKey } from "sequelize-typescript";

@Table({ schema: "job", tableName: "job" })
export class Job extends Model<Job> {
  @AutoIncrement
  @PrimaryKey
  @Column
  id: number;

  @Column
  title: string;

  @AfterCreate
  static async jobAfterCreate(instance, options) {
    // <--- need to call job service onCreate method here
  }

  @AfterUpdate
  static async jobAfterUpdate() {}

  @AfterDestroy
  static async jobAfterDestroy() {}
}

και εδώ είναι ο κώδικας για το Job.service.ts -

//imports not added
@Injectable()
export class JobService {
  constructor(
    @Inject("SEQUELIZE")
    private readonly sequelizeInstance: Sequelize,
    @Inject(forwardRef(() => ElasticsearchService))
    private readonly elasticsearchService: ElasticsearchService,
    @InjectModel(Job)
    private jobModel: typeof Job
  ) {}

  // here will write logic for updating elastic search index
  async onCreate(instance, options){
    console.log("ON CREATE INSTANCE:", instance);
    console.log("ON CREATE OPTIONS:", options);
  }
  async onDestroy(instance, options){
    console.log("ON DESTROY INSTANCE:", instance);
    console.log("ON DESTROY OPTIONS:", options);
  }
}

Προσπάθησα να ενέσω την υπηρεσία στο μοντέλο Job αλλά δεν λειτούργησε. Και δεν μπορώ να γράψω λογική Elasticsearch μέσα στο μοντέλο απευθείας επειδή για αυτό χρειάζομαι ElasticsearchService.

Απάντηση #1

Η λύση είναι να αντικαταστήσετε τον πάροχο

Ο κύριος τρόπος εισαγωγής πληροφοριών στα μοντέλα είναι η υπερισχύση της συμπεριφοράς εισαγωγής.

Πρώτα, θα χρειαστεί να προσθέσετε μια στατική ιδιότητα που αναφέρεται στην υπηρεσία στο μοντέλο σας.

Πρόκειται να χρησιμοποιήσω τον εκπέμπτη γεγονότων ως παράδειγμα εδώ.

Η Κλάση Μοντέλου Σας

import {Model, Table, Column, AfterCreate} from "sequelize-typescript"; 
import { EventEmitter2 } from "@nestjs/event-emitter";

@Table()
export class SomeModel extends <SomeModel> {

  // this would be your referencing
  public static EventEmitter: EventEmitter2;

  @Column
  public someColumn: string;


  @AfterCreate
  public static triggerSomeEvent(instance: SomeModel) {
    SomeModel.EventEmitter.emit('YourEvent', instance);
  } 
}

Το module όπου πρόκειται να χρησιμοποιήσετε το μοντέλο

Τώρα υπερκαλύπτουμε τη διαδικασία προεπιλεγμένης έγχυσης.

import { EntitiesMetadataStorage } from '@nestjs/sequelize/dist/entities-metadata.storage';
import {
  getConnectionToken,
  getModelToken,
  SequelizeModule,
} from '@nestjs/sequelize';
import { EventEmitter2 } from '@nestjs/event-emitter';

// The provider override
const modelInjector: Provider = {
  provide: getModelToken(AccountabilityPartnerModel, DEFAULT_CONNECTION_NAME),
  useFactory: (connection: Sequelize, eventEmitter: EventEmitter2) => {
    SomeModel.EventEmitter = eventEmitter;
    if (!connection.repositoryMode) {
      return SomeModel;
    }
    return connection.getRepository(SomeModelas any);
  },
  inject: [getConnectionToken(DEFAULT_CONNECTION_NAME), EventEmitter2],
};

// Updating the meta information of sequelize-typescript package to handle connection injection in to the model overridden.

EntitiesMetadataStorage.addEntitiesByConnection(DEFAULT_CONNECTION_NAME, [
  SomeModel,
]);


// our custom module being used rather than the Sequelize.forFeature([SomeModel])
const someModelModule: DynamicModule = {
  module: SequelizeModule,
  providers: [modelInjector],
  exports: [modelInjector],
};


@Module({
  imports: [someModelModule],
  providers: [SomeService],
})
export class SomeModule {
}

Ενέχετε το μοντέλο σας στην υπηρεσία σας όπως θα κάνατε χρησιμοποιώντας το Sequelize.forFeature και InjectModel όπως υποδεικνύεται παρακάτω.

@Injectable()
export class SomeService {
 constructor(@InjectModel(SomeModel) someModel: typeof SomeModel) {}

 public someFunction(data: any) {
   this.someModel.EventEmitter.emit('YourEvent', data);
 }
}