const { throwTypeError } = require("./Errors");

/**
 * Prepares a new Update
 */
class Update{
    #instance;
    #database;
    #table;

    #data;
    #where;
    #whereValues;
    #force;
    constructor(instance, defaultDatabase, table){
        this.#instance = instance;
        this.#database = defaultDatabase;
        this.#table = table;
    }

    /**
     * Updates all matching rows with the given object
     * @param {Object} object - The object with the data to update. Keys represent column names
     * @returns {this}
     */
    data(object){
        if (!object) throw new Error("data object must not be empty");
        if (typeof object !== "object") throwTypeError("object", object);
        this.#data = object;
        return this;
    }

    /**
     * Selects a database for this query
     * @param {String} database - Name of the database
     * @returns {this}
     */
    selectDatabase(database){
        if (!database) throw new Error("database must not be empty");
        if (typeof database !== "string") throwTypeError("string", database);
        this.#database = database;
        return this;
    }

    /**
     * Enables update of all rows
     * @returns {this}
     */
    force(){
        this.#force = true;
        return this;
    }

    /**
     * Adds a where-clause to the query
     * - Values should be set as ? in the string and given in left-to-right order via the 'values'-array to minimize the risk of sql-injection
     * @param {String} string - The where-clause as a string with ? representing each values.
     * @param {Array<Any>} values - Array containing values replacing the ? in the string (from left to right) 
     * @returns {this}
     */
    where(string, values=[]){
        if (!string) throw new Error("string must not be empty");
        if (typeof string !== "string") throwTypeError("string", string);
        if (!Array.isArray(values)) throwTypeError("array", values);
        this.#where = string;
        this.#whereValues = values;
        return this;
    }

    /**
     * Executes the prepared querry
     * @returns {Any}
     */
    async execute(){
        if (!this.#instance.isConnected()) throw new Error(`Can't execute query: Instance has no connection`);
        if (!this.#database) throw new Error(`Can't execute query: Database not selected`);
        if (!this.#where && !this.#force) throw new Error("Update: Tried to update all rows. If this was intentional, use .force() on Update");
        const values = [];
        const queryString = `UPDATE ${this.#database}.${this.#table} SET ${Object.keys(this.#data).map(col=>{values.push(this.#data[col]);return `${col}=?`})}${this.#where&&` WHERE ${this.#where}`}`;
        this.#where&&values.push(...this.#whereValues);
        return await this.#instance.queryRaw(queryString, values);
    }
}
module.exports = Update;