insert SQL join

This commit is contained in:
Jan Prochazka
2021-03-21 20:48:04 +01:00
parent d4989c75ca
commit a97e6dbcab
4 changed files with 234 additions and 8 deletions

View File

@@ -14,6 +14,7 @@
import { compact } from 'lodash';
import { onMount } from 'svelte';
import keycodes from '../utility/keycodes';
export let columns: TableControlColumn[];
export let rows;
@@ -21,16 +22,31 @@
export let selectable = false;
export let selectedIndex = 0;
$: columnList = _.compact(_.flatten(columns));
export let domTable;
let domTable;
$: columnList = _.compact(_.flatten(columns));
onMount(() => {
if (focusOnCreate) domTable.focus();
});
const handleKeyDown = event => {
if (event.keyCode == keycodes.downArrow) {
selectedIndex = Math.min(selectedIndex + 1, rows.length - 1);
}
if (event.keyCode == keycodes.upArrow) {
selectedIndex = Math.max(0, selectedIndex - 1);
}
};
</script>
<table bind:this={domTable} class:selectable>
<table
bind:this={domTable}
class:selectable
on:keydown
tabindex={selectable ? -1 : undefined}
on:keydown={handleKeyDown}
>
<thead>
<tr>
{#each columnList as col}

View File

@@ -3,10 +3,9 @@
export let value;
export let focused;
let domEditor;
export let domEditor;
if (focused) onMount(() => domEditor.focus());
</script>
<input type="text" {...$$restProps} bind:value on:change on:input bind:this={domEditor} />
<input type="text" {...$$restProps} bind:value on:change on:input bind:this={domEditor} on:keydown />

View File

@@ -0,0 +1,187 @@
<script lang="ts">
import FormStyledButton from '../elements/FormStyledButton.svelte';
import TableControl from '../elements/TableControl.svelte';
import TextField from '../forms/TextField.svelte';
import analyseQuerySources from '../query/analyseQuerySources';
import SqlEditor from '../query/SqlEditor.svelte';
import keycodes from '../utility/keycodes';
import ModalBase from './ModalBase.svelte';
import { closeCurrentModal } from './modalTools';
export let sql;
export let onInsert;
export let dbinfo;
export let engine;
let sourceIndex = 0;
let targetIndex = 0;
let joinIndex = 0;
let alias = '';
let domSource = null;
let domTarget = null;
let domAlias = null;
let domJoin = null;
const JOIN_TYPES = ['INNER JOIN', 'LEFT JOIN', 'RIGHT JOIN'];
$: sources = analyseQuerySources(sql, [...dbinfo.tables.map(x => x.pureName), ...dbinfo.views.map(x => x.pureName)]);
$: targets = computeTargets(sources, sourceIndex);
function computeTargets(sources, sourceIndex) {
const source = sources[sourceIndex];
if (!source) return [];
/** @type {import('dbgate-types').TableInfo} */
const table = dbinfo.tables.find(x => x.pureName == sources[sourceIndex].name);
if (!table) return [];
return [
...table.foreignKeys.map(fk => ({
baseColumns: fk.columns.map(x => x.columnName).join(', '),
refTable: fk.refTableName,
refColumns: fk.columns.map(x => x.refColumnName).join(', '),
constraintName: fk.constraintName,
columnMap: fk.columns,
})),
...table.dependencies.map(fk => ({
baseColumns: fk.columns.map(x => x.refColumnName).join(', '),
refTable: fk.pureName,
refColumns: fk.columns.map(x => x.columnName).join(', '),
constraintName: fk.constraintName,
columnMap: fk.columns.map(x => ({
columnName: x.refColumnName,
refColumnName: x.columnName,
})),
})),
];
}
$: sqlPreview = computePreview(joinIndex, sources, targets, sourceIndex, targetIndex, alias);
function computePreview(joinIndex, sources, targets, sourceIndex, targetIndex, alias) {
const source = sources[sourceIndex];
const target = targets[targetIndex];
if (source && target) {
return `${JOIN_TYPES[joinIndex]} ${target.refTable}${alias ? ` ${alias}` : ''} ON ${target.columnMap
.map(col => `${source.name}.${col.columnName} = ${alias || target.refTable}.${col.refColumnName}`)
.join(' AND ')}`;
}
return '';
}
const sourceKeyDown = event => {
if (event.keyCode == keycodes.enter || event.keyCode == keycodes.rightArrow) {
domTarget.focus();
}
};
const targetKeyDown = event => {
if (event.keyCode == keycodes.leftArrow) {
domSource.focus();
}
if (event.keyCode == keycodes.enter || event.keyCode == keycodes.rightArrow) {
domJoin.focus();
}
};
const joinKeyDown = event => {
if (event.keyCode == keycodes.leftArrow) {
domTarget.focus();
}
if (event.keyCode == keycodes.enter) {
domAlias.focus();
}
};
const aliasKeyDown = event => {
if (event.keyCode == keycodes.enter) {
event.preventDefault();
closeCurrentModal();
onInsert(sqlPreview);
}
};
</script>
<ModalBase {...$$restProps}>
<svelte:fragment slot="header">Insert join</svelte:fragment>
<div class="flex mb-3">
<div class="m-1">
<div class="m-1">Existing table</div>
<TableControl
rows={sources}
focusOnCreate
bind:selectedIndex={sourceIndex}
bind:domTable={domSource}
selectable
on:keydown={sourceKeyDown}
columns={[
{ fieldName: 'alias', header: 'Alias' },
{ fieldName: 'name', header: 'Name' },
]}
/>
</div>
<div class="m-1">
<div class="m-1">New table</div>
<TableControl
rows={targets}
bind:selectedIndex={targetIndex}
bind:domTable={domTarget}
selectable
on:keydown={targetKeyDown}
columns={[
{ fieldName: 'baseColumns', header: 'Column from' },
{ fieldName: 'refTable', header: 'Table to' },
{ fieldName: 'refColumns', header: 'Column to' },
]}
/>
</div>
<div class="m-1">
<div class="m-1">Join</div>
<TableControl
rows={JOIN_TYPES.map(name => ({ name }))}
bind:selectedIndex={joinIndex}
bind:domTable={domJoin}
selectable
on:keydown={joinKeyDown}
columns={[{ fieldName: 'name', header: 'Join type' }]}
/>
<div class="m-1">Alias</div>
<TextField
value={alias}
on:input={e => {
// @ts-ignore
alias = e.target.value;
}}
bind:domEditor={domAlias}
on:keydown={aliasKeyDown}
/>
</div>
</div>
<div class="sql">
<SqlEditor readOnly value={sqlPreview} {engine} />
</div>
<svelte:fragment slot="footer">
<FormStyledButton
value="OK"
onClick={() => {
closeCurrentModal();
onInsert(sqlPreview);
}}
/>
<FormStyledButton type="button" value="Close" onClick={closeCurrentModal} />
</svelte:fragment>
</ModalBase>
<style>
.sql {
position: relative;
height: 80px;
width: 40vw;
}
</style>

View File

@@ -10,6 +10,14 @@
testEnabled: () => getCurrentEditor() != null,
onClick: () => getCurrentEditor().formatCode(),
});
registerCommand({
id: 'query.insertSqlJoin',
category: 'Query',
name: 'Insert SQL Join',
keyText: 'Ctrl+J',
testEnabled: () => getCurrentEditor() != null,
onClick: () => getCurrentEditor().insertSqlJoin(),
});
registerFileCommands({
idPrefix: 'query',
category: 'Query',
@@ -25,7 +33,7 @@
</script>
<script lang="ts">
import { get_current_component } from 'svelte/internal';
import { get_current_component, insert } from 'svelte/internal';
import { getContext } from 'svelte';
import sqlFormatter from 'sql-formatter';
@@ -39,7 +47,7 @@
import applySqlTemplate from '../utility/applySqlTemplate';
import axiosInstance from '../utility/axiosInstance';
import { changeTab } from '../utility/common';
import { useConnectionInfo } from '../utility/metadataLoaders';
import { getDatabaseInfo, useConnectionInfo } from '../utility/metadataLoaders';
import socket from '../utility/socket';
import SocketMessageView from '../query/SocketMessageView.svelte';
import memberStore from '../utility/memberStore';
@@ -47,6 +55,8 @@
import ResultTabs from '../query/ResultTabs.svelte';
import { registerFileCommands } from '../commands/stdCommands';
import invalidateCommands from '../commands/invalidateCommands';
import { showModal } from '../modals/modalTools';
import InsertJoinModal from '../modals/InsertJoinModal.svelte';
export let tabid;
export let conid;
@@ -163,6 +173,19 @@
editor.clearSelection();
}
export async function insertSqlJoin() {
const dbinfo = await getDatabaseInfo({ conid, database });
showModal(InsertJoinModal, {
sql: getData(),
engine: $connection && $connection.engine,
dbinfo,
onInsert: text => {
const editor = domEditor.getEditor();
editor.session.insert(editor.getCursorPosition(), text);
},
});
}
const handleMesageClick = message => {
// console.log('EDITOR', editorRef.current.editor);
if (domEditor.getEditor()) {
@@ -190,6 +213,7 @@
{ divider: true },
{ command: 'query.toggleComment' },
{ command: 'query.formatCode' },
{ command: 'query.insertSqlJoin' },
{ divider: true },
{ command: 'query.save' },
{ command: 'query.saveAs' },