"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MySQLSchemaField = void 0;
const HotStaq_1 = require("../../HotStaq");
/**
 * The database field.
 */
class MySQLSchemaField {
    constructor(name, dataType = "", defaultValue = "", primaryKey = false, notNull = true, uniqueIndex = false, binaryColumn = false, unsignedDataType = false, fillZeroes = false, autoIncrement = false, generatedColumn = false, strAroundDefaultValue = "'") {
        if (typeof (name) === "string") {
            this.name = name;
            this.dataType = dataType;
            this.primaryKey = primaryKey;
            this.notNull = notNull;
            this.uniqueIndex = uniqueIndex;
            this.binaryColumn = binaryColumn;
            this.unsignedDataType = unsignedDataType;
            this.fillZeroes = fillZeroes;
            this.autoIncrement = autoIncrement;
            this.generatedColumn = generatedColumn;
            this.defaultValue = defaultValue;
            this.strAroundDefaultValue = strAroundDefaultValue;
        }
        else {
            this.name = name.name;
            this.dataType = name.dataType;
            this.primaryKey = name.primaryKey != null ? name.primaryKey : primaryKey;
            this.notNull = name.notNull != null ? name.notNull : notNull;
            this.uniqueIndex = name.uniqueIndex != null ? name.uniqueIndex : uniqueIndex;
            this.binaryColumn = name.binaryColumn != null ? name.binaryColumn : binaryColumn;
            this.unsignedDataType = name.unsignedDataType != null ? name.unsignedDataType : unsignedDataType;
            this.fillZeroes = name.fillZeroes != null ? name.fillZeroes : fillZeroes;
            this.autoIncrement = name.autoIncrement != null ? name.autoIncrement : autoIncrement;
            this.generatedColumn = name.generatedColumn != null ? name.generatedColumn : generatedColumn;
            this.defaultValue = name.defaultValue === undefined ? defaultValue : name.defaultValue;
            this.strAroundDefaultValue =
                name.strAroundDefaultValue === undefined ? strAroundDefaultValue : name.strAroundDefaultValue;
        }
        if (this.dataType == null)
            throw new Error(`No data type given for field ${this.name}`);
    }
    /**
     * Compare two different fields. This will iterate through all keys in each field. Any
     * string values found will have stringFilter applied to it, removing everything that
     * is in that stringFilter regex. Additionally for any empty strings found it will
     * compare to any undefined/null on the other side, and treat them as the same.
     *
     * @param field1 The first field to compare.
     * @param field2 The second field to compare.
     * @param onlyKeys Only compare using the provided keys. If set to null, this will compare
     * using all of the keys in these objects.
     * @param stringFilter The regex to be used to help make any filters on any detected
     * strings. The default regex provided will remove any whitespaces, single/doube quotes,
     * back ticks, and parenthesis. If this is set to null, it will not be used.
     */
    static compare(field1, field2, onlyKeys = null, stringFilter = new RegExp("(\\s+|\\'+|\\\"+|\\`+|\\(+|\\)+)", "g")) {
        if (onlyKeys == null) {
            onlyKeys = ["name", "dataType", "primaryKey", "notNull",
                "uniqueIndex", "binaryColumn", "unsignedDataType",
                "fillZeroes", "autoIncrement", "generatedColumn",
                "defaultValue"];
        }
        // Go through each key in both fields and compare the values.
        for (let iIdx = 0; iIdx < onlyKeys.length; iIdx++) {
            let key = onlyKeys[iIdx];
            // @ts-ignore
            let field1Value = field1[key];
            // @ts-ignore
            let field2Value = field2[key];
            if (stringFilter != null) {
                // If the key is a string, make them lowercase, remove any 
                // spaces and compare.
                if (typeof (field1Value) === "string") {
                    if ((field1Value != null) && (field2Value != null)) {
                        field1Value = field1Value.toLowerCase();
                        field2Value = field2Value.toLowerCase();
                        field1Value = field1Value.replace(stringFilter, "");
                        field2Value = field2Value.replace(stringFilter, "");
                    }
                    // Make exceptions here for when field1Value or field2Value is null
                    if (field1Value == "") {
                        if (field2Value == null)
                            continue;
                    }
                    if (field2Value == "") {
                        if (field1Value == null)
                            continue;
                    }
                }
            }
            if (field1Value !== field2Value)
                return (false);
        }
        return (true);
    }
    /**
     * Parse a JSON object and get a MySQLSchemaField object from it.
     * Warning! This is only partially implemented. This will not check
     * the following fields:
     * * Binary column
     * * unique
     * * zero-filled
     * * generated column
     */
    static parse(json) {
        let result = new MySQLSchemaField("");
        if (json["name"] != null)
            result.name = json["name"];
        if (json["Name"] != null)
            result.name = json["Name"];
        if (json["field"] != null)
            result.name = json["field"];
        if (json["Field"] != null)
            result.name = json["Field"];
        if (json["Type"] != null) {
            result.dataType = json["Type"];
            const pos = result.dataType.indexOf("unsigned");
            if (pos > -1) {
                result.dataType = result.dataType.substr(0, (pos - 1));
                result.unsignedDataType = true;
            }
        }
        if (json["Null"] != null)
            result.notNull = !HotStaq_1.HotStaq.parseBoolean(json["Null"]);
        if (json["Key"] != null) {
            let keyType = json["Key"];
            keyType = keyType.toLowerCase();
            if (keyType === "pri")
                result.primaryKey = true;
        }
        if (json["Extra"] != null) {
            let extraValue = json["Extra"];
            extraValue = extraValue.toLowerCase();
            if (extraValue === "auto_increment")
                result.autoIncrement = true;
        }
        if (json["Default"] != null)
            result.defaultValue = json["Default"];
        return (result);
    }
    /**
     * Generate the db command.
     */
    generate() {
        return __awaiter(this, void 0, void 0, function* () {
            let result = {
                "field": "",
                "constraint": "",
                "foreignKey": "",
                "primaryKey": "",
                "key": ""
            };
            let additionalStr = "";
            let defaultValue = this.defaultValue;
            const lowerDataType = this.dataType.toLowerCase();
            let strAroundDefaultValue = this.strAroundDefaultValue;
            if ((lowerDataType.indexOf("int") > 0) ||
                (lowerDataType.indexOf("float") > 0) ||
                (lowerDataType.indexOf("decimal") > 0)) {
                strAroundDefaultValue = "";
            }
            if ((lowerDataType.indexOf("date") > 0) ||
                (lowerDataType.indexOf("time") > 0) ||
                (lowerDataType.indexOf("year") > 0)) {
                strAroundDefaultValue = "";
            }
            if (this.unsignedDataType === true)
                additionalStr += "unsigned ";
            if (this.notNull === true) {
                additionalStr += "NOT NULL ";
                if (defaultValue === null)
                    throw new Error(`Field ${this.name} cannot have a default value of null when notNull is set to true.`);
                if (defaultValue !== "")
                    defaultValue = `${strAroundDefaultValue}${defaultValue}${strAroundDefaultValue}`;
            }
            else {
                additionalStr += "NULL ";
                if (defaultValue === null)
                    defaultValue = "NULL";
                else
                    defaultValue = `${strAroundDefaultValue}${defaultValue}${strAroundDefaultValue}`;
            }
            if (this.autoIncrement === true)
                additionalStr += "AUTO_INCREMENT ";
            if (defaultValue === "") {
                if ((lowerDataType.indexOf("int") > 0) ||
                    (lowerDataType.indexOf("float") > 0) ||
                    (lowerDataType.indexOf("decimal") > 0)) {
                    defaultValue = `0`;
                }
                else
                    defaultValue = `${strAroundDefaultValue}${strAroundDefaultValue}`;
            }
            let defaultValueStr = "";
            if (this.autoIncrement === false)
                defaultValueStr = ` DEFAULT ${defaultValue}`;
            result.field = `\`${this.name}\` ${this.dataType} ${additionalStr}${defaultValueStr}`;
            if (this.primaryKey === true)
                result.primaryKey = `${this.name}`;
            if (this.uniqueIndex === true)
                result.key = `UNIQUE KEY \`${this.name}_UNIQUE\` (\`${this.name}\`)`;
            return (result);
        });
    }
}
exports.MySQLSchemaField = MySQLSchemaField;
//# sourceMappingURL=MySQLSchemaField.js.map