/** * Returns types based on the database. */ class GenericTypes { /** * Constructor. * @param database {String} */ constructor(database) { this.database = database; } get null() { switch(this.database) { case 'postgresql': case 'sqlite': default: return 'NULL'; } } get integer() { switch(this.database) { case 'postgresql': case 'sqlite': default: return 'INTEGER'; } } get real() { switch(this.database) { case 'sqlite': return 'REAL'; case 'postgresql': default: return 'FLOAT'; } } get text() { switch (this.database) { case 'postgresql': case 'sqlite': default: return 'TEXT'; } } get varchar() { switch (this.database) { case 'postgresql': case 'sqlite': default: return 'VARCHAR'; } } get date() { switch (this.database) { case 'postgresql': case 'sqlite': default: return 'DATE'; } } get datetime() { switch (this.database) { case 'postgresql': return 'TIMESTAMP'; case 'sqlite': default: return 'DATETIME'; } } get serial() { switch (this.database) { case 'sqlite': return 'INTEGER AUTOINCREMENT NOT NULL'; case 'postgresql': default: return 'SERIAL'; } } get serialPK() { switch (this.database) { case 'sqlite': return 'INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL'; case 'postgresql': default: return 'SERIAL PRIMARY KEY UNIQUE'; } } /** * Returns the VARCHAR type with the specified length. * @param length {Number} */ getVarchar(length) { return `${this.varchar}(${length})`; } } /** * Returns sql statements based on the database. */ class GenericSql { /** * Constructor. * @param database {String} */ constructor(database) { this.database = database; this.types = new GenericTypes(database); this.constraints = { primaryKey: 'PRIMARY KEY', notNull: 'NOT NULL', unique: 'UNIQUE', like: 'LIKE', exists: 'EXISTS', and: 'AND', or: 'OR', in: 'IN', any: 'ANY', all: 'ALL' }; this.templates = { idcolumn: new Column('id', this.types.serialPK, []) }; } /** * Returns a value placeholder for the specified number. * @param number {Number} - the variables position. */ parameter(number) { switch (this.database) { case 'postgresql': return `$${number}`; case 'sqlite': return '?'; } } /** * A sum selector - calculates the sum of all values of the column * @param colname {String} - the name of the column where the sum is selected. * @returns {string} */ sum(colname) { switch (this.database) { case 'postgresql': case 'sqlite': return `SUM(${colname})`; } } /** * A avg selector - selects the average * @param colname {String} - the name of the column where the avg value is selected. * @returns {string} */ avg(colname) { switch (this.database) { case 'postgresql': case 'sqlite': return `AVG(${colname})`; } } /** * A min selector - selects the minimum * @param colname {String} - the name of the column where the min value is selected. * @returns {string} */ min(colname) { switch (this.database) { case 'postgresql': case 'sqlite': return `MIN(${colname})`; } } /** * A max selector - selects the maximum * @param colname {String} - the name of the column where the max value is selected. * @returns {string} */ max(colname) { switch (this.database) { case 'postgresql': case 'sqlite': return `MAX(${colname})`; } } /** * A count selector - counts the results * @param colname {String} - the name of the column to be counted. * @returns {string} */ count(colname) { switch (this.database) { case 'postgresql': case 'sqlite': return `COUNT(${colname}) count`; } } /** * A default constraint * @param expression {String} - the expression to generate the default value. * @returns {string} */ default(expression) { switch (this.database) { case 'postgresql': case 'sqlite': return `DEFAULT ${expression}`; } } /** * A where statement * @param row {String} - the row * @param operator {String} - the comparison operator * @param comparator {String} the value or row to compare to */ and(row, operator, comparator) { switch (this.database) { case 'postgresql': case 'sqlite': return `AND ${row} ${operator} ${comparator}`; } } /** * A or statement * @param row {String} - the row * @param operator {String} - the comparison operator * @param comparator {String} the value or row to compare to */ or(row, operator, comparator) { switch (this.database) { case 'postgresql': case 'sqlite': return `OR ${row} ${operator} ${comparator}`; } } /** * A where statement * @param row {String} - the row * @param operator {String} - the comparison operator * @param comparator {String} the value or row to compare to */ where(row, operator, comparator) { switch (this.database) { case 'postgresql': case 'sqlite': return `WHERE ${row} ${operator} ${comparator}`; } } /** * A limit statement. * @param count {Number} - the number of rows to return * @returns {string} */ limit(count) { switch (this.database) { case 'postgresql': case 'sqlite': return `LIMIT ${count}`; } } /** * Create Table statement * @param table {String} * @param rows {Array} * @returns {string} */ createTable(table, rows) { switch (this.database) { case 'postgresql': case 'sqlite': return `CREATE TABLE ${table} (${rows.map(x => x.sql).join(',')})`; } } /** * Create Table if it doesn't exist statement * @param table {String} * @param columns {Array} * @returns {string} */ createTableIfNotExists(table, columns) { switch (this.database) { case 'postgresql': case 'sqlite': return `CREATE TABLE IF NOT EXISTS ${table} (${columns.map(x => x.sql).join(',')})`; } } /** * Insert into the table. * @param table {String} - the table name * @param colValueObj {Object} - an object with keys as columnnames and values as columnvalues * @returns {string} */ insert(table, colValueObj) { let rownames = Object.keys(colValueObj); let values = Object.values(colValueObj); switch (this.database) { case 'postgresql': case 'sqlite': return `INSERT INTO ${table} (${rownames.join(',')}) values (${values.join(',')})`; } } /** * Updates the table with the rowValueObject. * @param table {String} - the table name * @param colValueObj {Object} - an object with keys as columnnames and values as columnvalues * @param conditions {Array|String} - conditions for the update row selection (WHERE ... [OR ...][AND ...] * @returns {string} */ update(table, colValueObj, conditions) { if (!(conditions instanceof Array)) conditions = [conditions]; switch (this.database) { case 'postgresql': case 'sqlite': return `UPDATE ${table} SET ${Object.entries(colValueObj).map(x => `${x[0]} = ${x[1]}`).join(',')} ${conditions.join(' ')}`; } } /** * Selects from a table * @param table {String} - the tablename * @param distinct {String|boolean} - should distinct values be selected? If yes provide distinct keyword. * @param colnames {Array|String} - the rows to select * @param conditions {Array|String} - conditions for the row selection (WHERE ... [OR ...][AND ...] * @param operations {Array|String} - operations on the selected rows * @returns {String} */ select(table, distinct, colnames, conditions, operations) { if (!(colnames instanceof Array)) colnames = [colnames]; if (!(conditions instanceof Array)) conditions = [conditions]; if (!(operations instanceof Array)) operations = [operations]; switch (this.database) { case 'postgresql': case 'sqlite': return `SELECT${distinct? ' ' + distinct : ''} ${colnames.join(', ')} FROM ${table} ${conditions.join(' ')} ${operations.join(' ')}`; } } /** * Deletes from a table * @param table {String} - the table name * @param conditions {Array|String} - conditions for the row selection (WHERE ... [OR ...][AND ...] */ delete(table, conditions) { if (!(conditions instanceof Array)) conditions = [conditions]; switch (this.database) { case 'postgresql': case 'sqlite': return `DELETE FROM ${table} ${conditions.join(' ')}`; } } } class Column { /** * Create a column for usage in the generic sql statements * @param name {String} * @param [type] {String} * @param [constraints] {Array} */ constructor(name, type, constraints) { this.name = name; this.type = type; this.constraints = constraints || []; if (!(constraints instanceof Array)) this.constraints = [constraints]; } /** * Sets the datatype of the row. * @param constraint {String} */ addConstraint(constraint) { this.constraints.push(constraint); } get sql() { return `${this.name} ${this.type} ${this.constraints.join(' ')}`; } } Object.assign(exports, { GenericSql: GenericSql, GenericTypes: GenericTypes, Column: Column });