diff --git a/engine/db/add.js b/engine/db/add.js new file mode 100644 index 0000000..f8f931c --- /dev/null +++ b/engine/db/add.js @@ -0,0 +1,154 @@ +/** + * Imports: Handle imports + */ + +const encrypt = require("../../functions/encrypt"); +const handler = require("../utils/handler"); +const sanitizeHtml = require("sanitize-html"); +const sanitizeHtmlOptions = require("../utils/sanitizeHtmlOptions"); + +/** + * add Function + * ============================================================================== + * @description Description + * + * @param {object} params - An object containing the function parameters. + * @param {string} params.dbFullName - Database full name + * @param {string} params.tableName - Table name + * @param {object} params.data - Data to add + * @param {DSQL_TableSchemaType?} params.tableSchema - Table schema + * @param {string?} params.duplicateColumnName - Duplicate column name + * @param {string?} params.duplicateColumnValue - Duplicate column value + * @param {boolean?} params.update - Update this row if it exists + * @param {string?} params.dbHost - Database host + * @param {string?} params.dbPassword - Database password + * @param {string?} params.dbUsername - Database username + * @param {string?} params.encryptionKey - Encryption key + * @param {string?} params.encryptionSalt - Encryption salt + * + * @returns {object} + */ +module.exports = async function add({ dbFullName, tableName, data, tableSchema, duplicateColumnName, duplicateColumnValue, update, dbHost, dbPassword, dbUsername, encryptionKey, encryptionSalt }) { + /** + * Initialize variables + */ + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + /** + * Handle function logic + */ + if (duplicateColumnName && typeof duplicateColumnName === "string") { + const duplicateValue = await handler({ + queryString: `SELECT * FROM \`${tableName}\` WHERE \`${duplicateColumnName}\`=?`, + queryValuesArray: [duplicateColumnValue], + database: dbFullName, + dbHost, + dbPassword, + dbUsername, + }); + + if (duplicateValue && duplicateValue[0] && !update) { + return null; + } else if (duplicateValue && duplicateValue[0] && update) { + return await update(); + } + } else if (duplicateColumnName && typeof duplicateColumnName === "object" && duplicateColumnValue && typeof duplicateColumnValue === "object") { + const duplicateArray = duplicateColumnName.map((dupColName, index) => { + return `\`${dupColName}\`='${duplicateColumnValue[index]}'`; + }); + + const duplicateValue = await handler({ + queryString: `SELECT * FROM ${tableName} WHERE ${duplicateArray.join(" AND ")}`, + database: dbFullName, + }); + + if (duplicateValue && duplicateValue[0] && !update) { + return null; + } + } + + /** + * Declare variables + * + * @description Declare "results" variable + */ + const dataKeys = Object.keys(data); + + let insertKeysArray = []; + let insertValuesArray = []; + + for (let i = 0; i < dataKeys.length; i++) { + const dataKey = dataKeys[i]; + let value = data[dataKey]; + + const targetFieldSchemaArray = tableSchema ? tableSchema?.fields.filter((field) => field.fieldName === dataKey) : null; + const targetFieldSchema = targetFieldSchemaArray && targetFieldSchemaArray[0] ? targetFieldSchemaArray[0] : null; + + if (!value) continue; + + if (targetFieldSchema?.encrypted) { + value = encrypt({ data: value, encryptionKey, encryptionSalt }); + } + + if (targetFieldSchema?.richText) { + value = sanitizeHtml(value, sanitizeHtmlOptions).replace(/\n|\r|\n\r/gm, ""); + } + + insertKeysArray.push("`" + dataKey + "`"); + + if (typeof value === "object") { + value = JSON.stringify(value); + } + + insertValuesArray.push(dataValue); + } + + /** ********************************************** */ + + insertKeysArray.push("date_created"); + insertValuesArray.push(Date()); + + insertKeysArray.push("date_created_code"); + insertValuesArray.push(Date.now()); + + /** ********************************************** */ + + insertKeysArray.push("date_updated"); + insertValuesArray.push(Date()); + + insertKeysArray.push("date_updated_code"); + insertValuesArray.push(Date.now()); + + /** ********************************************** */ + + const query = `INSERT INTO \`${tableName}\` (${insertKeysArray.join(",")}) VALUES (${insertValuesArray.map(() => "?").join(",")})`; + const queryValuesArray = insertValuesArray; + + // const newInsert = await dbHandler(query, queryValuesArray); + + // const query = `INSERT INTO ${tableName} (${insertKeysArray.join(",")}) VALUES (${insertValuesArray.join(",")})`; + + const newInsert = await handler({ + queryString: query, + database: dbFullName, + queryValuesArray, + dbHost, + dbPassword, + dbUsername, + encryptionKey, + encryptionSalt, + tableSchema, + }); + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + /** + * Return statement + */ + return newInsert; +}; diff --git a/engine/db/test/add.js b/engine/db/test/add.js new file mode 100644 index 0000000..a918d40 --- /dev/null +++ b/engine/db/test/add.js @@ -0,0 +1,125 @@ +const fs = require("fs"); +const dbHandler = require("../dbHandler"); + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +/** + * Add Database Entry + * ============================================================================== + * @param {object} params - foundUser if any + * @param {string} params.tableName - Table Name + * @param {object} params.data - Data to be added + * @param {string?} params.duplicateColumnName - Duplicate Column Name + * @param {string | number?} params.duplicateColumnValue - Duplicate Column Value + */ +async function addDbEntry({ tableName, data, duplicateColumnName, duplicateColumnValue }) { + /** + * Check Duplicate if specified + * + * @description Check Duplicate if specified + */ + if (duplicateColumnName) { + let duplicateEntry = await dbHandler(`SELECT ${duplicateColumnName} FROM ${tableName} WHERE ${duplicateColumnName}='${duplicateColumnValue}'`); + + if (duplicateEntry && duplicateEntry[0]) return null; + } + + /** + * Declare variables + * + * @description Declare "results" variable + */ + const dataKeys = Object.keys(data); + + let insertKeysArray = []; + let insertValuesArray = []; + + for (let i = 0; i < dataKeys.length; i++) { + const dataKey = dataKeys[i]; + let dataValue = data[dataKey]; + // const correspondingColumnObject = dbColumns.filter((col) => col.Field === dataKey); + // const { Field, Type, Null, Key, Default, Extra } = correspondingColumnObject; + + if (!dataValue) continue; + + insertKeysArray.push("`" + dataKey + "`"); + + if (typeof dataValue === "object") { + dataValue = JSON.stringify(data[dataKey]); + } + + // let parsedDataValue = dataValue.toString().replace(/\'/g, "\\'"); + + insertValuesArray.push(dataValue); + } + + /** ********************************************** */ + + let existingDateCreatedColumn = await dbHandler(`SHOW COLUMNS FROM \`${tableName}\` WHERE Field = 'date_created'`); + if (!existingDateCreatedColumn || !existingDateCreatedColumn[0]) { + await dbHandler(`ALTER TABLE ${tableName} ADD COLUMN date_created VARCHAR(255) NOT NULL`); + } + + insertKeysArray.push("date_created"); + insertValuesArray.push(Date()); + + /** ********************************************** */ + + let existingDateCreatedCodeColumn = await dbHandler(`SHOW COLUMNS FROM ${tableName} WHERE Field = 'date_created_code'`); + if (!existingDateCreatedCodeColumn || !existingDateCreatedCodeColumn[0]) { + await dbHandler(`ALTER TABLE ${tableName} ADD COLUMN date_created_code BIGINT NOT NULL`); + } + + insertKeysArray.push("date_created_code"); + insertValuesArray.push(Date.now()); + + /** ********************************************** */ + + let existingDateCodeColumn = await dbHandler(`SHOW COLUMNS FROM ${tableName} WHERE Field = 'date_code'`); + if (existingDateCodeColumn && existingDateCodeColumn[0]) { + insertKeysArray.push("date_code"); + insertValuesArray.push(Date.now()); + } + + /** ********************************************** */ + /** ********************************************** */ + /** ********************************************** */ + + let existingDateUpdatedColumn = await dbHandler(`SHOW COLUMNS FROM ${tableName} WHERE Field = 'date_updated'`); + if (!existingDateUpdatedColumn || !existingDateUpdatedColumn[0]) { + await dbHandler(`ALTER TABLE ${tableName} ADD COLUMN date_updated VARCHAR(255) NOT NULL`); + } + + insertKeysArray.push("date_updated"); + insertValuesArray.push(Date()); + + /** ********************************************** */ + + let existingDateUpdatedCodeColumn = await dbHandler(`SHOW COLUMNS FROM ${tableName} WHERE Field = 'date_updated_code'`); + if (!existingDateUpdatedCodeColumn || !existingDateUpdatedCodeColumn[0]) { + await dbHandler(`ALTER TABLE ${tableName} ADD COLUMN date_updated_code BIGINT NOT NULL`); + } + + insertKeysArray.push("date_updated_code"); + insertValuesArray.push(Date.now()); + + /** ********************************************** */ + + const query = `INSERT INTO ${tableName} (${insertKeysArray.join(",")}) VALUES (${insertValuesArray.map((val) => "?").join(",")})`; + const queryValuesArray = insertValuesArray; + + const newInsert = await dbHandler(query, queryValuesArray); + + /** ********************************************** */ + + return newInsert; + + /** ********************************************** */ + /** ********************************************** */ + /** ********************************************** */ +} diff --git a/engine/db/update.js b/engine/db/update.js new file mode 100644 index 0000000..2afee00 --- /dev/null +++ b/engine/db/update.js @@ -0,0 +1,139 @@ +/** + * Imports: Handle imports + */ + +const handler = require("../utils/handler"); + +/** + * Update DB Function + * ============================================================================== + * @description Description + * + * @param {object} params - An object containing the function parameters. + * @param {string} params.dbFullName - Database full name + * @param {string} params.tableName - Table name + * @param {object} params.data - Data to add + * @param {DSQL_TableSchemaType?} params.tableSchema - Table schema + * @param {string} params.identifierColumnName - Update row identifier column name + * @param {string|number} params.identifierValue - Update row identifier column value + * @param {boolean?} params.update - Update this row if it exists + * @param {string?} params.dbHost - Database host + * @param {string?} params.dbPassword - Database password + * @param {string?} params.dbUsername - Database username + * @param {string?} params.encryptionKey - Encryption key + * @param {string?} params.encryptionSalt - Encryption salt + * + * @returns {object} + */ +module.exports = async function update({ dbFullName, tableName, data, tableSchema, identifierColumnName, identifierValue, update, dbHost, dbPassword, dbUsername, encryptionKey, encryptionSalt }) { + /** + * Initialize variables + */ + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + /** + * Handle function logic + */ + if (duplicateColumnName && typeof duplicateColumnName === "string") { + const duplicateValue = await handler({ + queryString: `SELECT * FROM \`${tableName}\` WHERE \`${duplicateColumnName}\`=?`, + queryValuesArray: [duplicateColumnValue], + database: dbFullName, + dbHost, + dbPassword, + dbUsername, + }); + + if (duplicateValue && duplicateValue[0] && !update) { + return null; + } else if (duplicateValue && duplicateValue[0] && update) { + return await update(); + } + } else if (duplicateColumnName && typeof duplicateColumnName === "object" && duplicateColumnValue && typeof duplicateColumnValue === "object") { + const duplicateArray = duplicateColumnName.map((dupColName, index) => { + return `\`${dupColName}\`='${duplicateColumnValue[index]}'`; + }); + + const duplicateValue = await handler({ + queryString: `SELECT * FROM ${tableName} WHERE ${duplicateArray.join(" AND ")}`, + database: dbFullName, + }); + + if (duplicateValue && duplicateValue[0] && !update) { + return null; + } + } + + /** + * Declare variables + * + * @description Declare "results" variable + */ + const dataKeys = Object.keys(data); + + let insertKeysArray = []; + let insertValuesArray = []; + + for (let i = 0; i < dataKeys.length; i++) { + const dataKey = dataKeys[i]; + // const correspondingColumnObject = dbColumns.filter((col) => col.Field === dataKey); + // const { Field, Type, Null, Key, Default, Extra } = correspondingColumnObject; + let value = data[dataKey]; + + const targetFieldSchemaArray = tableSchema ? tableSchema?.fields.filter((field) => field.fieldName === dataKey) : null; + const targetFieldSchema = targetFieldSchemaArray && targetFieldSchemaArray[0] ? targetFieldSchemaArray[0] : null; + + if (!value) continue; + + if (targetFieldSchema?.encrypted) { + value = await encrypt(value); + } + + if (targetFieldSchema?.richText) { + value = sanitizeHtml(value, sanitizeHtmlOptions).replace(/\n|\r|\n\r/gm, ""); + } + + insertKeysArray.push("`" + dataKey + "`"); + + let parsedDataValue = value.toString().replace(/(?} + */ +module.exports = async function handler({ queryString, queryValuesArray, database, tableSchema, dbHost, dbUsername, dbPassword, encryptionKey, encryptionSalt }) { + const mysql = require("serverless-mysql")({ + config: { + host: dbHost, + user: dbUsername, + password: dbPassword, + database: database.toString().replace(/[^a-z0-9\_\-]/g, ""), + charset: "utf8mb4", + }, + }); + + /** + * Declare variables + * + * @description Declare "results" variable + */ + let results; + + /** + * Check if query values array is an array + */ + if (!queryString || !queryValuesArray || !Array.isArray(queryValuesArray) || !queryValuesArray[0]) { + return null; + } + /** + * Fetch from db + * + * @description Fetch data from db if no cache + */ + try { + /** + * Run Query + */ + results = await mysql.query(queryString, queryValuesArray); + + /** + * Clean up + */ + await mysql.end(); + } catch (error) { + /** + * Handle error and clean up + */ + console.log("\x1b[31mDSQL Database Handler ERROR\x1b[0m =>", database, error.message); + + /** + * Clean up + */ + await mysql.end(); + } + + /** + * Return results + * + * @description Return results add to cache if "req" param is passed + */ + if (results && tableSchema) { + try { + const unparsedResults = JSON.parse(JSON.stringify(results)); + const parsedResults = await parseDbResults({ unparsedResults: unparsedResults, tableSchema: tableSchema, encryptionKey, encryptionSalt }); + return parsedResults; + } catch (error) { + console.log("\x1b[31mDSQL Database Handler ERROR\x1b[0m =>", database, error.message); + return null; + } + } else if (results) { + return JSON.parse(JSON.stringify(results)); + } else { + console.log("\x1b[31mDSQL Database Handler No results returned\x1b[0m =>", results); + return null; + } +}; diff --git a/engine/utils/parseDbResults.js b/engine/utils/parseDbResults.js new file mode 100644 index 0000000..52ae234 --- /dev/null +++ b/engine/utils/parseDbResults.js @@ -0,0 +1,70 @@ +const decrypt = require("../../functions/decrypt"); +const defaultFieldsRegexp = require("./defaultFieldsRegexp"); + +/** + * Parse Database results + * ============================================================================== + * @description this function takes a database results array gotten from a DB handler + * function, decrypts encrypted fields, and returns an updated array with no encrypted + * fields + * + * @param {object} params - Single object params + * @param {{}[]} params.unparsedResults - Array of data objects containing Fields(keys) + * and corresponding values of the fields(values) + * @param {DSQL_TableSchemaType} params.tableSchema - Table schema + * @returns {Promise} + */ +module.exports = async function parseDbResults({ unparsedResults, tableSchema, encryptionKey, encryptionSalt }) { + /** + * Declare variables + * + * @description Declare "results" variable + */ + let parsedResults = []; + + try { + /** + * Declare variables + * + * @description Declare "results" variable + */ + for (let pr = 0; pr < unparsedResults.length; pr++) { + let result = unparsedResults[pr]; + + let resultFieldNames = Object.keys(result); + + for (let i = 0; i < resultFieldNames.length; i++) { + const resultFieldName = resultFieldNames[i]; + let resultFieldSchema = tableSchema.fields[i]; + + if (resultFieldName?.match(defaultFieldsRegexp)) { + continue; + } + + let value = result[resultFieldName]; + + if (typeof value !== "number" && !value) { + continue; + } + + if (resultFieldSchema?.encrypted) { + if (value?.match(/./)) { + result[resultFieldName] = decrypt({ encryptedString: value, encryptionKey, encryptionSalt }); + } + } + } + + parsedResults.push(result); + } + + /** + * Declare variables + * + * @description Declare "results" variable + */ + return parsedResults; + } catch (error) { + console.log("ERROR in parseDbResults Function =>", error.message); + return unparsedResults; + } +}; diff --git a/engine/utils/sanitizeHtmlOptions.js b/engine/utils/sanitizeHtmlOptions.js new file mode 100644 index 0000000..d9eb107 --- /dev/null +++ b/engine/utils/sanitizeHtmlOptions.js @@ -0,0 +1,9 @@ +const sanitizeHtmlOptions = { + allowedTags: ["b", "i", "em", "strong", "a", "p", "span", "ul", "ol", "li", "h1", "h2", "h3", "h4", "h5", "h6", "img"], + allowedAttributes: { + a: ["href"], + img: ["src", "alt", "width", "height", "class", "style"], + }, +}; + +module.exports = sanitizeHtmlOptions; diff --git a/package-lock.json b/package-lock.json index adf39bb..36810f1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,13 +1,513 @@ { "name": "datasquirel", - "version": "1.1.4", + "version": "1.1.60", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "datasquirel", - "version": "1.1.4", - "license": "ISC" + "version": "1.1.60", + "license": "ISC", + "dependencies": { + "sanitize-html": "^2.11.0", + "serverless-mysql": "^1.5.5" + } + }, + "node_modules/@types/mysql": { + "version": "2.15.21", + "resolved": "https://registry.npmjs.org/@types/mysql/-/mysql-2.15.21.tgz", + "integrity": "sha512-NPotx5CVful7yB+qZbWtXL2fA4e7aEHkihHLjklc6ID8aq7bhguHgeIoC1EmSNTAuCgI6ZXrjt2ZSaXnYX0EUg==", + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "20.4.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.0.tgz", + "integrity": "sha512-jfT7iTf/4kOQ9S7CHV9BIyRaQqHu67mOjsIQBC3BKZvzvUB6zLxEwJ6sBE3ozcvP8kF6Uk5PXN0Q+c0dfhGX0g==", + "optional": true + }, + "node_modules/bignumber.js": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", + "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==", + "engines": { + "node": "*" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/htmlparser2": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "entities": "^4.4.0" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "node_modules/mysql": { + "version": "2.18.1", + "resolved": "https://registry.npmjs.org/mysql/-/mysql-2.18.1.tgz", + "integrity": "sha512-Bca+gk2YWmqp2Uf6k5NFEurwY/0td0cpebAucFpY/3jhrwrVGuxU2uQFCHjU19SJfje0yQvi+rVWdq78hR5lig==", + "dependencies": { + "bignumber.js": "9.0.0", + "readable-stream": "2.3.7", + "safe-buffer": "5.1.2", + "sqlstring": "2.3.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/nanoid": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", + "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/parse-srcset": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/parse-srcset/-/parse-srcset-1.0.2.tgz", + "integrity": "sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==" + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "node_modules/postcss": { + "version": "8.4.25", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.25.tgz", + "integrity": "sha512-7taJ/8t2av0Z+sQEvNzCkpDynl0tX3uJMCODi6nT3PfASC7dYCWV9aQ+uiCf+KBD4SEFcu+GvJdGdwzQ6OSjCw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/sanitize-html": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-2.11.0.tgz", + "integrity": "sha512-BG68EDHRaGKqlsNjJ2xUB7gpInPA8gVx/mvjO743hZaeMCZ2DwzW7xvsqZ+KNU4QKwj86HJ3uu2liISf2qBBUA==", + "dependencies": { + "deepmerge": "^4.2.2", + "escape-string-regexp": "^4.0.0", + "htmlparser2": "^8.0.0", + "is-plain-object": "^5.0.0", + "parse-srcset": "^1.0.2", + "postcss": "^8.3.11" + } + }, + "node_modules/serverless-mysql": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/serverless-mysql/-/serverless-mysql-1.5.5.tgz", + "integrity": "sha512-QwaCtswn3GKCnqyVA0whwDFMIw91iKTeTvf6F++HoGiunfyvfJ2MdU8d3MKMQdKGNOXIvmUlLq/JVjxuPQxkrw==", + "dependencies": { + "mysql": "^2.18.1" + }, + "optionalDependencies": { + "@types/mysql": "^2.15.6" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sqlstring": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz", + "integrity": "sha512-ooAzh/7dxIG5+uDik1z/Rd1vli0+38izZhGzSa34FwR7IbelPWCCKSNIl8jlL/F7ERvy8CB2jNeM1E9i9mXMAQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + } + }, + "dependencies": { + "@types/mysql": { + "version": "2.15.21", + "resolved": "https://registry.npmjs.org/@types/mysql/-/mysql-2.15.21.tgz", + "integrity": "sha512-NPotx5CVful7yB+qZbWtXL2fA4e7aEHkihHLjklc6ID8aq7bhguHgeIoC1EmSNTAuCgI6ZXrjt2ZSaXnYX0EUg==", + "optional": true, + "requires": { + "@types/node": "*" + } + }, + "@types/node": { + "version": "20.4.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.0.tgz", + "integrity": "sha512-jfT7iTf/4kOQ9S7CHV9BIyRaQqHu67mOjsIQBC3BKZvzvUB6zLxEwJ6sBE3ozcvP8kF6Uk5PXN0Q+c0dfhGX0g==", + "optional": true + }, + "bignumber.js": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", + "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==" + }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==" + }, + "dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "requires": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + } + }, + "domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==" + }, + "domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "requires": { + "domelementtype": "^2.3.0" + } + }, + "domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "requires": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + } + }, + "entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==" + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" + }, + "htmlparser2": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", + "requires": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "entities": "^4.4.0" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "mysql": { + "version": "2.18.1", + "resolved": "https://registry.npmjs.org/mysql/-/mysql-2.18.1.tgz", + "integrity": "sha512-Bca+gk2YWmqp2Uf6k5NFEurwY/0td0cpebAucFpY/3jhrwrVGuxU2uQFCHjU19SJfje0yQvi+rVWdq78hR5lig==", + "requires": { + "bignumber.js": "9.0.0", + "readable-stream": "2.3.7", + "safe-buffer": "5.1.2", + "sqlstring": "2.3.1" + } + }, + "nanoid": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", + "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==" + }, + "parse-srcset": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/parse-srcset/-/parse-srcset-1.0.2.tgz", + "integrity": "sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==" + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "postcss": { + "version": "8.4.25", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.25.tgz", + "integrity": "sha512-7taJ/8t2av0Z+sQEvNzCkpDynl0tX3uJMCODi6nT3PfASC7dYCWV9aQ+uiCf+KBD4SEFcu+GvJdGdwzQ6OSjCw==", + "requires": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + } + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "sanitize-html": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-2.11.0.tgz", + "integrity": "sha512-BG68EDHRaGKqlsNjJ2xUB7gpInPA8gVx/mvjO743hZaeMCZ2DwzW7xvsqZ+KNU4QKwj86HJ3uu2liISf2qBBUA==", + "requires": { + "deepmerge": "^4.2.2", + "escape-string-regexp": "^4.0.0", + "htmlparser2": "^8.0.0", + "is-plain-object": "^5.0.0", + "parse-srcset": "^1.0.2", + "postcss": "^8.3.11" + } + }, + "serverless-mysql": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/serverless-mysql/-/serverless-mysql-1.5.5.tgz", + "integrity": "sha512-QwaCtswn3GKCnqyVA0whwDFMIw91iKTeTvf6F++HoGiunfyvfJ2MdU8d3MKMQdKGNOXIvmUlLq/JVjxuPQxkrw==", + "requires": { + "@types/mysql": "^2.15.6", + "mysql": "^2.18.1" + } + }, + "source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" + }, + "sqlstring": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz", + "integrity": "sha512-ooAzh/7dxIG5+uDik1z/Rd1vli0+38izZhGzSa34FwR7IbelPWCCKSNIl8jlL/F7ERvy8CB2jNeM1E9i9mXMAQ==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" } } } diff --git a/package.json b/package.json index 2a3095d..f11274e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "datasquirel", - "version": "1.1.59", + "version": "1.1.60", "description": "Cloud-based SQL data management tool", "main": "index.js", "scripts": { @@ -23,5 +23,9 @@ "bugs": { "url": "https://github.com/BenjaminToby/dsql/issues" }, - "homepage": "https://datasquirel.com/" + "homepage": "https://datasquirel.com/", + "dependencies": { + "sanitize-html": "^2.11.0", + "serverless-mysql": "^1.5.5" + } } diff --git a/types/engine.td.js b/types/engine.td.js new file mode 100644 index 0000000..d064dec --- /dev/null +++ b/types/engine.td.js @@ -0,0 +1,89 @@ +/** + * @typedef {string} DSQL_DatabaseFullName - Database full name(slug) including datasquirel data => "datasquirel_user_7_new_database" + */ + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +/** + * @typedef {object} DSQL_DatabaseSchemaType + * @property {string} dbName - Database Full name with spaces => "New Database" + * @property {string} dbSlug - Database Slug => "new_database" + * @property {string} dbFullName - Database full name(slug) including datasquirel data => "datasquirel_user_7_new_database" + * @property {string} [dbDescription] - Database brief description + * @property {string} [dbImage] - Database image - Defaults to "/images/default.png" + * @property {DSQL_TableSchemaType[]} tables - List of database tables + * @property {{ dbFullName: string }[]} [childrenDatabases] - List of children databases for current database which is parent + * @property {boolean} [childDatabase] - If current database is a child of a different parent database + * @property {string} [childDatabaseDbFullName] - Parent database full name => "datasquirel_user_7_new_database" + */ + +//////////////////////////////////////// + +/** + * @typedef {object} DSQL_TableSchemaType + * @property {string} tableName - Table slug (blog_posts) + * @property {string} tableFullName - Table full name with spaces => "Blog Posts" + * @property {string} [tableDescription] - Brief description of table + * @property {DSQL_FieldSchemaType[]} fields - List of table Fields + * @property {DSQL_IndexSchemaType[]} [indexes] - List of table indexes, if available + * @property {DSQL_ChildrenTablesType[]} childrenTables - List of children tables + * @property {boolean} [childTable] -If current table is a child clone + * @property {string} [childTableName] - Table slug of parent table => "blog_posts" + * @property {string} [childTableDbFullName] - Database full name(slug) including datasquirel data => "datasquirel_user_7_new_database" + * @property {string} [tableNameOld] - Old table name, incase of renaming table + */ + +/** + * @typedef {object} DSQL_ChildrenTablesType + * @property {string} dbNameFull - Database full name(slug) including datasquirel data => "datasquirel_user_7_new_database" + * @property {string} tableName - Table slug => "blog_posts" + */ + +//////////////////////////////////////// + +/** + * @typedef {object} DSQL_FieldSchemaType + * @property {string} fieldName - Field Name(slug) => "long_description" + * @property {string} [originName] - Field origin name(optional) + * @property {boolean} [updatedField] - Has this field been renamed? + * @property {string} dataType - Field Data type => "BIGIN" | "LONGTEXT" | "VARCHAR(***)" | ... + * @property {boolean} [nullValue] - Is this a null value or not? + * @property {boolean} [notNullValue] - Is this NOT a null value? + * @property {boolean} [primaryKey] - Is this the primary key for table? + * @property {boolean} [encrypted] - Is this field value encrypted? + * @property {boolean} [autoIncrement] - Does this table primary key increment automatically? + * @property {string|number} [defaultValue] - Value of field by default + * @property {string} [defaultValueLiteral] - SQL key word which generates value automatically => "CURRENT_TIMESTAMP" + * @property {DSQL_ForeignKeyType} [foreignKey] - Field foreign key reference object + */ + +/** + * @typedef {object} DSQL_ForeignKeyType + * @property {string} foreignKeyName - Unique Name of foreign key + * @property {string} destinationTableName - Reference table name(slug) => "blog_posts" + * @property {string} destinationTableColumnName - Reference column name(slug) => "id" + * @property {string} destinationTableColumnType - Reference table field type => "BIGINT" | "VARCHAR(***)" | ... + * @property {boolean} [cascadeDelete] - Does the reference table entry delete when this key is deleted? + * @property {boolean} [cascadeUpdate] - Does the reference table entry update when this key is updated? + */ + +//////////////////////////////////////// + +/** + * @typedef {object} DSQL_IndexSchemaType + * @property {string} indexName - Unique Name of index => "blog_text_index" + * @property {string} indexType - "regular" or "fullText" + * @property {DSQL_IndexTableFieldType[]} indexTableFields - List of Index table fields + */ + +/** + * @typedef {object} DSQL_IndexTableFieldType + * @property {string} value - Table Field Name + * @property {string} dataType - Table Field data type "VARCHAR(***)" | "BIGINT" | ... + */ + +////////////////////////////////////////