Commit a336deb2 authored by nanahira's avatar nanahira

add more hooks

parent 1893d4fd
...@@ -36,6 +36,32 @@ export class User extends IdBase() { ...@@ -36,6 +36,32 @@ export class User extends IdBase() {
@NotColumn() @NotColumn()
somethingElse: any; // Would not come from client input, and would not go into OpenAPI document. somethingElse: any; // Would not come from client input, and would not go into OpenAPI document.
// possible optional override operations
override isValidInCreation() { // Custom before-create check.
if (!this.name.length) {
return 'Name cannot be empty!';
}
}
override isValidInUpdate() { // Custom before-update check.
if (this.name && !this.name.length) {
return 'Name cannot be empty!';
}
}
override async beforeCreate() {
this.name = this.name.toLowerCase(); // Do something before create.
}
override async afterCreate() {
this.name = this.name.toUpperCase(); // Do something after create before sending to user.
}
override async beforeGet() {}
override async afterGet() {}
override async beforeUpdate() {}
} }
``` ```
......
...@@ -6,15 +6,19 @@ export interface DeletionWise { ...@@ -6,15 +6,19 @@ export interface DeletionWise {
deleteTime?: Date; deleteTime?: Date;
} }
export interface ImportWise { export interface EntityHooks {
isValidInCreation(): string | undefined; isValidInCreate(): string | undefined;
beforeSaving(): Promise<void>; beforeCreate(): Promise<void>;
afterSaving(): void; afterCreate(): Promise<void>;
beforeGet(): Promise<void>;
afterGet(): Promise<void>;
isValidInUpdate(): string | undefined;
beforeUpdate(): Promise<void>;
} }
export class TimeBase export class TimeBase
extends PageSettingsDto extends PageSettingsDto
implements DeletionWise, ImportWise implements DeletionWise, EntityHooks
{ {
@CreateDateColumn({ select: false }) @CreateDateColumn({ select: false })
@NotColumn() @NotColumn()
...@@ -28,15 +32,28 @@ export class TimeBase ...@@ -28,15 +32,28 @@ export class TimeBase
@NotColumn() @NotColumn()
deleteTime: Date; deleteTime: Date;
isValidInCreation(): string | undefined { isValidInCreate(): string | undefined {
return; return;
} }
// eslint-disable-next-line @typescript-eslint/no-empty-function // eslint-disable-next-line @typescript-eslint/no-empty-function
async beforeSaving(): Promise<void> {} async beforeCreate(): Promise<void> {}
// eslint-disable-next-line @typescript-eslint/no-empty-function // eslint-disable-next-line @typescript-eslint/no-empty-function
async afterSaving(): Promise<void> {} async afterCreate(): Promise<void> {}
// eslint-disable-next-line @typescript-eslint/no-empty-function
async beforeGet(): Promise<void> {}
// eslint-disable-next-line @typescript-eslint/no-empty-function
async afterGet(): Promise<void> {}
isValidInUpdate(): string | undefined {
return;
}
// eslint-disable-next-line @typescript-eslint/no-empty-function
async beforeUpdate(): Promise<void> {}
} }
export const TimeBaseFields: (keyof TimeBase)[] = [ export const TimeBaseFields: (keyof TimeBase)[] = [
......
...@@ -15,7 +15,7 @@ import { ...@@ -15,7 +15,7 @@ import {
} from 'typeorm'; } from 'typeorm';
import { import {
DeletionWise, DeletionWise,
ImportWise, EntityHooks,
PageSettingsFactory, PageSettingsFactory,
QueryWise, QueryWise,
} from './bases'; } from './bases';
...@@ -38,7 +38,7 @@ export type ValidCrudEntity<T> = Record<string, any> & { ...@@ -38,7 +38,7 @@ export type ValidCrudEntity<T> = Record<string, any> & {
id: any; id: any;
} & QueryWise<T> & } & QueryWise<T> &
DeletionWise & DeletionWise &
ImportWise & EntityHooks &
PageSettingsFactory; PageSettingsFactory;
export interface CrudOptions<T extends ValidCrudEntity<T>> { export interface CrudOptions<T extends ValidCrudEntity<T>> {
...@@ -143,7 +143,7 @@ export class CrudBase<T extends ValidCrudEntity<T>> { ...@@ -143,7 +143,7 @@ export class CrudBase<T extends ValidCrudEntity<T>> {
if (!ent) { if (!ent) {
throw new BlankReturnMessageDto(400, 'Invalid entity').toException(); throw new BlankReturnMessageDto(400, 'Invalid entity').toException();
} }
const invalidReason = ent.isValidInCreation(); const invalidReason = ent.isValidInCreate();
if (invalidReason) { if (invalidReason) {
throw new BlankReturnMessageDto(400, invalidReason).toException(); throw new BlankReturnMessageDto(400, invalidReason).toException();
} }
...@@ -169,10 +169,10 @@ export class CrudBase<T extends ValidCrudEntity<T>> { ...@@ -169,10 +169,10 @@ export class CrudBase<T extends ValidCrudEntity<T>> {
if (beforeCreate) { if (beforeCreate) {
await beforeCreate(repo); await beforeCreate(repo);
} }
await ent.beforeSaving(); await ent.beforeCreate();
try { try {
const savedEnt = await repo.save(ent as DeepPartial<T>); const savedEnt = await repo.save(ent as DeepPartial<T>);
await savedEnt.afterSaving(); await savedEnt.afterCreate();
} catch (e) { } catch (e) {
this.log.error( this.log.error(
`Failed to create entity ${JSON.stringify(ent)}: ${e.toString()}`, `Failed to create entity ${JSON.stringify(ent)}: ${e.toString()}`,
...@@ -246,6 +246,7 @@ export class CrudBase<T extends ValidCrudEntity<T>> { ...@@ -246,6 +246,7 @@ export class CrudBase<T extends ValidCrudEntity<T>> {
`${this.entityName} ID ${id} not found.`, `${this.entityName} ID ${id} not found.`,
).toException(); ).toException();
} }
await ent.afterGet();
return new this.entityReturnMessageDto(200, 'success', ent); return new this.entityReturnMessageDto(200, 'success', ent);
} }
...@@ -258,6 +259,7 @@ export class CrudBase<T extends ValidCrudEntity<T>> { ...@@ -258,6 +259,7 @@ export class CrudBase<T extends ValidCrudEntity<T>> {
const newEnt = new this.entityClass(); const newEnt = new this.entityClass();
if (ent) { if (ent) {
Object.assign(newEnt, ent); Object.assign(newEnt, ent);
await newEnt.beforeGet();
newEnt.applyQuery(query, this.entityAliasName); newEnt.applyQuery(query, this.entityAliasName);
} }
this._applyRelationsToQuery(query); this._applyRelationsToQuery(query);
...@@ -265,6 +267,7 @@ export class CrudBase<T extends ValidCrudEntity<T>> { ...@@ -265,6 +267,7 @@ export class CrudBase<T extends ValidCrudEntity<T>> {
extraQuery(query); extraQuery(query);
try { try {
const [ents, count] = await query.getManyAndCount(); const [ents, count] = await query.getManyAndCount();
await Promise.all(ents.map((ent) => ent.afterGet()));
return new this.entityPaginatedReturnMessageDto( return new this.entityPaginatedReturnMessageDto(
200, 200,
'success', 'success',
...@@ -289,13 +292,20 @@ export class CrudBase<T extends ValidCrudEntity<T>> { ...@@ -289,13 +292,20 @@ export class CrudBase<T extends ValidCrudEntity<T>> {
cond: FindOptionsWhere<T> = {}, cond: FindOptionsWhere<T> = {},
) { ) {
let result: UpdateResult; let result: UpdateResult;
const ent = new this.entityClass();
Object.assign(ent, entPart);
const invalidReason = ent.isValidInUpdate();
if (invalidReason) {
throw new BlankReturnMessageDto(400, invalidReason).toException();
}
await ent.beforeUpdate();
try { try {
result = await this.repo.update( result = await this.repo.update(
{ {
id, id,
...cond, ...cond,
}, },
entPart, ent,
); );
} catch (e) { } catch (e) {
this.log.error( this.log.error(
...@@ -344,7 +354,7 @@ export class CrudBase<T extends ValidCrudEntity<T>> { ...@@ -344,7 +354,7 @@ export class CrudBase<T extends ValidCrudEntity<T>> {
const invalidResults = _.compact( const invalidResults = _.compact(
await Promise.all( await Promise.all(
ents.map(async (ent) => { ents.map(async (ent) => {
const reason = ent.isValidInCreation(); const reason = ent.isValidInCreate();
if (reason) { if (reason) {
return { entry: ent, result: reason }; return { entry: ent, result: reason };
} }
...@@ -360,9 +370,9 @@ export class CrudBase<T extends ValidCrudEntity<T>> { ...@@ -360,9 +370,9 @@ export class CrudBase<T extends ValidCrudEntity<T>> {
const remainingEnts = ents.filter( const remainingEnts = ents.filter(
(ent) => !invalidResults.find((result) => result.entry === ent), (ent) => !invalidResults.find((result) => result.entry === ent),
); );
await Promise.all(remainingEnts.map((ent) => ent.beforeSaving())); await Promise.all(remainingEnts.map((ent) => ent.beforeCreate()));
const data = await this._batchCreate(remainingEnts, undefined, true); const data = await this._batchCreate(remainingEnts, undefined, true);
await Promise.all(data.results.map((e) => e.afterSaving())); await Promise.all(data.results.map((e) => e.afterCreate()));
const results = [ const results = [
...invalidResults, ...invalidResults,
...data.skipped, ...data.skipped,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment