create script callable from react

This commit is contained in:
Jan Prochazka
2020-02-03 20:34:38 +01:00
parent 680bed549f
commit 8a85cfe687
14 changed files with 147 additions and 95 deletions

View File

@@ -1,14 +1,19 @@
const mssql = require('mssql');
const mysql = require('mysql');
const pg = require('pg');
const fs = require('fs-extra');
const path = require('path');
const nativeModules = {
mssql,
mysql,
pg,
fs,
path,
};
function driverConnect(driver, connection) {
const driverModules = {
mssql,
mysql,
pg,
};
return driver.connect(driverModules, connection);
return driver.connect(nativeModules, connection);
}
module.exports = driverConnect;

View File

@@ -8,8 +8,8 @@ class SqlDumper {
putRaw(text) {
this.s += text;
}
putCmd(text) {
this.putRaw(text);
putCmd(format, ...args) {
this.put(format, ...args);
this.putRaw(';\n');
}
putFormattedValue(c, value) {

View File

@@ -1,7 +1,25 @@
const _ = require("lodash");
const mssql = require('./mssql');
const mysql = require('./mysql');
const postgres = require('./postgres');
const drivers = {
mssql,
mysql,
postgres,
}
/** @return {import('@dbgate/types').EngineDriver} */
function getDriver(connection) {
const { engine } = connection;
return require(`./${engine}`);
if (_.isString(connection)) {
return drivers[connection];
}
if (_.isPlainObject(connection)) {
const { engine } = connection;
if (engine) {
return drivers[engine];
}
}
throw new Error(`Cannot extract engine from ${connection}`)
}
module.exports = getDriver;

View File

@@ -1,42 +1,49 @@
const fs = require('fs-extra');
const fp = require('lodash/fp');
const path = require('path');
const _ = require('lodash');
const fp = require("lodash/fp");
const _ = require("lodash");
const DatabaseAnalayser = require('../default/DatabaseAnalyser');
const DatabaseAnalayser = require("../default/DatabaseAnalyser");
/** @returns {Promise<string>} */
async function loadQuery(name) {
return await fs.readFile(path.join(__dirname, name), 'utf-8');
async function loadQuery(pool, name) {
return await pool._nativeModules.fs.readFile(
pool._nativeModules.path.join(__dirname, name),
"utf-8"
);
}
const byTableFilter = table => x => x.pureName == table.pureName && x.schemaName == x.schemaName;
const byTableFilter = table => x =>
x.pureName == table.pureName && x.schemaName == x.schemaName;
function extractPrimaryKeys(table, pkColumns) {
const filtered = pkColumns.filter(byTableFilter(table));
if (filtered.length == 0) return undefined;
return {
..._.pick(filtered[0], ['constraintName', 'schemaName', 'pureName']),
constraintType: 'primaryKey',
columns: filtered.map(fp.pick('columnName')),
..._.pick(filtered[0], ["constraintName", "schemaName", "pureName"]),
constraintType: "primaryKey",
columns: filtered.map(fp.pick("columnName"))
};
}
function extractForeignKeys(table, fkColumns) {
const grouped = _.groupBy(fkColumns.filter(byTableFilter(table)), 'constraintName');
const grouped = _.groupBy(
fkColumns.filter(byTableFilter(table)),
"constraintName"
);
return _.keys(grouped).map(constraintName => ({
constraintName,
constraintType: 'foreignKey',
constraintType: "foreignKey",
..._.pick(grouped[constraintName][0], [
'constraintName',
'schemaName',
'pureName',
'refSchemaName',
'refTableName',
'updateAction',
'deleteAction',
"constraintName",
"schemaName",
"pureName",
"refSchemaName",
"refTableName",
"updateAction",
"deleteAction"
]),
columns: grouped[constraintName].map(fp.pick(['columnName', 'refColumnName'])),
columns: grouped[constraintName].map(
fp.pick(["columnName", "refColumnName"])
)
}));
}
@@ -53,15 +60,27 @@ class MsSqlAnalyser extends DatabaseAnalayser {
functions = false,
triggers = false
) {
let res = await loadQuery(resFileName);
res = res.replace('=[OBJECT_ID_CONDITION]', ' is not null');
let res = await loadQuery(this.pool, resFileName);
res = res.replace("=[OBJECT_ID_CONDITION]", " is not null");
return res;
}
async runAnalysis() {
const tables = await this.driver.query(this.pool, await this.createQuery('tables.sql'));
const columns = await this.driver.query(this.pool, await this.createQuery('columns.sql'));
const pkColumns = await this.driver.query(this.pool, await this.createQuery('primary_keys.sql'));
const fkColumns = await this.driver.query(this.pool, await this.createQuery('foreign_keys.sql'));
const tables = await this.driver.query(
this.pool,
await this.createQuery("tables.sql")
);
const columns = await this.driver.query(
this.pool,
await this.createQuery("columns.sql")
);
const pkColumns = await this.driver.query(
this.pool,
await this.createQuery("primary_keys.sql")
);
const fkColumns = await this.driver.query(
this.pool,
await this.createQuery("foreign_keys.sql")
);
this.result.tables = tables.rows.map(table => ({
...table,
@@ -70,10 +89,10 @@ class MsSqlAnalyser extends DatabaseAnalayser {
.map(({ isNullable, isIdentity, ...col }) => ({
...col,
notNull: !isNullable,
autoIncrement: !!isIdentity,
autoIncrement: !!isIdentity
})),
primaryKey: extractPrimaryKeys(table, pkColumns.rows),
foreignKeys: extractForeignKeys(table, fkColumns.rows),
foreignKeys: extractForeignKeys(table, fkColumns.rows)
}));
}
}

View File

@@ -12,14 +12,15 @@ const dialect = {
/** @type {import('@dbgate/types').EngineDriver} */
const driver = {
async connect({ mssql }, { server, port, user, password, database }) {
const pool = await mssql.connect({
async connect(nativeModules, { server, port, user, password, database }) {
const pool = await nativeModules.mssql.connect({
server,
port,
user,
password,
database
});
pool._nativeModules = nativeModules;
return pool;
},
async query(pool, sql) {

View File

@@ -1,13 +1,14 @@
const fs = require('fs-extra');
const fp = require('lodash/fp');
const path = require('path');
const _ = require('lodash');
const fp = require("lodash/fp");
const _ = require("lodash");
const DatabaseAnalayser = require('../default/DatabaseAnalyser');
const DatabaseAnalayser = require("../default/DatabaseAnalyser");
/** @returns {Promise<string>} */
async function loadQuery(name) {
return await fs.readFile(path.join(__dirname, name), 'utf-8');
async function loadQuery(pool, name) {
return await pool._nativeModules.fs.readFile(
pool._nativeModules.path.join(__dirname, name),
"utf-8"
);
}
class MySqlAnalyser extends DatabaseAnalayser {
@@ -23,14 +24,20 @@ class MySqlAnalyser extends DatabaseAnalayser {
functions = false,
triggers = false
) {
let res = await loadQuery(resFileName);
res = res.replace('=[OBJECT_NAME_CONDITION]', ' is not null');
res = res.replace('#DATABASE#', this.pool._database_name);
let res = await loadQuery(this.pool, resFileName);
res = res.replace("=[OBJECT_NAME_CONDITION]", " is not null");
res = res.replace("#DATABASE#", this.pool._database_name);
return res;
}
async runAnalysis() {
const tables = await this.driver.query(this.pool, await this.createQuery('tables.sql'));
const columns = await this.driver.query(this.pool, await this.createQuery('columns.sql'));
const tables = await this.driver.query(
this.pool,
await this.createQuery("tables.sql")
);
const columns = await this.driver.query(
this.pool,
await this.createQuery("columns.sql")
);
// const pkColumns = await this.driver.query(this.pool, await this.createQuery('primary_keys.sql'));
// const fkColumns = await this.driver.query(this.pool, await this.createQuery('foreign_keys.sql'));
@@ -41,9 +48,9 @@ class MySqlAnalyser extends DatabaseAnalayser {
.map(({ isNullable, extra, ...col }) => ({
...col,
notNull: !isNullable,
autoIncrement: extra && extra.toLowerCase().includes('auto_increment'),
autoIncrement: extra && extra.toLowerCase().includes("auto_increment")
})),
foreignKeys: [],
foreignKeys: []
// primaryKey: extractPrimaryKeys(table, pkColumns.rows),
// foreignKeys: extractForeignKeys(table, fkColumns.rows),
}));

View File

@@ -11,8 +11,8 @@ const dialect = {
/** @type {import('@dbgate/types').EngineDriver} */
const driver = {
async connect({ mysql }, { server, port, user, password, database }) {
const connection = mysql.createConnection({
async connect(nativeModules, { server, port, user, password, database }) {
const connection = nativeModules.mysql.createConnection({
host: server,
port,
user,
@@ -20,6 +20,7 @@ const driver = {
database
});
connection._database_name = database;
connection._nativeModules = nativeModules;
return connection;
},
async query(connection, sql) {

View File

@@ -10,8 +10,6 @@
"typescript": "^3.7.5"
},
"dependencies": {
"fs-extra": "^8.1.0",
"lodash": "^4.17.15",
"path": "^0.12.7"
"lodash": "^4.17.15"
}
}

View File

@@ -1,13 +1,14 @@
const fs = require('fs-extra');
const fp = require('lodash/fp');
const path = require('path');
const _ = require('lodash');
const fp = require("lodash/fp");
const _ = require("lodash");
const DatabaseAnalayser = require('../default/DatabaseAnalyser');
const DatabaseAnalayser = require("../default/DatabaseAnalyser");
/** @returns {Promise<string>} */
async function loadQuery(name) {
return await fs.readFile(path.join(__dirname, name), 'utf-8');
async function loadQuery(pool, name) {
return await pool._nativeModules.fs.readFile(
pool._nativeModules.path.join(__dirname, name),
"utf-8"
);
}
class MySqlAnalyser extends DatabaseAnalayser {
@@ -23,25 +24,34 @@ class MySqlAnalyser extends DatabaseAnalayser {
functions = false,
triggers = false
) {
let res = await loadQuery(resFileName);
res = res.replace('=[OBJECT_ID_CONDITION]', ' is not null');
let res = await loadQuery(this.pool, resFileName);
res = res.replace("=[OBJECT_ID_CONDITION]", " is not null");
return res;
}
async runAnalysis() {
const tables = await this.driver.query(this.pool, await this.createQuery('table_modifications.psql'));
const columns = await this.driver.query(this.pool, await this.createQuery('columns.psql'));
const tables = await this.driver.query(
this.pool,
await this.createQuery("table_modifications.psql")
);
const columns = await this.driver.query(
this.pool,
await this.createQuery("columns.psql")
);
// const pkColumns = await this.driver.query(this.pool, await this.createQuery('primary_keys.sql'));
// const fkColumns = await this.driver.query(this.pool, await this.createQuery('foreign_keys.sql'));
this.result.tables = tables.rows.map(table => ({
...table,
columns: columns.rows
.filter(col => col.pureName == table.pureName && col.schemaName == table.schemaName)
.filter(
col =>
col.pureName == table.pureName && col.schemaName == table.schemaName
)
.map(({ isNullable, ...col }) => ({
...col,
notNull: !isNullable,
notNull: !isNullable
})),
foreignKeys: [],
foreignKeys: []
// primaryKey: extractPrimaryKeys(table, pkColumns.rows),
// foreignKeys: extractForeignKeys(table, fkColumns.rows),
}));

View File

@@ -11,9 +11,10 @@ const dialect = {
/** @type {import('@dbgate/types').EngineDriver} */
const driver = {
async connect({pg}, { server, port, user, password, database }) {
const client = new pg.Client({ host: server, port, user, password, database: database || 'postgres' });
async connect(nativeModules, { server, port, user, password, database }) {
const client = new nativeModules.pg.Client({ host: server, port, user, password, database: database || 'postgres' });
await client.connect();
client._nativeModules = nativeModules;
return client;
},
async query(client, sql) {

View File

@@ -4,7 +4,7 @@ import { SqlDumper } from "./dumper";
import { DatabaseInfo } from "./dbinfo";
export interface EngineDriver {
connect(driverModules, { server, port, user, password, database }): any;
connect(nativeModules, { server, port, user, password, database }): any;
query(pool: any, sql: string): Promise<QueryResult>;
getVersion(pool: any): Promise<{ version: string }>;
listDatabases(

View File

@@ -21,7 +21,8 @@
"resize-observer-polyfill": "^1.5.1",
"socket.io-client": "^2.3.0",
"styled-components": "^4.4.1",
"uuid": "^3.4.0"
"uuid": "^3.4.0",
"@dbgate/engines": "^0.1.0"
},
"scripts": {
"start": "cross-env PORT=5000 react-scripts start",

View File

@@ -4,6 +4,7 @@ import styled from 'styled-components';
import theme from '../theme';
import AceEditor from 'react-ace';
import useDimensions from '../utility/useDimensions';
import engines from '@dbgate/engines';
const Wrapper = styled.div`
position: absolute;
@@ -23,6 +24,11 @@ export default function TableCreateScriptTab({ conid, database, schemaName, pure
params: { conid, database, schemaName, pureName },
});
/** @type {import('@dbgate/types').EngineDriver} */
const driver = engines('mssql');
const dumper = driver.createDumper();
dumper.putCmd('^select * ^from %f', { schemaName, pureName });
return (
<Wrapper ref={containerRef}>
<AceEditor
@@ -31,7 +37,7 @@ export default function TableCreateScriptTab({ conid, database, schemaName, pure
// onChange={onChange}
name="UNIQUE_ID_OF_DIV"
editorProps={{ $blockScrolling: true }}
value={sql}
value={dumper.s}
readOnly
fontSize="11pt"
width={`${width}px`}