UNPKG

lemon-core

Version:
192 lines 8.58 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.AbstractManager = void 0; /** * `model-manager.ts` * - base model manager * * @author Tim Hong <tim@lemoncloud.io> * @date 2020-06-05 initial version * * @copyright (C) 2020 LemonCloud Co Ltd. - All Rights Reserved. */ // eslint-disable-next-line @typescript-eslint/no-unused-vars const engine_1 = require("../../engine/"); const proxy_storage_service_1 = require("./proxy-storage-service"); const NS = engine_1.$U.NS('MMGR', 'cyan'); // default namespace name /** * class: `AbstractManager` * - abstract model manager to cover all models which extend CoreModel. * - feature to handle 'name' like unique value in same type. * - typed-storage based. * @abstract */ class AbstractManager extends proxy_storage_service_1.GeneralModelFilter { /** * default constructor * @param type model type string * @param parent service instance which implements StorageMakeable interface * @param fields list of model field names * @param uniqueField (optional) unique field name * @param ns (optional) namespace to be printed. pass NULL to suppress all logs. * global NS value will be used if not specified or undefined. */ constructor(type, parent, fields, uniqueField, ns) { super(fields); /** * hello of this service-identity */ this.hello = () => this.storage.hello(); this.NS = ns === undefined ? NS : ns; this.parent = parent; this.storage = parent.makeStorageService(type, fields, this); this.$unique = uniqueField ? this.storage.makeUniqueFieldManager(uniqueField) : null; } /** * type getter */ get type() { return this.storage.type; } /** * callback invoked just before the model is saved * - override this to customize default behavior to perform model validation, cleansing or normalization * @param model model object * @param origin original model currently in the storage */ onBeforeSave(model, origin) { return super.onBeforeSave(model, origin); } /** * default implementation of 'preparing' model * - prepare model w/ safe creation * @param id model-id to prepare * @param $def default model value * @param isCreate (optional) flag to allow creating a new model (default: true) */ prepare(id, $def, isCreate = true) { return __awaiter(this, void 0, void 0, function* () { if (!id) throw new Error(`404 NOT FOUND - id is not valid!`); // if 'isCreate' flag is set, read existing model or create initial model by calling abstract method 'prepareDefault' if (isCreate) return this.storage.readOrCreate(id, this.prepareDefault($def)); // otherwise just try to read model and throw 404 if it does not exist return this.storage.read(id).catch(e => { if (`${e.message || e}`.startsWith('404 NOT FOUND')) e = new Error(`404 NOT FOUND - ${this.type}:${id}`); throw e; }); }); } /** * default implementation of 'inserting' model * @param model model object */ insert(model) { return __awaiter(this, void 0, void 0, function* () { this.NS && (0, engine_1._inf)(this.NS, `insert(${this.type})...`); if (!model) throw new Error(`@model (${this.type}-model) is required!`); const $def = this.prepareDefault(null); const created = yield this.storage.insert($def); const id = `${(created && created.id) || ''}`; if (!id) throw new Error('.id (string) is missing - insert() failed!'); this.NS && (0, engine_1._log)(this.NS, `> model.base =`, engine_1.$U.json(model)); const $saves = Object.assign({}, model); // clone delete $saves.id; // ensure there is no 'id' field const saved = yield this.storage.save(id, $saves); this.NS && (0, engine_1._log)(this.NS, `> model.saved =`, engine_1.$U.json(saved)); return Object.assign(Object.assign(Object.assign({}, created), saved), { id }); }); } /** * default implementation of 'retrieving' model * @param id model id */ retrieve(id) { return __awaiter(this, void 0, void 0, function* () { this.NS && (0, engine_1._inf)(this.NS, `retrieve(${this.type}/${id})...`); if (!id) throw new Error(`@id is required - retrieve(${this.type}/${id})`); return this.storage.read(id).catch(e => { if (`${e.message}`.startsWith('404 NOT FOUND')) e = new Error(`404 NOT FOUND - ${this.type}:${id}`); throw e; }); }); } /** * default implementation of updating model * @param id model id * @param model model object * @param $inc (optional) incremental set */ update(id, model, $inc) { return __awaiter(this, void 0, void 0, function* () { this.NS && (0, engine_1._inf)(this.NS, `update(${this.type}/${id})...`); return this._updateModel(id, model, $inc, false); }); } /** * default implementation of 'upserting' model * @param id model id * @param model model object * @param $inc (optional) incremental set */ updateOrCreate(id, model, $inc) { return __awaiter(this, void 0, void 0, function* () { this.NS && (0, engine_1._inf)(this.NS, `updateOrCreate(${this.type}/${id})...`); return this._updateModel(id, model, $inc, true); }); } /** * default implementation of deleting model * @param id model id * @param destroy flag for hard delete or soft delete (by setting 'deletedAt' field) */ delete(id, destroy = true) { return __awaiter(this, void 0, void 0, function* () { this.NS && (0, engine_1._inf)(this.NS, `delete(${this.type}/${id})...`); if (!id) throw new Error(`@id is required - delete(${this.type}/${id})`); const $org = yield this.prepare(id, null, false); this.NS && (0, engine_1._log)(this.NS, `> model.org =`, engine_1.$U.json($org)); const deleted = yield this.storage.delete(id, destroy); this.NS && (0, engine_1._log)(this.NS, `> model.deleted =`, engine_1.$U.json(deleted)); return Object.assign(Object.assign(Object.assign({}, $org), deleted), { id }); }); } /** * internal implementation for 'update' and 'updateOrCreate' * @param id model id * @param model model object * @param $inc (optional) incremental set * @param isCreate (optional) flag to allow creating a new model (default: true) * @private */ _updateModel(id, model, $inc, isCreate = true) { return __awaiter(this, void 0, void 0, function* () { if (!id) throw new Error(`@id is required - updateModel(${this.type}/${id})`); const $org = yield this.prepare(id, null, isCreate); this.NS && (0, engine_1._log)(this.NS, `> model.org =`, engine_1.$U.json($org)); const $ups = Object.assign({}, model); const updated = yield this.storage.update(id, $ups, $inc); this.NS && (0, engine_1._log)(this.NS, `> model.updated =`, engine_1.$U.json(updated)); return Object.assign(Object.assign(Object.assign({}, $org), updated), { id }); }); } } exports.AbstractManager = AbstractManager; //# sourceMappingURL=model-manager.js.map