Skip to content

Commit

Permalink
#50 Added support for creating databases and tables
Browse files Browse the repository at this point in the history
  • Loading branch information
czprz committed Apr 2, 2022
1 parent 1463047 commit 337185a
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 34 deletions.
81 changes: 59 additions & 22 deletions bin/common/helper/mssql.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,9 @@ module.exports = new class {
* @returns {Promise<void>}
*/
async createTable(query) {
await this.#connect(query);
await sql.query(`CREATE TABLE ${query.database}`);
await this.#connect(query, true);
const statement = this.#getTableCreationQuery(query);
await sql.query(`CREATE TABLE ${statement}`);
await sql.close();
}

Expand All @@ -46,8 +47,9 @@ module.exports = new class {
* @returns {Promise<boolean>}
*/
async tableExists(query) {
const tableName = this.#getTableName(query); // Todo: Create a better solution for handling table name instead of two possible ways of obtaining it
await this.#connect(query);
const value = await sql.query(`SELECT CAST(CASE WHEN (SELECT TABLE_NAME FROM ${query.database}.INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = '${query.table}') IS NULL THEN 0 ELSE 1 END as bit) as tableExists`);
const value = await sql.query(`SELECT CAST(CASE WHEN (SELECT TABLE_NAME FROM ${query.database}.INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = '${tableName}') IS NULL THEN 0 ELSE 1 END as bit) as tableExists`);
await sql.close();

if (value.recordset == null || value.recordset.length === 0) {
Expand All @@ -63,24 +65,42 @@ module.exports = new class {
* @returns {Promise<void>}
*/
async insert(query) {
await this.#connect(query);
const insert = this.#mapDbDataToInsertQuery(query.data);
await this.#connect(query, true);
const insert = this.#getInsertQuery(query.data);
await sql.query(`INSERT INTO ${insert}`);
await sql.close();
}

/**
* Maps DbData into query string
* @param dbData {DbData[]}
* Establish SQL connection
* @param query {DbQuery}
* @param withDatabase {boolean}
* @return {Promise<void>}
*/
async #connect(query, withDatabase = false) {
await sql.connect({
server: "localhost",
user: query.username,
password: query.password,
database: withDatabase ? query.database : undefined,
options: {
trustServerCertificate: true
}
});
}

/**
* Maps DbColumn into query string
* @param dbColumns {DbColumn[]}
* @return {string}
*/
#mapDbDataToInsertQuery(dbData) {
#getInsertQuery(dbColumns) {
let columns = '';
let values = '';

for (const data of dbData) {
columns += `'${data.key}',`;
values += `'${data.value}',`;
for (const column of dbColumns) {
columns += `'${column.key}',`;
values += `'${column.value}',`;
}

columns = columns.slice(0, -1);
Expand All @@ -90,18 +110,35 @@ module.exports = new class {
}

/**
* Establish SQL connection
*
* @param query {DbQuery}
* @return {Promise<void>}
* @return {string}
*/
async #connect(query) {
await sql.connect({
server: "localhost",
user: query.username,
password: query.password,
options: {
trustServerCertificate: true
}
});
#getTableCreationQuery(query) {
if (typeof query.table === 'string') {
throw new Error('Table creation query cannot be run with a string');
}

let statement = '';
for (const column of query.table.columns) {
statement += `${column.key} ${column.valueType}, `;
}

return `dbo.${query.table.name} (${statement.slice(0, -2)})`;
}

/**
* Gets table name
* @param query {DbQuery}
* @return {string}
*/
#getTableName(query) {
if (query.table == null) {
// Todo: Pass runtime here for getting execution name
console.error('Missing table name');
return '';
}

return typeof query.table === 'string' ? query.table : query.table.name;
}
}
37 changes: 29 additions & 8 deletions bin/configuration/models.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,47 +131,68 @@ class Step {
class DbQuery {
/**
* Username for SQL connection
* @var {string}
* @return {string}
*/
username;

/**
* Password for SQL connection
* @var {string}
* @return {string}
*/
password;

/**
* Used for selecting between ('create-database', 'create-table', 'insert')
* @var {string}
* @return {string}
*/
option;

/**
* Database name necessary for DB Creation, Table Creation and Query execution
* @var {string}
* @return {string}
*/
database;

/**
* Table name necessary for Table Creation and Query Execution
* @var {string}
* Table necessary for Table Creation and Query Execution
* @return {string | DbTable}
*/
table;

/**
* Data currently only necessary for ('insert')
* @var {DbData[]}
* @return {DbColumn[]}
*/
data;
}

class DbData {
class DbTable {
/**
* Name of table on creation
* @return {string}
*/
name;

/**
* Columns created on table creation
* @return {DbColumn[]}
*/
columns;
}

class DbColumn {
/**
* Column name
* @var {string}
*/
key;

/**
* Column value type (Only required for creating table)
* @var {string}
*/
valueType;

/**
* Column value
*/
Expand Down
24 changes: 22 additions & 2 deletions bin/environments/executions/mssql/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ module.exports = new class {
* @returns {Promise<void>}
*/
async #createDatabase(execution) {
// Todo: Add validation of execution.sql to ensure everything needed is available..
if (!execution.sql.database) {
console.log(`mssql: '${execution.name}' could not find database name`);
return;
Expand All @@ -56,7 +57,9 @@ module.exports = new class {
* @param execution {Execution}
*/
async #createTable(execution) {
if (!execution.sql.database || execution.sql.table) {
// Todo: Add validation of execution.sql to ensure everything needed is available..
const tableName = this.#getTableName(execution.sql);
if (!execution.sql.database || !tableName) {
console.log(`mssql: '${execution.name}' could not find database or table name`);
return;
}
Expand Down Expand Up @@ -86,7 +89,9 @@ module.exports = new class {
* @returns {Promise<void>}
*/
async #insert(execution) {
if (!execution.sql.database || execution.sql.table) {
// Todo: Add validation of execution.sql to ensure everything needed is available..
const tableName = this.#getTableName(execution.sql);
if (!execution.sql.database || !tableName) {
console.log(`mssql: '${execution.name}' could not find database or table name`);
return;
}
Expand All @@ -109,5 +114,20 @@ module.exports = new class {
throw e;
}
}

/**
* Gets table name
* @param query {DbQuery}
* @return {string}
*/
#getTableName(query) {
if (query.table == null) {
// Todo: Pass runtime here for getting execution name
console.error('Missing table name');
return '';
}

return typeof query.table === 'string' ? query.table : query.table.name;
}
}

8 changes: 6 additions & 2 deletions bin/environments/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ module.exports = new class {
switch (true) {
case runtime.start:
case runtime.stop:
await this.#startOrStop(config, runtime);
await this.#run(config, runtime);
break;
default:
this.#showHelp(yargs);
Expand Down Expand Up @@ -76,7 +76,7 @@ module.exports = new class {
* @param runtime {Runtime}
* @returns {Promise<void>}
*/
async #startOrStop(config, runtime) {
async #run(config, runtime) {
const options = this.#getCustomOptions(config.environment);
const result = customOption.validateOptions(runtime.args, options);
if (!result.status) {
Expand All @@ -93,6 +93,10 @@ module.exports = new class {
}

for (const execution of config.environment) {
if (execution.type == null) {
console.error(chalk.redBright(`${execution.name}: Missing type!`));
return;
}
if ((execution.runtime && runtime.variables.length > 0 && !runtime.variables.some(x => x === execution.name)) ||
runtime.not.length > 0 && runtime.not.some(x => x === execution.name)) {
continue;
Expand Down

0 comments on commit 337185a

Please sign in to comment.