Client lifecycle hooks (#7407)

* Add example client lifecycle hooks

* AfterCreate, AfterDelete hooks
This commit is contained in:
Tom Moor
2024-08-27 07:28:21 -04:00
committed by GitHub
parent 043a8623b9
commit 7bd8738ecd
3 changed files with 90 additions and 2 deletions
+9
View File
@@ -12,7 +12,9 @@ import type CollectionsStore from "~/stores/CollectionsStore";
import Document from "~/models/Document";
import ParanoidModel from "~/models/base/ParanoidModel";
import { client } from "~/utils/ApiClient";
import Logger from "~/utils/Logger";
import Field from "./decorators/Field";
import { AfterUpdate } from "./decorators/Lifecycle";
export default class Collection extends ParanoidModel {
static modelName = "Collection";
@@ -324,4 +326,11 @@ export default class Collection extends ParanoidModel {
format,
includeAttachments,
});
// hooks
@AfterUpdate
static testing(model: Collection) {
Logger.info("lifecycle", "AfterUpdate", { model });
}
}
+19 -2
View File
@@ -4,6 +4,7 @@ import { JSONObject } from "@shared/types";
import type Store from "~/stores/base/Store";
import Logger from "~/utils/Logger";
import { getFieldsForModel } from "../decorators/Field";
import { LifecycleManager } from "../decorators/Lifecycle";
import { getRelationsForModelClass } from "../decorators/Relation";
export default abstract class Model {
@@ -84,6 +85,7 @@ export default abstract class Model {
params?: Record<string, any>,
options?: Record<string, string | boolean | number | undefined>
): Promise<Model> => {
const isNew = this.isNew;
this.isSaving = true;
try {
@@ -92,6 +94,12 @@ export default abstract class Model {
params = this.toAPI();
}
if (isNew) {
LifecycleManager.executeHooks(this.constructor, "beforeCreate", this);
} else {
LifecycleManager.executeHooks(this.constructor, "beforeUpdate", this);
}
const model = await this.store.save(
{
...params,
@@ -99,7 +107,7 @@ export default abstract class Model {
},
{
...options,
isNew: this.isNew,
isNew,
}
);
@@ -108,6 +116,12 @@ export default abstract class Model {
this.persistedAttributes = this.toAPI();
if (isNew) {
LifecycleManager.executeHooks(this.constructor, "afterCreate", this);
} else {
LifecycleManager.executeHooks(this.constructor, "afterUpdate", this);
}
return model;
} finally {
this.isSaving = false;
@@ -138,7 +152,10 @@ export default abstract class Model {
this.isSaving = true;
try {
return await this.store.delete(this);
LifecycleManager.executeHooks(this.constructor, "beforeDelete", this);
const response = await this.store.delete(this);
LifecycleManager.executeHooks(this.constructor, "afterDelete", this);
return response;
} finally {
this.isSaving = false;
}
+62
View File
@@ -0,0 +1,62 @@
export class LifecycleManager {
private static hooks = new Map();
public static getHooks(target: any, lifecycle: string) {
const key = `lifecycle:${lifecycle}`;
const modelHooks = this.hooks.get(target.name);
return modelHooks?.get(key) || [];
}
public static executeHooks(target: any, lifecycle: string, ...args: any[]) {
const hooks = this.getHooks(target, lifecycle);
hooks.forEach((hook: keyof typeof target) => {
target[hook](...args);
});
}
public static registerHook(
target: any,
propertyKey: string,
lifecycle: string
) {
const key = `lifecycle:${lifecycle}`;
let modelHooks = this.hooks.get(target.name);
if (!modelHooks) {
modelHooks = new Map();
this.hooks.set(target.name, modelHooks);
}
let lifecycleHooks = modelHooks.get(key);
if (!lifecycleHooks) {
lifecycleHooks = [];
modelHooks.set(key, lifecycleHooks);
}
lifecycleHooks.push(propertyKey);
}
}
export function BeforeCreate(target: any, propertyKey: string) {
LifecycleManager.registerHook(target, propertyKey, "beforeCreate");
}
export function AfterCreate(target: any, propertyKey: string) {
LifecycleManager.registerHook(target, propertyKey, "afterCreate");
}
export function BeforeUpdate(target: any, propertyKey: string) {
LifecycleManager.registerHook(target, propertyKey, "beforeUpdate");
}
export function AfterUpdate(target: any, propertyKey: string) {
LifecycleManager.registerHook(target, propertyKey, "afterUpdate");
}
export function BeforeDelete(target: any, propertyKey: string) {
LifecycleManager.registerHook(target, propertyKey, "beforeDelete");
}
export function AfterDelete(target: any, propertyKey: string) {
LifecycleManager.registerHook(target, propertyKey, "afterDelete");
}