mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-22 14:36:01 +00:00
#176 generate SQL from data
This commit is contained in:
@@ -143,6 +143,15 @@
|
|||||||
onClick: () => getCurrentDataGrid().clearFilter(),
|
onClick: () => getCurrentDataGrid().clearFilter(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
registerCommand({
|
||||||
|
id: 'dataGrid.generateSqlFromData',
|
||||||
|
category: 'Data grid',
|
||||||
|
name: 'Generate SQL',
|
||||||
|
keyText: 'Ctrl+G',
|
||||||
|
testEnabled: () => getCurrentDataGrid()?.generateSqlFromDataEnabled(),
|
||||||
|
onClick: () => getCurrentDataGrid().generateSqlFromData(),
|
||||||
|
});
|
||||||
|
|
||||||
registerCommand({
|
registerCommand({
|
||||||
id: 'dataGrid.openFreeTable',
|
id: 'dataGrid.openFreeTable',
|
||||||
category: 'Data grid',
|
category: 'Data grid',
|
||||||
@@ -233,6 +242,8 @@
|
|||||||
import { editJsonRowDocument } from '../jsonview/CollectionJsonRow.svelte';
|
import { editJsonRowDocument } from '../jsonview/CollectionJsonRow.svelte';
|
||||||
import createActivator, { getActiveComponent } from '../utility/createActivator';
|
import createActivator, { getActiveComponent } from '../utility/createActivator';
|
||||||
import CollapseButton from './CollapseButton.svelte';
|
import CollapseButton from './CollapseButton.svelte';
|
||||||
|
import GenerateSqlFromDataModal from '../modals/GenerateSqlFromDataModal.svelte';
|
||||||
|
import { showModal } from '../modals/modalTools';
|
||||||
|
|
||||||
export let onLoadNextData = undefined;
|
export let onLoadNextData = undefined;
|
||||||
export let grider = undefined;
|
export let grider = undefined;
|
||||||
@@ -528,6 +539,26 @@
|
|||||||
// selectedCells = [currentCell];
|
// selectedCells = [currentCell];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function generateSqlFromDataEnabled() {
|
||||||
|
return !!display?.baseTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function generateSqlFromData() {
|
||||||
|
const columnIndexes = _.uniq(selectedCells.map(x => x[1]));
|
||||||
|
columnIndexes.sort();
|
||||||
|
|
||||||
|
showModal(GenerateSqlFromDataModal, {
|
||||||
|
rows: getSelectedRowData(),
|
||||||
|
allColumns: display.baseTable.columns.map(x => x.columnName),
|
||||||
|
selectedColumns: columnIndexes.map(x => realColumnUniqueNames[x]),
|
||||||
|
keyColumns: display?.baseTable?.primaryKey?.columns?.map(x => x.columnName) || [
|
||||||
|
display.baseTable.columns[0].columnName,
|
||||||
|
],
|
||||||
|
engineDriver: display?.driver,
|
||||||
|
tableInfo: display.baseTable,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
$: autofillMarkerCell =
|
$: autofillMarkerCell =
|
||||||
selectedCells && selectedCells.length > 0 && _.uniq(selectedCells.map(x => x[0])).length == 1
|
selectedCells && selectedCells.length > 0 && _.uniq(selectedCells.map(x => x[0])).length == 1
|
||||||
? [_.max(selectedCells.map(x => x[0])), _.max(selectedCells.map(x => x[1]))]
|
? [_.max(selectedCells.map(x => x[0])), _.max(selectedCells.map(x => x[1]))]
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
import { getFormContext } from './FormProviderCore.svelte';
|
import { getFormContext } from './FormProviderCore.svelte';
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
|
|
||||||
export let disabled;
|
export let disabled = false;
|
||||||
|
|
||||||
const dispatch = createEventDispatcher();
|
const dispatch = createEventDispatcher();
|
||||||
|
|
||||||
|
|||||||
153
packages/web/src/modals/GenerateSqlFromDataModal.svelte
Normal file
153
packages/web/src/modals/GenerateSqlFromDataModal.svelte
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import FormStyledButton from '../elements/FormStyledButton.svelte';
|
||||||
|
import TableControl from '../elements/TableControl.svelte';
|
||||||
|
import FormProvider from '../forms/FormProvider.svelte';
|
||||||
|
import FormSubmit from '../forms/FormSubmit.svelte';
|
||||||
|
import TextField from '../forms/TextField.svelte';
|
||||||
|
import analyseQuerySources from '../query/analyseQuerySources';
|
||||||
|
import newQuery from '../query/newQuery';
|
||||||
|
import SqlEditor from '../query/SqlEditor.svelte';
|
||||||
|
import keycodes from '../utility/keycodes';
|
||||||
|
|
||||||
|
import ModalBase from './ModalBase.svelte';
|
||||||
|
import { closeCurrentModal } from './modalTools';
|
||||||
|
|
||||||
|
export let rows;
|
||||||
|
export let allColumns = [];
|
||||||
|
export let selectedColumns = [];
|
||||||
|
export let keyColumns = [];
|
||||||
|
export let tableInfo;
|
||||||
|
export let engineDriver;
|
||||||
|
|
||||||
|
let queryTypeIndex = 0;
|
||||||
|
let domQueryType = null;
|
||||||
|
|
||||||
|
let valueColumns = selectedColumns.filter(x => allColumns.includes(x));
|
||||||
|
let whereColumns = keyColumns.filter(x => allColumns.includes(x));
|
||||||
|
|
||||||
|
const QUERY_TYPES = ['INSERT', 'UPDATE', 'DELETE'];
|
||||||
|
|
||||||
|
$: sqlPreview = computePreview(rows, valueColumns, whereColumns, queryTypeIndex);
|
||||||
|
|
||||||
|
function computePreview(rows, valueColumns, whereColumns, queryTypeIndex) {
|
||||||
|
const queryType = QUERY_TYPES[queryTypeIndex];
|
||||||
|
|
||||||
|
const dmp = engineDriver.createDumper();
|
||||||
|
|
||||||
|
function putCondition(row) {
|
||||||
|
dmp.putCollection(' ^and ', whereColumns, col =>
|
||||||
|
row[col] == null ? dmp.put('%i ^is ^null', col) : dmp.put('%i=%v', col, row[col])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (queryType) {
|
||||||
|
case 'INSERT':
|
||||||
|
for (const row of rows) {
|
||||||
|
dmp.putCmd(
|
||||||
|
'^insert ^into %f (%,i) ^values (%,v)',
|
||||||
|
tableInfo,
|
||||||
|
valueColumns,
|
||||||
|
valueColumns.map(col => row[col])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'UPDATE':
|
||||||
|
for (const row of rows) {
|
||||||
|
dmp.put('^update %f ^set', tableInfo);
|
||||||
|
dmp.putCollection(', ', valueColumns, col => dmp.put('%i=%v', col, row[col]));
|
||||||
|
dmp.put(' ^where ');
|
||||||
|
putCondition(row);
|
||||||
|
dmp.endCommand();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'DELETE':
|
||||||
|
for (const row of rows) {
|
||||||
|
dmp.put('^delete ^from %f ^where ', tableInfo);
|
||||||
|
putCondition(row);
|
||||||
|
dmp.endCommand();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return dmp.s;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<FormProvider>
|
||||||
|
<ModalBase {...$$restProps}>
|
||||||
|
<svelte:fragment slot="header">Generate SQL from data</svelte:fragment>
|
||||||
|
|
||||||
|
<div class="flex mb-3">
|
||||||
|
<div class="m-1 col-4">
|
||||||
|
<div class="m-1">Choose query type</div>
|
||||||
|
|
||||||
|
<TableControl
|
||||||
|
rows={QUERY_TYPES.map(name => ({ name }))}
|
||||||
|
bind:selectedIndex={queryTypeIndex}
|
||||||
|
bind:domTable={domQueryType}
|
||||||
|
focusOnCreate
|
||||||
|
selectable
|
||||||
|
columns={[{ fieldName: 'name', header: 'Query type' }]}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="m-1 col-4">
|
||||||
|
<div class="m-1">Value columns</div>
|
||||||
|
|
||||||
|
{#each allColumns as column}
|
||||||
|
<div>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={valueColumns.includes(column)}
|
||||||
|
on:change={() => {
|
||||||
|
if (valueColumns.includes(column)) valueColumns = valueColumns.filter(x => x != column);
|
||||||
|
else valueColumns = [...valueColumns, column];
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{column}
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="m-1 col-4">
|
||||||
|
<div class="m-1">WHERE columns</div>
|
||||||
|
|
||||||
|
{#each allColumns as column}
|
||||||
|
<div>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={whereColumns.includes(column)}
|
||||||
|
on:change={() => {
|
||||||
|
if (whereColumns.includes(column)) whereColumns = whereColumns.filter(x => x != column);
|
||||||
|
else whereColumns = [...whereColumns, column];
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{column}
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="sql">
|
||||||
|
<SqlEditor readOnly value={sqlPreview} engine={engineDriver?.engine} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<svelte:fragment slot="footer">
|
||||||
|
<FormSubmit
|
||||||
|
value="OK"
|
||||||
|
on:click={() => {
|
||||||
|
newQuery({ initialData: sqlPreview });
|
||||||
|
closeCurrentModal();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<FormStyledButton type="button" value="Close" on:click={closeCurrentModal} />
|
||||||
|
</svelte:fragment>
|
||||||
|
</ModalBase>
|
||||||
|
</FormProvider>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.sql {
|
||||||
|
position: relative;
|
||||||
|
height: 30vh;
|
||||||
|
width: 40vw;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -104,7 +104,7 @@
|
|||||||
<svelte:fragment slot="header">Insert join</svelte:fragment>
|
<svelte:fragment slot="header">Insert join</svelte:fragment>
|
||||||
|
|
||||||
<div class="flex mb-3">
|
<div class="flex mb-3">
|
||||||
<div class="m-1">
|
<div class="m-1 col-3">
|
||||||
<div class="m-1">Existing table</div>
|
<div class="m-1">Existing table</div>
|
||||||
|
|
||||||
<TableControl
|
<TableControl
|
||||||
@@ -121,7 +121,7 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="m-1">
|
<div class="m-1 col-6">
|
||||||
<div class="m-1">New table</div>
|
<div class="m-1">New table</div>
|
||||||
|
|
||||||
<TableControl
|
<TableControl
|
||||||
@@ -138,7 +138,7 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="m-1">
|
<div class="m-1 col-3">
|
||||||
<div class="m-1">Join</div>
|
<div class="m-1">Join</div>
|
||||||
|
|
||||||
<TableControl
|
<TableControl
|
||||||
|
|||||||
@@ -12,10 +12,10 @@
|
|||||||
import useEffect from '../utility/useEffect';
|
import useEffect from '../utility/useEffect';
|
||||||
import { getContext } from 'svelte';
|
import { getContext } from 'svelte';
|
||||||
import { mountCodeCompletion } from './codeCompletion';
|
import { mountCodeCompletion } from './codeCompletion';
|
||||||
export let engine;
|
export let engine = null;
|
||||||
export let conid;
|
export let conid = null;
|
||||||
export let database;
|
export let database = null;
|
||||||
export let readOnly;
|
export let readOnly = false;
|
||||||
|
|
||||||
let domEditor;
|
let domEditor;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user