Add initial version of dijkstra backend cloudron image

This commit is contained in:
2020-10-12 11:27:15 +02:00
commit 4f5db9ab26
4209 changed files with 448228 additions and 0 deletions

View 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;

View 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
View 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;

View 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;