@webda/core
Version:
Expose API with Lambda
1,207 lines • 34.4 kB
JavaScript
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { EventEmitter } from "events";
import util from "util";
import { v4 as uuidv4 } from "uuid";
import { Core, EventEmitterUtils } from "../core.js";
import { WebdaError } from "../errors.js";
import { BinariesImpl, Binary } from "../services/binary.js";
import { WebdaQL } from "../stores/webdaql/query.js";
import { Throttler } from "../utils/throttler.js";
import { ModelLinksArray, ModelLinksSimpleArray, ModelMapLoaderImplementation, createModelLinksMap } from "./relations.js";
/**
* Expose the model through API or GraphQL if it exists
* The model will be exposed using its class name + 's'
* If you need to have a specific plural, use the annotation WebdaPlural
* to define the plural name
*
* @returns
*/
export function Expose(params = {}) {
return function (target) {
params.restrict ?? (params.restrict = {});
target.Expose = params;
};
}
/**
*
*/
export class CoreModelQuery {
constructor(type, model, attribute) {
this.attribute = attribute;
this.type = type;
this.model = model;
}
/**
* Retrieve target model definition
* @returns
*/
getTargetModel() {
this.targetModel ?? (this.targetModel = Core.get().getModel(this.type));
return this.targetModel;
}
/**
* Query the object
* @param query
* @returns
*/
query(query, context) {
return this.getTargetModel().query(this.completeQuery(query), true, context);
}
/**
* Complete the query with condition
* @param query
* @returns
*/
completeQuery(query) {
return WebdaQL.PrependCondition(query, `${this.attribute} = '${this.model.getUuid()}'`);
}
/**
*
* @param callback
* @param context
*/
async forEach(callback, query, context, parallelism = 3) {
const throttler = new Throttler();
throttler.setConcurrency(parallelism);
for await (const model of this.iterate(query, context)) {
throttler.execute(() => callback(model));
}
return throttler.wait();
}
/**
* Iterate through all
* @param context
* @returns
*/
iterate(query, context) {
return Core.get().getModelStore(this.getTargetModel()).iterate(this.completeQuery(query), context);
}
/**
* Get all the objects
* @returns
*/
async getAll(context) {
let res = [];
for await (const item of this.iterate(this.completeQuery(), context)) {
res.push(item);
}
return res;
}
}
__decorate([
NotEnumerable
], CoreModelQuery.prototype, "type", void 0);
__decorate([
NotEnumerable
], CoreModelQuery.prototype, "model", void 0);
__decorate([
NotEnumerable
], CoreModelQuery.prototype, "attribute", void 0);
__decorate([
NotEnumerable
], CoreModelQuery.prototype, "targetModel", void 0);
/**
* Make a property hidden from json and schema
*
* This property will not be saved in the store
* Nor it will be exposed in the API
*
* @param target
* @param propertyKey
*/
export function NotEnumerable(target, propertyKey) {
Object.defineProperty(target, propertyKey, {
set(value) {
Object.defineProperty(this, propertyKey, {
value,
writable: true,
configurable: true
});
},
configurable: true
});
}
const ActionsAnnotated = new Map();
/**
* Define an object method as an action
* @param target
* @param propertyKey
*/
export function Action(options = {}) {
return function (target, propertyKey) {
let custom = target;
const global = typeof target === "function";
if (!global) {
custom = target.constructor;
}
if (!ActionsAnnotated.has(custom)) {
ActionsAnnotated.set(custom, {});
}
const actions = ActionsAnnotated.get(custom);
actions[options.name || propertyKey] = {
...options,
global,
method: propertyKey
};
};
}
export class ModelRef {
constructor(uuid, model, parent) {
this.uuid = uuid;
this.model = model;
this.uuid = uuid === "" ? undefined : model.completeUid(uuid);
this.store = Core.get().getModelStore(model);
}
async get(context) {
return (await this.store.get(this.uuid))?.setContext(context || this.parent?.getContext());
}
set(id) {
this.uuid = id instanceof CoreModel ? id.getUuid() : id;
this.parent?.__dirty.add(Object.keys(this.parent).find(k => this.parent[k] === this));
}
toString() {
return this.uuid;
}
toJSON() {
return this.uuid;
}
getUuid() {
return this.uuid;
}
async deleteItemFromCollection(prop, index, itemWriteCondition, itemWriteConditionField) {
const updateDate = await this.store.deleteItemFromCollection(this.uuid, prop, index, itemWriteCondition, itemWriteConditionField);
await this.model.emitSync("Store.PartialUpdated", {
object_id: this.uuid,
store: this.store,
updateDate,
partial_update: {
deleteItem: {
property: prop,
index: index
}
}
});
return this;
}
async upsertItemToCollection(prop, item, index, itemWriteCondition, itemWriteConditionField) {
const updateDate = await this.store.upsertItemToCollection(this.uuid, prop, item, index, itemWriteCondition, itemWriteConditionField);
await this.model.emitSync("Store.PartialUpdated", {
object_id: this.uuid,
store: this.store,
updateDate,
partial_update: {
addItem: {
value: item,
property: prop,
index: index
}
}
});
return this;
}
exists() {
return this.store.exists(this.uuid);
}
delete() {
return this.store.delete(this.uuid);
}
conditionalPatch(updates, conditionField, condition) {
return this.store.conditionalPatch(this.uuid, updates, conditionField, condition);
}
patch(updates) {
return this.store.conditionalPatch(this.uuid, updates, null, undefined);
}
async setAttribute(attribute, value) {
await this.store.setAttribute(this.uuid, attribute, value);
return this;
}
async removeAttribute(attribute, itemWriteCondition, itemWriteConditionField) {
await this.store.removeAttribute(this.uuid, attribute, itemWriteCondition, itemWriteConditionField);
await this.model?.emitSync("Store.PartialUpdated", {
object_id: this.uuid,
store: this.store,
partial_update: {
deleteAttribute: attribute
}
});
return this;
}
async incrementAttributes(info) {
const updateDate = await this.store.incrementAttributes(this.uuid, info);
await this.model.emitSync("Store.PartialUpdated", {
object_id: this.uuid,
store: this.store,
updateDate,
partial_update: {
increments: info
}
});
return this;
}
}
__decorate([
NotEnumerable
], ModelRef.prototype, "store", void 0);
__decorate([
NotEnumerable
], ModelRef.prototype, "model", void 0);
__decorate([
NotEnumerable
], ModelRef.prototype, "parent", void 0);
export class ModelRefWithCreate extends ModelRef {
/**
* Allow to create a model
* @param defaultValue
* @param context
* @param withSave
* @returns
*/
async create(defaultValue, context, withSave = true) {
let result = new this.model().setContext(context).load(defaultValue, true).setUuid(this.uuid);
if (withSave) {
await result.save();
}
return result;
}
/**
* Load a model from the known store
*
* @param this the class from which the static is called
* @param id of the object to load
* @param defaultValue if object not found return a default object
* @param context to set on the object
* @returns
*/
async getOrCreate(defaultValue, context, withSave = true) {
return (await this.get()) || this.create(defaultValue, context, withSave);
}
}
export class ModelRefCustom extends ModelRef {
constructor(uuid, model, data, parent) {
super(uuid, model, parent);
this.uuid = uuid;
Object.assign(this, data);
}
toJSON() {
return this;
}
getUuid() {
return this.uuid;
}
}
export const Emitters = new WeakMap();
/**
* Basic Object in Webda
*
* It is used to define a data stored
* Any variable starting with _ can only be set by the server
* Any variable starting with __ won't be exported outside of the server
*
* @class
* @WebdaModel
*/
class CoreModel {
constructor() {
this.__dirty = new Set();
this.__class = new.target;
// Get the store automatically now
this.__store = Core.get()?.getModelStore(new.target);
// Get the type automatically now
this.__type = process.env.WEBDA_V2_COMPATIBLE
? Core.get()?.getApplication().getModelFromInstance(this)
: Core.get()?.getApplication().getShortId(Core.get()?.getApplication().getModelFromInstance(this));
}
/**
* Listen to events on the model
* @param event
* @param listener
* @param async
*/
static on(event, listener, async = false) {
if (!Emitters.has(this)) {
Emitters.set(this, new EventEmitter());
}
// TODO Manage async
if (async) {
Core.get()
.getService("AsyncEvents")
.bindAsyncListener(this, event, listener);
}
else {
Emitters.get(this).on(event, listener);
}
return this;
}
/**
* Emit an event for this class
* @param this
* @param event
* @param evt
*/
static emit(event, evt) {
let clazz = this;
// @ts-ignore
while (clazz) {
// Emit for all parent class
if (Emitters.has(clazz)) {
EventEmitterUtils.emit(Emitters.get(clazz), event, evt);
}
// @ts-ignore
if (clazz === CoreModel) {
break;
}
clazz = Object.getPrototypeOf(clazz);
}
}
/**
* Emit an event for this class and wait for all listeners to finish
* @param this
* @param event
* @param evt
*/
static async emitSync(event, evt) {
let clazz = this;
let p = [];
// @ts-ignore
while (clazz) {
// Emit for all parent class
if (Emitters.has(clazz)) {
p.push(EventEmitterUtils.emitSync(Emitters.get(clazz), event, evt));
}
// @ts-ignore
if (clazz === CoreModel) {
break;
}
clazz = Object.getPrototypeOf(clazz);
}
await Promise.all(p);
}
/**
* Listen to events on the model asynchronously
* @param event
* @param listener
*/
static onAsync(event, listener, queue) {
return this.on(event, listener, true);
}
/**
*
* @param event
* @param listener
* @returns
*/
static addListener(event, listener) {
return this.on(event, listener);
}
static emitter(method, ...args) {
if (!Emitters.has(this)) {
Emitters.set(this, new EventEmitter());
}
// @ts-ignore
return Emitters.get(this)[method](...args);
}
static removeListener(...args) {
return this.emitter("removeListener", ...args);
}
static off(...args) {
return this.emitter("off", ...args);
}
static once(...args) {
return this.emitter("once", ...args);
}
static removeAllListeners(...args) {
return this.emitter("removeAllListeners", ...args);
}
static setMaxListeners(...args) {
return this.emitter("setMaxListeners", ...args);
}
static getMaxListeners(...args) {
return this.emitter("getMaxListeners", ...args);
}
static listeners(...args) {
return this.emitter("listeners", ...args);
}
static rawListeners(...args) {
return this.emitter("rawListeners", ...args);
}
static listenerCount(...args) {
return this.emitter("listenerCount", ...args);
}
static prependListener(...args) {
return this.emitter("prependListener", ...args);
}
static prependOnceListener(...args) {
return this.emitter("prependOnceListener", ...args);
}
static eventNames(...args) {
return this.emitter("eventNames", ...args);
}
/**
*
* @returns
*/
static getRelations() {
return Core.get()?.getApplication().getRelations(this);
}
/**
* Do not declare any public events by default
* @returns
*/
static getClientEvents() {
return [];
}
/**
* Does not allow any event by default
* @param _event
* @param _context
* @returns
*/
static authorizeClientEvent(_event, _context, _model) {
return false;
}
/**
* Get Store for this model
* @param this
* @returns
*/
static store() {
if (!Core.get()) {
throw new Error("Webda not initialized");
}
return Core.get().getModelStore(this);
}
/**
* Complete the uid with prefix if any
*
* Useful when object are stored with a prefix for full uuid
* @param uid
* @returns
*/
static completeUid(uid) {
return uid;
}
/**
* Return the known schema
* @returns
*/
static getSchema() {
const app = Core.get()?.getApplication();
return app?.getSchema(app.getModelFromConstructor(this));
}
/**
* Get a reference to a model
* @param this
* @param uid
* @returns
*/
static ref(uid) {
return new ModelRefWithCreate(uid, this);
}
/**
* Get a reference to a model
* @param this
* @param uid
* @returns
*/
static create(data) {
return new this().load(data, true).save();
}
/**
* Get identifier for this model
* @returns
*/
static getIdentifier(short = true) {
const res = Core.get().getApplication().getModelName(this);
if (short) {
return Core.get().getApplication().getShortId(res);
}
else {
return res;
}
}
/**
* Get the model hierarchy
*
* Ancestors will contain every model it inherits from
* Children will contain every model that inherits from this model in a tree structure
*/
static getHierarchy() {
return Core.get().getApplication().getModelHierarchy(this);
}
/**
* Unflat an object
* @param data
* @param split
* @returns
*/
static unflat(data, split = "#") {
const res = {};
for (let i in data) {
const attrs = i.split(split);
let attr = attrs.shift();
let cur = res;
while (attr) {
if (attrs.length) {
cur[attr] ?? (cur[attr] = {});
cur = cur[attr];
}
else {
cur[attr] = data[i];
}
attr = attrs.shift();
}
}
return res;
}
/**
* Create subobject for a model
*
* Useful for counters
*
* @param split
* @returns
*/
unflat(split = "#") {
return CoreModel.unflat(this, split);
}
/**
* Flat an object into another
*
* {
* a: {
* b: 1
* },
* c: 1
* }
*
* become
*
* {
* "a#b": 1
* "c": 1
* }
*
* @param target
* @param data
* @param split
* @param prefix
*/
static flat(target, data, split = "#", prefix = "") {
for (let i in data) {
if (typeof data[i] === "object") {
CoreModel.flat(target, data[i], split, i + split);
}
else {
target[prefix + i] = data[i];
}
}
}
/**
* Complete the query with __type/__types
* @param query
* @param includeSubclass
* @returns
*/
static completeQuery(query, includeSubclass = true) {
if (!query.includes("__type")) {
let condition;
const app = Core.get().getApplication();
const name = app.getShortId(app.getModelName(this));
if (includeSubclass) {
condition = `__types CONTAINS "${name}"`;
}
else {
condition = `__type = "${name}"`;
}
return WebdaQL.PrependCondition(query, condition);
}
return query;
}
/**
* Iterate through the model
*
* How to use a iterator is:
*
* ```
* for await (const model of CoreModel.iterate()) {
* // Do something with my model
* }
* ```
*
* @param this
* @param query
* @param includeSubclass
* @param context
* @returns
*/
static iterate(query = "", includeSubclass = true, context) {
// @ts-ignore
return this.store().iterate(this.completeQuery(query, includeSubclass), context);
}
/**
* Query for models
* @param this
* @param id
* @returns
*/
static async query(query = "", includeSubclass = true, context) {
// @ts-ignore
return this.store().query(this.completeQuery(query, includeSubclass), context);
}
/**
* Return a proxy to the object to detect if dirty
* @returns
*/
getProxy() {
const subProxier = prop => {
return {
set: (target, p, value) => {
this.__dirty.add(prop);
target[p] = value;
return true;
},
get: (target, p) => {
if (Array.isArray(target[p]) || target[p] instanceof Object) {
return new Proxy(target[p], subProxier(prop));
}
return target[p];
},
deleteProperty: (t, property) => {
delete t[property];
this.__dirty.add(prop);
return true;
}
};
};
const proxier = {
deleteProperty: (t, property) => {
delete t[property];
this.__dirty.add(property);
return true;
},
set: (target, p, value) => {
if (p !== "__dirty") {
target.__dirty.add(p);
}
target[p] = value;
return true;
},
get: (target, p) => {
if (typeof p === "string" && p.startsWith("__")) {
return target[p];
}
if (Array.isArray(target[p]) || target[p] instanceof Object) {
return new Proxy(target[p], subProxier(p));
}
return target[p];
}
};
return new Proxy(this, proxier);
}
/**
* Return true if needs a save
* @returns
*/
isDirty() {
return this.__dirty.size > 0;
}
/**
*
* @returns the uuid of the object
*/
getUuid() {
// @ts-ignore
return this[this.__class.getUuidField()];
}
/**
*
* @param uuid
* @param target
*/
setUuid(uuid, target = this) {
target[this.__class.getUuidField()] = uuid;
return target;
}
/**
* Get actions callable on an object
*
* This will expose them by the Store with /storeUrl/{uuid}/{action}
*/
static getActions() {
const actions = [];
// Explore all parent classes to collect all known actions
let clazz = this;
// @ts-ignore
while (clazz !== CoreModel) {
if (ActionsAnnotated.has(clazz)) {
actions.push(ActionsAnnotated.get(clazz));
}
clazz = Object.getPrototypeOf(clazz);
}
// Reduce right to give priority to the last class:
return actions.reduceRight((v, c) => ({ ...v, ...c }), {});
}
/**
* Return the expressable query for permission
*
* @param context of the query
* @returns
*/
static getPermissionQuery(_ctx) {
return null;
}
async checkAct(context, action) {
let msg = await this.canAct(context, action);
if (msg !== true) {
throw new WebdaError.Forbidden(msg === false ? "No permission" : msg);
}
}
/**
* By default nothing is permitted on a CoreModel
* @returns
*/
async canAct(_context, _action) {
return "This model does not support any action: override canAct";
}
/**
* Get the UUID property
*/
static getUuidField() {
return "uuid";
}
/**
* Create an object
* @returns
*/
static factory(object, context) {
return object instanceof this ? object : new this().setContext(context).load(object, context === undefined);
}
/**
* Detect what looks like a CoreModel but can be from different version
* @param object
* @returns
*/
static instanceOf(object) {
return (typeof object.toStoredJSON === "function" && object.__class && object.__class.factory && object.__class.instanceOf);
}
/**
* Return a unique reference within the application to the object
*
* It contains the Store containing it
* @returns
*/
getFullUuid() {
return `${this.__type.replace(/\//, "-")}$${this.getUuid()}`;
}
/**
* Get an object from the full uuid
* @param core
* @param fullUuid
* @param partials
* @returns
*/
static async fromFullUuid(fullUuid, core = Core.get(), partials) {
const [model, uuid] = fullUuid.split("$");
let modelObject = core.getApplication().getModel(model.replace("-", "/"));
if (partials) {
return new modelObject().load(partials, true).setUuid(uuid);
}
return new modelObject().setUuid(uuid).get();
}
/**
* Allow to define custom permission per attribute
*
* This method allows you to do permission based attribute
* But also a mask destructive attribute
*
* @param key
* @param value
* @param mode
* @param context
* @returns updated value
*/
attributePermission(key, value, mode, context) {
if (mode === "WRITE") {
return key.startsWith("_") ? undefined : value;
}
else {
return !key.startsWith("__") ? value : undefined;
}
}
/**
* Load an object from RAW
*
* @param raw data
* @param secure if false will ignore any _ variable
*/
load(raw, secure = false, relations = true) {
// Object assign with filter
for (let prop in raw) {
let val = raw[prop];
if (!secure) {
val = this.attributePermission(prop, raw[prop], "WRITE");
if (val === undefined) {
continue;
}
}
// @ts-ignore
this[prop] = val;
}
if (this._creationDate) {
this._creationDate = new Date(this._creationDate);
}
if (this._lastUpdate) {
this._lastUpdate = new Date(this._lastUpdate);
}
if (!this.getUuid()) {
this.setUuid(this.generateUid(raw));
}
if (relations) {
this.handleRelations();
}
return this;
}
/**
* Patch every attribute that is based on a relation
* to add all the helpers
*/
handleRelations() {
var _a, _b;
const rel = Core.get()
?.getApplication()
?.getRelations(this) || {};
for (let link of rel.links || []) {
const model = Core.get().getModel(link.model);
if (link.type === "LINK") {
this[_a = link.attribute] ?? (this[_a] = "");
if (typeof this[link.attribute] === "string") {
this[link.attribute] = new ModelRef(this[link.attribute], model, this);
}
}
else if (link.type === "LINKS_ARRAY") {
this[link.attribute] = new ModelLinksArray(model, this[link.attribute], this);
}
else if (link.type === "LINKS_SIMPLE_ARRAY") {
this[link.attribute] = new ModelLinksSimpleArray(model, this[link.attribute], this);
}
else if (link.type === "LINKS_MAP") {
this[link.attribute] = createModelLinksMap(model, this[link.attribute], this);
}
}
for (let link of rel.maps || []) {
this[link.attribute] = (this[link.attribute] || []).map(el => new ModelMapLoaderImplementation(Core.get().getModel(link.model), el, this));
}
for (let query of rel.queries || []) {
this[query.attribute] = new CoreModelQuery(query.model, this, query.targetAttribute);
}
if (rel.parent) {
this[_b = rel.parent.attribute] ?? (this[_b] = "");
if (typeof this[rel.parent.attribute] === "string") {
this[rel.parent.attribute] = new ModelRef(this[rel.parent.attribute], Core.get().getModel(rel.parent.model), this);
}
}
for (let binary of rel.binaries || []) {
if (binary.cardinality === "ONE") {
this[binary.attribute] = new Binary(binary.attribute, this);
}
else {
this[binary.attribute] = new BinariesImpl().assign(this, binary.attribute);
}
}
}
/**
* Context of the request
*/
setContext(ctx) {
this.__ctx = ctx;
return this;
}
/**
* Get object context
*
* Global object does not belong to a request
*/
getContext() {
return this.__ctx || Core.get().getGlobalContext();
}
/**
* Return the object registered store
*/
getStore() {
return this.__store;
}
/**
* Get the object
* @returns
*/
async get() {
return this.refresh();
}
/**
* Get the object again
*
* @throws Error if the object is not coming from a store
*/
async refresh() {
let obj = await this.__store.get(this.getUuid());
if (obj) {
Object.assign(this, obj);
for (let i in this) {
// @ts-ignore
if (obj[i] !== this[i]) {
delete this[i];
}
}
this.handleRelations();
}
return this;
}
/**
* Delete this object
*
* @throws Error if the object is not coming from a store
*/
async delete() {
return this.__store.delete(this);
}
/**
* Patch current object with this update
* @param obj
* @param conditionField if null no condition used otherwise fallback to lastUpdate
* @param conditionValue
*/
async patch(obj, conditionField, conditionValue) {
await this.__store.patch({ [this.__class.getUuidField()]: this.getUuid(), ...obj }, true, conditionField, conditionValue);
Object.assign(this, obj);
}
/**
* Save this object
*
* @throws Error if the object is not coming from a store
*/
async save(full, ...args) {
// If proxy is not used and not field specified call save
if ((!util.types.isProxy(this) && full === undefined) || full === true) {
if (!this._creationDate || !this._lastUpdate) {
await this.__store.create(this, this.getContext());
}
else {
await this.__store.update(this);
}
return this;
}
const patch = {
[this.__class.getUuidField()]: this.getUuid()
};
if (typeof full === "string") {
[full, ...args].forEach(k => {
patch[k] = this[k];
});
}
else {
for (let entry of this.__dirty.entries()) {
patch[entry[0]] = this[entry[0]];
}
}
await this.__store.patch(patch);
this.__dirty.clear();
return this;
}
/**
* Validate objet modification
*
* @param ctx
* @param updates
*/
async validate(ctx, updates, ignoreRequired = false) {
ctx.getWebda().validateSchema(this, updates, ignoreRequired);
return true;
}
/**
* Generate uuid for the object
*
* @param object
* @returns
*/
generateUid(_object = undefined) {
return uuidv4().toString();
}
/**
* Return the object to be serialized without the __store
*
* @param stringify
* @returns
*/
toStoredJSON(stringify = false) {
let obj = this._toJSON(true);
if (stringify) {
return JSON.stringify(obj);
}
return obj;
}
/**
* Get a pre typed service
*
* @param service to retrieve
* WARNING: Only object attached to a store can retrieve service
*/
getService(service) {
return this.__store.getService(service);
}
/**
* Remove the specific attributes if not secure
*
*
*
* @param secure serialize server fields also
* @returns filtered object to be serialized
*/
_toJSON(secure) {
let obj = {};
for (let i in this) {
let value = this[i];
if (!secure) {
value = this.attributePermission(i, value, "READ");
}
if (value === undefined)
continue;
if (value instanceof ModelRef) {
obj[i] = value.toString();
}
else if (value instanceof Binary) {
obj[i] = value.toJSON();
}
else {
obj[i] = value;
}
}
return obj;
}
/**
* Return the object without sensitive attributes
*
* @returns Object to serialize
*/
toJSON() {
return this._toJSON(false);
}
/**
* Called when object is about to be deleted
*/
async _onDelete() {
// Empty to be overriden
}
/**
* Called when object has been deleted
*/
async _onDeleted() {
// Empty to be overriden
}
/**
* Called when object is retrieved
*/
async _onGet() {
// Empty to be overriden
}
/**
* Called when object is about to be saved
*/
async _onSave() {
// Empty to be overriden
}
/**
* Called when object is saved
*/
async _onSaved() {
// Empty to be overriden
}
/**
* Called when object is about to be updates
*
* @param updates to be send
*/
async _onUpdate(_updates) {
// Empty to be overriden
}
/**
* Called when object is updated
*/
async _onUpdated() {
// Empty to be overriden
}
/**
* Set attribute on the object and database
* @param property
* @param value
*/
async setAttribute(property, value) {
await this.getRef().setAttribute(property, value);
this[property] = value;
}
/**
* Remove attribute from both the object and db
* @param property
*/
async removeAttribute(property) {
await this.getRef().removeAttribute(property);
delete this[property];
}
/**
* Increment an attribute both in store and object
* @param property
* @param value
*/
async incrementAttribute(property, value) {
return this.incrementAttributes([{ property, value }]);
}
/**
* Return a model ref
* @returns
*/
getRef() {
return new ModelRef(this.getUuid(), this.__class);
}
/**
* Increment a attributes both in store and object
* @param info
*/
async incrementAttributes(info) {
var _a;
await this.getRef().incrementAttributes(info);
for (let inc of info) {
this[_a = inc.property] ?? (this[_a] = 0);
this[inc.property] += inc.value;
}
}
}
__decorate([
NotEnumerable
], CoreModel.prototype, "__class", void 0);
__decorate([
NotEnumerable
], CoreModel.prototype, "__ctx", void 0);
__decorate([
NotEnumerable
], CoreModel.prototype, "__store", void 0);
__decorate([
NotEnumerable
], CoreModel.prototype, "__dirty", void 0);
/**
* CoreModel with a uuid
*/
class UuidModel extends CoreModel {
/**
* @override
*/
validate(ctx, updates, ignoreRequired) {
updates.uuid ?? (updates.uuid = this.generateUid());
return super.validate(ctx, updates, ignoreRequired);
}
}
export { CoreModel, UuidModel };
//# sourceMappingURL=coremodel.js.map