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 _isNumber from 'lodash/isNumber';
import _isDate from 'lodash/isDate';
import _isArray from 'lodash/isArray';
import _isPlainObject from 'lodash/isPlainObject';
import uuidv1 from 'uuid/v1';
export class SqlDumper implements AlterProcessor {
@ -57,6 +59,9 @@ export class SqlDumper implements AlterProcessor {
this.putRaw(this.escapeString(value));
this.putRaw("'");
}
putByteArrayValue(value) {
this.putRaw('NULL');
}
putValue(value) {
if (value === null) this.putRaw('NULL');
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 (_isNumber(value)) this.putRaw(value.toString());
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');
}
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) {
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) {
@ -10,3 +14,33 @@ export function hexStringToArray(inputString) {
}
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}
{:else if value?.type == 'Buffer' && _.isArray(value.data)}
{#if value.data.length <= 16}
<span class="value">{arrayToHexString(value.data)}</span>
<span class="value">{'0x' + arrayToHexString(value.data)}</span>
{:else}
<span class="null">({value.data.length} bytes)</span>
{/if}

View File

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

View File

@ -1,27 +1,10 @@
<script lang="ts" context="module">
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 (_.isPlainObject(value) || _.isArray(value)) return JSON.stringify(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 lang="ts">
@ -29,7 +12,7 @@
import { onMount } from 'svelte';
import createRef from '../utility/createRef';
import _ from 'lodash';
import { arrayToHexString, hexStringToArray } from 'dbgate-tools';
import { arrayToHexString, parseCellValue, stringifyCellValue } from 'dbgate-tools';
export let inplaceEditorState;
export let dispatchInsplaceEditor;
@ -53,7 +36,7 @@
case keycodes.enter:
if (isChangedRef.get()) {
// grider.setCellValue(rowIndex, uniqueName, editor.value);
onSetValue(getStoredValue(cellValue, domEditor.value));
onSetValue(parseCellValue(domEditor.value));
isChangedRef.set(false);
}
domEditor.blur();
@ -62,7 +45,7 @@
case keycodes.s:
if (event.ctrlKey) {
if (isChangedRef.get()) {
onSetValue(getStoredValue(cellValue, domEditor.value));
onSetValue(parseCellValue(domEditor.value));
// grider.setCellValue(rowIndex, uniqueName, editor.value);
isChangedRef.set(false);
}
@ -75,7 +58,7 @@
function handleBlur() {
if (isChangedRef.get()) {
onSetValue(getStoredValue(cellValue, domEditor.value));
onSetValue(parseCellValue(domEditor.value));
// grider.setCellValue(rowIndex, uniqueName, editor.value);
isChangedRef.set(false);
}
@ -83,7 +66,7 @@
}
onMount(() => {
domEditor.value = inplaceEditorState.text || getEditedValue(cellValue);
domEditor.value = inplaceEditorState.text || stringifyCellValue(cellValue);
domEditor.focus();
if (inplaceEditorState.selectAll) {
domEditor.select();

View File

@ -1,5 +1,5 @@
import _ from 'lodash';
import { arrayToHexString } from 'dbgate-tools';
import { arrayToHexString, stringifyCellValue } from 'dbgate-tools';
import yaml from 'js-yaml';
export function copyTextToClipboard(text) {
@ -69,12 +69,7 @@ export function copyTextToClipboard(text) {
export function extractRowCopiedValue(row, col) {
let value = row[col];
if (value === undefined) value = _.get(row, col);
if (value === null) return '(NULL)';
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;
return stringifyCellValue(value);
}
const clipboardTextFormatter = (delimiter, headers) => (columns, rows) => {

View File

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

View File

@ -1,4 +1,4 @@
const { SqlDumper, testEqualColumns } = global.DBGATE_TOOLS;
const { SqlDumper, testEqualColumns, arrayToHexString } = global.DBGATE_TOOLS;
class MsSqlDumper extends SqlDumper {
constructor(driver, options) {
@ -27,6 +27,10 @@ class MsSqlDumper extends SqlDumper {
super.putStringValue(value);
}
putByteArrayValue(value) {
super.putRaw('0x' + arrayToHexString(value));
}
allowIdentityInsert(table, allow) {
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);
}
putValue(value) {
if (value && value.type == 'Buffer' && _isArray(value.data)) {
this.putRaw(`unhex('${arrayToHexString(value.data)}')`);
} else {
super.putValue(value);
}
putByteArrayValue(value) {
this.putRaw(`unhex('${arrayToHexString(value)}')`);
}
}

View File

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

View File

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