Refactor to classes (#4190)

This commit is contained in:
Igor Savin 2021-01-01 17:46:10 +02:00 committed by GitHub
parent 936126c0f0
commit b43dadbe01
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 469 additions and 477 deletions

View File

@ -11,6 +11,7 @@ function augmentWithBuilderInterface(Target) {
if (!data.length) {
return '';
}
return data
.map((statement) => {
return formatQuery(statement.sql, statement.bindings, tz, this.client);

View File

@ -10,9 +10,9 @@ const Client = require('../../client');
const Formatter = require('../../formatter');
const Transaction = require('./transaction');
const QueryCompiler = require('./query/compiler');
const SchemaCompiler = require('./schema/compiler');
const TableCompiler = require('./schema/tablecompiler');
const ColumnCompiler = require('./schema/columncompiler');
const SchemaCompiler = require('./schema/mssql-compiler');
const TableCompiler = require('./schema/mssql-tablecompiler');
const ColumnCompiler = require('./schema/mssql-columncompiler');
const SQL_INT4 = { MIN: -2147483648, MAX: 2147483647 };
const SQL_BIGINT_SAFE = { MIN: -9007199254740991, MAX: 9007199254740991 };

View File

@ -1,21 +1,18 @@
// MySQL Schema Compiler
// -------
const { inherits } = require('util');
const SchemaCompiler = require('../../../schema/compiler');
function SchemaCompiler_MSSQL(client, builder) {
SchemaCompiler.call(this, client, builder);
}
inherits(SchemaCompiler_MSSQL, SchemaCompiler);
class SchemaCompiler_MSSQL extends SchemaCompiler {
constructor(client, builder) {
super(client, builder);
}
Object.assign(SchemaCompiler_MSSQL.prototype, {
dropTablePrefix: 'DROP TABLE ',
dropTableIfExists(tableName) {
const name = this.formatter.wrap(prefixedTableName(this.schema, tableName));
this.pushQuery(
`if object_id('${name}', 'U') is not null DROP TABLE ${name}`
);
},
}
// Rename a table on the schema.
renameTable(tableName, to) {
@ -24,7 +21,7 @@ Object.assign(SchemaCompiler_MSSQL.prototype, {
prefixedTableName(this.schema, tableName)
)}, ${this.formatter.parameter(to)}`
);
},
}
// Check whether a table exists on the query.
hasTable(tableName) {
@ -36,7 +33,7 @@ Object.assign(SchemaCompiler_MSSQL.prototype, {
`select object_id from sys.tables ` +
`where object_id = object_id(${formattedTable})`;
this.pushQuery({ sql, output: (resp) => resp.length > 0 });
},
}
// Check whether a column exists on the schema.
hasColumn(tableName, column) {
@ -49,8 +46,10 @@ Object.assign(SchemaCompiler_MSSQL.prototype, {
`where name = ${formattedColumn} ` +
`and object_id = object_id(${formattedTable})`;
this.pushQuery({ sql, output: (resp) => resp.length > 0 });
},
});
}
}
SchemaCompiler_MSSQL.prototype.dropTablePrefix = 'DROP TABLE ';
function prefixedTableName(prefix, table) {
return prefix ? `${prefix}.${table}` : table;

View File

@ -7,9 +7,9 @@ const Client = require('../../client');
const Transaction = require('./transaction');
const QueryCompiler = require('./query/compiler');
const SchemaCompiler = require('./schema/compiler');
const TableCompiler = require('./schema/tablecompiler');
const ColumnCompiler = require('./schema/columncompiler');
const SchemaCompiler = require('./schema/mysql-compiler');
const TableCompiler = require('./schema/mysql-tablecompiler');
const ColumnCompiler = require('./schema/mysql-columncompiler');
const { makeEscape } = require('../../query/string');

View File

@ -1,16 +1,12 @@
// MySQL Schema Compiler
// -------
const { inherits } = require('util');
const SchemaCompiler = require('../../../schema/compiler');
const some = require('lodash/some');
class SchemaCompiler_MySQL extends SchemaCompiler {
constructor(client, builder) {
super(client, builder);
}
function SchemaCompiler_MySQL(client, builder) {
SchemaCompiler.call(this, client, builder);
}
inherits(SchemaCompiler_MySQL, SchemaCompiler);
Object.assign(SchemaCompiler_MySQL.prototype, {
// Rename a table on the schema.
renameTable(tableName, to) {
this.pushQuery(
@ -18,7 +14,7 @@ Object.assign(SchemaCompiler_MySQL.prototype, {
to
)}`
);
},
}
// Check whether a table exists on the query.
hasTable(tableName) {
@ -39,14 +35,14 @@ Object.assign(SchemaCompiler_MySQL.prototype, {
return resp.length > 0;
},
});
},
}
// Check whether a column exists on the schema.
hasColumn(tableName, column) {
this.pushQuery({
sql: `show columns from ${this.formatter.wrap(tableName)}`,
output(resp) {
return some(resp, (row) => {
return resp.some((row) => {
return (
this.client.wrapIdentifier(row.Field) ===
this.client.wrapIdentifier(column)
@ -54,7 +50,7 @@ Object.assign(SchemaCompiler_MySQL.prototype, {
});
},
});
},
});
}
}
module.exports = SchemaCompiler_MySQL;

View File

@ -3,10 +3,10 @@
const { inherits } = require('util');
const Client = require('../../client');
const SchemaCompiler = require('./schema/compiler');
const ColumnBuilder = require('./schema/columnbuilder');
const ColumnCompiler = require('./schema/columncompiler');
const TableCompiler = require('./schema/tablecompiler');
const SchemaCompiler = require('./schema/oracle-compiler');
const ColumnBuilder = require('./schema/oracle-columnbuilder');
const ColumnCompiler = require('./schema/oracle-columncompiler');
const TableCompiler = require('./schema/oracle-tablecompiler');
const { isConnectionError } = require('./utils');
// Always initialize with the "QueryBuilder" and "QueryCompiler"

View File

@ -1,81 +0,0 @@
// Oracle Schema Compiler
// -------
const { inherits } = require('util');
const SchemaCompiler = require('../../../schema/compiler');
const utils = require('../utils');
const Trigger = require('./trigger');
function SchemaCompiler_Oracle() {
SchemaCompiler.apply(this, arguments);
}
inherits(SchemaCompiler_Oracle, SchemaCompiler);
// Rename a table on the schema.
SchemaCompiler_Oracle.prototype.renameTable = function (tableName, to) {
const renameTable = Trigger.renameTableAndAutoIncrementTrigger(
this.client.logger,
tableName,
to
);
this.pushQuery(renameTable);
};
// Check whether a table exists on the query.
SchemaCompiler_Oracle.prototype.hasTable = function (tableName) {
this.pushQuery({
sql:
'select TABLE_NAME from USER_TABLES where TABLE_NAME = ' +
this.formatter.parameter(tableName),
output(resp) {
return resp.length > 0;
},
});
};
// Check whether a column exists on the schema.
SchemaCompiler_Oracle.prototype.hasColumn = function (tableName, column) {
const sql =
`select COLUMN_NAME from ALL_TAB_COLUMNS ` +
`where TABLE_NAME = ${this.formatter.parameter(tableName)} ` +
`and COLUMN_NAME = ${this.formatter.parameter(column)}`;
this.pushQuery({ sql, output: (resp) => resp.length > 0 });
};
SchemaCompiler_Oracle.prototype.dropSequenceIfExists = function (sequenceName) {
this.pushQuery(
utils.wrapSqlWithCatch(
`drop sequence ${this.formatter.wrap(sequenceName)}`,
-2289
)
);
};
SchemaCompiler_Oracle.prototype._dropRelatedSequenceIfExists = function (
tableName
) {
// removing the sequence that was possibly generated by increments() column
const sequenceName = utils.generateCombinedName(
this.client.logger,
'seq',
tableName
);
this.dropSequenceIfExists(sequenceName);
};
SchemaCompiler_Oracle.prototype.dropTable = function (tableName) {
this.pushQuery(`drop table ${this.formatter.wrap(tableName)}`);
// removing the sequence that was possibly generated by increments() column
this._dropRelatedSequenceIfExists(tableName);
};
SchemaCompiler_Oracle.prototype.dropTableIfExists = function (tableName) {
this.pushQuery(
utils.wrapSqlWithCatch(`drop table ${this.formatter.wrap(tableName)}`, -942)
);
// removing the sequence that was possibly generated by increments() column
this._dropRelatedSequenceIfExists(tableName);
};
module.exports = SchemaCompiler_Oracle;

View File

@ -0,0 +1,82 @@
// Oracle Schema Compiler
// -------
const SchemaCompiler = require('../../../schema/compiler');
const utils = require('../utils');
const Trigger = require('./trigger');
class SchemaCompiler_Oracle extends SchemaCompiler {
constructor() {
super(...arguments);
}
// Rename a table on the schema.
renameTable(tableName, to) {
const renameTable = Trigger.renameTableAndAutoIncrementTrigger(
this.client.logger,
tableName,
to
);
this.pushQuery(renameTable);
}
// Check whether a table exists on the query.
hasTable(tableName) {
this.pushQuery({
sql:
'select TABLE_NAME from USER_TABLES where TABLE_NAME = ' +
this.formatter.parameter(tableName),
output(resp) {
return resp.length > 0;
},
});
}
// Check whether a column exists on the schema.
hasColumn(tableName, column) {
const sql =
`select COLUMN_NAME from ALL_TAB_COLUMNS ` +
`where TABLE_NAME = ${this.formatter.parameter(tableName)} ` +
`and COLUMN_NAME = ${this.formatter.parameter(column)}`;
this.pushQuery({ sql, output: (resp) => resp.length > 0 });
}
dropSequenceIfExists(sequenceName) {
this.pushQuery(
utils.wrapSqlWithCatch(
`drop sequence ${this.formatter.wrap(sequenceName)}`,
-2289
)
);
}
_dropRelatedSequenceIfExists(tableName) {
// removing the sequence that was possibly generated by increments() column
const sequenceName = utils.generateCombinedName(
this.client.logger,
'seq',
tableName
);
this.dropSequenceIfExists(sequenceName);
}
dropTable(tableName) {
this.pushQuery(`drop table ${this.formatter.wrap(tableName)}`);
// removing the sequence that was possibly generated by increments() column
this._dropRelatedSequenceIfExists(tableName);
}
dropTableIfExists(tableName) {
this.pushQuery(
utils.wrapSqlWithCatch(
`drop table ${this.formatter.wrap(tableName)}`,
-942
)
);
// removing the sequence that was possibly generated by increments() column
this._dropRelatedSequenceIfExists(tableName);
}
}
module.exports = SchemaCompiler_Oracle;

View File

@ -6,7 +6,7 @@ const isEmpty = require('lodash/isEmpty');
const map = require('lodash/map');
const values = require('lodash/values');
const QueryCompiler = require('./query/compiler');
const ColumnCompiler = require('./schema/columncompiler');
const ColumnCompiler = require('./schema/oracledb-columncompiler');
const { BlobHelper, ReturningHelper, isConnectionError } = require('./utils');
const stream = require('stream');
const { promisify, inherits } = require('util');

View File

@ -1,5 +1,5 @@
const { inherits } = require('util');
const ColumnCompiler_Oracle = require('../../oracle/schema/columncompiler');
const ColumnCompiler_Oracle = require('../../oracle/schema/oracle-columncompiler');
const { isObject } = require('../../../util/is');
function ColumnCompiler_Oracledb() {

View File

@ -7,9 +7,9 @@ const Client = require('../../client');
const Transaction = require('./transaction');
const QueryCompiler = require('./query/compiler');
const ColumnCompiler = require('./schema/columncompiler');
const TableCompiler = require('./schema/tablecompiler');
const SchemaCompiler = require('./schema/compiler');
const ColumnCompiler = require('./schema/pg-columncompiler');
const TableCompiler = require('./schema/pg-tablecompiler');
const SchemaCompiler = require('./schema/pg-compiler');
const { makeEscape } = require('../../query/string');
const { isString } = require('../../util/is');

View File

@ -1,109 +0,0 @@
// PostgreSQL Schema Compiler
// -------
const { inherits } = require('util');
const SchemaCompiler = require('../../../schema/compiler');
function SchemaCompiler_PG() {
SchemaCompiler.apply(this, arguments);
}
inherits(SchemaCompiler_PG, SchemaCompiler);
// Check whether the current table
SchemaCompiler_PG.prototype.hasTable = function (tableName) {
let sql = 'select * from information_schema.tables where table_name = ?';
const bindings = [tableName];
if (this.schema) {
sql += ' and table_schema = ?';
bindings.push(this.schema);
} else {
sql += ' and table_schema = current_schema()';
}
this.pushQuery({
sql,
bindings,
output(resp) {
return resp.rows.length > 0;
},
});
};
// Compile the query to determine if a column exists in a table.
SchemaCompiler_PG.prototype.hasColumn = function (tableName, columnName) {
let sql =
'select * from information_schema.columns where table_name = ? and column_name = ?';
const bindings = [tableName, columnName];
if (this.schema) {
sql += ' and table_schema = ?';
bindings.push(this.schema);
} else {
sql += ' and table_schema = current_schema()';
}
this.pushQuery({
sql,
bindings,
output(resp) {
return resp.rows.length > 0;
},
});
};
SchemaCompiler_PG.prototype.qualifiedTableName = function (tableName) {
const name = this.schema ? `${this.schema}.${tableName}` : tableName;
return this.formatter.wrap(name);
};
// Compile a rename table command.
SchemaCompiler_PG.prototype.renameTable = function (from, to) {
this.pushQuery(
`alter table ${this.qualifiedTableName(
from
)} rename to ${this.formatter.wrap(to)}`
);
};
SchemaCompiler_PG.prototype.createSchema = function (schemaName) {
this.pushQuery(`create schema ${this.formatter.wrap(schemaName)}`);
};
SchemaCompiler_PG.prototype.createSchemaIfNotExists = function (schemaName) {
this.pushQuery(
`create schema if not exists ${this.formatter.wrap(schemaName)}`
);
};
SchemaCompiler_PG.prototype.dropSchema = function (schemaName) {
this.pushQuery(`drop schema ${this.formatter.wrap(schemaName)}`);
};
SchemaCompiler_PG.prototype.dropSchemaIfExists = function (schemaName) {
this.pushQuery(`drop schema if exists ${this.formatter.wrap(schemaName)}`);
};
SchemaCompiler_PG.prototype.dropExtension = function (extensionName) {
this.pushQuery(`drop extension ${this.formatter.wrap(extensionName)}`);
};
SchemaCompiler_PG.prototype.dropExtensionIfExists = function (extensionName) {
this.pushQuery(
`drop extension if exists ${this.formatter.wrap(extensionName)}`
);
};
SchemaCompiler_PG.prototype.createExtension = function (extensionName) {
this.pushQuery(`create extension ${this.formatter.wrap(extensionName)}`);
};
SchemaCompiler_PG.prototype.createExtensionIfNotExists = function (
extensionName
) {
this.pushQuery(
`create extension if not exists ${this.formatter.wrap(extensionName)}`
);
};
module.exports = SchemaCompiler_PG;

View File

@ -0,0 +1,107 @@
// PostgreSQL Schema Compiler
// -------
const SchemaCompiler = require('../../../schema/compiler');
class SchemaCompiler_PG extends SchemaCompiler {
constructor() {
super(...arguments);
}
// Check whether the current table
hasTable(tableName) {
let sql = 'select * from information_schema.tables where table_name = ?';
const bindings = [tableName];
if (this.schema) {
sql += ' and table_schema = ?';
bindings.push(this.schema);
} else {
sql += ' and table_schema = current_schema()';
}
this.pushQuery({
sql,
bindings,
output(resp) {
return resp.rows.length > 0;
},
});
}
// Compile the query to determine if a column exists in a table.
hasColumn(tableName, columnName) {
let sql =
'select * from information_schema.columns where table_name = ? and column_name = ?';
const bindings = [tableName, columnName];
if (this.schema) {
sql += ' and table_schema = ?';
bindings.push(this.schema);
} else {
sql += ' and table_schema = current_schema()';
}
this.pushQuery({
sql,
bindings,
output(resp) {
return resp.rows.length > 0;
},
});
}
qualifiedTableName(tableName) {
const name = this.schema ? `${this.schema}.${tableName}` : tableName;
return this.formatter.wrap(name);
}
// Compile a rename table command.
renameTable(from, to) {
this.pushQuery(
`alter table ${this.qualifiedTableName(
from
)} rename to ${this.formatter.wrap(to)}`
);
}
createSchema(schemaName) {
this.pushQuery(`create schema ${this.formatter.wrap(schemaName)}`);
}
createSchemaIfNotExists(schemaName) {
this.pushQuery(
`create schema if not exists ${this.formatter.wrap(schemaName)}`
);
}
dropSchema(schemaName) {
this.pushQuery(`drop schema ${this.formatter.wrap(schemaName)}`);
}
dropSchemaIfExists(schemaName) {
this.pushQuery(`drop schema if exists ${this.formatter.wrap(schemaName)}`);
}
dropExtension(extensionName) {
this.pushQuery(`drop extension ${this.formatter.wrap(extensionName)}`);
}
dropExtensionIfExists(extensionName) {
this.pushQuery(
`drop extension if exists ${this.formatter.wrap(extensionName)}`
);
}
createExtension(extensionName) {
this.pushQuery(`create extension ${this.formatter.wrap(extensionName)}`);
}
createExtensionIfNotExists(extensionName) {
this.pushQuery(
`create extension if not exists ${this.formatter.wrap(extensionName)}`
);
}
}
module.exports = SchemaCompiler_PG;

View File

@ -6,10 +6,10 @@ const map = require('lodash/map');
const Transaction = require('./transaction');
const QueryCompiler = require('./query/compiler');
const ColumnBuilder = require('./schema/columnbuilder');
const ColumnCompiler = require('./schema/columncompiler');
const TableCompiler = require('./schema/tablecompiler');
const SchemaCompiler = require('./schema/compiler');
const ColumnBuilder = require('./schema/redshift-columnbuilder');
const ColumnCompiler = require('./schema/redshift-columncompiler');
const TableCompiler = require('./schema/redshift-tablecompiler');
const SchemaCompiler = require('./schema/redshift-compiler');
function Client_Redshift(config) {
Client_PG.apply(this, arguments);

View File

@ -1,14 +0,0 @@
/* eslint max-len: 0 */
// Redshift Table Builder & Compiler
// -------
const { inherits } = require('util');
const SchemaCompiler_PG = require('../../postgres/schema/compiler');
function SchemaCompiler_Redshift() {
SchemaCompiler_PG.apply(this, arguments);
}
inherits(SchemaCompiler_Redshift, SchemaCompiler_PG);
module.exports = SchemaCompiler_Redshift;

View File

@ -2,7 +2,7 @@
// -------
const { inherits } = require('util');
const ColumnCompiler_PG = require('../../postgres/schema/columncompiler');
const ColumnCompiler_PG = require('../../postgres/schema/pg-columncompiler');
function ColumnCompiler_Redshift() {
ColumnCompiler_PG.apply(this, arguments);

View File

@ -0,0 +1,14 @@
/* eslint max-len: 0 */
// Redshift Table Builder & Compiler
// -------
const SchemaCompiler_PG = require('../../postgres/schema/pg-compiler');
class SchemaCompiler_Redshift extends SchemaCompiler_PG {
constructor() {
super(...arguments);
}
}
module.exports = SchemaCompiler_Redshift;

View File

@ -5,7 +5,7 @@
const { inherits } = require('util');
const has = require('lodash/has');
const TableCompiler_PG = require('../../postgres/schema/tablecompiler');
const TableCompiler_PG = require('../../postgres/schema/pg-tablecompiler');
function TableCompiler_Redshift() {
TableCompiler_PG.apply(this, arguments);

View File

@ -8,9 +8,9 @@ const Client = require('../../client');
const Transaction = require('./transaction');
const QueryCompiler = require('./query/compiler');
const SchemaCompiler = require('./schema/compiler');
const ColumnCompiler = require('./schema/columncompiler');
const TableCompiler = require('./schema/tablecompiler');
const SchemaCompiler = require('./schema/sqlite-compiler');
const ColumnCompiler = require('./schema/sqlite-columncompiler');
const TableCompiler = require('./schema/sqlite-tablecompiler');
const SQLite3_DDL = require('./schema/ddl');
const SQLite3_Formatter = require('./formatter');

View File

@ -1,49 +0,0 @@
// SQLite3: Column Builder & Compiler
// -------
const { inherits } = require('util');
const SchemaCompiler = require('../../../schema/compiler');
const some = require('lodash/some');
// Schema Compiler
// -------
function SchemaCompiler_SQLite3() {
SchemaCompiler.apply(this, arguments);
}
inherits(SchemaCompiler_SQLite3, SchemaCompiler);
// Compile the query to determine if a table exists.
SchemaCompiler_SQLite3.prototype.hasTable = function (tableName) {
const sql =
`select * from sqlite_master ` +
`where type = 'table' and name = ${this.formatter.parameter(tableName)}`;
this.pushQuery({ sql, output: (resp) => resp.length > 0 });
};
// Compile the query to determine if a column exists.
SchemaCompiler_SQLite3.prototype.hasColumn = function (tableName, column) {
this.pushQuery({
sql: `PRAGMA table_info(${this.formatter.wrap(tableName)})`,
output(resp) {
return some(resp, (col) => {
return (
this.client.wrapIdentifier(col.name.toLowerCase()) ===
this.client.wrapIdentifier(column.toLowerCase())
);
});
},
});
};
// Compile a rename table command.
SchemaCompiler_SQLite3.prototype.renameTable = function (from, to) {
this.pushQuery(
`alter table ${this.formatter.wrap(from)} rename to ${this.formatter.wrap(
to
)}`
);
};
module.exports = SchemaCompiler_SQLite3;

View File

@ -0,0 +1,48 @@
// SQLite3: Column Builder & Compiler
// -------
const SchemaCompiler = require('../../../schema/compiler');
const some = require('lodash/some');
// Schema Compiler
// -------
class SchemaCompiler_SQLite3 extends SchemaCompiler {
constructor() {
super(...arguments);
}
// Compile the query to determine if a table exists.
hasTable(tableName) {
const sql =
`select * from sqlite_master ` +
`where type = 'table' and name = ${this.formatter.parameter(tableName)}`;
this.pushQuery({ sql, output: (resp) => resp.length > 0 });
}
// Compile the query to determine if a column exists.
hasColumn(tableName, column) {
this.pushQuery({
sql: `PRAGMA table_info(${this.formatter.wrap(tableName)})`,
output(resp) {
return some(resp, (col) => {
return (
this.client.wrapIdentifier(col.name.toLowerCase()) ===
this.client.wrapIdentifier(column.toLowerCase())
);
});
},
});
}
// Compile a rename table command.
renameTable(from, to) {
this.pushQuery(
`alter table ${this.formatter.wrap(from)} rename to ${this.formatter.wrap(
to
)}`
);
}
}
module.exports = SchemaCompiler_SQLite3;

View File

@ -7,55 +7,38 @@ const {
// The "SchemaCompiler" takes all of the query statements which have been
// gathered in the "SchemaBuilder" and turns them into an array of
// properly formatted / bound query strings.
function SchemaCompiler(client, builder) {
this.builder = builder;
this._commonBuilder = this.builder;
this.client = client;
this.schema = builder._schema;
this.formatter = client.formatter(builder);
this.sequence = [];
}
class SchemaCompiler {
constructor(client, builder) {
this.builder = builder;
this._commonBuilder = this.builder;
this.client = client;
this.schema = builder._schema;
this.formatter = client.formatter(builder);
this.sequence = [];
}
function throwOnlyPGError(operationName) {
throw new Error(
`${operationName} is not supported for this dialect (only PostgreSQL supports it currently).`
);
}
Object.assign(SchemaCompiler.prototype, {
pushQuery: pushQuery,
pushAdditional: pushAdditional,
unshiftQuery: unshiftQuery,
createTable: buildTable('create'),
createTableIfNotExists: buildTable('createIfNot'),
createSchema: () => {
createSchema() {
throwOnlyPGError('createSchema');
},
createSchemaIfNotExists: () => {
}
createSchemaIfNotExists() {
throwOnlyPGError('createSchemaIfNotExists');
},
dropSchema: () => {
}
dropSchema() {
throwOnlyPGError('dropSchema');
},
dropSchemaIfExists: () => {
}
dropSchemaIfExists() {
throwOnlyPGError('dropSchemaIfExists');
},
alterTable: buildTable('alter'),
dropTablePrefix: 'drop table ',
}
dropTable(tableName) {
this.pushQuery(
this.dropTablePrefix +
this.formatter.wrap(prefixedTableName(this.schema, tableName))
);
},
}
dropTableIfExists(tableName) {
this.pushQuery(
@ -63,11 +46,11 @@ Object.assign(SchemaCompiler.prototype, {
'if exists ' +
this.formatter.wrap(prefixedTableName(this.schema, tableName))
);
},
}
raw(sql, bindings) {
this.sequence.push(this.client.raw(sql, bindings).toSQL());
},
}
toSQL() {
const sequence = this.builder._sequence;
@ -76,8 +59,18 @@ Object.assign(SchemaCompiler.prototype, {
this[query.method].apply(this, query.args);
}
return this.sequence;
},
});
}
}
SchemaCompiler.prototype.dropTablePrefix = 'drop table ';
SchemaCompiler.prototype.alterTable = buildTable('alter');
SchemaCompiler.prototype.createTable = buildTable('create');
SchemaCompiler.prototype.createTableIfNotExists = buildTable('createIfNot');
SchemaCompiler.prototype.pushQuery = pushQuery;
SchemaCompiler.prototype.pushAdditional = pushAdditional;
SchemaCompiler.prototype.unshiftQuery = unshiftQuery;
function buildTable(type) {
return function (tableName, fn) {
@ -102,4 +95,10 @@ function prefixedTableName(prefix, table) {
return prefix ? `${prefix}.${table}` : table;
}
function throwOnlyPGError(operationName) {
throw new Error(
`${operationName} is not supported for this dialect (only PostgreSQL supports it currently).`
);
}
module.exports = SchemaCompiler;

View File

@ -12,63 +12,142 @@ const toArray = require('lodash/toArray');
const helpers = require('../util/helpers');
const { isString, isFunction } = require('../util/is');
function TableBuilder(client, method, tableName, fn) {
this.client = client;
this._fn = fn;
this._method = method;
this._schemaName = undefined;
this._tableName = tableName;
this._statements = [];
this._single = {};
class TableBuilder {
constructor(client, method, tableName, fn) {
this.client = client;
this._fn = fn;
this._method = method;
this._schemaName = undefined;
this._tableName = tableName;
this._statements = [];
this._single = {};
if (!isFunction(this._fn)) {
throw new TypeError(
'A callback function must be supplied to calls against `.createTable` ' +
'and `.table`'
);
if (!isFunction(this._fn)) {
throw new TypeError(
'A callback function must be supplied to calls against `.createTable` ' +
'and `.table`'
);
}
}
setSchema(schemaName) {
this._schemaName = schemaName;
}
// Convert the current tableBuilder object "toSQL"
// giving us additional methods if we're altering
// rather than creating the table.
toSQL() {
if (this._method === 'alter') {
extend(this, AlterMethods);
}
this._fn.call(this, this);
return this.client.tableCompiler(this).toSQL();
}
// The "timestamps" call is really just sets the `created_at` and `updated_at` columns.
timestamps() {
const method = arguments[0] === true ? 'timestamp' : 'datetime';
const createdAt = this[method]('created_at');
const updatedAt = this[method]('updated_at');
if (arguments[1] === true) {
const now = this.client.raw('CURRENT_TIMESTAMP');
createdAt.notNullable().defaultTo(now);
updatedAt.notNullable().defaultTo(now);
}
return;
}
// Set the comment value for a table, they're only allowed to be called
// once per table.
comment(value) {
if (typeof value !== 'string') {
throw new TypeError('Table comment must be string');
}
this._single.comment = value;
}
// Set a foreign key on the table, calling
// `table.foreign('column_name').references('column').on('table').onDelete()...
// Also called from the ColumnBuilder context when chaining.
foreign(column, keyName) {
const foreignData = { column: column, keyName: keyName };
this._statements.push({
grouping: 'alterTable',
method: 'foreign',
args: [foreignData],
});
let returnObj = {
references(tableColumn) {
let pieces;
if (isString(tableColumn)) {
pieces = tableColumn.split('.');
}
if (!pieces || pieces.length === 1) {
foreignData.references = pieces ? pieces[0] : tableColumn;
return {
on(tableName) {
if (typeof tableName !== 'string') {
throw new TypeError(
`Expected tableName to be a string, got: ${typeof tableName}`
);
}
foreignData.inTable = tableName;
return returnObj;
},
inTable() {
return this.on.apply(this, arguments);
},
};
}
foreignData.inTable = pieces[0];
foreignData.references = pieces[1];
return returnObj;
},
withKeyName(keyName) {
foreignData.keyName = keyName;
return returnObj;
},
onUpdate(statement) {
foreignData.onUpdate = statement;
return returnObj;
},
onDelete(statement) {
foreignData.onDelete = statement;
return returnObj;
},
_columnBuilder(builder) {
extend(builder, returnObj);
returnObj = builder;
return builder;
},
};
return returnObj;
}
}
TableBuilder.prototype.setSchema = function (schemaName) {
this._schemaName = schemaName;
};
[
// Each of the index methods can be called individually, with the
// column name to be used, e.g. table.unique('column').
'index',
'primary',
'unique',
// Convert the current tableBuilder object "toSQL"
// giving us additional methods if we're altering
// rather than creating the table.
TableBuilder.prototype.toSQL = function () {
if (this._method === 'alter') {
extend(this, AlterMethods);
}
this._fn.call(this, this);
return this.client.tableCompiler(this).toSQL();
};
each(
[
// Each of the index methods can be called individually, with the
// column name to be used, e.g. table.unique('column').
'index',
'primary',
'unique',
// Key specific
'dropPrimary',
'dropUnique',
'dropIndex',
'dropForeign',
],
function (method) {
TableBuilder.prototype[method] = function () {
this._statements.push({
grouping: 'alterTable',
method,
args: toArray(arguments),
});
return this;
};
}
);
// Key specific
'dropPrimary',
'dropUnique',
'dropIndex',
'dropForeign',
].forEach((method) => {
TableBuilder.prototype[method] = function () {
this._statements.push({
grouping: 'alterTable',
method,
args: toArray(arguments),
});
return this;
};
});
// Warn for dialect-specific table methods, since that's the
// only time these are supported.
@ -163,7 +242,7 @@ const columnTypes = [
// For each of the column methods, create a new "ColumnBuilder" interface,
// push it onto the "allStatements" stack, and then return the interface,
// with which we can add indexes, etc.
each(columnTypes, function (type) {
columnTypes.forEach((type) => {
TableBuilder.prototype[type] = function () {
const args = toArray(arguments);
const builder = this.client.columnBuilder(this, type, args);
@ -175,86 +254,6 @@ each(columnTypes, function (type) {
};
});
// The "timestamps" call is really just sets the `created_at` and `updated_at` columns.
TableBuilder.prototype.timestamps = function timestamps() {
const method = arguments[0] === true ? 'timestamp' : 'datetime';
const createdAt = this[method]('created_at');
const updatedAt = this[method]('updated_at');
if (arguments[1] === true) {
const now = this.client.raw('CURRENT_TIMESTAMP');
createdAt.notNullable().defaultTo(now);
updatedAt.notNullable().defaultTo(now);
}
return;
};
// Set the comment value for a table, they're only allowed to be called
// once per table.
TableBuilder.prototype.comment = function (value) {
if (typeof value !== 'string') {
throw new TypeError('Table comment must be string');
}
this._single.comment = value;
};
// Set a foreign key on the table, calling
// `table.foreign('column_name').references('column').on('table').onDelete()...
// Also called from the ColumnBuilder context when chaining.
TableBuilder.prototype.foreign = function (column, keyName) {
const foreignData = { column: column, keyName: keyName };
this._statements.push({
grouping: 'alterTable',
method: 'foreign',
args: [foreignData],
});
let returnObj = {
references(tableColumn) {
let pieces;
if (isString(tableColumn)) {
pieces = tableColumn.split('.');
}
if (!pieces || pieces.length === 1) {
foreignData.references = pieces ? pieces[0] : tableColumn;
return {
on(tableName) {
if (typeof tableName !== 'string') {
throw new TypeError(
`Expected tableName to be a string, got: ${typeof tableName}`
);
}
foreignData.inTable = tableName;
return returnObj;
},
inTable() {
return this.on.apply(this, arguments);
},
};
}
foreignData.inTable = pieces[0];
foreignData.references = pieces[1];
return returnObj;
},
withKeyName(keyName) {
foreignData.keyName = keyName;
return returnObj;
},
onUpdate(statement) {
foreignData.onUpdate = statement;
return returnObj;
},
onDelete(statement) {
foreignData.onDelete = statement;
return returnObj;
},
_columnBuilder(builder) {
extend(builder, returnObj);
returnObj = builder;
return builder;
},
};
return returnObj;
};
const AlterMethods = {
// Renames the current column `from` the current
// TODO: this.column(from).rename(to)