support blob values #211

This commit is contained in:
Jan Prochazka 2022-02-03 14:29:46 +01:00
parent 1d52e02107
commit 7297976843
12 changed files with 112 additions and 42 deletions

View File

@ -22,6 +22,8 @@ import {
import _isString from 'lodash/isString'; import _isString from 'lodash/isString';
import _isNumber from 'lodash/isNumber'; import _isNumber from 'lodash/isNumber';
import _isDate from 'lodash/isDate'; import _isDate from 'lodash/isDate';
import _isArray from 'lodash/isArray';
import _isPlainObject from 'lodash/isPlainObject';
import uuidv1 from 'uuid/v1'; import uuidv1 from 'uuid/v1';
export class SqlDumper implements AlterProcessor { export class SqlDumper implements AlterProcessor {
@ -57,6 +59,9 @@ export class SqlDumper implements AlterProcessor {
this.putRaw(this.escapeString(value)); this.putRaw(this.escapeString(value));
this.putRaw("'"); this.putRaw("'");
} }
putByteArrayValue(value) {
this.putRaw('NULL');
}
putValue(value) { putValue(value) {
if (value === null) this.putRaw('NULL'); if (value === null) this.putRaw('NULL');
else if (value === true) this.putRaw('1'); else if (value === true) this.putRaw('1');
@ -64,6 +69,8 @@ export class SqlDumper implements AlterProcessor {
else if (_isString(value)) this.putStringValue(value); else if (_isString(value)) this.putStringValue(value);
else if (_isNumber(value)) this.putRaw(value.toString()); else if (_isNumber(value)) this.putRaw(value.toString());
else if (_isDate(value)) this.putStringValue(new Date(value).toISOString()); else if (_isDate(value)) this.putStringValue(new Date(value).toISOString());
else if (value?.type == 'Buffer' && _isArray(value?.data)) this.putByteArrayValue(value?.data);
else if (_isPlainObject(value) || _isArray(value)) this.putStringValue(JSON.stringify(value));
else this.putRaw('NULL'); else this.putRaw('NULL');
} }
putCmd(format, ...args) { putCmd(format, ...args) {

View File

@ -1,5 +1,9 @@
import _isString from 'lodash/isString';
import _isArray from 'lodash/isArray';
import _isPlainObject from 'lodash/isPlainObject';
export function arrayToHexString(byteArray) { export function arrayToHexString(byteArray) {
return byteArray.reduce((output, elem) => output + ('0' + elem.toString(16)).slice(-2), ''); return byteArray.reduce((output, elem) => output + ('0' + elem.toString(16)).slice(-2), '').toUpperCase();
} }
export function hexStringToArray(inputString) { export function hexStringToArray(inputString) {
@ -10,3 +14,33 @@ export function hexStringToArray(inputString) {
} }
return res; return res;
} }
export function parseCellValue(value) {
if (!_isString(value)) return value;
if (value == '(NULL)') return null;
const mHex = value.match(/^0x([0-9a-fA-F][0-9a-fA-F])+$/);
if (mHex) {
return {
type: 'Buffer',
data: hexStringToArray(value.substring(2)),
};
}
const mOid = value.match(/^ObjectId\("([0-9a-f]{24})"\)$/);
if (mOid) {
return { $oid: mOid[1] };
}
return value;
}
export function stringifyCellValue(value) {
if (value === null) return '(NULL)';
if (value === undefined) return '(NoField)';
if (value?.type == 'Buffer' && _isArray(value.data)) return '0x' + arrayToHexString(value.data);
if (value?.$oid) return `ObjectId("${value?.$oid}")`;
if (_isPlainObject(value) || _isArray(value)) return JSON.stringify(value);
return value;
}

View File

@ -0,0 +1,35 @@
<script lang="ts">
import _ from 'lodash';
import ErrorInfo from '../elements/ErrorInfo.svelte';
export let selection;
function extractPicture(values) {
const value = values;
if (value?.type == 'Buffer' && _.isArray(value?.data)) {
return 'data:image/png;base64, ' + btoa(String.fromCharCode.apply(null, value?.data));
}
return null;
}
$: picture = extractPicture(selection[0]?.value);
</script>
{#if picture}
<div class="wrapper">
<img src={picture} />
</div>
{:else}
<ErrorInfo message="Error showing picture" alignTop />
{/if}
<style>
.wrapper {
overflow: auto;
/* position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0; */
}
</style>

View File

@ -120,7 +120,7 @@
{/if} {/if}
{:else if value?.type == 'Buffer' && _.isArray(value.data)} {:else if value?.type == 'Buffer' && _.isArray(value.data)}
{#if value.data.length <= 16} {#if value.data.length <= 16}
<span class="value">{arrayToHexString(value.data)}</span> <span class="value">{'0x' + arrayToHexString(value.data)}</span>
{:else} {:else}
<span class="null">({value.data.length} bytes)</span> <span class="null">({value.data.length} bytes)</span>
{/if} {/if}

View File

@ -235,7 +235,7 @@
<script lang="ts"> <script lang="ts">
import { GridDisplay } from 'dbgate-datalib'; import { GridDisplay } from 'dbgate-datalib';
import { driverBase } from 'dbgate-tools'; import { driverBase, parseCellValue } from 'dbgate-tools';
import { getContext } from 'svelte'; import { getContext } from 'svelte';
import _ from 'lodash'; import _ from 'lodash';
import registerCommand from '../commands/registerCommand'; import registerCommand from '../commands/registerCommand';
@ -1176,7 +1176,7 @@
} }
let colIndex = startCol; let colIndex = startCol;
for (const cell of rowData) { for (const cell of rowData) {
setCellValue([rowIndex, colIndex], cell == '(NULL)' ? null : cell); setCellValue([rowIndex, colIndex], parseCellValue(cell));
colIndex += 1; colIndex += 1;
} }
rowIndex += 1; rowIndex += 1;

View File

@ -1,27 +1,10 @@
<script lang="ts" context="module"> <script lang="ts" context="module">
function getEditedValue(value) { function getEditedValue(value) {
if (value?.type == 'Buffer' && _.isArray(value.data)) return arrayToHexString(value.data); if (value?.type == 'Buffer' && _.isArray(value.data)) return '0x' + arrayToHexString(value.data);
if (value?.$oid) return `ObjectId("${value?.$oid}")`; if (value?.$oid) return `ObjectId("${value?.$oid}")`;
if (_.isPlainObject(value) || _.isArray(value)) return JSON.stringify(value); if (_.isPlainObject(value) || _.isArray(value)) return JSON.stringify(value);
return value; return value;
} }
function getStoredValue(originalValue, newString) {
if (originalValue?.type == 'Buffer' && _.isArray(originalValue?.data)) {
return {
type: 'Buffer',
data: hexStringToArray(newString),
};
}
if (_.isString(newString)) {
const m = newString.match(/ObjectId\("([0-9a-f]{24})"\)/);
if (m) {
return { $oid: m[1] };
}
}
return newString;
}
</script> </script>
<script lang="ts"> <script lang="ts">
@ -29,7 +12,7 @@
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import createRef from '../utility/createRef'; import createRef from '../utility/createRef';
import _ from 'lodash'; import _ from 'lodash';
import { arrayToHexString, hexStringToArray } from 'dbgate-tools'; import { arrayToHexString, parseCellValue, stringifyCellValue } from 'dbgate-tools';
export let inplaceEditorState; export let inplaceEditorState;
export let dispatchInsplaceEditor; export let dispatchInsplaceEditor;
@ -53,7 +36,7 @@
case keycodes.enter: case keycodes.enter:
if (isChangedRef.get()) { if (isChangedRef.get()) {
// grider.setCellValue(rowIndex, uniqueName, editor.value); // grider.setCellValue(rowIndex, uniqueName, editor.value);
onSetValue(getStoredValue(cellValue, domEditor.value)); onSetValue(parseCellValue(domEditor.value));
isChangedRef.set(false); isChangedRef.set(false);
} }
domEditor.blur(); domEditor.blur();
@ -62,7 +45,7 @@
case keycodes.s: case keycodes.s:
if (event.ctrlKey) { if (event.ctrlKey) {
if (isChangedRef.get()) { if (isChangedRef.get()) {
onSetValue(getStoredValue(cellValue, domEditor.value)); onSetValue(parseCellValue(domEditor.value));
// grider.setCellValue(rowIndex, uniqueName, editor.value); // grider.setCellValue(rowIndex, uniqueName, editor.value);
isChangedRef.set(false); isChangedRef.set(false);
} }
@ -75,7 +58,7 @@
function handleBlur() { function handleBlur() {
if (isChangedRef.get()) { if (isChangedRef.get()) {
onSetValue(getStoredValue(cellValue, domEditor.value)); onSetValue(parseCellValue(domEditor.value));
// grider.setCellValue(rowIndex, uniqueName, editor.value); // grider.setCellValue(rowIndex, uniqueName, editor.value);
isChangedRef.set(false); isChangedRef.set(false);
} }
@ -83,7 +66,7 @@
} }
onMount(() => { onMount(() => {
domEditor.value = inplaceEditorState.text || getEditedValue(cellValue); domEditor.value = inplaceEditorState.text || stringifyCellValue(cellValue);
domEditor.focus(); domEditor.focus();
if (inplaceEditorState.selectAll) { if (inplaceEditorState.selectAll) {
domEditor.select(); domEditor.select();

View File

@ -1,5 +1,5 @@
import _ from 'lodash'; import _ from 'lodash';
import { arrayToHexString } from 'dbgate-tools'; import { arrayToHexString, stringifyCellValue } from 'dbgate-tools';
import yaml from 'js-yaml'; import yaml from 'js-yaml';
export function copyTextToClipboard(text) { export function copyTextToClipboard(text) {
@ -69,12 +69,7 @@ export function copyTextToClipboard(text) {
export function extractRowCopiedValue(row, col) { export function extractRowCopiedValue(row, col) {
let value = row[col]; let value = row[col];
if (value === undefined) value = _.get(row, col); if (value === undefined) value = _.get(row, col);
if (value === null) return '(NULL)'; return stringifyCellValue(value);
if (value === undefined) return '(NoField)';
if (value && value.$oid) return `ObjectId("${value.$oid}")`;
if (value && value.type == 'Buffer' && _.isArray(value.data)) return arrayToHexString(value.data);
if (_.isPlainObject(value) || _.isArray(value)) return JSON.stringify(value);
return value;
} }
const clipboardTextFormatter = (delimiter, headers) => (columns, rows) => { const clipboardTextFormatter = (delimiter, headers) => (columns, rows) => {

View File

@ -24,6 +24,12 @@
component: JsonRowView, component: JsonRowView,
single: false, single: false,
}, },
{
type: 'picture',
title: 'Picture',
component: PictureCellView,
single: true,
},
]; ];
function autodetect(selection) { function autodetect(selection) {
@ -51,6 +57,7 @@
import JsonCellView from '../celldata/JsonCellView.svelte'; import JsonCellView from '../celldata/JsonCellView.svelte';
import JsonRowView from '../celldata/JsonRowView.svelte'; import JsonRowView from '../celldata/JsonRowView.svelte';
import PictureCellView from '../celldata/PictureCellView.svelte';
import TextCellViewNoWrap from '../celldata/TextCellViewNoWrap.svelte'; import TextCellViewNoWrap from '../celldata/TextCellViewNoWrap.svelte';
import TextCellViewWrap from '../celldata/TextCellViewWrap.svelte'; import TextCellViewWrap from '../celldata/TextCellViewWrap.svelte';
import ErrorInfo from '../elements/ErrorInfo.svelte'; import ErrorInfo from '../elements/ErrorInfo.svelte';
@ -124,5 +131,6 @@
.data { .data {
display: flex; display: flex;
flex: 1; flex: 1;
position: relative;
} }
</style> </style>

View File

@ -1,4 +1,4 @@
const { SqlDumper, testEqualColumns } = global.DBGATE_TOOLS; const { SqlDumper, testEqualColumns, arrayToHexString } = global.DBGATE_TOOLS;
class MsSqlDumper extends SqlDumper { class MsSqlDumper extends SqlDumper {
constructor(driver, options) { constructor(driver, options) {
@ -27,6 +27,10 @@ class MsSqlDumper extends SqlDumper {
super.putStringValue(value); super.putStringValue(value);
} }
putByteArrayValue(value) {
super.putRaw('0x' + arrayToHexString(value));
}
allowIdentityInsert(table, allow) { allowIdentityInsert(table, allow) {
this.putCmd('^set ^identity_insert %f %k', table, allow ? 'on' : 'off'); this.putCmd('^set ^identity_insert %f %k', table, allow ? 'on' : 'off');
} }

View File

@ -65,12 +65,8 @@ class Dumper extends SqlDumper {
this.putCmd('^create ^table %f (^select * ^from %f)', targetName, sourceName); this.putCmd('^create ^table %f (^select * ^from %f)', targetName, sourceName);
} }
putValue(value) { putByteArrayValue(value) {
if (value && value.type == 'Buffer' && _isArray(value.data)) { this.putRaw(`unhex('${arrayToHexString(value)}')`);
this.putRaw(`unhex('${arrayToHexString(value.data)}')`);
} else {
super.putValue(value);
}
} }
} }

View File

@ -92,6 +92,10 @@ class Dumper extends SqlDumper {
else if (value === false) this.putRaw('false'); else if (value === false) this.putRaw('false');
else super.putValue(value); else super.putValue(value);
} }
putByteArrayValue(value) {
this.putRaw(`e'\\\\x${arrayToHexString(value)}'`);
}
} }
module.exports = Dumper; module.exports = Dumper;

View File

@ -8,6 +8,10 @@ class Dumper extends SqlDumper {
renameTable(obj, newname) { renameTable(obj, newname) {
this.putCmd('^alter ^table %f ^rename ^to %i', obj, newname); this.putCmd('^alter ^table %f ^rename ^to %i', obj, newname);
} }
putByteArrayValue(value) {
this.putRaw(`x'${arrayToHexString(value)}'`);
}
} }
module.exports = Dumper; module.exports = Dumper;