@decaf-ts/core
Version:
Core persistence module for the decaf framework
103 lines • 3.64 kB
JavaScript
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