Add initial version of dijkstra backend cloudron image
This commit is contained in:
21
node_modules/knex/lib/dialects/sqlite3/formatter.js
generated
vendored
Normal file
21
node_modules/knex/lib/dialects/sqlite3/formatter.js
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
const Formatter = require('../../formatter');
|
||||
const Raw = require('../../raw');
|
||||
|
||||
module.exports = class SQlite3_Formatter extends Formatter {
|
||||
values(values) {
|
||||
if (Array.isArray(values)) {
|
||||
if (Array.isArray(values[0])) {
|
||||
return `( values ${values
|
||||
.map((value) => `(${this.parameterize(value)})`)
|
||||
.join(', ')})`;
|
||||
}
|
||||
return `(${this.parameterize(values)})`;
|
||||
}
|
||||
|
||||
if (values instanceof Raw) {
|
||||
return `(${this.parameter(values)})`;
|
||||
}
|
||||
|
||||
return this.parameter(values);
|
||||
}
|
||||
};
|
||||
171
node_modules/knex/lib/dialects/sqlite3/index.js
generated
vendored
Normal file
171
node_modules/knex/lib/dialects/sqlite3/index.js
generated
vendored
Normal file
@@ -0,0 +1,171 @@
|
||||
// SQLite3
|
||||
// -------
|
||||
const Bluebird = require('bluebird');
|
||||
|
||||
const inherits = require('inherits');
|
||||
const { isUndefined, map, defaults } = require('lodash');
|
||||
const { promisify } = require('util');
|
||||
|
||||
const Client = require('../../client');
|
||||
|
||||
const QueryCompiler = require('./query/compiler');
|
||||
const SchemaCompiler = require('./schema/compiler');
|
||||
const ColumnCompiler = require('./schema/columncompiler');
|
||||
const TableCompiler = require('./schema/tablecompiler');
|
||||
const SQLite3_DDL = require('./schema/ddl');
|
||||
const SQLite3_Formatter = require('./formatter');
|
||||
|
||||
function Client_SQLite3(config) {
|
||||
Client.call(this, config);
|
||||
if (isUndefined(config.useNullAsDefault)) {
|
||||
this.logger.warn(
|
||||
'sqlite does not support inserting default values. Set the ' +
|
||||
'`useNullAsDefault` flag to hide this warning. ' +
|
||||
'(see docs http://knexjs.org/#Builder-insert).'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
inherits(Client_SQLite3, Client);
|
||||
|
||||
Object.assign(Client_SQLite3.prototype, {
|
||||
dialect: 'sqlite3',
|
||||
|
||||
driverName: 'sqlite3',
|
||||
|
||||
_driver() {
|
||||
return require('sqlite3');
|
||||
},
|
||||
|
||||
schemaCompiler() {
|
||||
return new SchemaCompiler(this, ...arguments);
|
||||
},
|
||||
|
||||
queryCompiler() {
|
||||
return new QueryCompiler(this, ...arguments);
|
||||
},
|
||||
|
||||
columnCompiler() {
|
||||
return new ColumnCompiler(this, ...arguments);
|
||||
},
|
||||
|
||||
tableCompiler() {
|
||||
return new TableCompiler(this, ...arguments);
|
||||
},
|
||||
|
||||
ddl(compiler, pragma, connection) {
|
||||
return new SQLite3_DDL(this, compiler, pragma, connection);
|
||||
},
|
||||
|
||||
wrapIdentifierImpl(value) {
|
||||
return value !== '*' ? `\`${value.replace(/`/g, '``')}\`` : '*';
|
||||
},
|
||||
|
||||
// Get a raw connection from the database, returning a promise with the connection object.
|
||||
acquireRawConnection() {
|
||||
return new Bluebird((resolve, reject) => {
|
||||
const db = new this.driver.Database(
|
||||
this.connectionSettings.filename,
|
||||
(err) => {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
resolve(db);
|
||||
}
|
||||
);
|
||||
});
|
||||
},
|
||||
|
||||
// Used to explicitly close a connection, called internally by the pool when
|
||||
// a connection times out or the pool is shutdown.
|
||||
async destroyRawConnection(connection) {
|
||||
const close = promisify((cb) => connection.close(cb));
|
||||
return close();
|
||||
},
|
||||
|
||||
// Runs the query on the specified connection, providing the bindings and any
|
||||
// other necessary prep work.
|
||||
_query(connection, obj) {
|
||||
const { method } = obj;
|
||||
let callMethod;
|
||||
switch (method) {
|
||||
case 'insert':
|
||||
case 'update':
|
||||
case 'counter':
|
||||
case 'del':
|
||||
callMethod = 'run';
|
||||
break;
|
||||
default:
|
||||
callMethod = 'all';
|
||||
}
|
||||
return new Bluebird(function(resolver, rejecter) {
|
||||
if (!connection || !connection[callMethod]) {
|
||||
return rejecter(
|
||||
new Error(`Error calling ${callMethod} on connection.`)
|
||||
);
|
||||
}
|
||||
connection[callMethod](obj.sql, obj.bindings, function(err, response) {
|
||||
if (err) return rejecter(err);
|
||||
obj.response = response;
|
||||
|
||||
// We need the context here, as it contains
|
||||
// the "this.lastID" or "this.changes"
|
||||
obj.context = this;
|
||||
return resolver(obj);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
_stream(connection, sql, stream) {
|
||||
const client = this;
|
||||
return new Bluebird(function(resolver, rejecter) {
|
||||
stream.on('error', rejecter);
|
||||
stream.on('end', resolver);
|
||||
return client
|
||||
._query(connection, sql)
|
||||
.then((obj) => obj.response)
|
||||
.then((rows) => rows.forEach((row) => stream.write(row)))
|
||||
.catch(function(err) {
|
||||
stream.emit('error', err);
|
||||
})
|
||||
.then(function() {
|
||||
stream.end();
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
// Ensures the response is returned in the same format as other clients.
|
||||
processResponse(obj, runner) {
|
||||
const ctx = obj.context;
|
||||
let { response } = obj;
|
||||
if (obj.output) return obj.output.call(runner, response);
|
||||
switch (obj.method) {
|
||||
case 'select':
|
||||
case 'pluck':
|
||||
case 'first':
|
||||
if (obj.method === 'pluck') response = map(response, obj.pluck);
|
||||
return obj.method === 'first' ? response[0] : response;
|
||||
case 'insert':
|
||||
return [ctx.lastID];
|
||||
case 'del':
|
||||
case 'update':
|
||||
case 'counter':
|
||||
return ctx.changes;
|
||||
default:
|
||||
return response;
|
||||
}
|
||||
},
|
||||
|
||||
poolDefaults() {
|
||||
return defaults(
|
||||
{ min: 1, max: 1 },
|
||||
Client.prototype.poolDefaults.call(this)
|
||||
);
|
||||
},
|
||||
|
||||
formatter() {
|
||||
return new SQLite3_Formatter(this, ...arguments);
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = Client_SQLite3;
|
||||
176
node_modules/knex/lib/dialects/sqlite3/query/compiler.js
generated
vendored
Normal file
176
node_modules/knex/lib/dialects/sqlite3/query/compiler.js
generated
vendored
Normal file
@@ -0,0 +1,176 @@
|
||||
// SQLite3 Query Builder & Compiler
|
||||
|
||||
const inherits = require('inherits');
|
||||
const QueryCompiler = require('../../../query/compiler');
|
||||
const {
|
||||
assign,
|
||||
each,
|
||||
isEmpty,
|
||||
isString,
|
||||
noop,
|
||||
reduce,
|
||||
identity,
|
||||
} = require('lodash');
|
||||
|
||||
function QueryCompiler_SQLite3(client, builder) {
|
||||
QueryCompiler.call(this, client, builder);
|
||||
|
||||
const { returning } = this.single;
|
||||
|
||||
if (returning) {
|
||||
this.client.logger.warn(
|
||||
'.returning() is not supported by sqlite3 and will not have any effect.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
inherits(QueryCompiler_SQLite3, QueryCompiler);
|
||||
|
||||
assign(QueryCompiler_SQLite3.prototype, {
|
||||
// The locks are not applicable in SQLite3
|
||||
forShare: emptyStr,
|
||||
|
||||
forUpdate: emptyStr,
|
||||
|
||||
// SQLite requires us to build the multi-row insert as a listing of select with
|
||||
// unions joining them together. So we'll build out this list of columns and
|
||||
// then join them all together with select unions to complete the queries.
|
||||
insert() {
|
||||
const insertValues = this.single.insert || [];
|
||||
let sql = this.with() + `insert into ${this.tableName} `;
|
||||
|
||||
if (Array.isArray(insertValues)) {
|
||||
if (insertValues.length === 0) {
|
||||
return '';
|
||||
} else if (
|
||||
insertValues.length === 1 &&
|
||||
insertValues[0] &&
|
||||
isEmpty(insertValues[0])
|
||||
) {
|
||||
return sql + this._emptyInsertValue;
|
||||
}
|
||||
} else if (typeof insertValues === 'object' && isEmpty(insertValues)) {
|
||||
return sql + this._emptyInsertValue;
|
||||
}
|
||||
|
||||
const insertData = this._prepInsert(insertValues);
|
||||
|
||||
if (isString(insertData)) {
|
||||
return sql + insertData;
|
||||
}
|
||||
|
||||
if (insertData.columns.length === 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
sql += `(${this.formatter.columnize(insertData.columns)})`;
|
||||
|
||||
// backwards compatible error
|
||||
if (this.client.valueForUndefined !== null) {
|
||||
each(insertData.values, (bindings) => {
|
||||
each(bindings, (binding) => {
|
||||
if (binding === undefined)
|
||||
throw new TypeError(
|
||||
'`sqlite` does not support inserting default values. Specify ' +
|
||||
'values explicitly or use the `useNullAsDefault` config flag. ' +
|
||||
'(see docs http://knexjs.org/#Builder-insert).'
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (insertData.values.length === 1) {
|
||||
const parameters = this.formatter.parameterize(
|
||||
insertData.values[0],
|
||||
this.client.valueForUndefined
|
||||
);
|
||||
return sql + ` values (${parameters})`;
|
||||
}
|
||||
|
||||
const blocks = [];
|
||||
let i = -1;
|
||||
while (++i < insertData.values.length) {
|
||||
let i2 = -1;
|
||||
const block = (blocks[i] = []);
|
||||
let current = insertData.values[i];
|
||||
current = current === undefined ? this.client.valueForUndefined : current;
|
||||
while (++i2 < insertData.columns.length) {
|
||||
block.push(
|
||||
this.formatter.alias(
|
||||
this.formatter.parameter(current[i2]),
|
||||
this.formatter.wrap(insertData.columns[i2])
|
||||
)
|
||||
);
|
||||
}
|
||||
blocks[i] = block.join(', ');
|
||||
}
|
||||
return sql + ' select ' + blocks.join(' union all select ');
|
||||
},
|
||||
|
||||
// Compile a truncate table statement into SQL.
|
||||
truncate() {
|
||||
const { table } = this.single;
|
||||
return {
|
||||
sql: `delete from ${this.tableName}`,
|
||||
output() {
|
||||
return this.query({
|
||||
sql: `delete from sqlite_sequence where name = '${table}'`,
|
||||
}).catch(noop);
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
// Compiles a `columnInfo` query
|
||||
columnInfo() {
|
||||
const column = this.single.columnInfo;
|
||||
|
||||
// The user may have specified a custom wrapIdentifier function in the config. We
|
||||
// need to run the identifiers through that function, but not format them as
|
||||
// identifiers otherwise.
|
||||
const table = this.client.customWrapIdentifier(this.single.table, identity);
|
||||
|
||||
return {
|
||||
sql: `PRAGMA table_info(\`${table}\`)`,
|
||||
output(resp) {
|
||||
const maxLengthRegex = /.*\((\d+)\)/;
|
||||
const out = reduce(
|
||||
resp,
|
||||
function(columns, val) {
|
||||
let { type } = val;
|
||||
let maxLength = type.match(maxLengthRegex);
|
||||
if (maxLength) {
|
||||
maxLength = maxLength[1];
|
||||
}
|
||||
type = maxLength ? type.split('(')[0] : type;
|
||||
columns[val.name] = {
|
||||
type: type.toLowerCase(),
|
||||
maxLength,
|
||||
nullable: !val.notnull,
|
||||
defaultValue: val.dflt_value,
|
||||
};
|
||||
return columns;
|
||||
},
|
||||
{}
|
||||
);
|
||||
return (column && out[column]) || out;
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
limit() {
|
||||
const noLimit = !this.single.limit && this.single.limit !== 0;
|
||||
if (noLimit && !this.single.offset) return '';
|
||||
|
||||
// Workaround for offset only,
|
||||
// see http://stackoverflow.com/questions/10491492/sqllite-with-skip-offset-only-not-limit
|
||||
return `limit ${this.formatter.parameter(
|
||||
noLimit ? -1 : this.single.limit
|
||||
)}`;
|
||||
},
|
||||
});
|
||||
|
||||
function emptyStr() {
|
||||
return '';
|
||||
}
|
||||
|
||||
module.exports = QueryCompiler_SQLite3;
|
||||
27
node_modules/knex/lib/dialects/sqlite3/schema/columncompiler.js
generated
vendored
Normal file
27
node_modules/knex/lib/dialects/sqlite3/schema/columncompiler.js
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
const inherits = require('inherits');
|
||||
const ColumnCompiler = require('../../../schema/columncompiler');
|
||||
|
||||
// Column Compiler
|
||||
// -------
|
||||
|
||||
function ColumnCompiler_SQLite3() {
|
||||
ColumnCompiler.apply(this, arguments);
|
||||
this.modifiers = ['nullable', 'defaultTo'];
|
||||
}
|
||||
inherits(ColumnCompiler_SQLite3, ColumnCompiler);
|
||||
|
||||
// Types
|
||||
// -------
|
||||
|
||||
ColumnCompiler_SQLite3.prototype.double = ColumnCompiler_SQLite3.prototype.decimal = ColumnCompiler_SQLite3.prototype.floating =
|
||||
'float';
|
||||
ColumnCompiler_SQLite3.prototype.timestamp = 'datetime';
|
||||
ColumnCompiler_SQLite3.prototype.enu = function(allowed) {
|
||||
return `text check (${this.formatter.wrap(this.args[0])} in ('${allowed.join(
|
||||
"', '"
|
||||
)}'))`;
|
||||
};
|
||||
|
||||
ColumnCompiler_SQLite3.prototype.json = 'json';
|
||||
|
||||
module.exports = ColumnCompiler_SQLite3;
|
||||
49
node_modules/knex/lib/dialects/sqlite3/schema/compiler.js
generated
vendored
Normal file
49
node_modules/knex/lib/dialects/sqlite3/schema/compiler.js
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
// SQLite3: Column Builder & Compiler
|
||||
// -------
|
||||
const inherits = require('inherits');
|
||||
const SchemaCompiler = require('../../../schema/compiler');
|
||||
|
||||
const { some } = require('lodash');
|
||||
|
||||
// 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;
|
||||
330
node_modules/knex/lib/dialects/sqlite3/schema/ddl.js
generated
vendored
Normal file
330
node_modules/knex/lib/dialects/sqlite3/schema/ddl.js
generated
vendored
Normal file
@@ -0,0 +1,330 @@
|
||||
// SQLite3_DDL
|
||||
//
|
||||
// All of the SQLite3 specific DDL helpers for renaming/dropping
|
||||
// columns and changing datatypes.
|
||||
// -------
|
||||
|
||||
const {
|
||||
assign,
|
||||
uniqueId,
|
||||
find,
|
||||
identity,
|
||||
map,
|
||||
omit,
|
||||
invert,
|
||||
fromPairs,
|
||||
some,
|
||||
negate,
|
||||
isEmpty,
|
||||
chunk,
|
||||
} = require('lodash');
|
||||
|
||||
// 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.
|
||||
function SQLite3_DDL(client, tableCompiler, pragma, connection) {
|
||||
this.client = client;
|
||||
this.tableCompiler = tableCompiler;
|
||||
this.pragma = pragma;
|
||||
this.tableNameRaw = this.tableCompiler.tableNameRaw;
|
||||
this.alteredName = uniqueId('_knex_temp_alter');
|
||||
this.connection = connection;
|
||||
this.formatter =
|
||||
client && client.config && client.config.wrapIdentifier
|
||||
? client.config.wrapIdentifier
|
||||
: (value) => value;
|
||||
}
|
||||
|
||||
assign(SQLite3_DDL.prototype, {
|
||||
tableName() {
|
||||
return this.formatter(this.tableNameRaw, (value) => value);
|
||||
},
|
||||
|
||||
getColumn: async function(column) {
|
||||
const currentCol = find(this.pragma, (col) => {
|
||||
return (
|
||||
this.client.wrapIdentifier(col.name).toLowerCase() ===
|
||||
this.client.wrapIdentifier(column).toLowerCase()
|
||||
);
|
||||
});
|
||||
if (!currentCol)
|
||||
throw new Error(
|
||||
`The column ${column} is not in the ${this.tableName()} table`
|
||||
);
|
||||
return currentCol;
|
||||
},
|
||||
|
||||
getTableSql() {
|
||||
this.trx.disableProcessing();
|
||||
return this.trx
|
||||
.raw(
|
||||
`SELECT name, sql FROM sqlite_master WHERE type="table" AND name="${this.tableName()}"`
|
||||
)
|
||||
.then((result) => {
|
||||
this.trx.enableProcessing();
|
||||
return result;
|
||||
});
|
||||
},
|
||||
|
||||
renameTable: async function() {
|
||||
return this.trx.raw(
|
||||
`ALTER TABLE "${this.tableName()}" RENAME TO "${this.alteredName}"`
|
||||
);
|
||||
},
|
||||
|
||||
dropOriginal() {
|
||||
return this.trx.raw(`DROP TABLE "${this.tableName()}"`);
|
||||
},
|
||||
|
||||
dropTempTable() {
|
||||
return this.trx.raw(`DROP TABLE "${this.alteredName}"`);
|
||||
},
|
||||
|
||||
copyData() {
|
||||
return this.trx
|
||||
.raw(`SELECT * FROM "${this.tableName()}"`)
|
||||
.then((result) =>
|
||||
this.insertChunked(20, this.alteredName, identity, result)
|
||||
);
|
||||
},
|
||||
|
||||
reinsertData(iterator) {
|
||||
return this.trx
|
||||
.raw(`SELECT * FROM "${this.alteredName}"`)
|
||||
.then((result) =>
|
||||
this.insertChunked(20, this.tableName(), iterator, result)
|
||||
);
|
||||
},
|
||||
|
||||
async insertChunked(chunkSize, target, iterator, result) {
|
||||
iterator = iterator || identity;
|
||||
const chunked = chunk(result, chunkSize);
|
||||
for (const batch of chunked) {
|
||||
await this.trx
|
||||
.queryBuilder()
|
||||
.table(target)
|
||||
.insert(map(batch, iterator));
|
||||
}
|
||||
},
|
||||
|
||||
createTempTable(createTable) {
|
||||
return this.trx.raw(
|
||||
createTable.sql.replace(this.tableName(), this.alteredName)
|
||||
);
|
||||
},
|
||||
|
||||
_doReplace(sql, from, to) {
|
||||
const oneLineSql = sql.replace(/\s+/g, ' ');
|
||||
const matched = oneLineSql.match(/^CREATE TABLE\s+(\S+)\s*\((.*)\)/);
|
||||
|
||||
const tableName = matched[1];
|
||||
const defs = matched[2];
|
||||
|
||||
if (!defs) {
|
||||
throw new Error('No column definitions in this statement!');
|
||||
}
|
||||
|
||||
let parens = 0,
|
||||
args = [],
|
||||
ptr = 0;
|
||||
let i = 0;
|
||||
const x = defs.length;
|
||||
for (i = 0; i < x; i++) {
|
||||
switch (defs[i]) {
|
||||
case '(':
|
||||
parens++;
|
||||
break;
|
||||
case ')':
|
||||
parens--;
|
||||
break;
|
||||
case ',':
|
||||
if (parens === 0) {
|
||||
args.push(defs.slice(ptr, i));
|
||||
ptr = i + 1;
|
||||
}
|
||||
break;
|
||||
case ' ':
|
||||
if (ptr === i) {
|
||||
ptr = i + 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
args.push(defs.slice(ptr, i));
|
||||
|
||||
const fromIdentifier = from.replace(/[`"'[\]]/g, '');
|
||||
|
||||
args = args.map((item) => {
|
||||
let split = item.trim().split(' ');
|
||||
|
||||
// SQLite supports all quoting mechanisms prevalent in all major dialects of SQL
|
||||
// and preserves the original quoting in sqlite_master.
|
||||
//
|
||||
// Also, identifiers are never case sensitive, not even when quoted.
|
||||
//
|
||||
// Ref: https://www.sqlite.org/lang_keywords.html
|
||||
const fromMatchCandidates = [
|
||||
new RegExp(`\`${fromIdentifier}\``, 'i'),
|
||||
new RegExp(`"${fromIdentifier}"`, 'i'),
|
||||
new RegExp(`'${fromIdentifier}'`, 'i'),
|
||||
new RegExp(`\\[${fromIdentifier}\\]`, 'i'),
|
||||
];
|
||||
if (fromIdentifier.match(/^\S+$/)) {
|
||||
fromMatchCandidates.push(new RegExp(`\\b${fromIdentifier}\\b`, 'i'));
|
||||
}
|
||||
|
||||
const doesMatchFromIdentifier = (target) =>
|
||||
some(fromMatchCandidates, (c) => target.match(c));
|
||||
|
||||
const replaceFromIdentifier = (target) =>
|
||||
fromMatchCandidates.reduce(
|
||||
(result, candidate) => result.replace(candidate, to),
|
||||
target
|
||||
);
|
||||
|
||||
if (doesMatchFromIdentifier(split[0])) {
|
||||
// column definition
|
||||
if (to) {
|
||||
split[0] = to;
|
||||
return split.join(' ');
|
||||
}
|
||||
return ''; // for deletions
|
||||
}
|
||||
|
||||
// skip constraint name
|
||||
const idx = /constraint/i.test(split[0]) ? 2 : 0;
|
||||
|
||||
// primary key and unique constraints have one or more
|
||||
// columns from this table listed between (); replace
|
||||
// one if it matches
|
||||
if (/primary|unique/i.test(split[idx])) {
|
||||
const ret = item.replace(/\(.*\)/, replaceFromIdentifier);
|
||||
// If any member columns are dropped then uniqueness/pk constraint
|
||||
// can not be retained
|
||||
if (ret !== item && isEmpty(to)) return '';
|
||||
return ret;
|
||||
}
|
||||
|
||||
// foreign keys have one or more columns from this table
|
||||
// listed between (); replace one if it matches
|
||||
// foreign keys also have a 'references' clause
|
||||
// which may reference THIS table; if it does, replace
|
||||
// column references in that too!
|
||||
if (/foreign/.test(split[idx])) {
|
||||
split = item.split(/ references /i);
|
||||
// the quoted column names save us from having to do anything
|
||||
// other than a straight replace here
|
||||
const replacedKeySpec = replaceFromIdentifier(split[0]);
|
||||
|
||||
if (split[0] !== replacedKeySpec) {
|
||||
// If we are removing one or more columns of a foreign
|
||||
// key, then we should not retain the key at all
|
||||
if (isEmpty(to)) return '';
|
||||
else split[0] = replacedKeySpec;
|
||||
}
|
||||
|
||||
if (split[1].slice(0, tableName.length) === tableName) {
|
||||
// self-referential foreign key
|
||||
const replacedKeyTargetSpec = split[1].replace(
|
||||
/\(.*\)/,
|
||||
replaceFromIdentifier
|
||||
);
|
||||
if (split[1] !== replacedKeyTargetSpec) {
|
||||
// If we are removing one or more columns of a foreign
|
||||
// key, then we should not retain the key at all
|
||||
if (isEmpty(to)) return '';
|
||||
else split[1] = replacedKeyTargetSpec;
|
||||
}
|
||||
}
|
||||
return split.join(' references ');
|
||||
}
|
||||
|
||||
return item;
|
||||
});
|
||||
|
||||
args = args.filter(negate(isEmpty));
|
||||
|
||||
if (args.length === 0) {
|
||||
throw new Error('Unable to drop last column from table');
|
||||
}
|
||||
|
||||
return oneLineSql
|
||||
.replace(/\(.*\)/, () => `(${args.join(', ')})`)
|
||||
.replace(/,\s*([,)])/, '$1');
|
||||
},
|
||||
|
||||
// Boy, this is quite a method.
|
||||
renameColumn: async function(from, to) {
|
||||
return this.client.transaction(
|
||||
async (trx) => {
|
||||
this.trx = trx;
|
||||
const column = await this.getColumn(from);
|
||||
const sql = await this.getTableSql(column);
|
||||
const a = this.client.wrapIdentifier(from);
|
||||
const b = this.client.wrapIdentifier(to);
|
||||
const createTable = sql[0];
|
||||
const newSql = this._doReplace(createTable.sql, a, b);
|
||||
if (sql === newSql) {
|
||||
throw new Error('Unable to find the column to change');
|
||||
}
|
||||
|
||||
const { from: mappedFrom, to: mappedTo } = invert(
|
||||
this.client.postProcessResponse(
|
||||
invert({
|
||||
from,
|
||||
to,
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
return this.reinsertMapped(createTable, newSql, (row) => {
|
||||
row[mappedTo] = row[mappedFrom];
|
||||
return omit(row, mappedFrom);
|
||||
});
|
||||
},
|
||||
{ connection: this.connection }
|
||||
);
|
||||
},
|
||||
|
||||
dropColumn: async function(columns) {
|
||||
return this.client.transaction(
|
||||
(trx) => {
|
||||
this.trx = trx;
|
||||
return Promise.all(columns.map((column) => this.getColumn(column)))
|
||||
.then(() => this.getTableSql())
|
||||
.then((sql) => {
|
||||
const createTable = sql[0];
|
||||
let newSql = createTable.sql;
|
||||
columns.forEach((column) => {
|
||||
const a = this.client.wrapIdentifier(column);
|
||||
newSql = this._doReplace(newSql, a, '');
|
||||
});
|
||||
if (sql === newSql) {
|
||||
throw new Error('Unable to find the column to change');
|
||||
}
|
||||
const mappedColumns = Object.keys(
|
||||
this.client.postProcessResponse(
|
||||
fromPairs(columns.map((column) => [column, column]))
|
||||
)
|
||||
);
|
||||
return this.reinsertMapped(createTable, newSql, (row) =>
|
||||
omit(row, ...mappedColumns)
|
||||
);
|
||||
});
|
||||
},
|
||||
{ connection: this.connection }
|
||||
);
|
||||
},
|
||||
|
||||
reinsertMapped(createTable, newSql, mapRow) {
|
||||
return Promise.resolve()
|
||||
.then(() => this.createTempTable(createTable))
|
||||
.then(() => this.copyData())
|
||||
.then(() => this.dropOriginal())
|
||||
.then(() => this.trx.raw(newSql))
|
||||
.then(() => this.reinsertData(mapRow))
|
||||
.then(() => this.dropTempTable());
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = SQLite3_DDL;
|
||||
156
node_modules/knex/lib/dialects/sqlite3/schema/tablecompiler.js
generated
vendored
Normal file
156
node_modules/knex/lib/dialects/sqlite3/schema/tablecompiler.js
generated
vendored
Normal file
@@ -0,0 +1,156 @@
|
||||
const inherits = require('inherits');
|
||||
const TableCompiler = require('../../../schema/tablecompiler');
|
||||
|
||||
const { filter, values } = require('lodash');
|
||||
|
||||
// Table Compiler
|
||||
// -------
|
||||
|
||||
function TableCompiler_SQLite3() {
|
||||
TableCompiler.apply(this, arguments);
|
||||
this.primaryKey = void 0;
|
||||
}
|
||||
inherits(TableCompiler_SQLite3, TableCompiler);
|
||||
|
||||
// Create a new table.
|
||||
TableCompiler_SQLite3.prototype.createQuery = function(columns, ifNot) {
|
||||
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 += ')';
|
||||
|
||||
this.pushQuery(sql);
|
||||
};
|
||||
|
||||
TableCompiler_SQLite3.prototype.addColumns = function(columns, prefix) {
|
||||
if (prefix) {
|
||||
throw new Error('Sqlite does not support alter column.');
|
||||
}
|
||||
for (let i = 0, l = columns.sql.length; i < l; i++) {
|
||||
this.pushQuery({
|
||||
sql: `alter table ${this.tableName()} add column ${columns.sql[i]}`,
|
||||
bindings: columns.bindings[i],
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Compile a drop unique key command.
|
||||
TableCompiler_SQLite3.prototype.dropUnique = function(columns, indexName) {
|
||||
indexName = indexName
|
||||
? this.formatter.wrap(indexName)
|
||||
: this._indexCommand('unique', this.tableNameRaw, columns);
|
||||
this.pushQuery(`drop index ${indexName}`);
|
||||
};
|
||||
|
||||
TableCompiler_SQLite3.prototype.dropIndex = function(columns, indexName) {
|
||||
indexName = indexName
|
||||
? this.formatter.wrap(indexName)
|
||||
: this._indexCommand('index', this.tableNameRaw, columns);
|
||||
this.pushQuery(`drop index ${indexName}`);
|
||||
};
|
||||
|
||||
// Compile a unique key command.
|
||||
TableCompiler_SQLite3.prototype.unique = function(columns, indexName) {
|
||||
indexName = indexName
|
||||
? this.formatter.wrap(indexName)
|
||||
: this._indexCommand('unique', this.tableNameRaw, columns);
|
||||
columns = this.formatter.columnize(columns);
|
||||
this.pushQuery(
|
||||
`create unique index ${indexName} on ${this.tableName()} (${columns})`
|
||||
);
|
||||
};
|
||||
|
||||
// Compile a plain index key command.
|
||||
TableCompiler_SQLite3.prototype.index = function(columns, indexName) {
|
||||
indexName = indexName
|
||||
? this.formatter.wrap(indexName)
|
||||
: this._indexCommand('index', this.tableNameRaw, columns);
|
||||
columns = this.formatter.columnize(columns);
|
||||
this.pushQuery(
|
||||
`create index ${indexName} on ${this.tableName()} (${columns})`
|
||||
);
|
||||
};
|
||||
|
||||
TableCompiler_SQLite3.prototype.primary = TableCompiler_SQLite3.prototype.foreign = function() {
|
||||
if (this.method !== 'create' && this.method !== 'createIfNot') {
|
||||
this.client.logger.warn(
|
||||
'SQLite3 Foreign & Primary keys may only be added on create'
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
TableCompiler_SQLite3.prototype.primaryKeys = function() {
|
||||
const pks = filter(this.grouped.alterTable || [], { method: 'primary' });
|
||||
if (pks.length > 0 && pks[0].args.length > 0) {
|
||||
const columns = pks[0].args[0];
|
||||
let constraintName = pks[0].args[1] || '';
|
||||
if (constraintName) {
|
||||
constraintName = ' constraint ' + this.formatter.wrap(constraintName);
|
||||
}
|
||||
return `,${constraintName} primary key (${this.formatter.columnize(
|
||||
columns
|
||||
)})`;
|
||||
}
|
||||
};
|
||||
|
||||
TableCompiler_SQLite3.prototype.foreignKeys = function() {
|
||||
let sql = '';
|
||||
const foreignKeys = filter(this.grouped.alterTable || [], {
|
||||
method: 'foreign',
|
||||
});
|
||||
for (let i = 0, l = foreignKeys.length; i < l; i++) {
|
||||
const foreign = foreignKeys[i].args[0];
|
||||
const column = this.formatter.columnize(foreign.column);
|
||||
const references = this.formatter.columnize(foreign.references);
|
||||
const foreignTable = this.formatter.wrap(foreign.inTable);
|
||||
let constraintName = foreign.keyName || '';
|
||||
if (constraintName) {
|
||||
constraintName = ' constraint ' + this.formatter.wrap(constraintName);
|
||||
}
|
||||
sql += `,${constraintName} foreign key(${column}) references ${foreignTable}(${references})`;
|
||||
if (foreign.onDelete) sql += ` on delete ${foreign.onDelete}`;
|
||||
if (foreign.onUpdate) sql += ` on update ${foreign.onUpdate}`;
|
||||
}
|
||||
return sql;
|
||||
};
|
||||
|
||||
TableCompiler_SQLite3.prototype.createTableBlock = function() {
|
||||
return this.getColumns()
|
||||
.concat()
|
||||
.join(',');
|
||||
};
|
||||
|
||||
// Compile a rename column command... very complex in sqlite
|
||||
TableCompiler_SQLite3.prototype.renameColumn = function(from, to) {
|
||||
const compiler = this;
|
||||
this.pushQuery({
|
||||
sql: `PRAGMA table_info(${this.tableName()})`,
|
||||
output(pragma) {
|
||||
return compiler.client
|
||||
.ddl(compiler, pragma, this.connection)
|
||||
.renameColumn(from, to);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
TableCompiler_SQLite3.prototype.dropColumn = function() {
|
||||
const compiler = this;
|
||||
const columns = values(arguments);
|
||||
this.pushQuery({
|
||||
sql: `PRAGMA table_info(${this.tableName()})`,
|
||||
output(pragma) {
|
||||
return compiler.client
|
||||
.ddl(compiler, pragma, this.connection)
|
||||
.dropColumn(columns);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = TableCompiler_SQLite3;
|
||||
Reference in New Issue
Block a user