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);
}
}
