Source: models/maps/_Global.js

const ValidateSchema = require('../../validation/validateSchema');
const CRUD = require('../../services/database/crud');
const { isObjectID } = require('../../helpers/database/relationalFields');
const { increaseDocProp } = require('../../helpers/database/dbHelpers');

/**
 * Represents a global map in the application, extending the ValidateSchema class.
 * @module GlobalMap
 * @extends ValidateSchema
 * @namespace Models
 */
class GlobalMap extends ValidateSchema {
    /**
     * Creates a new instance of the GlobalMap class.
     * @param {Object} setup - The setup object.
     * @param {Object} parent - The parent object.
     * @throws {Error} If the creation of GlobalMap fails.
     */
    constructor(setup, parent) {
        super(setup.validationRules || {});
        if (isObjectID(setup)) return;

        const User = require('@models/collections/User');
        const { _id, index, author, cod, createdAt, modifiedAt, collectionName} = setup || {};

        try {
            this.collectionName = collectionName;
            this._id = _id && _id.toString();
            this.index = index;
            this.author = author || User.currentUser();
            this.cod = cod;
            this.createdAt = createdAt && new Date(createdAt).toLocaleString();
            this.modifiedAt = modifiedAt && new Date(modifiedAt).toLocaleString();
    
            this.getParent = () => parent;
        } catch (err) {
            throw new Error.Log(err);
        }
    }

    /**
     * Returns the parent object of the GlobalMap instance.
     * @returns {Object} - The parent object.
     */
    get parent() {
        return this.getParent();
    }

    /**
     * Returns the string representation of the index property.
     * @returns {string} - The string representation of the index property.
     */
    get stringIndex() {
        return String(this.index);
    }

    /**
     * Asynchronously retrieves the current user associated with the GlobalMap instance.
     * @returns {Promise<Object>} - A promise resolving to the current user object.
     * @throws {Error} If there is an error during the retrieval process.
     */
    async getCurrentUser() {
        const User = require('@models/collections/User');
        const UID = User.currentUser();
        const user = await CRUD.getDoc({
            collectionName: 'users',
            filter: UID
        }).initialize();

        return user;
    }

    /**
     * Asynchronously saves the GlobalMap instance to the database.
     * @param {string} collectionName - The name of the collection to save the instance.
     * @returns {Promise<GlobalMap>} - A promise resolving to the saved GlobalMap instance.
     * @throws {Error} If there is an error during the saving process.
     */
    async saveDB(collectionName) {
        try {
            const created = await CRUD.create(collectionName || this.collectionName, {...this});

            if (created instanceof Error.Log) {
                return new Error.Log(created);
            }

            if (created) {
                Object.entries(created.initialize() || {}).map(([key, value]) => {
                    this[key] = value;
                });
    
                return this;
            }

            throw new Error.Log(created);
        } catch (err) {
            throw new Error.Log(err);
        }
    }

    /**
     * Asynchronously loads the GlobalMap instance from the database.
     * @param {string} collectionName - The name of the collection to load the instance.
     * @returns {Promise<GlobalMap>} - A promise resolving to the loaded GlobalMap instance.
     * @throws {Error} If there is an error during the loading process.
     */
    async loadDB(collectionName) {
        if (!collectionName) {
            collectionName = this.collectionName;
        }

        try {
            const loaded = await CRUD.getDoc({collectionName, filter: this._id}).defaultPopulate();
            
            if (loaded instanceof Error.Log) {
                throw new Error.Log(loaded);
            }

            return loaded.initialize();
        } catch (err) {
            throw new Error.Log(err);
        }
    }

    /**
     * Asynchronously updates the GlobalMap instance in the database.
     * @param {Object} updateParams - The update parameters including collectionName, filter, and data.
     * @returns {Promise<GlobalMap>} - A promise resolving to the updated GlobalMap instance.
     * @throws {Error} If there is an error during the update process.
     */
    async updateDB({collectionName, filter, data}) {
        const collection = collectionName || this.collectionName;

        try {
            if (!collection) throw new Error.Log('database.missing_params', 'collectionName', '_Global.updateDB');

            const loaded = await CRUD.update({collectionName: collection, filter: filter || this._id, data, options: {returnDocs: true} });
            if (loaded instanceof Error.Log) {
                throw new Error.Log(loaded);
            }

            return loaded.initialize();
        } catch (err) {
            throw new Error.Log(err);
        }
    }

    /**
     * Asynchronously deletes the GlobalMap instance from the database.
     * @param {string} collectionName - The name of the collection to delete the instance.
     * @param {Object} filter - The filter object for deletion.
     * @returns {Promise<Object>} - A promise resolving to the deletion result.
     * @throws {Error} If there is an error during the deletion process.
     */
    async deleteDB(collectionName, filter) {
        try {
            const deleted = await CRUD.del({
                collectionName: collectionName || this.collectionName,
                filter: filter || this._id
            });

            if (deleted instanceof Error.Log) {
                throw deleted;
            }

            return deleted;
        } catch (err) { 
            throw new Error.Log(err);
        }
    }

    /**
     * Asynchronously increases a property value in the GlobalMap instance.
     * @param {string} propKey - The property key to increase.
     * @param {number} value - The value by which the property should be increased (default is 1).
     * @returns {Promise<GlobalMap>} - A promise resolving to the updated GlobalMap instance.
     * @throws {Error} If there is an error during the property increase process.
     */
    async increaseProp(propKey, value) {
        if (!propKey) throw new Error.Log()
        const increaseAmount = value || 1;
        const increaseValue = {[propKey]: increaseAmount};

        try {
            if (!this.collectionName || !propKey) {
                return new Error.Log('database.missing_params', ['this.collectionName', 'propKey'], '_Global.updateDB')
            }

            const increased = await increaseDocProp(this.collectionName, {_id: this._id}, increaseValue);
            if (increased instanceof Error.Log) {
                return increased;
            }

            increased[propKey] = increased[propKey] + increaseAmount;
            return increased;
        } catch (err) {
            throw new Error.Log('helpers.increase_doc_prop', this.collectionName, this._id, increaseValue);
        }
    }
}

module.exports = GlobalMap;