Initial commit
This commit is contained in:
400
node_modules/knex/lib/dialects/sqlite3/schema/ddl.js
generated
vendored
Executable file
400
node_modules/knex/lib/dialects/sqlite3/schema/ddl.js
generated
vendored
Executable file
@@ -0,0 +1,400 @@
|
||||
// SQLite3_DDL
|
||||
//
|
||||
// All of the SQLite3 specific DDL helpers for renaming/dropping
|
||||
// columns and changing datatypes.
|
||||
// -------
|
||||
|
||||
const identity = require('lodash/identity');
|
||||
const { nanonum } = require('../../../util/nanoid');
|
||||
const {
|
||||
copyData,
|
||||
dropOriginal,
|
||||
renameTable,
|
||||
getTableSql,
|
||||
isForeignCheckEnabled,
|
||||
setForeignCheck,
|
||||
executeForeignCheck,
|
||||
} = require('./internal/sqlite-ddl-operations');
|
||||
const { parseCreateTable, parseCreateIndex } = require('./internal/parser');
|
||||
const {
|
||||
compileCreateTable,
|
||||
compileCreateIndex,
|
||||
} = require('./internal/compiler');
|
||||
const { isEqualId, includesId } = require('./internal/utils');
|
||||
|
||||
// So altering the schema in SQLite3 is a major pain.
|
||||
// We have our own object to deal with the renaming and altering the types
|
||||
// for sqlite3 things.
|
||||
class SQLite3_DDL {
|
||||
constructor(client, tableCompiler, pragma, connection) {
|
||||
this.client = client;
|
||||
this.tableCompiler = tableCompiler;
|
||||
this.pragma = pragma;
|
||||
this.tableNameRaw = this.tableCompiler.tableNameRaw;
|
||||
this.alteredName = `_knex_temp_alter${nanonum(3)}`;
|
||||
this.connection = connection;
|
||||
this.formatter = (value) =>
|
||||
this.client.customWrapIdentifier(value, identity);
|
||||
this.wrap = (value) => this.client.wrapIdentifierImpl(value);
|
||||
}
|
||||
|
||||
tableName() {
|
||||
return this.formatter(this.tableNameRaw);
|
||||
}
|
||||
|
||||
getTableSql() {
|
||||
const tableName = this.tableName();
|
||||
|
||||
return this.client.transaction(
|
||||
async (trx) => {
|
||||
trx.disableProcessing();
|
||||
const result = await trx.raw(getTableSql(tableName));
|
||||
trx.enableProcessing();
|
||||
|
||||
return {
|
||||
createTable: result.filter((create) => create.type === 'table')[0]
|
||||
.sql,
|
||||
createIndices: result
|
||||
.filter((create) => create.type === 'index')
|
||||
.map((create) => create.sql),
|
||||
};
|
||||
},
|
||||
{ connection: this.connection }
|
||||
);
|
||||
}
|
||||
|
||||
async isForeignCheckEnabled() {
|
||||
const result = await this.client
|
||||
.raw(isForeignCheckEnabled())
|
||||
.connection(this.connection);
|
||||
|
||||
return result[0].foreign_keys === 1;
|
||||
}
|
||||
|
||||
async setForeignCheck(enable) {
|
||||
await this.client.raw(setForeignCheck(enable)).connection(this.connection);
|
||||
}
|
||||
|
||||
renameTable(trx) {
|
||||
return trx.raw(renameTable(this.alteredName, this.tableName()));
|
||||
}
|
||||
|
||||
dropOriginal(trx) {
|
||||
return trx.raw(dropOriginal(this.tableName()));
|
||||
}
|
||||
|
||||
copyData(trx, columns) {
|
||||
return trx.raw(copyData(this.tableName(), this.alteredName, columns));
|
||||
}
|
||||
|
||||
async alterColumn(columns) {
|
||||
const { createTable, createIndices } = await this.getTableSql();
|
||||
|
||||
const parsedTable = parseCreateTable(createTable);
|
||||
parsedTable.table = this.alteredName;
|
||||
|
||||
parsedTable.columns = parsedTable.columns.map((column) => {
|
||||
const newColumnInfo = columns.find((c) => isEqualId(c.name, column.name));
|
||||
|
||||
if (newColumnInfo) {
|
||||
column.type = newColumnInfo.type;
|
||||
|
||||
column.constraints.default =
|
||||
newColumnInfo.defaultTo !== null
|
||||
? {
|
||||
name: null,
|
||||
value: newColumnInfo.defaultTo,
|
||||
expression: false,
|
||||
}
|
||||
: null;
|
||||
|
||||
column.constraints.notnull = newColumnInfo.notNull
|
||||
? { name: null, conflict: null }
|
||||
: null;
|
||||
|
||||
column.constraints.null = newColumnInfo.notNull
|
||||
? null
|
||||
: column.constraints.null;
|
||||
}
|
||||
|
||||
return column;
|
||||
});
|
||||
|
||||
const newTable = compileCreateTable(parsedTable, this.wrap);
|
||||
|
||||
return this.generateAlterCommands(newTable, createIndices);
|
||||
}
|
||||
|
||||
async dropColumn(columns) {
|
||||
const { createTable, createIndices } = await this.getTableSql();
|
||||
|
||||
const parsedTable = parseCreateTable(createTable);
|
||||
parsedTable.table = this.alteredName;
|
||||
|
||||
parsedTable.columns = parsedTable.columns.filter(
|
||||
(parsedColumn) =>
|
||||
parsedColumn.expression || !includesId(columns, parsedColumn.name)
|
||||
);
|
||||
|
||||
if (parsedTable.columns.length === 0) {
|
||||
throw new Error('Unable to drop last column from table');
|
||||
}
|
||||
|
||||
parsedTable.constraints = parsedTable.constraints.filter((constraint) => {
|
||||
if (constraint.type === 'PRIMARY KEY' || constraint.type === 'UNIQUE') {
|
||||
return constraint.columns.every(
|
||||
(constraintColumn) =>
|
||||
constraintColumn.expression ||
|
||||
!includesId(columns, constraintColumn.name)
|
||||
);
|
||||
} else if (constraint.type === 'FOREIGN KEY') {
|
||||
return (
|
||||
constraint.columns.every(
|
||||
(constraintColumnName) => !includesId(columns, constraintColumnName)
|
||||
) &&
|
||||
(constraint.references.table !== parsedTable.table ||
|
||||
constraint.references.columns.every(
|
||||
(referenceColumnName) => !includesId(columns, referenceColumnName)
|
||||
))
|
||||
);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
const newColumns = parsedTable.columns.map((column) => column.name);
|
||||
|
||||
const newTable = compileCreateTable(parsedTable, this.wrap);
|
||||
|
||||
const newIndices = [];
|
||||
for (const createIndex of createIndices) {
|
||||
const parsedIndex = parseCreateIndex(createIndex);
|
||||
|
||||
parsedIndex.columns = parsedIndex.columns.filter(
|
||||
(parsedColumn) =>
|
||||
parsedColumn.expression || !includesId(columns, parsedColumn.name)
|
||||
);
|
||||
|
||||
if (parsedIndex.columns.length > 0) {
|
||||
newIndices.push(compileCreateIndex(parsedIndex, this.wrap));
|
||||
}
|
||||
}
|
||||
|
||||
return this.alter(newTable, newIndices, newColumns);
|
||||
}
|
||||
|
||||
async dropForeign(columns, foreignKeyName) {
|
||||
const { createTable, createIndices } = await this.getTableSql();
|
||||
|
||||
const parsedTable = parseCreateTable(createTable);
|
||||
parsedTable.table = this.alteredName;
|
||||
|
||||
if (!foreignKeyName) {
|
||||
parsedTable.columns = parsedTable.columns.map((column) => ({
|
||||
...column,
|
||||
references: includesId(columns, column.name) ? null : column.references,
|
||||
}));
|
||||
}
|
||||
|
||||
parsedTable.constraints = parsedTable.constraints.filter((constraint) => {
|
||||
if (constraint.type === 'FOREIGN KEY') {
|
||||
if (foreignKeyName) {
|
||||
return (
|
||||
!constraint.name || !isEqualId(constraint.name, foreignKeyName)
|
||||
);
|
||||
}
|
||||
|
||||
return constraint.columns.every(
|
||||
(constraintColumnName) => !includesId(columns, constraintColumnName)
|
||||
);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
const newTable = compileCreateTable(parsedTable, this.wrap);
|
||||
|
||||
return this.alter(newTable, createIndices);
|
||||
}
|
||||
|
||||
async dropPrimary(constraintName) {
|
||||
const { createTable, createIndices } = await this.getTableSql();
|
||||
|
||||
const parsedTable = parseCreateTable(createTable);
|
||||
parsedTable.table = this.alteredName;
|
||||
|
||||
parsedTable.columns = parsedTable.columns.map((column) => ({
|
||||
...column,
|
||||
primary: null,
|
||||
}));
|
||||
|
||||
parsedTable.constraints = parsedTable.constraints.filter((constraint) => {
|
||||
if (constraint.type === 'PRIMARY KEY') {
|
||||
if (constraintName) {
|
||||
return (
|
||||
!constraint.name || !isEqualId(constraint.name, constraintName)
|
||||
);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
const newTable = compileCreateTable(parsedTable, this.wrap);
|
||||
|
||||
return this.alter(newTable, createIndices);
|
||||
}
|
||||
|
||||
async primary(columns, constraintName) {
|
||||
const { createTable, createIndices } = await this.getTableSql();
|
||||
|
||||
const parsedTable = parseCreateTable(createTable);
|
||||
parsedTable.table = this.alteredName;
|
||||
|
||||
parsedTable.columns = parsedTable.columns.map((column) => ({
|
||||
...column,
|
||||
primary: null,
|
||||
}));
|
||||
|
||||
parsedTable.constraints = parsedTable.constraints.filter(
|
||||
(constraint) => constraint.type !== 'PRIMARY KEY'
|
||||
);
|
||||
|
||||
parsedTable.constraints.push({
|
||||
type: 'PRIMARY KEY',
|
||||
name: constraintName || null,
|
||||
columns: columns.map((column) => ({
|
||||
name: column,
|
||||
expression: false,
|
||||
collation: null,
|
||||
order: null,
|
||||
})),
|
||||
conflict: null,
|
||||
});
|
||||
|
||||
const newTable = compileCreateTable(parsedTable, this.wrap);
|
||||
|
||||
return this.alter(newTable, createIndices);
|
||||
}
|
||||
|
||||
async foreign(foreignInfo) {
|
||||
const { createTable, createIndices } = await this.getTableSql();
|
||||
|
||||
const parsedTable = parseCreateTable(createTable);
|
||||
parsedTable.table = this.alteredName;
|
||||
|
||||
parsedTable.constraints.push({
|
||||
type: 'FOREIGN KEY',
|
||||
name: foreignInfo.keyName || null,
|
||||
columns: foreignInfo.column,
|
||||
references: {
|
||||
table: foreignInfo.inTable,
|
||||
columns: foreignInfo.references,
|
||||
delete: foreignInfo.onDelete || null,
|
||||
update: foreignInfo.onUpdate || null,
|
||||
match: null,
|
||||
deferrable: null,
|
||||
},
|
||||
});
|
||||
|
||||
const newTable = compileCreateTable(parsedTable, this.wrap);
|
||||
|
||||
return this.generateAlterCommands(newTable, createIndices);
|
||||
}
|
||||
|
||||
async setNullable(column, isNullable) {
|
||||
const { createTable, createIndices } = await this.getTableSql();
|
||||
|
||||
const parsedTable = parseCreateTable(createTable);
|
||||
parsedTable.table = this.alteredName;
|
||||
|
||||
const parsedColumn = parsedTable.columns.find((c) =>
|
||||
isEqualId(column, c.name)
|
||||
);
|
||||
|
||||
if (!parsedColumn) {
|
||||
throw new Error(
|
||||
`.setNullable: Column ${column} does not exist in table ${this.tableName()}.`
|
||||
);
|
||||
}
|
||||
|
||||
parsedColumn.constraints.notnull = isNullable
|
||||
? null
|
||||
: { name: null, conflict: null };
|
||||
|
||||
parsedColumn.constraints.null = isNullable
|
||||
? parsedColumn.constraints.null
|
||||
: null;
|
||||
|
||||
const newTable = compileCreateTable(parsedTable, this.wrap);
|
||||
|
||||
return this.generateAlterCommands(newTable, createIndices);
|
||||
}
|
||||
|
||||
async alter(newSql, createIndices, columns) {
|
||||
const wasForeignCheckEnabled = await this.isForeignCheckEnabled();
|
||||
|
||||
if (wasForeignCheckEnabled) {
|
||||
await this.setForeignCheck(false);
|
||||
}
|
||||
|
||||
try {
|
||||
await this.client.transaction(
|
||||
async (trx) => {
|
||||
await trx.raw(newSql);
|
||||
await this.copyData(trx, columns);
|
||||
await this.dropOriginal(trx);
|
||||
await this.renameTable(trx);
|
||||
|
||||
for (const createIndex of createIndices) {
|
||||
await trx.raw(createIndex);
|
||||
}
|
||||
|
||||
if (wasForeignCheckEnabled) {
|
||||
const foreignViolations = await trx.raw(executeForeignCheck());
|
||||
|
||||
if (foreignViolations.length > 0) {
|
||||
throw new Error('FOREIGN KEY constraint failed');
|
||||
}
|
||||
}
|
||||
},
|
||||
{ connection: this.connection }
|
||||
);
|
||||
} finally {
|
||||
if (wasForeignCheckEnabled) {
|
||||
await this.setForeignCheck(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async generateAlterCommands(newSql, createIndices, columns) {
|
||||
const sql = [];
|
||||
const pre = [];
|
||||
const post = [];
|
||||
let check = null;
|
||||
|
||||
sql.push(newSql);
|
||||
sql.push(copyData(this.tableName(), this.alteredName, columns));
|
||||
sql.push(dropOriginal(this.tableName()));
|
||||
sql.push(renameTable(this.alteredName, this.tableName()));
|
||||
|
||||
for (const createIndex of createIndices) {
|
||||
sql.push(createIndex);
|
||||
}
|
||||
|
||||
const isForeignCheckEnabled = await this.isForeignCheckEnabled();
|
||||
|
||||
if (isForeignCheckEnabled) {
|
||||
pre.push(setForeignCheck(false));
|
||||
post.push(setForeignCheck(true));
|
||||
|
||||
check = executeForeignCheck();
|
||||
}
|
||||
|
||||
return { pre, sql, check, post };
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = SQLite3_DDL;
|
||||
Reference in New Issue
Block a user