diff --git a/src/Application.ts b/src/Application.ts index 8c0aa51..add9925 100644 --- a/src/Application.ts +++ b/src/Application.ts @@ -13,7 +13,7 @@ import Controller from "./Controller.js"; import Migration, {MigrationType} from "./db/Migration.js"; import MysqlConnectionManager from "./db/MysqlConnectionManager.js"; import {ValidationBag, ValidationError} from "./db/Validator.js"; -import Extendable from "./Extendable.js"; +import Extendable, {MissingComponentError} from "./Extendable.js"; import {BadRequestError, HttpError, NotFoundHttpError, ServerError, ServiceUnavailableHttpError} from "./HttpError.js"; import {logger, loggingContextMiddleware} from "./Logger.js"; import SecurityError from "./SecurityError.js"; @@ -384,6 +384,16 @@ export default abstract class Application implements Extendable>(type: Type): boolean { + return !!this.asOptional(type); + } + + public require>(type: Type): void { + if (!this.has(type)) { + throw new MissingComponentError(type); + } + } + public async isInNodeModules(): Promise { return await doesFileExist('node_modules/swaf'); } diff --git a/src/Extendable.ts b/src/Extendable.ts index 3af7dd5..3d7caf8 100644 --- a/src/Extendable.ts +++ b/src/Extendable.ts @@ -4,4 +4,17 @@ export default interface Extendable { as(type: Type): C; asOptional(type: Type): C | null; + + has(type: Type): boolean; + + /** + * @throws MissingComponentError + */ + require(type: Type): void; +} + +export class MissingComponentError extends Error { + public constructor(type: Type) { + super(`Required component ${type.name} was not found.`); + } } diff --git a/src/db/Model.ts b/src/db/Model.ts index decee8f..30f79fb 100644 --- a/src/db/Model.ts +++ b/src/db/Model.ts @@ -1,7 +1,7 @@ import {Request} from "express"; import {Connection} from "mysql"; -import Extendable from "../Extendable.js"; +import Extendable, {MissingComponentError} from "../Extendable.js"; import {Type} from "../Utils.js"; import ModelComponent from "./ModelComponent.js"; import ModelFactory, {PrimaryKeyValue} from "./ModelFactory.js"; @@ -99,6 +99,16 @@ export default abstract class Model implements Extendable> return null; } + public has>(type: Type): boolean { + return !!this.asOptional(type); + } + + public require>(type: Type): void { + if (!this.has(type)) { + throw new MissingComponentError(type); + } + } + public updateWithData(data: Pick | Record): void { for (const property of this._properties) { if (data[property] !== undefined) {