mongo query splitter, copy as mongo insert

This commit is contained in:
Jan Prochazka
2021-12-02 10:00:48 +01:00
parent 368993597c
commit 536897a84c
10 changed files with 67 additions and 14 deletions

View File

@@ -228,7 +228,7 @@ function changeSetInsertToSql(
const table = dbinfo.tables.find(x => x.schemaName == item.schemaName && x.pureName == item.pureName); const table = dbinfo.tables.find(x => x.schemaName == item.schemaName && x.pureName == item.pureName);
if (table) { if (table) {
const autoIncCol = table.columns.find(x => x.autoIncrement); const autoIncCol = table.columns.find(x => x.autoIncrement);
console.log('autoIncCol', autoIncCol); // console.log('autoIncCol', autoIncCol);
if (autoIncCol && fields.find(x => x.targetColumn == autoIncCol.columnName)) { if (autoIncCol && fields.find(x => x.targetColumn == autoIncCol.columnName)) {
autoInc = true; autoInc = true;
} }
@@ -375,7 +375,7 @@ export function getChangeSetInsertedRows(changeSet: ChangeSet, name?: NamedObjec
} }
export function changeSetInsertNewRow(changeSet: ChangeSet, name?: NamedObjectInfo): ChangeSet { export function changeSetInsertNewRow(changeSet: ChangeSet, name?: NamedObjectInfo): ChangeSet {
console.log('INSERT', name); // console.log('INSERT', name);
const insertedRows = getChangeSetInsertedRows(changeSet, name); const insertedRows = getChangeSetInsertedRows(changeSet, name);
return { return {
...changeSet, ...changeSet,

View File

@@ -89,10 +89,12 @@ export class CollectionGridDisplay extends GridDisplay {
setConfig: ChangeConfigFunc, setConfig: ChangeConfigFunc,
cache: GridCache, cache: GridCache,
setCache: ChangeCacheFunc, setCache: ChangeCacheFunc,
loadedRows loadedRows,
changeSet
) { ) {
super(config, setConfig, cache, setCache, driver); super(config, setConfig, cache, setCache, driver);
this.columns = analyseCollectionDisplayColumns(loadedRows, this); const changedDocs = _.compact([...changeSet.inserts, ...changeSet.updates].map(chs => chs.document));
this.columns = analyseCollectionDisplayColumns([...(loadedRows || []), ...changedDocs], this);
this.filterable = true; this.filterable = true;
this.sortable = true; this.sortable = true;
this.editable = true; this.editable = true;

View File

@@ -8,6 +8,9 @@ export interface SplitterOptions {
allowGoDelimiter: boolean; allowGoDelimiter: boolean;
allowDollarDollarString: boolean; allowDollarDollarString: boolean;
noSplit: boolean; noSplit: boolean;
doubleDashComments: boolean;
multilineComments: boolean;
javaScriptComments: boolean;
} }
export const defaultSplitterOptions: SplitterOptions = { export const defaultSplitterOptions: SplitterOptions = {
@@ -20,6 +23,10 @@ export const defaultSplitterOptions: SplitterOptions = {
allowGoDelimiter: false, allowGoDelimiter: false,
allowDollarDollarString: false, allowDollarDollarString: false,
noSplit: false, noSplit: false,
doubleDashComments: true,
multilineComments: true,
javaScriptComments: false,
}; };
export const mysqlSplitterOptions: SplitterOptions = { export const mysqlSplitterOptions: SplitterOptions = {
@@ -59,6 +66,14 @@ export const sqliteSplitterOptions: SplitterOptions = {
stringEscapes: { "'": "'", '"': '"' }, stringEscapes: { "'": "'", '"': '"' },
}; };
export const mongoSplitterOptions: SplitterOptions = {
...defaultSplitterOptions,
stringsBegins: ["'", '"'],
stringsEnds: { "'": "'", '"': '"' },
stringEscapes: { "'": '\\', '"': '\\' },
};
export const noSplitSplitterOptions: SplitterOptions = { export const noSplitSplitterOptions: SplitterOptions = {
...defaultSplitterOptions, ...defaultSplitterOptions,

View File

@@ -113,7 +113,7 @@ function scanToken(context: SplitLineContext): Token {
return EOLN_TOKEN; return EOLN_TOKEN;
} }
if (ch == '-' && s[pos + 1] == '-') { if (context.options.doubleDashComments && ch == '-' && s[pos + 1] == '-') {
while (pos < context.end && s[pos] != '\n') pos++; while (pos < context.end && s[pos] != '\n') pos++;
return { return {
type: 'comment', type: 'comment',
@@ -121,7 +121,7 @@ function scanToken(context: SplitLineContext): Token {
}; };
} }
if (ch == '/' && s[pos + 1] == '*') { if (context.options.multilineComments && ch == '/' && s[pos + 1] == '*') {
pos += 2; pos += 2;
while (pos < context.end) { while (pos < context.end) {
if (s[pos] == '*' && s[pos + 1] == '/') break; if (s[pos] == '*' && s[pos + 1] == '/') break;
@@ -222,7 +222,7 @@ export function splitQueryLine(context: SplitLineContext) {
} }
export function getInitialDelimiter(options: SplitterOptions) { export function getInitialDelimiter(options: SplitterOptions) {
return options?.allowSemicolon === false ? null : SEMICOLON return options?.allowSemicolon === false ? null : SEMICOLON;
} }
export function splitQuery(sql: string, options: SplitterOptions = null): string[] { export function splitQuery(sql: string, options: SplitterOptions = null): string[] {
const usedOptions = { const usedOptions = {

View File

@@ -1,4 +1,10 @@
import { mysqlSplitterOptions, mssqlSplitterOptions, postgreSplitterOptions, noSplitSplitterOptions } from './options'; import {
mysqlSplitterOptions,
mssqlSplitterOptions,
postgreSplitterOptions,
mongoSplitterOptions,
noSplitSplitterOptions,
} from './options';
import { splitQuery } from './splitQuery'; import { splitQuery } from './splitQuery';
test('simple query', () => { test('simple query', () => {
@@ -77,3 +83,9 @@ test('no split', () => {
const output = splitQuery(input, noSplitSplitterOptions); const output = splitQuery(input, noSplitSplitterOptions);
expect(output).toEqual(['SELECT 1;SELECT 2']); expect(output).toEqual(['SELECT 1;SELECT 2']);
}); });
test('split mongo', () => {
const input = 'db.collection.insert({x:1});db.collection.insert({y:2})';
const output = splitQuery(input, mongoSplitterOptions);
expect(output).toEqual(['db.collection.insert({x:1})', 'db.collection.insert({y:2})']);
});

View File

@@ -250,6 +250,7 @@
import { showModal } from '../modals/modalTools'; import { showModal } from '../modals/modalTools';
import { updateStatuBarInfo } from '../widgets/StatusBar.svelte'; import { updateStatuBarInfo } from '../widgets/StatusBar.svelte';
import StatusBarTabItem from '../widgets/StatusBarTabItem.svelte'; import StatusBarTabItem from '../widgets/StatusBarTabItem.svelte';
import { findCommand } from '../commands/runCommand';
export let onLoadNextData = undefined; export let onLoadNextData = undefined;
export let grider = undefined; export let grider = undefined;
@@ -265,6 +266,8 @@
export let focusOnVisible = false; export let focusOnVisible = false;
export let formViewAvailable = false; export let formViewAvailable = false;
export let errorMessage = undefined; export let errorMessage = undefined;
export let pureName = undefined;
export let schemaName = undefined;
export let isLoadedAll; export let isLoadedAll;
export let loadedTime; export let loadedTime;
@@ -379,8 +382,8 @@
// @ts-ignore // @ts-ignore
const columns = colIndexes.map(col => realColumnUniqueNames[col]); const columns = colIndexes.map(col => realColumnUniqueNames[col]);
copyRowsToClipboard(format, columns, rows, { copyRowsToClipboard(format, columns, rows, {
schemaName: display?.baseTable?.schemaName, schemaName,
pureName: display?.baseTable?.pureName || 'target', pureName: pureName || 'target',
driver: display?.driver || driverBase, driver: display?.driver || driverBase,
keyColumns: display?.baseTable?.primaryKey?.columns?.map(col => col.columnName) || [ keyColumns: display?.baseTable?.primaryKey?.columns?.map(col => col.columnName) || [
display?.columns ? display?.columns[0].columnName : columns[0], display?.columns ? display?.columns[0].columnName : columns[0],
@@ -1218,6 +1221,12 @@
{#if display.filterCount > 0} {#if display.filterCount > 0}
<FormStyledButton value="Reset filter" on:click={() => display.clearFilters()} /> <FormStyledButton value="Reset filter" on:click={() => display.clearFilters()} />
{/if} {/if}
<FormStyledButton
value="Add document"
on:click={() => {
findCommand('collectionTable.newJson')?.onClick();
}}
/>
</div> </div>
{:else if grider.errors && grider.errors.length > 0} {:else if grider.errors && grider.errors.length > 0}
<div> <div>

View File

@@ -29,7 +29,7 @@
</div> </div>
<div slot="footer"> <div slot="footer">
<FormSubmit <FormStyledButton
value="Save" value="Save"
on:click={() => { on:click={() => {
try { try {

View File

@@ -55,6 +55,7 @@
import { registerMenu } from '../utility/contextMenu'; import { registerMenu } from '../utility/contextMenu';
import EditJsonModal from '../modals/EditJsonModal.svelte'; import EditJsonModal from '../modals/EditJsonModal.svelte';
import ChangeSetGrider from '../datagrid/ChangeSetGrider'; import ChangeSetGrider from '../datagrid/ChangeSetGrider';
import { setContext } from 'svelte';
export let tabid; export let tabid;
export let conid; export let conid;
@@ -89,7 +90,8 @@
config.update, config.update,
$cache, $cache,
cache.update, cache.update,
loadedRows loadedRows,
$changeSetStore?.value
) )
: null; : null;
// $: console.log('LOADED ROWS MONGO', loadedRows); // $: console.log('LOADED ROWS MONGO', loadedRows);
@@ -145,6 +147,9 @@
} }
registerMenu({ command: 'collectionTable.save', tag: 'save' }, { command: 'collectionTable.newJson', tag: 'edit' }); registerMenu({ command: 'collectionTable.save', tag: 'save' }, { command: 'collectionTable.newJson', tag: 'edit' });
const collapsedLeftColumnStore = writable(false);
setContext('collapsedLeftColumnStore', collapsedLeftColumnStore);
</script> </script>
<DataGrid <DataGrid

View File

@@ -132,6 +132,11 @@ const clipboardUpdatesFormatter = () => (columns, rows, options) => {
return dmp.s; return dmp.s;
}; };
const clipboardMongoInsertFormatter = () => (columns, rows, options) => {
const { pureName } = options;
return rows.map(row => `db.${pureName}.insert(${JSON.stringify(_.pick(row, columns), undefined, 2)});`).join('\n');
};
export function formatClipboardRows(format, columns, rows, options) { export function formatClipboardRows(format, columns, rows, options) {
if (format in copyRowsFormatDefs) { if (format in copyRowsFormatDefs) {
return copyRowsFormatDefs[format].formatter(columns, rows, options); return copyRowsFormatDefs[format].formatter(columns, rows, options);
@@ -185,4 +190,9 @@ export const copyRowsFormatDefs = {
name: 'SQL UPDATEs', name: 'SQL UPDATEs',
formatter: clipboardUpdatesFormatter(), formatter: clipboardUpdatesFormatter(),
}, },
mongoInsert: {
label: 'Copy as Mongo INSERTs',
name: 'Mongo UPDATEs',
formatter: clipboardMongoInsertFormatter(),
},
}; };

View File

@@ -1,7 +1,7 @@
const _isString = require('lodash/isString'); const _isString = require('lodash/isString');
const { driverBase } = global.DBGATE_TOOLS; const { driverBase } = global.DBGATE_TOOLS;
const Dumper = require('./Dumper'); const Dumper = require('./Dumper');
const { noSplitSplitterOptions } = require('dbgate-query-splitter/lib/options'); const { mongoSplitterOptions } = require('dbgate-query-splitter/lib/options');
const mongoIdRegex = /^[0-9a-f]{24}$/; const mongoIdRegex = /^[0-9a-f]{24}$/;
@@ -36,7 +36,7 @@ const driver = {
supportsDatabaseUrl: true, supportsDatabaseUrl: true,
databaseUrlPlaceholder: 'e.g. mongodb://username:password@mongodb.mydomain.net/dbname', databaseUrlPlaceholder: 'e.g. mongodb://username:password@mongodb.mydomain.net/dbname',
getQuerySplitterOptions: () => noSplitSplitterOptions, getQuerySplitterOptions: () => mongoSplitterOptions,
showConnectionField: (field, values) => { showConnectionField: (field, values) => {
if (field == 'useDatabaseUrl') return true; if (field == 'useDatabaseUrl') return true;