mirror of
https://github.com/knex/knex.git
synced 2025-12-28 15:38:41 +00:00
parent
2b1e37ca44
commit
7c52de9f23
@ -98,8 +98,8 @@ class Client extends EventEmitter {
|
||||
return new SchemaCompiler(this, builder);
|
||||
}
|
||||
|
||||
tableBuilder(type, tableName, fn) {
|
||||
return new TableBuilder(this, type, tableName, fn);
|
||||
tableBuilder(type, tableName, tableNameLike, fn) {
|
||||
return new TableBuilder(this, type, tableName, tableNameLike, fn);
|
||||
}
|
||||
|
||||
tableCompiler(tableBuilder) {
|
||||
|
||||
@ -14,18 +14,24 @@ class TableCompiler_MSSQL extends TableCompiler {
|
||||
super(client, tableBuilder);
|
||||
}
|
||||
|
||||
createQuery(columns, ifNot) {
|
||||
const createStatement = ifNot
|
||||
? `if object_id('${this.tableName()}', 'U') is null CREATE TABLE `
|
||||
: 'CREATE TABLE ';
|
||||
const sql =
|
||||
createStatement +
|
||||
this.tableName() +
|
||||
(this._formatting ? ' (\n ' : ' (') +
|
||||
columns.sql.join(this._formatting ? ',\n ' : ', ') +
|
||||
')';
|
||||
createQuery(columns, ifNot, like) {
|
||||
let createStatement = ifNot
|
||||
? `if object_id('${this.tableName()}', 'U') is null `
|
||||
: '';
|
||||
|
||||
this.pushQuery(sql);
|
||||
if (like) {
|
||||
// This query copy only columns and not all indexes and keys like other databases.
|
||||
createStatement += `SELECT * INTO ${this.tableName()} FROM ${this.tableNameLike()} WHERE 0=1`;
|
||||
} else {
|
||||
createStatement +=
|
||||
'CREATE TABLE ' +
|
||||
this.tableName() +
|
||||
(this._formatting ? ' (\n ' : ' (') +
|
||||
columns.sql.join(this._formatting ? ',\n ' : ', ') +
|
||||
')';
|
||||
}
|
||||
|
||||
this.pushQuery(createStatement);
|
||||
|
||||
if (this.single.comment) {
|
||||
this.comment(this.single.comment);
|
||||
|
||||
@ -13,14 +13,19 @@ class TableCompiler_MySQL extends TableCompiler {
|
||||
super(client, tableBuilder);
|
||||
}
|
||||
|
||||
createQuery(columns, ifNot) {
|
||||
createQuery(columns, ifNot, like) {
|
||||
const createStatement = ifNot
|
||||
? 'create table if not exists '
|
||||
: 'create table ';
|
||||
const { client } = this;
|
||||
let conn = {};
|
||||
const columnsSql = ' (' + columns.sql.join(', ') + ')';
|
||||
let sql =
|
||||
createStatement + this.tableName() + ' (' + columns.sql.join(', ') + ')';
|
||||
createStatement +
|
||||
this.tableName() +
|
||||
(like && this.tableNameLike()
|
||||
? ' like ' + this.tableNameLike()
|
||||
: columnsSql);
|
||||
|
||||
// Check if the connection settings are set.
|
||||
if (client.connectionSettings) {
|
||||
@ -31,8 +36,7 @@ class TableCompiler_MySQL extends TableCompiler {
|
||||
const collation = this.single.collate || conn.collate || '';
|
||||
const engine = this.single.engine || '';
|
||||
|
||||
// var conn = builder.client.connectionSettings;
|
||||
if (charset) sql += ` default character set ${charset}`;
|
||||
if (charset && !like) sql += ` default character set ${charset}`;
|
||||
if (collation) sql += ` collate ${collation}`;
|
||||
if (engine) sql += ` engine = ${engine}`;
|
||||
|
||||
|
||||
@ -53,8 +53,13 @@ class TableCompiler_Oracle extends TableCompiler {
|
||||
}
|
||||
|
||||
// Adds the "create" query to the query sequence.
|
||||
createQuery(columns, ifNot) {
|
||||
const sql = `create table ${this.tableName()} (${columns.sql.join(', ')})`;
|
||||
createQuery(columns, ifNot, like) {
|
||||
const columnsSql =
|
||||
like && this.tableNameLike()
|
||||
? ' as (select * from ' + this.tableNameLike() + ' where 0=1)'
|
||||
: ' (' + columns.sql.join(', ') + ')';
|
||||
const sql = `create table ${this.tableName()}${columnsSql}`;
|
||||
|
||||
this.pushQuery({
|
||||
// catch "name is already used by an existing object" for workaround for "if not exists"
|
||||
sql: ifNot ? utils.wrapSqlWithCatch(sql, -955) : sql,
|
||||
|
||||
@ -40,12 +40,17 @@ class TableCompiler_PG extends TableCompiler {
|
||||
}
|
||||
|
||||
// Adds the "create" query to the query sequence.
|
||||
createQuery(columns, ifNot) {
|
||||
createQuery(columns, ifNot, like) {
|
||||
const createStatement = ifNot
|
||||
? 'create table if not exists '
|
||||
: 'create table ';
|
||||
const columnsSql = ' (' + columns.sql.join(', ') + ')';
|
||||
let sql =
|
||||
createStatement + this.tableName() + ' (' + columns.sql.join(', ') + ')';
|
||||
createStatement +
|
||||
this.tableName() +
|
||||
(like && this.tableNameLike()
|
||||
? ' (like ' + this.tableNameLike() + ' including all)'
|
||||
: columnsSql);
|
||||
if (this.single.inherits)
|
||||
sql += ` inherits (${this.formatter.wrap(this.single.inherits)})`;
|
||||
this.pushQuery({
|
||||
|
||||
@ -26,12 +26,17 @@ class TableCompiler_Redshift extends TableCompiler_PG {
|
||||
// TODO: have to disable setting not null on columns that already exist...
|
||||
|
||||
// Adds the "create" query to the query sequence.
|
||||
createQuery(columns, ifNot) {
|
||||
createQuery(columns, ifNot, like) {
|
||||
const createStatement = ifNot
|
||||
? 'create table if not exists '
|
||||
: 'create table ';
|
||||
const columnsSql = ' (' + columns.sql.join(', ') + ')';
|
||||
let sql =
|
||||
createStatement + this.tableName() + ' (' + columns.sql.join(', ') + ')';
|
||||
createStatement +
|
||||
this.tableName() +
|
||||
(like && this.tableNameLike()
|
||||
? ' (like ' + this.tableNameLike() + ')'
|
||||
: columnsSql);
|
||||
if (this.single.inherits)
|
||||
sql += ` like (${this.formatter.wrap(this.single.inherits)})`;
|
||||
this.pushQuery({
|
||||
|
||||
@ -12,20 +12,23 @@ class TableCompiler_SQLite3 extends TableCompiler {
|
||||
}
|
||||
|
||||
// Create a new table.
|
||||
createQuery(columns, ifNot) {
|
||||
createQuery(columns, ifNot, like) {
|
||||
const createStatement = ifNot
|
||||
? 'create table if not exists '
|
||||
: 'create table ';
|
||||
let sql =
|
||||
createStatement + this.tableName() + ' (' + columns.sql.join(', ');
|
||||
|
||||
// SQLite forces primary keys to be added when the table is initially created
|
||||
// so we will need to check for a primary key commands and add the columns
|
||||
// to the table's declaration here so they can be created on the tables.
|
||||
sql += this.foreignKeys() || '';
|
||||
sql += this.primaryKeys() || '';
|
||||
sql += ')';
|
||||
let sql = createStatement + this.tableName();
|
||||
|
||||
if (like && this.tableNameLike()) {
|
||||
sql += ' as select * from ' + this.tableNameLike() + ' where 0=1';
|
||||
} else {
|
||||
// so we will need to check for a primary key commands and add the columns
|
||||
// to the table's declaration here so they can be created on the tables.
|
||||
sql += ' (' + columns.sql.join(', ');
|
||||
sql += this.foreignKeys() || '';
|
||||
sql += this.primaryKeys() || '';
|
||||
sql += ')';
|
||||
}
|
||||
this.pushQuery(sql);
|
||||
}
|
||||
|
||||
|
||||
@ -45,6 +45,7 @@ class SchemaBuilder extends EventEmitter {
|
||||
[
|
||||
'createTable',
|
||||
'createTableIfNotExists',
|
||||
'createTableLike',
|
||||
'createSchema',
|
||||
'createSchemaIfNotExists',
|
||||
'dropSchema',
|
||||
|
||||
@ -82,15 +82,14 @@ SchemaCompiler.prototype.dropTablePrefix = 'drop table ';
|
||||
SchemaCompiler.prototype.alterTable = buildTable('alter');
|
||||
SchemaCompiler.prototype.createTable = buildTable('create');
|
||||
SchemaCompiler.prototype.createTableIfNotExists = buildTable('createIfNot');
|
||||
SchemaCompiler.prototype.createTableLike = buildTable('createLike');
|
||||
|
||||
SchemaCompiler.prototype.pushQuery = pushQuery;
|
||||
SchemaCompiler.prototype.pushAdditional = pushAdditional;
|
||||
SchemaCompiler.prototype.unshiftQuery = unshiftQuery;
|
||||
|
||||
function buildTable(type) {
|
||||
return function (tableName, fn) {
|
||||
const builder = this.client.tableBuilder(type, tableName, fn);
|
||||
|
||||
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) {
|
||||
@ -103,7 +102,24 @@ function buildTable(type) {
|
||||
for (let i = 0, l = sql.length; i < l; i++) {
|
||||
this.sequence.push(sql[i]);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
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 prefixedTableName(prefix, table) {
|
||||
|
||||
@ -13,16 +13,17 @@ const helpers = require('../util/helpers');
|
||||
const { isString, isFunction } = require('../util/is');
|
||||
|
||||
class TableBuilder {
|
||||
constructor(client, method, tableName, fn) {
|
||||
constructor(client, method, tableName, tableNameLike, fn) {
|
||||
this.client = client;
|
||||
this._fn = fn;
|
||||
this._method = method;
|
||||
this._schemaName = undefined;
|
||||
this._tableName = tableName;
|
||||
this._tableNameLike = tableNameLike;
|
||||
this._statements = [];
|
||||
this._single = {};
|
||||
|
||||
if (!isFunction(this._fn)) {
|
||||
if (!tableNameLike && !isFunction(this._fn)) {
|
||||
throw new TypeError(
|
||||
'A callback function must be supplied to calls against `.createTable` ' +
|
||||
'and `.table`'
|
||||
@ -41,7 +42,10 @@ class TableBuilder {
|
||||
if (this._method === 'alter') {
|
||||
extend(this, AlterMethods);
|
||||
}
|
||||
this._fn.call(this, this);
|
||||
// With 'create table ... like' callback function is useless.
|
||||
if (this._fn) {
|
||||
this._fn.call(this, this);
|
||||
}
|
||||
return this.client.tableCompiler(this).toSQL();
|
||||
}
|
||||
|
||||
|
||||
@ -21,6 +21,7 @@ class TableCompiler {
|
||||
this.method = tableBuilder._method;
|
||||
this.schemaNameRaw = tableBuilder._schemaName;
|
||||
this.tableNameRaw = tableBuilder._tableName;
|
||||
this.tableNameLikeRaw = tableBuilder._tableNameLike;
|
||||
this.single = tableBuilder._single;
|
||||
this.grouped = groupBy(tableBuilder._statements, 'grouping');
|
||||
|
||||
@ -45,14 +46,14 @@ class TableCompiler {
|
||||
// If this is a table "creation", we need to first run through all
|
||||
// of the columns to build them into a single string,
|
||||
// and then run through anything else and push it to the query sequence.
|
||||
create(ifNot) {
|
||||
create(ifNot, like) {
|
||||
const columnBuilders = this.getColumns();
|
||||
const columns = columnBuilders.map((col) => col.toSQL());
|
||||
const columnTypes = this.getColumnTypes(columns);
|
||||
if (this.createAlterTableMethods) {
|
||||
this.alterTableForCreate(columnTypes);
|
||||
}
|
||||
this.createQuery(columnTypes, ifNot);
|
||||
this.createQuery(columnTypes, ifNot, like);
|
||||
this.columnQueries(columns);
|
||||
delete this.single.comment;
|
||||
this.alterTable();
|
||||
@ -63,6 +64,14 @@ class TableCompiler {
|
||||
this.create(true);
|
||||
}
|
||||
|
||||
createLike() {
|
||||
this.create(false, true);
|
||||
}
|
||||
|
||||
createLikeIfNot() {
|
||||
this.create(true, true);
|
||||
}
|
||||
|
||||
// If we're altering the table, we need to one-by-one
|
||||
// go through and handle each of the queries associated
|
||||
// with altering the table's schema.
|
||||
@ -219,6 +228,14 @@ class TableCompiler {
|
||||
return this.formatter.wrap(name);
|
||||
}
|
||||
|
||||
tableNameLike() {
|
||||
const name = this.schemaNameRaw
|
||||
? `${this.schemaNameRaw}.${this.tableNameLikeRaw}`
|
||||
: this.tableNameLikeRaw;
|
||||
|
||||
return this.formatter.wrap(name);
|
||||
}
|
||||
|
||||
// Generate all of the alter column statements necessary for the query.
|
||||
alterTable() {
|
||||
const alterTable = this.grouped.alterTable || [];
|
||||
|
||||
@ -271,6 +271,57 @@ describe('Schema (misc)', () => {
|
||||
});
|
||||
|
||||
describe('createTable', () => {
|
||||
describe('like another table', () => {
|
||||
before(async () => {
|
||||
await knex.schema.createTable('table_to_copy', (table) => {
|
||||
table.increments('id');
|
||||
table.string('data');
|
||||
table.index('data', 'data_index');
|
||||
});
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await knex.schema.dropTableIfExists('table_copied');
|
||||
await knex.schema.dropTableIfExists('table_to_copy');
|
||||
});
|
||||
|
||||
it('copy table', async () => {
|
||||
await knex.schema
|
||||
.createTableLike('table_copied', 'table_to_copy')
|
||||
.testSql((tester) => {
|
||||
tester('mysql', [
|
||||
'create table `table_copied` like `table_to_copy`',
|
||||
]);
|
||||
tester(
|
||||
['pg', 'cockroachdb'],
|
||||
[
|
||||
'create table "table_copied" (like "table_to_copy" including all)',
|
||||
]
|
||||
);
|
||||
tester('pg-redshift', [
|
||||
'create table "table_copied" (like "table_to_copy")',
|
||||
]);
|
||||
tester('sqlite3', [
|
||||
'create table `table_copied` as select * from `table_to_copy` where 0=1',
|
||||
]);
|
||||
tester('oracledb', [
|
||||
'create table "table_copied" as (select * from "table_to_copy" where 0=1)',
|
||||
]);
|
||||
tester('mssql', [
|
||||
'SELECT * INTO [table_copied] FROM [table_to_copy] WHERE 0=1',
|
||||
]);
|
||||
});
|
||||
|
||||
expect(await knex.schema.hasTable('table_copied')).to.equal(true);
|
||||
|
||||
await knex('table_copied')
|
||||
.columnInfo()
|
||||
.then((res) => {
|
||||
expect(Object.keys(res)).to.have.all.members(['id', 'data']);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('increments types - postgres', () => {
|
||||
if (!isPgBased(knex)) {
|
||||
return Promise.resolve();
|
||||
|
||||
@ -38,6 +38,17 @@ describe('MSSQL SchemaBuilder', function () {
|
||||
);
|
||||
});
|
||||
|
||||
it('create table like another', function () {
|
||||
tableSql = client
|
||||
.schemaBuilder()
|
||||
.createTableLike('users_like', 'users')
|
||||
.toSQL();
|
||||
equal(1, tableSql.length);
|
||||
expect(tableSql[0].sql).to.equal(
|
||||
'SELECT * INTO [users_like] FROM [users] WHERE 0=1'
|
||||
);
|
||||
});
|
||||
|
||||
it('test basic create table with incrementing without primary key', function () {
|
||||
tableSql = client.schemaBuilder().createTable('users', function (table) {
|
||||
table.increments('id', { primaryKey: false });
|
||||
|
||||
@ -34,6 +34,17 @@ module.exports = function (dialect) {
|
||||
);
|
||||
});
|
||||
|
||||
it('create table like another', function () {
|
||||
tableSql = client
|
||||
.schemaBuilder()
|
||||
.createTableLike('users_like', 'users')
|
||||
.toSQL();
|
||||
equal(1, tableSql.length);
|
||||
expect(tableSql[0].sql).to.equal(
|
||||
'create table `users_like` like `users`'
|
||||
);
|
||||
});
|
||||
|
||||
it('test basic create table with incrementing without primary key', function () {
|
||||
tableSql = client
|
||||
.schemaBuilder()
|
||||
|
||||
@ -41,6 +41,17 @@ describe('Oracle SchemaBuilder', function () {
|
||||
);
|
||||
});
|
||||
|
||||
it('create table like another', function () {
|
||||
tableSql = client
|
||||
.schemaBuilder()
|
||||
.createTableLike('users_like', 'users')
|
||||
.toSQL();
|
||||
equal(1, tableSql.length);
|
||||
expect(tableSql[0].sql).to.equal(
|
||||
'create table "users_like" as (select * from "users" where 0=1)'
|
||||
);
|
||||
});
|
||||
|
||||
it('test basic create table if not exists', function () {
|
||||
tableSql = client
|
||||
.schemaBuilder()
|
||||
|
||||
@ -25,6 +25,15 @@ describe('OracleDb SchemaBuilder', function () {
|
||||
);
|
||||
});
|
||||
|
||||
it('test basic create table like', function () {
|
||||
tableSql = client.schemaBuilder().createTableLike('users_like', 'users');
|
||||
|
||||
equal(1, tableSql.toSQL().length);
|
||||
expect(tableSql.toSQL()[0].sql).to.equal(
|
||||
'create table "users_like" as (select * from "users" where 0=1)'
|
||||
);
|
||||
});
|
||||
|
||||
it('test basic create table if not exists', function () {
|
||||
tableSql = client
|
||||
.schemaBuilder()
|
||||
|
||||
@ -112,6 +112,17 @@ describe('PostgreSQL SchemaBuilder', function () {
|
||||
);
|
||||
});
|
||||
|
||||
it('create table like another', function () {
|
||||
tableSql = client
|
||||
.schemaBuilder()
|
||||
.createTableLike('users_like', 'users')
|
||||
.toSQL();
|
||||
equal(1, tableSql.length);
|
||||
expect(tableSql[0].sql).to.equal(
|
||||
'create table "users_like" (like "users" including all)'
|
||||
);
|
||||
});
|
||||
|
||||
it('basic alter table', function () {
|
||||
tableSql = client
|
||||
.schemaBuilder()
|
||||
|
||||
@ -26,6 +26,17 @@ describe('Redshift SchemaBuilder', function () {
|
||||
);
|
||||
});
|
||||
|
||||
it('create table like another', function () {
|
||||
tableSql = client
|
||||
.schemaBuilder()
|
||||
.createTableLike('users_like', 'users')
|
||||
.toSQL();
|
||||
equal(1, tableSql.length);
|
||||
expect(tableSql[0].sql).to.equal(
|
||||
'create table "users_like" (like "users")'
|
||||
);
|
||||
});
|
||||
|
||||
it('basic alter table', function () {
|
||||
tableSql = client
|
||||
.schemaBuilder()
|
||||
|
||||
@ -36,6 +36,19 @@ describe('SQLite SchemaBuilder', function () {
|
||||
);
|
||||
});
|
||||
|
||||
it('basic create table like', function () {
|
||||
tableSql = client
|
||||
.schemaBuilder()
|
||||
.createTableLike('users', 'users_like')
|
||||
.toSQL();
|
||||
|
||||
equal(1, tableSql.length);
|
||||
equal(
|
||||
tableSql[0].sql,
|
||||
'create table `users` as select * from `users_like` where 0=1'
|
||||
);
|
||||
});
|
||||
|
||||
it('create json table', function () {
|
||||
tableSql = client
|
||||
.schemaBuilder()
|
||||
|
||||
7
types/index.d.ts
vendored
7
types/index.d.ts
vendored
@ -1841,6 +1841,11 @@ export declare namespace Knex {
|
||||
tableName: string,
|
||||
callback: (tableBuilder: CreateTableBuilder) => any
|
||||
): SchemaBuilder;
|
||||
createTableLike(
|
||||
tableName: string,
|
||||
tableNameLike: string,
|
||||
callback: (tableBuilder: CreateTableBuilder) => any
|
||||
): SchemaBuilder;
|
||||
createSchema(schemaName: string): SchemaBuilder;
|
||||
createSchemaIfNotExists(schemaName: string): SchemaBuilder;
|
||||
alterTable(
|
||||
@ -2479,7 +2484,7 @@ export declare namespace Knex {
|
||||
queryCompiler(builder: any): any;
|
||||
schemaBuilder(): SchemaBuilder;
|
||||
schemaCompiler(builder: SchemaBuilder): any;
|
||||
tableBuilder(type: any, tableName: any, fn: any): TableBuilder;
|
||||
tableBuilder(type: any, tableName: any, tableNameLike: any, fn: any): TableBuilder;
|
||||
tableCompiler(tableBuilder: any): any;
|
||||
columnBuilder(tableBuilder: any, type: any, args: any): ColumnBuilder;
|
||||
columnCompiler(tableBuilder: any, columnBuilder: any): any;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user