UNPKG

@decaf-ts/for-couchdb

Version:
155 lines 7.03 kB
import { Repository } from "@decaf-ts/core"; import { Model } from "@decaf-ts/decorator-validation"; import { getMetadata, setMetadata } from "./metadata.js"; import { enforceDBDecorators, reduceErrorsToPrint, InternalError, OperationKeys, ValidationError, BulkCrudOperationKeys, } from "@decaf-ts/db-decorators"; export class CouchDBRepository extends Repository { constructor(adapter, model, force = false) { super(adapter, model, force); } assignMetadata(target, source) { const apply = (instance, carrier) => { const metadataSource = carrier ?? instance; const metadata = getMetadata(metadataSource); if (metadata) setMetadata(instance, metadata); return instance; }; if (Array.isArray(target)) { return target.map((model, index) => { const carrier = Array.isArray(source) ? source[index] : source; return apply(model, carrier); }); } const carrier = Array.isArray(source) ? source?.[0] : source; return apply(target, carrier); } async create(model, ...args) { const result = await super.create(model, ...args); this.assignMetadata(result); this.assignMetadata(model, result); return result; } async createAll(models, ...args) { const results = await super.createAll(models, ...args); this.assignMetadata(results); this.assignMetadata(models, results); return results; } async read(id, ...args) { const result = await super.read(id, ...args); return this.assignMetadata(result); } async readAll(ids, ...args) { const results = await super.readAll(ids, ...args); return this.assignMetadata(results); } async update(model, ...args) { const result = await super.update(model, ...args); this.assignMetadata(result); this.assignMetadata(model, result); return result; } async updateAll(models, ...args) { const results = await super.updateAll(models, ...args); this.assignMetadata(results); this.assignMetadata(models, results); return results; } async delete(id, ...args) { const result = await super.delete(id, ...args); return this.assignMetadata(result); } async deleteAll(ids, ...args) { const results = await super.deleteAll(ids, ...args); return this.assignMetadata(results); } /** * @description Prepares a model for update. * @summary Validates the model and prepares it for update in the database. * @param {M} model - The model to update. * @param {...any[]} args - Additional arguments. * @return The prepared model and context arguments. * @throws {InternalError} If the model has no primary key value. * @throws {ValidationError} If the model fails validation. */ async updatePrefix(model, ...args) { const { ctx, ctxArgs, log } = (await this.logCtx(args, OperationKeys.UPDATE, true)).for(this.updatePrefix); const ignoreHandlers = ctx.get("ignoreHandlers"); const ignoreValidate = ctx.get("ignoreValidation"); log.silly(`handlerSetting: ${ignoreHandlers}, validationSetting: ${ignoreValidate}`); const pk = model[this.pk]; if (!pk) throw new InternalError(`No value for the Id is defined under the property ${this.pk}`); let oldModel; let oldMetadata; if (ctx.get("applyUpdateValidation")) { oldModel = await this.read(pk); oldMetadata = oldModel ? getMetadata(oldModel) : undefined; if (ctx.get("mergeForUpdate")) model = Model.merge(oldModel, model, this.class); } if (!ignoreHandlers) await enforceDBDecorators(this, ctx, model, OperationKeys.UPDATE, OperationKeys.ON, oldModel); if (!ignoreValidate) { const propsToIgnore = ctx.get("ignoredValidationProperties") || []; log.silly(`ignored validation properties: ${propsToIgnore}`); const errors = await Promise.resolve(model.hasErrors(oldModel, ...propsToIgnore)); if (errors) throw new ValidationError(errors.toString()); } if (oldMetadata) setMetadata(model, oldMetadata); return [model, ...ctxArgs, oldModel]; } /** * @description Prepares multiple models for update. * @summary Validates multiple models and prepares them for update in the database. * @param {M[]} models - The models to update. * @param {...any[]} args - Additional arguments. * @return {Promise<any[]>} The prepared models and context arguments. * @throws {InternalError} If any model has no primary key value. * @throws {ValidationError} If any model fails validation. */ async updateAllPrefix(models, ...args) { const { ctx, ctxArgs, log } = (await this.logCtx(args, BulkCrudOperationKeys.UPDATE_ALL, true)).for(this.updateAllPrefix); const ignoreHandlers = ctx.get("ignoreHandlers"); const ignoreValidate = ctx.get("ignoreValidation"); log.silly(`handlerSetting: ${ignoreHandlers}, ignoredValidation: ${ignoreValidate}`); const ids = models.map((m) => { const id = m[this.pk]; if (!id) throw new InternalError("missing id on update operation"); return id; }); let oldModels; if (ctx.get("applyUpdateValidation")) { oldModels = await this.readAll(ids, ctx); models = models.map((m, i) => { if (ctx.get("mergeForUpdate")) m = Model.merge(oldModels[i], m, this.class); const oldMetadata = getMetadata(oldModels[i]); if (oldMetadata) setMetadata(m, oldMetadata); return m; }); } if (!ignoreHandlers) await Promise.all(models.map((m, i) => enforceDBDecorators(this, ctx, m, OperationKeys.UPDATE, OperationKeys.ON, oldModels ? oldModels[i] : undefined))); if (!ignoreValidate) { const ignoredProps = ctx.get("ignoredValidationProperties") || []; log.silly(`ignored validation properties: ${ignoredProps}`); let modelsValidation; if (!ctx.get("applyUpdateValidation")) { modelsValidation = await Promise.resolve(models.map((m) => m.hasErrors(...ignoredProps))); } else { modelsValidation = await Promise.all(models.map((m, i) => Promise.resolve(m.hasErrors(oldModels[i], ...ignoredProps)))); } const errorMessages = reduceErrorsToPrint(modelsValidation); if (errorMessages) throw new ValidationError(errorMessages); } return [models, ...ctxArgs, oldModels]; } } //# sourceMappingURL=repository.js.map