UNPKG

@decaf-ts/core

Version:

Core persistence module for the decaf framework

103 lines 3.64 kB
import { Adapter } from "./Adapter.js"; import { InternalError } from "@decaf-ts/db-decorators"; import { LoggedClass } from "@decaf-ts/logging"; import { PersistenceKeys } from "./constants.js"; import { Decoration, Metadata, metadata } from "@decaf-ts/decoration"; import { MigrationRuleError } from "./errors.js"; import { Model } from "@decaf-ts/decorator-validation"; import { Context } from "./Context.js"; export function prefixMethod(obj, after, prefix, afterName) { async function wrapper(...args) { let results; try { results = await Promise.resolve(prefix.call(this, ...args)); } catch (e) { if (e instanceof MigrationRuleError) return; throw e; } return Promise.resolve(after.apply(this, results)); } const wrapped = wrapper.bind(obj); const name = afterName ? afterName : after.name; Object.defineProperty(wrapped, "name", { enumerable: true, configurable: true, writable: false, value: name, }); obj[name] = wrapped; } export class AbsMigration extends LoggedClass { constructor() { super(); this.transaction = true; [this.up, this.down].forEach((m) => { const name = m.name; prefixMethod(this, m, this.prefix(name)); }); } get adapter() { const meta = Metadata.get(this.constructor, PersistenceKeys.MIGRATION); if (!meta) throw new InternalError(`No migration metadata for ${this.constructor.name}`); const flavour = meta.flavour; return Adapter.get(flavour); } async enforceRules(qr, adapter, ctx) { const rules = Metadata.get(this.constructor, PersistenceKeys.MIGRATION)?.rules; if (!rules || !rules.length) return true; for (const rule of rules) { const result = await rule(qr, adapter, ctx); if (!result) return false; } return true; } prefix(name) { return async function preffix(qrOrAdapter) { let qr; if (qrOrAdapter instanceof Adapter) { qr = this.getQueryRunner(qrOrAdapter.client); } else { qr = qrOrAdapter; qrOrAdapter = this.adapter; } const ctx = await Context.args("migration", Model, [name], qrOrAdapter); const allowed = await this.enforceRules(qr, qrOrAdapter, ctx.context); if (!allowed) { ctx.context.logger.verbose(`Skipping migration ${this.constructor.name} due to rules`); throw new MigrationRuleError("Migration skipped for rule enforcement"); } return [qr, qrOrAdapter, ctx.context]; }.bind(this); } } export function migration(flavour, rules) { function innerMigration(flavour, rules) { return function (original) { const current = Metadata["innerGet"](Symbol.for(PersistenceKeys.MIGRATION), flavour) || []; Metadata.set(PersistenceKeys.MIGRATION, flavour, [ ...current, { class: original, }, ]); return metadata(PersistenceKeys.MIGRATION, { flavour: flavour, rules: rules, })(original); }; } return Decoration.for(PersistenceKeys.MIGRATION) .define({ decorator: innerMigration, args: [flavour, rules], }) .apply(); } //# sourceMappingURL=migrations.js.map