forked from geolba/tethys.backend
120 lines
4.1 KiB
TypeScript
120 lines
4.1 KiB
TypeScript
|
import { BaseModel as LucidBaseModel } from '@ioc:Adonis/Lucid/Orm';
|
||
|
// import { ManyToManyQueryClient } from '@ioc:Adonis/Lucid/Orm';
|
||
|
|
||
|
// export class CustomManyToManyQueryClient extends ManyToManyQueryClient {
|
||
|
// public attach(
|
||
|
// relatedIds: any | any[],
|
||
|
// pivotAttributes: any = {},
|
||
|
// trx?: ReturnType<typeof this.model.transaction>
|
||
|
// ) {
|
||
|
// return super.attach(relatedIds, (row) => {
|
||
|
// row.pivot.fill(pivotAttributes);
|
||
|
// }, trx);
|
||
|
// }
|
||
|
// }
|
||
|
|
||
|
/**
|
||
|
* Helper to find if value is a valid Object or
|
||
|
* not
|
||
|
*/
|
||
|
export function isObject(value: any): boolean {
|
||
|
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
||
|
}
|
||
|
|
||
|
export default class BaseModel extends LucidBaseModel {
|
||
|
/**
|
||
|
* When `fill` method is called, then we may have a situation where it
|
||
|
* removed the values which exists in `original` and hence the dirty
|
||
|
* diff has to do a negative diff as well
|
||
|
*/
|
||
|
// private fillInvoked: boolean = false;
|
||
|
|
||
|
public static fillable: string[] = [];
|
||
|
|
||
|
public fill(attributes: any, allowExtraProperties: boolean = false): this {
|
||
|
this.$attributes = {};
|
||
|
// const Model = this.constructor as typeof BaseModel;
|
||
|
|
||
|
// for (const key in attributes) {
|
||
|
// if (Model.fillable.includes(key)) {
|
||
|
// const value = attributes[key];
|
||
|
// if (Model.$hasColumn(key)) {
|
||
|
// this[key] = value;
|
||
|
// }
|
||
|
// }
|
||
|
// }
|
||
|
this.mergeFillableAttributes(attributes, allowExtraProperties);
|
||
|
// this.fillInvoked = true;
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Merge bulk attributes with existing attributes.
|
||
|
*
|
||
|
* 1. If key is unknown, it will be added to the `extras` object.
|
||
|
* 2. If key is defined as a relationship, it will be ignored and one must call `$setRelated`.
|
||
|
*/
|
||
|
public mergeFillableAttributes(values: any, allowExtraProperties: boolean = false): this {
|
||
|
const Model = this.constructor as typeof BaseModel;
|
||
|
|
||
|
/**
|
||
|
* Merge values with the attributes
|
||
|
*/
|
||
|
if (isObject(values)) {
|
||
|
// Object.keys(values).forEach((key) => {
|
||
|
for (const key in values) {
|
||
|
if (Model.fillable.includes(key)) {
|
||
|
const value = values[key];
|
||
|
|
||
|
/**
|
||
|
* Set as column
|
||
|
*/
|
||
|
if (Model.$hasColumn(key)) {
|
||
|
this[key] = value;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Resolve the attribute name from the column names. Since people
|
||
|
* usaully define the column names directly as well by
|
||
|
* accepting them directly from the API.
|
||
|
*/
|
||
|
const attributeName = Model.$keys.columnsToAttributes.get(key);
|
||
|
if (attributeName) {
|
||
|
this[attributeName] = value;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* If key is defined as a relation, then ignore it, since one
|
||
|
* must pass a qualified model to `this.$setRelated()`
|
||
|
*/
|
||
|
if (Model.$relationsDefinitions.has(key)) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* If the property already exists on the model, then set it
|
||
|
* as it is vs defining it as an extra property
|
||
|
*/
|
||
|
if (this.hasOwnProperty(key)) {
|
||
|
this[key] = value;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Raise error when not instructed to ignore non-existing properties.
|
||
|
*/
|
||
|
if (!allowExtraProperties) {
|
||
|
throw new Error(`Cannot define "${key}" on "${Model.name}" model, since it is not defined as a model property`);
|
||
|
}
|
||
|
|
||
|
this.$extras[key] = value;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return this;
|
||
|
}
|
||
|
}
|