2025-03-23 21:00:08 +01:00

188 lines
5.0 KiB
JavaScript

const {
pushQuery,
pushAdditional,
unshiftQuery,
} = require('./internal/helpers');
// 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.
class SchemaCompiler {
constructor(client, builder) {
this.builder = builder;
this._commonBuilder = this.builder;
this.client = client;
this.schema = builder._schema;
this.bindings = [];
this.bindingsHolder = this;
this.formatter = client.formatter(builder);
this.formatter.bindings = this.bindings;
this.sequence = [];
}
createSchema() {
throwOnlyPGError('createSchema');
}
createSchemaIfNotExists() {
throwOnlyPGError('createSchemaIfNotExists');
}
dropSchema() {
throwOnlyPGError('dropSchema');
}
dropSchemaIfExists() {
throwOnlyPGError('dropSchemaIfExists');
}
dropTable(tableName) {
this.pushQuery(
this.dropTablePrefix +
this.formatter.wrap(prefixedTableName(this.schema, tableName))
);
}
dropTableIfExists(tableName) {
this.pushQuery(
this.dropTablePrefix +
'if exists ' +
this.formatter.wrap(prefixedTableName(this.schema, tableName))
);
}
dropView(viewName) {
this._dropView(viewName, false, false);
}
dropViewIfExists(viewName) {
this._dropView(viewName, true, false);
}
dropMaterializedView(viewName) {
throw new Error('materialized views are not supported by this dialect.');
}
dropMaterializedViewIfExists(viewName) {
throw new Error('materialized views are not supported by this dialect.');
}
renameView(from, to) {
throw new Error(
'rename view is not supported by this dialect (instead drop then create another view).'
);
}
refreshMaterializedView() {
throw new Error('materialized views are not supported by this dialect.');
}
_dropView(viewName, ifExists, materialized) {
this.pushQuery(
(materialized ? this.dropMaterializedViewPrefix : this.dropViewPrefix) +
(ifExists ? 'if exists ' : '') +
this.formatter.wrap(prefixedTableName(this.schema, viewName))
);
}
raw(sql, bindings) {
this.sequence.push(this.client.raw(sql, bindings).toSQL());
}
toSQL() {
const sequence = this.builder._sequence;
for (let i = 0, l = sequence.length; i < l; i++) {
const query = sequence[i];
this[query.method].apply(this, query.args);
}
return this.sequence;
}
async generateDdlCommands() {
const generatedCommands = this.toSQL();
return {
pre: [],
sql: Array.isArray(generatedCommands)
? generatedCommands
: [generatedCommands],
check: null,
post: [],
};
}
}
SchemaCompiler.prototype.dropTablePrefix = 'drop table ';
SchemaCompiler.prototype.dropViewPrefix = 'drop view ';
SchemaCompiler.prototype.dropMaterializedViewPrefix = 'drop materialized view ';
SchemaCompiler.prototype.alterViewPrefix = 'alter view ';
SchemaCompiler.prototype.alterTable = buildTable('alter');
SchemaCompiler.prototype.createTable = buildTable('create');
SchemaCompiler.prototype.createTableIfNotExists = buildTable('createIfNot');
SchemaCompiler.prototype.createTableLike = buildTable('createLike');
SchemaCompiler.prototype.createView = buildView('create');
SchemaCompiler.prototype.createViewOrReplace = buildView('createOrReplace');
SchemaCompiler.prototype.createMaterializedView = buildView(
'createMaterializedView'
);
SchemaCompiler.prototype.alterView = buildView('alter');
SchemaCompiler.prototype.pushQuery = pushQuery;
SchemaCompiler.prototype.pushAdditional = pushAdditional;
SchemaCompiler.prototype.unshiftQuery = unshiftQuery;
function build(builder) {
// pass queryContext down to tableBuilder but do not overwrite it if already set
const queryContext = this.builder.queryContext();
if (queryContext !== undefined && builder.queryContext() === undefined) {
builder.queryContext(queryContext);
}
builder.setSchema(this.schema);
const sql = builder.toSQL();
for (let i = 0, l = sql.length; i < l; i++) {
this.sequence.push(sql[i]);
}
}
function buildTable(type) {
if (type === 'createLike') {
return function (tableName, tableNameLike, fn) {
const builder = this.client.tableBuilder(
type,
tableName,
tableNameLike,
fn
);
build.call(this, builder);
};
} else {
return function (tableName, fn) {
const builder = this.client.tableBuilder(type, tableName, null, fn);
build.call(this, builder);
};
}
}
function buildView(type) {
return function (viewName, fn) {
const builder = this.client.viewBuilder(type, viewName, fn);
build.call(this, builder);
};
}
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;