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;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
import ModelPermission from "../../../Types/BaseDatabase/ModelPermission";
import { getColumnAccessControlForAllColumns } from "../../../Types/Database/AccessControl/ColumnAccessControl";
import { getColumnBillingAccessControlForAllColumns } from "../../../Types/Database/AccessControl/ColumnBillingAccessControl";
import Columns from "../../../Types/Database/Columns";
import ColumnType from "../../../Types/Database/ColumnType";
import TableColumn, { getTableColumn, getTableColumns, } from "../../../Types/Database/TableColumn";
import TableColumnType from "../../../Types/Database/TableColumnType";
import { getFirstColorFieldColumn } from "../../../Types/Database/ColorField";
import BadDataException from "../../../Types/Exception/BadDataException";
import JSONFunctions from "../../../Types/JSONFunctions";
import ObjectID from "../../../Types/ObjectID";
import Text from "../../../Types/Text";
import { BaseEntity, CreateDateColumn, DeleteDateColumn, PrimaryGeneratedColumn, UpdateDateColumn, VersionColumn, } from "typeorm";
export default class DatabaseBaseModel extends BaseEntity {
    constructor(id) {
        super();
        this._id = undefined;
        this.createdAt = undefined;
        this.updatedAt = undefined;
        this.deletedAt = undefined;
        this.version = undefined;
        this.isPermissionIf = {};
        if (id) {
            this.id = id;
        }
    }
    getHashedColumns() {
        var _a;
        const dictionary = getTableColumns(this);
        const columns = [];
        for (const key in dictionary) {
            if ((_a = dictionary[key]) === null || _a === void 0 ? void 0 : _a.hashed) {
                columns.push(key);
            }
        }
        return new Columns(columns);
    }
    getDisplayColumnPlaceholderAs(columnName) {
        var _a;
        return ((_a = getTableColumn(this, columnName)) === null || _a === void 0 ? void 0 : _a.placeholder) || null;
    }
    getDisplayColumnTitleAs(columnName) {
        var _a;
        return ((_a = getTableColumn(this, columnName)) === null || _a === void 0 ? void 0 : _a.title) || null;
    }
    getDisplayColumnDescriptionAs(columnName) {
        var _a;
        return ((_a = getTableColumn(this, columnName)) === null || _a === void 0 ? void 0 : _a.description) || null;
    }
    getEncryptedColumns() {
        var _a;
        const dictionary = getTableColumns(this);
        const columns = [];
        for (const key in dictionary) {
            if ((_a = dictionary[key]) === null || _a === void 0 ? void 0 : _a.encrypted) {
                columns.push(key);
            }
        }
        return new Columns(columns);
    }
    getTableColumns() {
        return new Columns(Object.keys(getTableColumns(this)));
    }
    getFirstColorColumn() {
        return getFirstColorFieldColumn(this);
    }
    canQueryMultiTenant() {
        return Boolean(this.isMultiTenantRequestAllowed);
    }
    isUserQueryWithoutTenantAllowed() {
        return Boolean(this.allowUserQueryWithoutTenant);
    }
    getTableColumnMetadata(columnName) {
        const dictionary = getTableColumns(this);
        return dictionary[columnName];
    }
    hasColumn(columnName) {
        return Boolean(getTableColumn(this, columnName));
    }
    getColumnBillingAccessControl(columnName) {
        const dictionary = getColumnBillingAccessControlForAllColumns(this);
        return dictionary[columnName];
    }
    getColumnAccessControlFor(columnName) {
        return this.getColumnAccessControlForAllColumns()[columnName] || null;
    }
    getColumnAccessControlForAllColumns() {
        const dictionary = getColumnAccessControlForAllColumns(this);
        const defaultColumns = [
            "_id",
            "createdAt",
            "deletedAt",
            "updatedAt",
        ];
        for (const key of defaultColumns) {
            dictionary[key] = {
                read: this.readRecordPermissions,
                create: this.createRecordPermissions,
                update: this.updateRecordPermissions,
            };
        }
        return dictionary;
    }
    hasValue(columnName) {
        return Boolean(this[columnName]);
    }
    getValue(columnName) {
        return this[columnName];
    }
    setValue(columnName, value) {
        this[columnName] = value;
    }
    removeValue(columnName) {
        this[columnName] = undefined;
    }
    doesPermissionHaveConditions(permission) {
        return this.isPermissionIf[permission]
            ? this.isPermissionIf[permission]
            : null;
    }
    getUniqueColumns() {
        var _a;
        const dictionary = getTableColumns(this);
        const columns = [];
        for (const key in dictionary) {
            if ((_a = dictionary[key]) === null || _a === void 0 ? void 0 : _a.unique) {
                columns.push(key);
            }
        }
        return new Columns(columns);
    }
    setSlugifyColumn(columnName) {
        this.slugifyColumn = columnName;
    }
    getTotalItemsByColumnName() {
        return this.totalItemsByColumnName;
    }
    getTotalItemsByErrorMessage() {
        return this.totalItemsErrorMessage;
    }
    getTotalItemsNumber() {
        return this.totalItemsNumber;
    }
    getRequiredColumns() {
        var _a;
        const dictionary = getTableColumns(this);
        const columns = [];
        for (const key in dictionary) {
            if ((_a = dictionary[key]) === null || _a === void 0 ? void 0 : _a.required) {
                columns.push(key);
            }
        }
        return new Columns(columns);
    }
    getSlugifyColumn() {
        return this.slugifyColumn;
    }
    getCrudApiPath() {
        return this.crudApiPath;
    }
    getSaveSlugToColumn() {
        return this.saveSlugToColumn;
    }
    getTenantColumn() {
        return this.tenantColumn;
    }
    getAccessControlColumn() {
        return this.accessControlColumn;
    }
    getUserColumn() {
        return this.currentUserCanAccessColumnBy;
    }
    get id() {
        return this._id ? new ObjectID(this._id) : null;
    }
    set id(value) {
        if (value) {
            this._id = value.toString();
        }
    }
    isDefaultValueColumn(columnName) {
        return Boolean(getTableColumn(this, columnName).isDefaultValueColumn);
    }
    getColumnValue(columnName) {
        if (getTableColumn(this, columnName) && this[columnName]) {
            return this[columnName];
        }
        return null;
    }
    setColumnValue(columnName, value) {
        if (getTableColumn(this, columnName)) {
            return (this[columnName] = value);
        }
    }
    isTableColumn(columnName) {
        return Boolean(getTableColumn(this, columnName));
    }
    isEntityColumn(columnName) {
        const tableColumnType = getTableColumn(this, columnName);
        if (!tableColumnType) {
            throw new BadDataException("TableColumnMetadata not found for " + columnName + " column");
        }
        return Boolean(tableColumnType.type === TableColumnType.Entity ||
            tableColumnType.type === TableColumnType.EntityArray);
    }
    isHashedStringColumn(columnName) {
        const tableColumnType = getTableColumn(this, columnName);
        if (!tableColumnType) {
            throw new BadDataException("TableColumnMetadata not found for " + columnName + " column");
        }
        return Boolean(tableColumnType.type === TableColumnType.HashedString);
    }
    isFileColumn(columnName) {
        const tableColumnType = getTableColumn(this, columnName);
        if (!tableColumnType || !tableColumnType.modelType) {
            return false;
        }
        const fileModel = new tableColumnType.modelType();
        if (fileModel.isFileModel()) {
            return true;
        }
        return false;
    }
    hasPermission(_permissions) {
        return false;
    }
    isTenantModel() {
        return false;
    }
    isFileModel() {
        return false;
    }
    isAccessControlModel() {
        return false;
    }
    isUserModel() {
        return false;
    }
    hasCreatePermissions(userProjectPermissions, columnName) {
        let modelPermission = this.createRecordPermissions;
        if (columnName) {
            const columnAccessControl = this.getColumnAccessControlFor(columnName);
            if (columnAccessControl) {
                modelPermission = columnAccessControl.create;
            }
        }
        return ModelPermission.hasPermissions(userProjectPermissions, modelPermission);
    }
    getReadPermissions() {
        return this.readRecordPermissions;
    }
    getReadBillingPlan() {
        return this.readBillingPlan;
    }
    getCreateBillingPlan() {
        return this.createBillingPlan;
    }
    getUpdateBillingPlan() {
        return this.updateBillingPlan;
    }
    getDeleteBillingPlan() {
        return this.deleteBillingPlan;
    }
    getCreatePermissions() {
        return this.createRecordPermissions;
    }
    getUpdatePermissions() {
        return this.updateRecordPermissions;
    }
    getDeletePermissions() {
        return this.deleteRecordPermissions;
    }
    hasReadPermissions(userProjectPermissions, columnName) {
        let modelPermission = this.readRecordPermissions;
        if (columnName) {
            const columnAccessControl = this.getColumnAccessControlFor(columnName);
            if (columnAccessControl) {
                modelPermission = columnAccessControl.read;
            }
        }
        return ModelPermission.hasPermissions(userProjectPermissions, modelPermission);
    }
    hasDeletePermissions(userProjectPermissions) {
        const modelPermission = this.deleteRecordPermissions;
        return ModelPermission.hasPermissions(userProjectPermissions, modelPermission);
    }
    hasUpdatePermissions(userProjectPermissions, columnName) {
        let modelPermission = this.updateRecordPermissions;
        if (columnName) {
            const columnAccessControl = this.getColumnAccessControlFor(columnName);
            if (columnAccessControl) {
                modelPermission = columnAccessControl.update;
            }
        }
        return ModelPermission.hasPermissions(userProjectPermissions, modelPermission);
    }
    getAPIDocumentationPath() {
        return Text.pascalCaseToDashes(this.tableName);
    }
    static toJSON(model, modelType) {
        const json = this.toJSONObject(model, modelType);
        return JSONFunctions.serialize(json);
    }
    static toJSONObject(model, modelType) {
        const json = {};
        const vanillaModel = new modelType();
        for (const key of vanillaModel.getTableColumns().columns) {
            if (model[key] === undefined) {
                continue;
            }
            const tableColumnMetadata = vanillaModel.getTableColumnMetadata(key);
            if (tableColumnMetadata) {
                if (model[key] &&
                    tableColumnMetadata.modelType &&
                    tableColumnMetadata.type === TableColumnType.Entity &&
                    model[key] instanceof DatabaseBaseModel) {
                    json[key] = this.toJSONObject(model[key], tableColumnMetadata.modelType);
                }
                else if (model[key] &&
                    Array.isArray(model[key]) &&
                    model[key].length > 0 &&
                    tableColumnMetadata.modelType &&
                    tableColumnMetadata.type === TableColumnType.EntityArray) {
                    json[key] = this.toJSONObjectArray(model[key], tableColumnMetadata.modelType);
                }
                else {
                    json[key] = model[key];
                }
            }
        }
        return json;
    }
    static toJSONObjectArray(list, modelType) {
        const array = [];
        for (const item of list) {
            array.push(this.toJSONObject(item, modelType));
        }
        return array;
    }
    static toJSONArray(list, modelType) {
        const array = [];
        for (const item of list) {
            array.push(this.toJSON(item, modelType));
        }
        return array;
    }
    static _fromJSON(json, type) {
        if (json instanceof DatabaseBaseModel) {
            return json;
        }
        json = JSONFunctions.deserialize(json);
        const baseModel = new type();
        for (let key of Object.keys(json)) {
            if (key === "id") {
                key = "_id";
                json["_id"] = json["id"];
                delete json["id"];
            }
            const tableColumnMetadata = baseModel.getTableColumnMetadata(key);
            if (tableColumnMetadata) {
                if (json[key] &&
                    tableColumnMetadata.modelType &&
                    tableColumnMetadata.type === TableColumnType.Entity) {
                    if (json[key] &&
                        Array.isArray(json[key]) &&
                        json[key].length > 0) {
                        json[key] = json[key][0];
                    }
                    baseModel[key] = this.fromJSON(json[key], tableColumnMetadata.modelType);
                }
                else if (json[key] &&
                    tableColumnMetadata.modelType &&
                    tableColumnMetadata.type === TableColumnType.EntityArray) {
                    if (json[key] && !Array.isArray(json[key])) {
                        json[key] = [json[key]];
                    }
                    baseModel[key] = this.fromJSONArray(json[key], tableColumnMetadata.modelType);
                }
                else {
                    baseModel[key] = json[key];
                }
            }
        }
        return baseModel;
    }
    static fromJSON(json, type) {
        if (Array.isArray(json)) {
            const arr = [];
            for (const item of json) {
                if (item instanceof DatabaseBaseModel) {
                    arr.push(item);
                    continue;
                }
                arr.push(this._fromJSON(item, type));
            }
            return arr;
        }
        if (json instanceof DatabaseBaseModel) {
            return json;
        }
        return this._fromJSON(json, type);
    }
    static fromJSONObject(json, type) {
        if (json instanceof DatabaseBaseModel) {
            return json;
        }
        return this.fromJSON(json, type);
    }
    static fromJSONArray(json, type) {
        const arr = [];
        for (const item of json) {
            arr.push(this._fromJSON(item, type));
        }
        return arr;
    }
}
__decorate([
    TableColumn({
        title: "ID",
        type: TableColumnType.ObjectID,
        description: "ID of this object",
        computed: true,
        canReadOnRelationQuery: true,
    }),
    PrimaryGeneratedColumn("uuid"),
    __metadata("design:type", String)
], DatabaseBaseModel.prototype, "_id", void 0);
__decorate([
    TableColumn({
        title: "Created At",
        type: TableColumnType.Date,
        computed: true,
        description: "Date and Time when the object was created.",
    }),
    CreateDateColumn({
        type: ColumnType.Date,
    }),
    __metadata("design:type", Date)
], DatabaseBaseModel.prototype, "createdAt", void 0);
__decorate([
    TableColumn({
        title: "Updated At",
        type: TableColumnType.Date,
        computed: true,
        description: "Date and Time when the object was updated.",
    }),
    UpdateDateColumn({
        type: ColumnType.Date,
    }),
    __metadata("design:type", Date)
], DatabaseBaseModel.prototype, "updatedAt", void 0);
__decorate([
    TableColumn({
        title: "Deleted At",
        type: TableColumnType.Date,
        computed: true,
        description: "Date and Time when the object was deleted.",
    }),
    DeleteDateColumn({
        type: ColumnType.Date,
    }),
    __metadata("design:type", Date)
], DatabaseBaseModel.prototype, "deletedAt", void 0);
__decorate([
    TableColumn({
        title: "Version",
        type: TableColumnType.Number,
        computed: true,
        description: "Object version",
        hideColumnInDocumentation: true,
    }),
    VersionColumn(),
    __metadata("design:type", Number)
], DatabaseBaseModel.prototype, "version", void 0);
//# sourceMappingURL=DatabaseBaseModel.js.map