@grouparoo/core
Version:
The Grouparoo Core
202 lines (177 loc) • 4.93 kB
text/typescript
import { redis } from "actionhero";
import {
Table,
Column,
CreatedAt,
UpdatedAt,
AllowNull,
BeforeCreate,
DataType,
BeforeSave,
BeforeDestroy,
DefaultScope,
Default,
AfterSave,
AfterDestroy,
} from "sequelize-typescript";
import { Source } from "./Source";
import { ModelConfigurationObject } from "../classes/codeConfig";
import { APIData } from "../modules/apiData";
import { ConfigWriter } from "../modules/configWriter";
import { LockableHelper } from "../modules/lockableHelper";
import { Destination } from "./Destination";
import { Group } from "./Group";
import { GrouparooRecord } from "./GrouparooRecord";
import { RunOps } from "../modules/ops/runs";
import { StateMachine } from "../modules/stateMachine";
import { CommonModel } from "../classes/commonModel";
import { CLS } from "../modules/cls";
import { ModelsCache } from "../modules/caches/modelsCache";
export const ModelTypes = ["profile", "account", "event", "custom"] as const;
export type ModelType = typeof ModelTypes[number];
const STATES = ["ready", "deleted"] as const;
const STATE_TRANSITIONS: StateMachine.StateTransition[] = [
{ from: "draft", to: "ready", checks: [] },
{ from: "ready", to: "deleted", checks: [] },
{
from: "deleted",
to: "ready",
checks: [],
},
];
(() => ({
where: { state: "ready" },
}))
({ tableName: "models", paranoid: false })
export class GrouparooModel extends CommonModel<GrouparooModel> {
idPrefix() {
return "mod";
}
({ primaryKey: true })
id: string;
createdAt: Date;
updatedAt: Date;
(false)
name: string;
(false)
(DataType.ENUM(...ModelTypes))
type: ModelType;
locked: string;
(false)
("ready")
(DataType.ENUM(...STATES))
state: typeof STATES[number];
getIcon() {
switch (this.type) {
case "profile":
return "user";
case "account":
return "building";
case "event":
return "location-arrow";
case "custom":
return "database";
default:
throw new Error(`no icon for ${this.type} model`);
}
}
async run(destinationId?: string) {
return RunOps.run(this, destinationId);
}
async stopPreviousRuns() {
return RunOps.stopPreviousRuns(this);
}
async apiData() {
return {
id: this.id,
name: this.name,
type: this.type,
state: this.state,
locked: this.locked,
icon: this.getIcon(),
createdAt: APIData.formatDate(this.createdAt),
updatedAt: APIData.formatDate(this.updatedAt),
};
}
getConfigId() {
return this.idIsDefault() ? ConfigWriter.generateId(this.name) : this.id;
}
async getConfigObject(): Promise<ModelConfigurationObject> {
if (!this.name) return;
return {
class: "Model",
id: this.getConfigId(),
name: this.name,
type: this.type,
};
}
// --- Class Methods --- //
static async ensureValidType(instance: GrouparooModel) {
if (!ModelTypes.includes(instance.type)) {
throw new Error(
`${instance.type} is not a valid model type (${ModelTypes.join(", ")})`
);
}
}
static async noUpdateIfLocked(instance: GrouparooModel) {
await LockableHelper.beforeSave(instance);
}
static async updateState(instance: GrouparooModel) {
await StateMachine.transition(instance, STATE_TRANSITIONS);
}
static async noDestroyIfLocked(instance: GrouparooModel) {
await LockableHelper.beforeDestroy(instance);
}
static async ensureNotInUse(instance: GrouparooModel) {
const sources = await Source.scope(null).findAll({
where: { modelId: instance.id },
});
if (sources.length > 0) {
throw new Error(
`cannot delete this model, source ${sources[0].id} relies on it`
);
}
const destinations = await Destination.scope(null).findAll({
where: { modelId: instance.id },
});
if (destinations.length > 0) {
throw new Error(
`cannot delete this model, destination ${destinations[0].id} relies on it`
);
}
const groups = await Group.scope(null).findAll({
where: { modelId: instance.id },
});
if (groups.length > 0) {
throw new Error(
`cannot delete this model, group ${groups[0].id} relies on it`
);
}
const records = await GrouparooRecord.unscoped().count({
where: { modelId: instance.id },
});
if (records > 0) {
throw new Error(
`cannot delete this model, ${records} records rely on it`
);
}
}
static async invalidateCache() {
ModelsCache.invalidate();
await CLS.afterCommit(
async () => await redis.doCluster("api.rpc.model.invalidateCache")
);
}
}