mirror of
https://github.com/dbgate/dbgate
synced 2024-11-07 20:26:23 +00:00
Merge branch 'master' into tableeditor2
This commit is contained in:
commit
a5cc99005a
@ -1,6 +1,6 @@
|
||||
{
|
||||
"private": true,
|
||||
"version": "4.2.7",
|
||||
"version": "4.2.8-beta.2",
|
||||
"name": "dbgate-all",
|
||||
"workspaces": [
|
||||
"packages/*",
|
||||
|
@ -8,6 +8,7 @@ const consoleObjectWriter = require('./consoleObjectWriter');
|
||||
const jsonLinesWriter = require('./jsonLinesWriter');
|
||||
const jsonArrayWriter = require('./jsonArrayWriter');
|
||||
const jsonLinesReader = require('./jsonLinesReader');
|
||||
const sqlDataWriter = require('./sqlDataWriter');
|
||||
const jslDataReader = require('./jslDataReader');
|
||||
const archiveWriter = require('./archiveWriter');
|
||||
const archiveReader = require('./archiveReader');
|
||||
@ -29,6 +30,7 @@ const dbgateApi = {
|
||||
jsonLinesWriter,
|
||||
jsonArrayWriter,
|
||||
jsonLinesReader,
|
||||
sqlDataWriter,
|
||||
fakeObjectReader,
|
||||
consoleObjectWriter,
|
||||
jslDataReader,
|
||||
|
54
packages/api/src/shell/sqlDataWriter.js
Normal file
54
packages/api/src/shell/sqlDataWriter.js
Normal file
@ -0,0 +1,54 @@
|
||||
const fs = require('fs');
|
||||
const stream = require('stream');
|
||||
const path = require('path');
|
||||
const { driverBase } = require('dbgate-tools');
|
||||
const requireEngineDriver = require('../utility/requireEngineDriver');
|
||||
|
||||
class SqlizeStream extends stream.Transform {
|
||||
constructor({ fileName }) {
|
||||
super({ objectMode: true });
|
||||
this.wasHeader = false;
|
||||
this.tableName = path.parse(fileName).name;
|
||||
this.driver = driverBase;
|
||||
}
|
||||
_transform(chunk, encoding, done) {
|
||||
let skip = false;
|
||||
if (!this.wasHeader) {
|
||||
if (
|
||||
chunk.__isStreamHeader ||
|
||||
// TODO remove isArray test
|
||||
Array.isArray(chunk.columns)
|
||||
) {
|
||||
skip = true;
|
||||
this.tableName = chunk.pureName;
|
||||
if (chunk.engine) {
|
||||
// @ts-ignore
|
||||
this.driver = requireEngineDriver(chunk.engine) || driverBase;
|
||||
}
|
||||
}
|
||||
this.wasHeader = true;
|
||||
}
|
||||
if (!skip) {
|
||||
const dmp = this.driver.createDumper();
|
||||
dmp.put(
|
||||
'^insert ^into %f (%,i) ^values (%,v);\n',
|
||||
{ pureName: this.tableName },
|
||||
Object.keys(chunk),
|
||||
Object.values(chunk)
|
||||
);
|
||||
this.push(dmp.s);
|
||||
}
|
||||
done();
|
||||
}
|
||||
}
|
||||
|
||||
async function sqlDataWriter({ fileName, driver, encoding = 'utf-8' }) {
|
||||
console.log(`Writing file ${fileName}`);
|
||||
const stringify = new SqlizeStream({ fileName });
|
||||
const fileStream = fs.createWriteStream(fileName, encoding);
|
||||
stringify.pipe(fileStream);
|
||||
stringify['finisher'] = fileStream;
|
||||
return stringify;
|
||||
}
|
||||
|
||||
module.exports = sqlDataWriter;
|
@ -4,7 +4,10 @@ import _groupBy from 'lodash/groupBy';
|
||||
import _pick from 'lodash/pick';
|
||||
import _compact from 'lodash/compact';
|
||||
|
||||
const STRUCTURE_FIELDS = ['tables', 'collections', 'views', 'matviews', 'functions', 'procedures', 'triggers'];
|
||||
|
||||
const fp_pick = arg => array => _pick(array, arg);
|
||||
|
||||
export class DatabaseAnalyser {
|
||||
structure: DatabaseInfo;
|
||||
modifications: DatabaseModification[];
|
||||
@ -23,8 +26,20 @@ export class DatabaseAnalyser {
|
||||
|
||||
async _computeSingleObjectId() {}
|
||||
|
||||
addEngineField(db: DatabaseInfo) {
|
||||
if (!this.driver?.engine) return;
|
||||
for (const field of STRUCTURE_FIELDS) {
|
||||
if (!db[field]) continue;
|
||||
for (const item of db[field]) {
|
||||
item.engine = this.driver.engine;
|
||||
}
|
||||
}
|
||||
db.engine = this.driver.engine;
|
||||
return db;
|
||||
}
|
||||
|
||||
async fullAnalysis() {
|
||||
const res = await this._runAnalysis();
|
||||
const res = this.addEngineField(await this._runAnalysis());
|
||||
// console.log('FULL ANALYSIS', res);
|
||||
return res;
|
||||
}
|
||||
@ -33,7 +48,7 @@ export class DatabaseAnalyser {
|
||||
// console.log('Analysing SINGLE OBJECT', name, typeField);
|
||||
this.singleObjectFilter = { ...name, typeField };
|
||||
await this._computeSingleObjectId();
|
||||
const res = await this._runAnalysis();
|
||||
const res = this.addEngineField(await this._runAnalysis());
|
||||
// console.log('SINGLE OBJECT RES', res);
|
||||
const obj =
|
||||
res[typeField]?.length == 1
|
||||
@ -50,11 +65,11 @@ export class DatabaseAnalyser {
|
||||
if (this.modifications == null) {
|
||||
// modifications not implemented, perform full analysis
|
||||
this.structure = null;
|
||||
return this._runAnalysis();
|
||||
return this.addEngineField(await this._runAnalysis());
|
||||
}
|
||||
if (this.modifications.length == 0) return null;
|
||||
console.log('DB modifications detected:', this.modifications);
|
||||
return this.mergeAnalyseResult(await this._runAnalysis());
|
||||
return this.addEngineField(this.mergeAnalyseResult(await this._runAnalysis()));
|
||||
}
|
||||
|
||||
mergeAnalyseResult(newlyAnalysed) {
|
||||
@ -66,7 +81,7 @@ export class DatabaseAnalyser {
|
||||
}
|
||||
|
||||
const res = {};
|
||||
for (const field of ['tables', 'collections', 'views', 'matviews', 'functions', 'procedures', 'triggers']) {
|
||||
for (const field of STRUCTURE_FIELDS) {
|
||||
const removedIds = this.modifications
|
||||
.filter(x => x.action == 'remove' && x.objectTypeField == field)
|
||||
.map(x => x.objectId);
|
||||
|
1
packages/types/dbinfo.d.ts
vendored
1
packages/types/dbinfo.d.ts
vendored
@ -106,4 +106,5 @@ export interface DatabaseInfoObjects {
|
||||
|
||||
export interface DatabaseInfo extends DatabaseInfoObjects {
|
||||
schemas: SchemaInfo[];
|
||||
engine?: string;
|
||||
}
|
||||
|
@ -51,11 +51,11 @@
|
||||
}
|
||||
|
||||
:global(.theme-type-dark) .inner {
|
||||
--json-tree-string-color: #efc5c5;
|
||||
--json-tree-symbol-color: #efc5c5;
|
||||
--json-tree-boolean-color: #a6b3f5;
|
||||
--json-tree-function-color: #a6b3f5;
|
||||
--json-tree-number-color: #bfbdf2;
|
||||
--json-tree-string-color: #ffc5c5;
|
||||
--json-tree-symbol-color: #ffc5c5;
|
||||
--json-tree-boolean-color: #b6c3ff;
|
||||
--json-tree-function-color: #b6c3ff;
|
||||
--json-tree-number-color: #bfbdff;
|
||||
--json-tree-label-color: #e9aaed;
|
||||
--json-tree-arrow-color: #d4d4d4;
|
||||
--json-tree-null-color: #dcdcdc;
|
||||
|
@ -171,7 +171,6 @@
|
||||
if (_.isPlainObject(value) || _.isArray(value)) return JSON.stringify(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
@ -666,43 +665,52 @@
|
||||
|
||||
function handleGridWheel(event) {
|
||||
if (event.shiftKey) {
|
||||
let newFirstVisibleColumnScrollIndex = firstVisibleColumnScrollIndex;
|
||||
if (event.deltaY > 0) {
|
||||
newFirstVisibleColumnScrollIndex++;
|
||||
}
|
||||
if (event.deltaY < 0) {
|
||||
newFirstVisibleColumnScrollIndex--;
|
||||
}
|
||||
if (newFirstVisibleColumnScrollIndex > maxScrollColumn) {
|
||||
newFirstVisibleColumnScrollIndex = maxScrollColumn;
|
||||
}
|
||||
if (newFirstVisibleColumnScrollIndex < 0) {
|
||||
newFirstVisibleColumnScrollIndex = 0;
|
||||
}
|
||||
firstVisibleColumnScrollIndex = newFirstVisibleColumnScrollIndex;
|
||||
|
||||
domHorizontalScroll.scroll(newFirstVisibleColumnScrollIndex);
|
||||
scrollHorizontal(event.deltaY, event.deltaX);
|
||||
} else {
|
||||
let newFirstVisibleRowScrollIndex = firstVisibleRowScrollIndex;
|
||||
if (event.deltaY > 0) {
|
||||
newFirstVisibleRowScrollIndex += wheelRowCount;
|
||||
}
|
||||
if (event.deltaY < 0) {
|
||||
newFirstVisibleRowScrollIndex -= wheelRowCount;
|
||||
}
|
||||
let rowCount = grider.rowCount;
|
||||
if (newFirstVisibleRowScrollIndex + visibleRowCountLowerBound > rowCount) {
|
||||
newFirstVisibleRowScrollIndex = rowCount - visibleRowCountLowerBound + 1;
|
||||
}
|
||||
if (newFirstVisibleRowScrollIndex < 0) {
|
||||
newFirstVisibleRowScrollIndex = 0;
|
||||
}
|
||||
firstVisibleRowScrollIndex = newFirstVisibleRowScrollIndex;
|
||||
|
||||
domVerticalScroll.scroll(newFirstVisibleRowScrollIndex);
|
||||
scrollHorizontal(event.deltaX, event.deltaY);
|
||||
scrollVertical(event.deltaX, event.deltaY);
|
||||
}
|
||||
}
|
||||
|
||||
function scrollVertical(deltaX, deltaY) {
|
||||
let newFirstVisibleRowScrollIndex = firstVisibleRowScrollIndex;
|
||||
if (deltaY > 0 && deltaX === -0) {
|
||||
newFirstVisibleRowScrollIndex += wheelRowCount;
|
||||
} else if (deltaY < 0 && deltaX === -0) {
|
||||
newFirstVisibleRowScrollIndex -= wheelRowCount;
|
||||
}
|
||||
|
||||
let rowCount = grider.rowCount;
|
||||
if (newFirstVisibleRowScrollIndex + visibleRowCountLowerBound > rowCount) {
|
||||
newFirstVisibleRowScrollIndex = rowCount - visibleRowCountLowerBound + 1;
|
||||
}
|
||||
if (newFirstVisibleRowScrollIndex < 0) {
|
||||
newFirstVisibleRowScrollIndex = 0;
|
||||
}
|
||||
|
||||
firstVisibleRowScrollIndex = newFirstVisibleRowScrollIndex;
|
||||
domVerticalScroll.scroll(newFirstVisibleRowScrollIndex);
|
||||
}
|
||||
|
||||
function scrollHorizontal(deltaX, deltaY) {
|
||||
let newFirstVisibleColumnScrollIndex = firstVisibleColumnScrollIndex;
|
||||
if (deltaX > 0 && deltaY === -0) {
|
||||
newFirstVisibleColumnScrollIndex++;
|
||||
} else if (deltaX < 0 && deltaY === -0) {
|
||||
newFirstVisibleColumnScrollIndex--;
|
||||
}
|
||||
|
||||
if (newFirstVisibleColumnScrollIndex > maxScrollColumn) {
|
||||
newFirstVisibleColumnScrollIndex = maxScrollColumn;
|
||||
}
|
||||
if (newFirstVisibleColumnScrollIndex < 0) {
|
||||
newFirstVisibleColumnScrollIndex = 0;
|
||||
}
|
||||
|
||||
firstVisibleColumnScrollIndex = newFirstVisibleColumnScrollIndex;
|
||||
domHorizontalScroll.scroll(newFirstVisibleColumnScrollIndex);
|
||||
}
|
||||
|
||||
function getSelectedRowIndexes() {
|
||||
if (selectedCells.find(x => x[0] == 'header')) return _.range(0, grider.rowCount);
|
||||
return _.uniq((selectedCells || []).map(x => x[0])).filter(x => _.isNumber(x));
|
||||
@ -980,7 +988,6 @@
|
||||
);
|
||||
|
||||
const menu = getContextMenu();
|
||||
|
||||
</script>
|
||||
|
||||
{#if !display || (!isDynamicStructure && (!columns || columns.length == 0))}
|
||||
@ -1001,7 +1008,13 @@
|
||||
{/each}
|
||||
</div>
|
||||
{:else}
|
||||
<div class="container" bind:clientWidth={containerWidth} bind:clientHeight={containerHeight} use:contextMenu={menu}>
|
||||
<div
|
||||
class="container"
|
||||
bind:clientWidth={containerWidth}
|
||||
bind:clientHeight={containerHeight}
|
||||
use:contextMenu={menu}
|
||||
on:wheel={handleGridWheel}
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
class="focus-field"
|
||||
@ -1019,7 +1032,6 @@
|
||||
on:mousedown={handleGridMouseDown}
|
||||
on:mousemove={handleGridMouseMove}
|
||||
on:mouseup={handleGridMouseUp}
|
||||
on:wheel={handleGridWheel}
|
||||
>
|
||||
<thead>
|
||||
<tr>
|
||||
@ -1187,5 +1199,4 @@
|
||||
right: 40px;
|
||||
bottom: 20px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
@ -15,6 +15,13 @@ const jsonFormat = {
|
||||
writerFunc: 'jsonArrayWriter',
|
||||
};
|
||||
|
||||
const sqlFormat = {
|
||||
storageType: 'sql',
|
||||
extension: 'sql',
|
||||
name: 'SQL',
|
||||
writerFunc: 'sqlDataWriter',
|
||||
};
|
||||
|
||||
const jsonlQuickExport = {
|
||||
label: 'JSON lines',
|
||||
extension: 'jsonl',
|
||||
@ -37,8 +44,19 @@ const jsonQuickExport = {
|
||||
}),
|
||||
};
|
||||
|
||||
const sqlQuickExport = {
|
||||
label: 'SQL',
|
||||
extension: 'sql',
|
||||
createWriter: fileName => ({
|
||||
functionName: 'sqlDataWriter',
|
||||
props: {
|
||||
fileName,
|
||||
},
|
||||
}),
|
||||
};
|
||||
|
||||
export function buildFileFormats(plugins): FileFormatDefinition[] {
|
||||
const res = [jsonlFormat, jsonFormat];
|
||||
const res = [jsonlFormat, jsonFormat, sqlFormat];
|
||||
for (const { content } of plugins) {
|
||||
const { fileFormats } = content;
|
||||
if (fileFormats) res.push(...fileFormats);
|
||||
@ -47,7 +65,7 @@ export function buildFileFormats(plugins): FileFormatDefinition[] {
|
||||
}
|
||||
|
||||
export function buildQuickExports(plugins): QuickExportDefinition[] {
|
||||
const res = [jsonQuickExport, jsonlQuickExport];
|
||||
const res = [jsonQuickExport, jsonlQuickExport, sqlQuickExport];
|
||||
for (const { content } of plugins) {
|
||||
if (content.quickExports) res.push(...content.quickExports);
|
||||
}
|
||||
|
@ -69,11 +69,16 @@
|
||||
.main {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
position: relative;
|
||||
overflow-y: scroll;
|
||||
background-color: var(--theme-bg-0);
|
||||
}
|
||||
table {
|
||||
flex: 1;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user