mirror of
https://github.com/dbgate/dbgate
synced 2024-11-07 20:26:23 +00:00
support blob values #211
This commit is contained in:
parent
1d52e02107
commit
7297976843
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
35
packages/web/src/celldata/PictureCellView.svelte
Normal file
35
packages/web/src/celldata/PictureCellView.svelte
Normal 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>
|
@ -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}
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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) => {
|
||||
|
@ -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>
|
||||
|
@ -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');
|
||||
}
|
||||
|
@ -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)}')`);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user