lemon-core
Version:
Lemon Serverless Micro-Service Platform
192 lines • 8.58 kB
JavaScript
"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(` (${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(` 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(` 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(` 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