added plugins

This commit is contained in:
Jan Prochazka
2021-04-13 16:17:53 +02:00
parent 446e7c139f
commit 4d5cc119f2
115 changed files with 5519 additions and 24 deletions

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021 Jan Prochazka
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,6 @@
[![styled with prettier](https://img.shields.io/badge/styled_with-prettier-ff69b4.svg)](https://github.com/prettier/prettier)
[![NPM version](https://img.shields.io/npm/v/dbgate-plugin-mysql.svg)](https://www.npmjs.com/package/dbgate-plugin-mysql)
# dbgate-plugin-mysql
Use DbGate for install of this plugin

View File

@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<path style="fill:#F2F2F2;" d="M512,256c0,36.937-7.826,72.056-21.911,103.769c-2.288,5.183-4.765,10.271-7.387,15.266
C439.85,456.474,354.408,512,256,512c-103.685,0-192.972-61.639-233.221-150.277c-7.022-15.464-12.549-31.744-16.394-48.661
C2.205,294.713,0,275.613,0,256C0,114.615,114.615,0,256,0c115.012,0,212.302,75.839,244.611,180.245
c1.024,3.323,1.985,6.687,2.884,10.073v0.01c1.672,6.332,3.114,12.737,4.305,19.247c0.554,3.03,1.055,6.071,1.494,9.132
c0.303,2.048,0.585,4.096,0.825,6.165c0.46,3.699,0.825,7.429,1.118,11.18C511.739,242.636,512,249.292,512,256z"/>
<g>
<path style="fill:#5181A2;" d="M367.961,77.614c0,0,7.42,7.632,8.691,13.355c0,0,5.3-4.028,1.696-10.387
C374.744,74.222,367.961,77.614,367.961,77.614z"/>
<path style="fill:#5181A2;" d="M503.495,190.318c-6.666-3.354-12.727-5.339-17.471-6.51c-6.416-1.588-11.609-6.311-13.855-12.528
c-2.884-7.973-8.255-20.888-18.139-40.458c-19.508-38.578-41.127-50.448-55.327-60.416c-9.32-6.541-21.567-7.868-28.881-8.014
c-3.688-0.073-7.241-1.421-10.073-3.793c-7.45-6.269-22.1-13.636-26.76-10.877c-5.726,3.396,0,11.243,8.046,21.201
c8.056,9.968,9.759,20.992,15.475,35.83c2.644,6.844,5.831,10.982,8.485,13.448c2.779,2.591,3.688,6.614,2.215,10.104
c-5.371,12.696-7.168,28.776-4.127,43.645c3.605,17.596,11.87,17.387,11.87,17.387c-0.846-23.531,11.452-33.708,11.452-33.708
c11.233,34.335,36.885,59.988,36.885,59.988c-20.773-7.419-36.247-41.336-36.247-41.336s-1.693,1.693-3.177,12.936
c-1.484,11.233-15.057,18.014-25.015-6.572c-9.968-24.597,2.967-55.547,2.967-55.547c-5.726-2.968-17.596-30.312-17.596-34.555
c0-4.232-4.671-13.563-10.386-19.289c-5.726-5.716-16.959-22.256-3.814-29.884c13.134-7.638,39.215,12.925,39.215,12.925
c41.127-1.484,83.519,48.546,90.3,66.351c6.781,17.805,25.861,53.426,25.861,53.426c5.413,1.641,10.501,3.762,15.214,6.175
C501.635,183.568,502.596,186.932,503.495,190.318z"/>
<path style="fill:#5181A2;" d="M511.237,236.053c-0.209-0.094-0.408-0.199-0.606-0.293c-13.145-6.363-18.442-19.717-18.442-19.717
c3.406-3.406,9.446-5.36,15.611-6.468c0.554,3.03,1.055,6.071,1.494,9.132c-2.299,0.449-3.751,0.721-3.751,0.721
c0,1.296,1.808,3.229,4.577,5.444C510.579,228.571,510.945,232.302,511.237,236.053z"/>
</g>
<g>
<path style="fill:#FFA600;" d="M133.371,374.659H113.34c0,0,0-45.777-6.677-100.153L75.18,374.659H58.964l-31.953-99.673
c0,0-3.72,29.288-4.232,86.737c-7.022-15.464-12.549-31.744-16.394-48.661c1.473-21.264,3.542-44.44,6.322-63.352h26.07
l29.727,92.526l31.483-92.526h23.845C123.831,249.71,133.371,331.264,133.371,374.659z"/>
<path style="fill:#FFA600;" d="M144.423,283.452l20.668-0.318c0,0,23.212,69.637,20.987,78.222c0,0,14.945-41.655,18.761-78.222
h20.35c0,0-10.812,73.771-43.88,112.564c-12.375,14.517-26.262,14.695-38.799,9.236v-11.143c0,0,17.177,6.042,26.081-6.678
c7.168-10.24,0.322-27.898-5.938-46.671C161.135,335.896,144.423,283.452,144.423,283.452z"/>
</g>
<g>
<path style="fill:#5181A2;" d="M237.908,365.491l5.405-10.812c0,0,37.204,16.534,46.742,0c9.539-16.534,0.318-25.438-18.442-35.296
c-18.76-9.858-38.475-22.258-29.89-49.287c8.586-27.028,54.056-25.12,67.093-12.083l-4.451,10.493c0,0-33.705-14.309-42.926,4.451
c-9.221,18.76,15.263,27.664,20.987,30.208c5.724,2.544,37.521,15.58,34.024,38.793s-17.807,37.521-50.558,34.659
C254.124,373.758,247.447,371.85,237.908,365.491z"/>
<path style="fill:#5181A2;" d="M405.452,367c14.054-11.295,20.083-31.389,20.083-54.293c0-35.328-10.167-63.969-50.333-63.969
c-34.586,0-50.333,28.641-50.333,63.969s11.515,63.969,50.333,63.969c5.622,0,10.721-0.7,15.318-2.017l29.905,17.544l7.314-14.315
L405.452,367z M375.202,361.357c-22.507,0-29.184-21.786-29.184-48.65c0-26.875,6.363-48.65,29.184-48.65
c23.28,0,29.174,21.776,29.174,48.65C404.375,339.571,398.482,361.357,375.202,361.357z"/>
<path style="fill:#5181A2;" d="M490.088,359.769c-2.288,5.183-4.765,10.271-7.387,15.266h-39.382V250.378h19.717v109.39H490.088z"
/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@@ -0,0 +1,39 @@
{
"name": "dbgate-plugin-mysql",
"main": "dist/backend.js",
"version": "1.2.2",
"homepage": "https://github.com/dbgate/dbgate-plugin-mysql",
"description": "MySQL connect plugin for DbGate",
"repository": {
"type": "git",
"url": "https://github.com/dbgate/dbgate-plugin-mysql.git"
},
"funding": "https://www.paypal.com/paypalme/JanProchazkaCz/30eur",
"author": "Jan Prochazka",
"license": "MIT",
"keywords": [
"sql",
"dbgate",
"dbgateplugin",
"mysql"
],
"files": [
"dist"
],
"scripts": {
"build:frontend": "webpack --config webpack-frontend.config",
"build:backend": "webpack --config webpack-backend.config.js",
"build": "yarn build:frontend && yarn build:backend",
"plugin": "yarn build && yarn pack && dbgate-plugin dbgate-plugin-mysql",
"plugout": "dbgate-plugout dbgate-plugin-mysql",
"prepublishOnly": "yarn build"
},
"devDependencies": {
"@verycrazydog/mysql-parser": "^1.2.0",
"dbgate-plugin-tools": "^1.0.4",
"dbgate-tools": "^4.0.3-rc.1",
"mysql2": "^2.2.5",
"webpack": "^4.42.0",
"webpack-cli": "^3.3.11"
}
}

View File

@@ -0,0 +1,9 @@
module.exports = {
trailingComma: 'es5',
tabWidth: 2,
semi: true,
singleQuote: true,
arrowParen: 'avoid',
arrowParens: 'avoid',
printWidth: 120,
};

View File

@@ -0,0 +1,222 @@
const fp = require('lodash/fp');
const _ = require('lodash');
const sql = require('./sql');
const { DatabaseAnalyser } = require('dbgate-tools');
const { isTypeString, isTypeNumeric } = require('dbgate-tools');
const { rangeStep } = require('lodash/fp');
function getColumnInfo({
isNullable,
extra,
columnName,
dataType,
charMaxLength,
numericPrecision,
numericScale,
defaultValue,
}) {
let fullDataType = dataType;
if (charMaxLength && isTypeString(dataType)) fullDataType = `${dataType}(${charMaxLength})`;
if (numericPrecision && numericScale && isTypeNumeric(dataType))
fullDataType = `${dataType}(${numericPrecision},${numericScale})`;
return {
notNull: !isNullable || isNullable == 'NO' || isNullable == 'no',
autoIncrement: extra && extra.toLowerCase().includes('auto_increment'),
columnName,
dataType: fullDataType,
defaultValue,
};
}
function objectTypeToField(type) {
if (type == 'VIEW') return 'views';
if (type == 'BASE TABLE') return 'tables';
return null;
}
class Analyser extends DatabaseAnalyser {
constructor(pool, driver) {
super(pool, driver);
}
createQuery(resFileName, typeFields) {
let res = sql[resFileName];
if (this.singleObjectFilter) {
const { typeField, pureName } = this.singleObjectFilter;
if (!typeFields || !typeFields.includes(typeField)) return null;
res = res.replace('=[OBJECT_NAME_CONDITION]', ` = '${pureName}'`).replace('#DATABASE#', this.pool._database_name);
return res;
}
if (!this.modifications || !typeFields || this.modifications.length == 0) {
res = res.replace('=[OBJECT_NAME_CONDITION]', ' is not null');
} else {
const filterNames = this.modifications
.filter(x => typeFields.includes(x.objectTypeField) && (x.action == 'add' || x.action == 'change'))
.map(x => x.newName && x.newName.pureName)
.filter(Boolean);
if (filterNames.length == 0) {
res = res.replace('=[OBJECT_NAME_CONDITION]', ' IS NULL');
} else {
res = res.replace('=[OBJECT_NAME_CONDITION]', ` in (${filterNames.map(x => `'${x}'`).join(',')})`);
}
}
res = res.replace('#DATABASE#', this.pool._database_name);
return res;
}
getRequestedViewNames(allViewNames) {
if (this.singleObjectFilter) {
const { typeField, pureName } = this.singleObjectFilter;
if (typeField == 'views') return [pureName];
}
if (this.modifications) {
return this.modifications.filter(x => x.objectTypeField == 'views').map(x => x.newName.pureName);
}
return allViewNames;
}
async getViewTexts(allViewNames) {
const res = {};
for (const viewName of this.getRequestedViewNames(allViewNames)) {
const resp = await this.driver.query(this.pool, `SHOW CREATE VIEW \`${viewName}\``);
res[viewName] = resp.rows[0]['Create View'];
}
return res;
}
async _runAnalysis() {
const tables = await this.driver.query(this.pool, this.createQuery('tables', ['tables']));
const columns = await this.driver.query(this.pool, this.createQuery('columns', ['tables', 'views']));
const pkColumns = await this.driver.query(this.pool, this.createQuery('primaryKeys', ['tables']));
const fkColumns = await this.driver.query(this.pool, this.createQuery('foreignKeys', ['tables']));
const views = await this.driver.query(this.pool, this.createQuery('views', ['views']));
const programmables = await this.driver.query(
this.pool,
this.createQuery('programmables', ['procedures', 'functions'])
);
const viewTexts = await this.getViewTexts(views.rows.map(x => x.pureName));
return this.mergeAnalyseResult({
tables: tables.rows.map(table => ({
...table,
objectId: table.pureName,
columns: columns.rows.filter(col => col.pureName == table.pureName).map(getColumnInfo),
primaryKey: DatabaseAnalyser.extractPrimaryKeys(table, pkColumns.rows),
foreignKeys: DatabaseAnalyser.extractForeignKeys(table, fkColumns.rows),
})),
views: views.rows.map(view => ({
...view,
objectId: view.pureName,
columns: columns.rows.filter(col => col.pureName == view.pureName).map(getColumnInfo),
createSql: viewTexts[view.pureName],
requiresFormat: true,
})),
procedures: programmables.rows
.filter(x => x.objectType == 'PROCEDURE')
.map(fp.omit(['objectType']))
.map(x => ({ ...x, objectId: x.pureName })),
functions: programmables.rows
.filter(x => x.objectType == 'FUNCTION')
.map(fp.omit(['objectType']))
.map(x => ({ ...x, objectId: x.pureName })),
});
}
getDeletedObjectsForField(nameArray, objectTypeField) {
return this.structure[objectTypeField]
.filter(x => !nameArray.includes(x.pureName))
.map(x => ({
oldName: _.pick(x, ['pureName']),
action: 'remove',
objectTypeField,
objectId: x.pureName,
}));
}
getDeletedObjects(nameArray) {
return [
...this.getDeletedObjectsForField(nameArray, 'tables'),
...this.getDeletedObjectsForField(nameArray, 'views'),
...this.getDeletedObjectsForField(nameArray, 'procedures'),
...this.getDeletedObjectsForField(nameArray, 'functions'),
...this.getDeletedObjectsForField(nameArray, 'triggers'),
];
}
async getModifications() {
const tableModificationsQueryData = await this.driver.query(this.pool, this.createQuery('tableModifications'));
const procedureModificationsQueryData = await this.driver.query(
this.pool,
this.createQuery('procedureModifications')
);
const functionModificationsQueryData = await this.driver.query(
this.pool,
this.createQuery('functionModifications')
);
const allModifications = _.compact([
...tableModificationsQueryData.rows.map(x => {
if (x.objectType == 'BASE TABLE') return { ...x, objectTypeField: 'tables' };
if (x.objectType == 'VIEW') return { ...x, objectTypeField: 'views' };
return null;
}),
...procedureModificationsQueryData.rows.map(x => ({
objectTypeField: 'procedures',
modifyDate: x.Modified,
pureName: x.Name,
})),
...functionModificationsQueryData.rows.map(x => ({
objectTypeField: 'functions',
modifyDate: x.Modified,
pureName: x.Name,
})),
]);
// console.log('allModifications', allModifications);
// console.log(
// 'DATES',
// this.structure.procedures.map((x) => x.modifyDate)
// );
// console.log('MOD - SRC', modifications);
// console.log(
// 'MODs',
// this.structure.tables.map((x) => x.modifyDate)
// );
const modifications = allModifications.map(x => {
const { objectType, modifyDate, pureName } = x;
const field = objectTypeToField(objectType);
if (!field || !this.structure[field]) return null;
// @ts-ignore
const obj = this.structure[field].find(x => x.pureName == pureName);
// object not modified
if (obj && Math.abs(new Date(modifyDate).getTime() - new Date(obj.modifyDate).getTime()) < 1000) return null;
// console.log('MODIFICATION OF ', field, pureName, modifyDate, obj.modifyDate);
/** @type {import('dbgate-types').DatabaseModification} */
const action = obj
? {
newName: { pureName },
oldName: _.pick(obj, ['pureName']),
action: 'change',
objectTypeField: field,
objectId: pureName,
}
: {
newName: { pureName },
action: 'add',
objectTypeField: field,
objectId: pureName,
};
return action;
});
return [..._.compact(modifications), ...this.getDeletedObjects([...allModifications.map(x => x.pureName)])];
}
}
module.exports = Analyser;

View File

@@ -0,0 +1,186 @@
const _ = require('lodash');
const stream = require('stream');
const driverBase = require('../frontend/driver');
const Analyser = require('./Analyser');
const mysql2 = require('mysql2');
const { createBulkInsertStreamBase, makeUniqueColumnNames } = require('dbgate-tools');
const mysqlSplitter = require('@verycrazydog/mysql-parser');
function extractColumns(fields) {
if (fields) {
const res = fields.map(col => ({
columnName: col.name,
}));
makeUniqueColumnNames(res);
return res;
}
return null;
}
function zipDataRow(rowArray, columns) {
return _.zipObject(
columns.map(x => x.columnName),
rowArray
);
}
async function runQueryItem(connection, sql) {
return new Promise((resolve, reject) => {
connection.query(sql, function (error, results, fields) {
if (error) reject(error);
const columns = extractColumns(fields);
resolve({ rows: results && columns && results.map && results.map(row => zipDataRow(row, columns)), columns });
});
});
}
async function runStreamItem(connection, sql, options) {
return new Promise((resolve, reject) => {
const query = connection.query(sql);
let columns = [];
// const handleInfo = (info) => {
// const { message, lineNumber, procName } = info;
// options.info({
// message,
// line: lineNumber,
// procedure: procName,
// time: new Date(),
// severity: 'info',
// });
// };
const handleEnd = () => {
resolve();
};
const handleRow = row => {
if (row && row.constructor && row.constructor.name == 'OkPacket') {
options.info({
message: `${row.affectedRows} rows affected`,
time: new Date(),
severity: 'info',
});
} else {
if (columns) {
options.row(zipDataRow(row, columns));
}
}
};
const handleFields = fields => {
columns = extractColumns(fields);
if (columns) options.recordset(columns);
};
const handleError = error => {
console.log('ERROR', error);
const { message, lineNumber, procName } = error;
options.info({
message,
line: lineNumber,
procedure: procName,
time: new Date(),
severity: 'error',
});
};
query.on('error', handleError).on('fields', handleFields).on('result', handleRow).on('end', handleEnd);
});
}
/** @type {import('dbgate-types').EngineDriver} */
const driver = {
...driverBase,
analyserClass: Analyser,
async connect({ server, port, user, password, database, ssl }) {
const connection = mysql2.createConnection({
host: server,
port,
user,
password,
database,
ssl,
rowsAsArray: true,
supportBigNumbers: true,
bigNumberStrings: true,
// TODO: test following options
// multipleStatements: true,
// dateStrings: true,
});
connection._database_name = database;
return connection;
},
async query(connection, sql) {
if (sql == null) {
return {
rows: [],
columns: [],
};
}
const sqlSplitted = mysqlSplitter.split(sql);
let res = {
rows: [],
columns: [],
};
for (const sqlItem of sqlSplitted) {
const resultItem = await runQueryItem(connection, sqlItem);
if (resultItem.rows && resultItem.columns && resultItem.columns.length > 0) {
res = resultItem;
}
}
return res;
},
async stream(connection, sql, options) {
const sqlSplitted = mysqlSplitter.split(sql);
for (const sqlItem of sqlSplitted) {
await runStreamItem(connection, sqlItem, options);
}
options.done();
},
async readQuery(connection, sql, structure) {
const query = connection.query(sql);
const pass = new stream.PassThrough({
objectMode: true,
highWaterMark: 100,
});
let columns = [];
query
.on('error', err => {
console.error(err);
pass.end();
})
.on('fields', fields => {
columns = extractColumns(fields);
pass.write({
__isStreamHeader: true,
...(structure || { columns }),
});
})
.on('result', row => pass.write(zipDataRow(row, columns)))
.on('end', () => pass.end());
return pass;
},
async getVersion(connection) {
const { rows } = await this.query(connection, "show variables like 'version'");
const version = rows[0].Value;
return { version };
},
async listDatabases(connection) {
const { rows } = await this.query(connection, 'show databases');
return rows.map(x => ({ name: x.Database }));
},
async writeTable(pool, name, options) {
// @ts-ignore
return createBulkInsertStreamBase(this, stream, pool, name, options);
},
};
module.exports = driver;

View File

@@ -0,0 +1,6 @@
const driver = require('./driver');
module.exports = {
packageName: 'dbgate-plugin-mysql',
driver,
};

View File

@@ -0,0 +1,15 @@
module.exports = `
select
TABLE_NAME as pureName,
COLUMN_NAME as columnName,
IS_NULLABLE as isNullable,
DATA_TYPE as dataType,
CHARACTER_MAXIMUM_LENGTH as charMaxLength,
NUMERIC_PRECISION as numericPrecision,
NUMERIC_SCALE as numericScale,
COLUMN_DEFAULT as defaultValue,
EXTRA as extra
from INFORMATION_SCHEMA.COLUMNS
where TABLE_SCHEMA = '#DATABASE#' and TABLE_NAME =[OBJECT_NAME_CONDITION]
order by ORDINAL_POSITION
`;

View File

@@ -0,0 +1,17 @@
module.exports = `
select
REFERENTIAL_CONSTRAINTS.CONSTRAINT_NAME as constraintName,
REFERENTIAL_CONSTRAINTS.TABLE_NAME as pureName,
REFERENTIAL_CONSTRAINTS.UPDATE_RULE as updateAction,
REFERENTIAL_CONSTRAINTS.DELETE_RULE as deleteAction,
REFERENTIAL_CONSTRAINTS.REFERENCED_TABLE_NAME as refTableName,
KEY_COLUMN_USAGE.COLUMN_NAME as columnName,
KEY_COLUMN_USAGE.REFERENCED_COLUMN_NAME as refColumnName
from INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS
inner join INFORMATION_SCHEMA.KEY_COLUMN_USAGE
on REFERENTIAL_CONSTRAINTS.TABLE_NAME = KEY_COLUMN_USAGE.TABLE_NAME
and REFERENTIAL_CONSTRAINTS.CONSTRAINT_NAME = KEY_COLUMN_USAGE.CONSTRAINT_NAME
and REFERENTIAL_CONSTRAINTS.CONSTRAINT_SCHEMA = KEY_COLUMN_USAGE.CONSTRAINT_SCHEMA
where REFERENTIAL_CONSTRAINTS.CONSTRAINT_SCHEMA = '#DATABASE#' and REFERENTIAL_CONSTRAINTS.TABLE_NAME =[OBJECT_NAME_CONDITION]
order by KEY_COLUMN_USAGE.ORDINAL_POSITION
`;

View File

@@ -0,0 +1,3 @@
module.exports = `
SHOW FUNCTION STATUS WHERE Db = '#DATABASE#'
`;

View File

@@ -0,0 +1,21 @@
const columns = require('./columns');
const tables = require('./tables');
const primaryKeys = require('./primaryKeys');
const foreignKeys = require('./foreignKeys');
const tableModifications = require('./tableModifications');
const views = require('./views');
const programmables = require('./programmables');
const procedureModifications = require('./procedureModifications');
const functionModifications = require('./functionModifications');
module.exports = {
columns,
tables,
primaryKeys,
foreignKeys,
tableModifications,
views,
programmables,
procedureModifications,
functionModifications,
};

View File

@@ -0,0 +1,12 @@
module.exports = `select
TABLE_CONSTRAINTS.CONSTRAINT_NAME as constraintName,
TABLE_CONSTRAINTS.TABLE_NAME as pureName,
KEY_COLUMN_USAGE.COLUMN_NAME as columnName
from INFORMATION_SCHEMA.TABLE_CONSTRAINTS
inner join INFORMATION_SCHEMA.KEY_COLUMN_USAGE
on TABLE_CONSTRAINTS.TABLE_NAME = KEY_COLUMN_USAGE.TABLE_NAME
and TABLE_CONSTRAINTS.CONSTRAINT_NAME = KEY_COLUMN_USAGE.CONSTRAINT_NAME
and TABLE_CONSTRAINTS.CONSTRAINT_SCHEMA = KEY_COLUMN_USAGE.CONSTRAINT_SCHEMA
where TABLE_CONSTRAINTS.CONSTRAINT_SCHEMA = '#DATABASE#' and TABLE_CONSTRAINTS.TABLE_NAME =[OBJECT_NAME_CONDITION] AND TABLE_CONSTRAINTS.CONSTRAINT_TYPE = 'PRIMARY KEY'
order by KEY_COLUMN_USAGE.ORDINAL_POSITION
`;

View File

@@ -0,0 +1,3 @@
module.exports = `
SHOW PROCEDURE STATUS WHERE Db = '#DATABASE#'
`;

View File

@@ -0,0 +1,9 @@
module.exports = `
select
ROUTINE_NAME as pureName,
ROUTINE_TYPE as objectType,
COALESCE(LAST_ALTERED, CREATED) as modifyDate,
ROUTINE_DEFINITION as createSql
from information_schema.routines
where ROUTINE_SCHEMA = '#DATABASE#' and ROUTINE_NAME =[OBJECT_NAME_CONDITION]
`;

View File

@@ -0,0 +1,8 @@
module.exports = `
select
TABLE_NAME as pureName,
TABLE_TYPE as objectType,
case when ENGINE='InnoDB' then CREATE_TIME else coalesce(UPDATE_TIME, CREATE_TIME) end as modifyDate
from information_schema.tables
where TABLE_SCHEMA = '#DATABASE#'
`;

View File

@@ -0,0 +1,7 @@
module.exports = `
select
TABLE_NAME as pureName,
case when ENGINE='InnoDB' then CREATE_TIME else coalesce(UPDATE_TIME, CREATE_TIME) end as modifyDate
from information_schema.tables
where TABLE_SCHEMA = '#DATABASE#' and TABLE_TYPE='BASE TABLE' and TABLE_NAME =[OBJECT_NAME_CONDITION];
`;

View File

@@ -0,0 +1,7 @@
module.exports = `
select
TABLE_NAME as pureName,
coalesce(UPDATE_TIME, CREATE_TIME) as modifyDate
from information_schema.tables
where TABLE_SCHEMA = '#DATABASE#' and TABLE_NAME =[OBJECT_NAME_CONDITION] and TABLE_TYPE = 'VIEW';
`;

View File

@@ -0,0 +1,68 @@
const { SqlDumper } = require('dbgate-tools');
class Dumper extends SqlDumper {
/** @param type {import('dbgate-types').TransformType} */
transform(type, dumpExpr) {
switch (type) {
case 'GROUP:YEAR':
case 'YEAR':
this.put('^year(%c)', dumpExpr);
break;
case 'MONTH':
this.put('^month(%c)', dumpExpr);
break;
case 'DAY':
this.put('^day(%c)', dumpExpr);
break;
case 'GROUP:MONTH':
this.put("^date_format(%c, '%s')", dumpExpr, '%Y-%m');
break;
case 'GROUP:DAY':
this.put("^date_format(%c, '%s')", dumpExpr, '%Y-%m-%d');
break;
default:
dumpExpr();
break;
}
}
renameTable(obj, newName) {
this.putCmd('^rename ^table %f ^to %i', obj, newName);
}
changeColumn(oldcol, newcol, constraints) {
this.put('^alter ^table %f ^change ^column %i %i ', oldcol, oldcol.columnName, newcol.columnName);
this.columnDefinition(newcol, true, true, true);
this.inlineConstraints(constraints);
this.endCommand();
}
renameColumn(column, newcol) {
this.changeColumn(
column,
{
...column,
columnName: newcol,
},
[]
);
}
enableConstraints(table, enabled) {
this.putCmd('^set FOREIGN_KEY_CHECKS = %s', enabled ? '1' : '0');
}
comment(value) {
this.put('/* %s */', value);
}
beginTransaction() {
this.putCmd('^start ^transaction');
}
selectTableIntoNewTable(sourceName, targetName) {
this.putCmd('^create ^table %f (^select * ^from %f)', targetName, sourceName);
}
}
module.exports = Dumper;

View File

@@ -0,0 +1,27 @@
const { driverBase } = require('dbgate-tools');
const Dumper = require('./Dumper');
/** @type {import('dbgate-types').SqlDialect} */
const dialect = {
rangeSelect: true,
stringEscapeChar: '\\',
fallbackDataType: 'longtext',
enableConstraintsPerTable: false,
anonymousPrimaryKey: true,
explicitDropConstraint: true,
quoteIdentifier(s) {
return '`' + s + '`';
},
};
/** @type {import('dbgate-types').EngineDriver} */
const driver = {
...driverBase,
dumperClass: Dumper,
dialect,
engine: 'mysql@dbgate-plugin-mysql',
title: 'MySQL / MariaDB',
defaultPort: 3306,
};
module.exports = driver;

View File

@@ -0,0 +1,6 @@
import driver from './driver';
export default {
packageName: 'dbgate-plugin-mysql',
driver,
};

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,23 @@
var webpack = require('webpack');
var path = require('path');
var config = {
context: __dirname + '/src/backend',
entry: {
app: './index.js',
},
target: 'node',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'backend.js',
libraryTarget: 'commonjs2',
},
// uncomment for disable minimalization
// optimization: {
// minimize: false,
// },
};
module.exports = config;

View File

@@ -0,0 +1,24 @@
var webpack = require("webpack");
var path = require("path");
var config = {
context: __dirname + "/src/frontend",
entry: {
app: "./index.js",
},
target: "web",
output: {
path: path.resolve(__dirname, "dist"),
filename: "frontend.js",
libraryTarget: "var",
library: 'plugin',
},
// uncomment for disable minimalization
// optimization: {
// minimize: false,
// },
};
module.exports = config;