mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-17 22:36:01 +00:00
bigint support #1087
This commit is contained in:
@@ -12,6 +12,7 @@ const {
|
||||
ScriptWriterEval,
|
||||
SqlGenerator,
|
||||
playJsonScriptWriter,
|
||||
serializeJsTypesForJsonStringify,
|
||||
} = require('dbgate-tools');
|
||||
const requireEngineDriver = require('../utility/requireEngineDriver');
|
||||
const { connectUtility } = require('../utility/connectUtility');
|
||||
@@ -232,7 +233,7 @@ async function handleQueryData({ msgid, sql, range }, skipReadonlyCheck = false)
|
||||
try {
|
||||
if (!skipReadonlyCheck) ensureExecuteCustomScript(driver);
|
||||
const res = await driver.query(dbhan, sql, { range });
|
||||
process.send({ msgtype: 'response', msgid, ...res });
|
||||
process.send({ msgtype: 'response', msgid, ...serializeJsTypesForJsonStringify(res) });
|
||||
} catch (err) {
|
||||
process.send({
|
||||
msgtype: 'response',
|
||||
|
||||
@@ -4,6 +4,7 @@ const fs = require('fs');
|
||||
const _ = require('lodash');
|
||||
|
||||
const { jsldir } = require('../utility/directories');
|
||||
const { serializeJsTypesReplacer } = require('dbgate-tools');
|
||||
|
||||
class QueryStreamTableWriter {
|
||||
constructor(sesid = undefined) {
|
||||
@@ -38,7 +39,7 @@ class QueryStreamTableWriter {
|
||||
|
||||
row(row) {
|
||||
// console.log('ACCEPT ROW', row);
|
||||
this.currentStream.write(JSON.stringify(row) + '\n');
|
||||
this.currentStream.write(JSON.stringify(row, serializeJsTypesReplacer) + '\n');
|
||||
this.currentRowCount += 1;
|
||||
|
||||
if (!this.plannedStats) {
|
||||
|
||||
@@ -20,6 +20,7 @@ export function getFilterValueExpression(value, dataType?) {
|
||||
if (value === true) return 'TRUE';
|
||||
if (value === false) return 'FALSE';
|
||||
if (value.$oid) return `ObjectId("${value.$oid}")`;
|
||||
if (value.$bigint) return value.$bigint;
|
||||
if (value.type == 'Buffer' && Array.isArray(value.data)) {
|
||||
return '0x' + arrayToHexString(value.data);
|
||||
}
|
||||
|
||||
@@ -2,14 +2,18 @@ import P from 'parsimmon';
|
||||
import moment from 'moment';
|
||||
import { Condition } from 'dbgate-sqltree';
|
||||
import { interpretEscapes, token, word, whitespace } from './common';
|
||||
import { hexStringToArray } from 'dbgate-tools';
|
||||
import { hexStringToArray, parseNumberSafe } from 'dbgate-tools';
|
||||
import { FilterBehaviour, TransformType } from 'dbgate-types';
|
||||
|
||||
const binaryCondition =
|
||||
(operator, numberDualTesting = false) =>
|
||||
value => {
|
||||
const numValue = parseFloat(value);
|
||||
if (numberDualTesting && !isNaN(numValue)) {
|
||||
const numValue = parseNumberSafe(value);
|
||||
if (
|
||||
numberDualTesting &&
|
||||
// @ts-ignore
|
||||
!isNaN(numValue)
|
||||
) {
|
||||
return {
|
||||
conditionType: 'or',
|
||||
conditions: [
|
||||
@@ -345,17 +349,17 @@ const createParser = (filterBehaviour: FilterBehaviour) => {
|
||||
|
||||
string1Num: () =>
|
||||
token(P.regexp(/"-?(0|[1-9][0-9]*)([.][0-9]+)?([eE][+-]?[0-9]+)?"/, 1))
|
||||
.map(Number)
|
||||
.map(parseNumberSafe)
|
||||
.desc('numer quoted'),
|
||||
|
||||
string2Num: () =>
|
||||
token(P.regexp(/'-?(0|[1-9][0-9]*)([.][0-9]+)?([eE][+-]?[0-9]+)?'/, 1))
|
||||
.map(Number)
|
||||
.map(parseNumberSafe)
|
||||
.desc('numer quoted'),
|
||||
|
||||
number: () =>
|
||||
token(P.regexp(/-?(0|[1-9][0-9]*)([.][0-9]+)?([eE][+-]?[0-9]+)?/))
|
||||
.map(Number)
|
||||
.map(parseNumberSafe)
|
||||
.desc('number'),
|
||||
|
||||
objectid: () => token(P.regexp(/ObjectId\(['"]?[0-9a-f]{24}['"]?\)/)).desc('ObjectId'),
|
||||
|
||||
@@ -16,11 +16,17 @@ function isLike(value, test) {
|
||||
return res;
|
||||
}
|
||||
|
||||
function extractRawValue(value) {
|
||||
if (value?.$bigint) return value.$bigint;
|
||||
if (value?.$oid) return value.$oid;
|
||||
return value;
|
||||
}
|
||||
|
||||
export function evaluateCondition(condition: Condition, values) {
|
||||
switch (condition.conditionType) {
|
||||
case 'binary':
|
||||
const left = evaluateExpression(condition.left, values);
|
||||
const right = evaluateExpression(condition.right, values);
|
||||
const left = extractRawValue(evaluateExpression(condition.left, values));
|
||||
const right = extractRawValue(evaluateExpression(condition.right, values));
|
||||
switch (condition.operator) {
|
||||
case '=':
|
||||
return left == right;
|
||||
@@ -50,10 +56,15 @@ export function evaluateCondition(condition: Condition, values) {
|
||||
case 'or':
|
||||
return condition.conditions.some(cond => evaluateCondition(cond, values));
|
||||
case 'like':
|
||||
return isLike(evaluateExpression(condition.left, values), evaluateExpression(condition.right, values));
|
||||
break;
|
||||
return isLike(
|
||||
extractRawValue(evaluateExpression(condition.left, values)),
|
||||
extractRawValue(evaluateExpression(condition.right, values))
|
||||
);
|
||||
case 'notLike':
|
||||
return !isLike(evaluateExpression(condition.left, values), evaluateExpression(condition.right, values));
|
||||
return !isLike(
|
||||
extractRawValue(evaluateExpression(condition.left, values)),
|
||||
extractRawValue(evaluateExpression(condition.right, values))
|
||||
);
|
||||
case 'not':
|
||||
return !evaluateCondition(condition.condition, values);
|
||||
case 'anyColumnPass':
|
||||
|
||||
@@ -78,6 +78,7 @@ export class SqlDumper implements AlterProcessor {
|
||||
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 (value?.$bigint) this.putRaw(value?.$bigint);
|
||||
else if (_isPlainObject(value) || _isArray(value)) this.putStringValue(JSON.stringify(value));
|
||||
else this.put('^null');
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import _isDate from 'lodash/isDate';
|
||||
import _isNumber from 'lodash/isNumber';
|
||||
import _isPlainObject from 'lodash/isPlainObject';
|
||||
import _pad from 'lodash/pad';
|
||||
import _cloneDeepWith from 'lodash/cloneDeepWith';
|
||||
import { DataEditorTypesBehaviour } from 'dbgate-types';
|
||||
|
||||
export type EditorDataType =
|
||||
@@ -208,6 +209,12 @@ export function stringifyCellValue(
|
||||
}
|
||||
}
|
||||
}
|
||||
if (value?.$bigint) {
|
||||
return {
|
||||
value: value.$bigint,
|
||||
gridStyle: 'valueCellStyle',
|
||||
};
|
||||
}
|
||||
|
||||
if (editorTypes?.parseDateAsDollar) {
|
||||
if (value?.$date) {
|
||||
@@ -343,6 +350,9 @@ export function shouldOpenMultilineDialog(value) {
|
||||
if (value?.$date) {
|
||||
return false;
|
||||
}
|
||||
if (value?.$bigint) {
|
||||
return false;
|
||||
}
|
||||
if (_isPlainObject(value) || _isArray(value)) {
|
||||
return true;
|
||||
}
|
||||
@@ -573,3 +583,44 @@ export function jsonLinesParse(jsonLines: string): any[] {
|
||||
})
|
||||
.filter(x => x);
|
||||
}
|
||||
|
||||
export function serializeJsTypesForJsonStringify(obj) {
|
||||
return _cloneDeepWith(obj, value => {
|
||||
if (typeof value === 'bigint') {
|
||||
return { $bigint: value.toString() };
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function deserializeJsTypesFromJsonParse(obj) {
|
||||
return _cloneDeepWith(obj, value => {
|
||||
if (value?.$bigint) {
|
||||
return BigInt(value.$bigint);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function serializeJsTypesReplacer(key, value) {
|
||||
if (typeof value === 'bigint') {
|
||||
return { $bigint: value.toString() };
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
export function deserializeJsTypesReviver(key, value) {
|
||||
if (value?.$bigint) {
|
||||
return BigInt(value.$bigint);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
export function parseNumberSafe(value) {
|
||||
if (/^-?[0-9]+$/.test(value)) {
|
||||
const parsed = parseInt(value);
|
||||
if (Number.isSafeInteger(parsed)) {
|
||||
return parsed;
|
||||
}
|
||||
return BigInt(value);
|
||||
}
|
||||
return parseFloat(value);
|
||||
}
|
||||
|
||||
@@ -54,7 +54,8 @@
|
||||
|
||||
$: style = computeStyle(maxWidth, col);
|
||||
|
||||
$: isJson = _.isPlainObject(value) && !(value?.type == 'Buffer' && _.isArray(value.data)) && !value.$oid;
|
||||
$: isJson =
|
||||
_.isPlainObject(value) && !(value?.type == 'Buffer' && _.isArray(value.data)) && !value.$oid && !value.$bigint;
|
||||
|
||||
// don't parse JSON for explicit data types
|
||||
$: jsonParsedValue = !editorTypes?.explicitDataType && isJsonLikeLongString(value) ? safeJsonParse(value) : null;
|
||||
|
||||
@@ -72,6 +72,7 @@ export function countColumnSizes(grider: Grider, columns, containerWidth, displa
|
||||
let text = value;
|
||||
if (_.isArray(value)) text = `[${value.length} items]`;
|
||||
else if (value?.$oid) text = `ObjectId("${value.$oid}")`;
|
||||
else if (value?.$bigint) text = value.$bigint;
|
||||
else if (isJsonLikeLongString(value) && safeJsonParse(value)) text = '(JSON)';
|
||||
const width = context.measureText(text).width + 8;
|
||||
// console.log('colName', colName, text, width);
|
||||
|
||||
@@ -13,6 +13,7 @@ import { callServerPing } from './connectionsPinger';
|
||||
import { batchDispatchCacheTriggers, dispatchCacheChange } from './cache';
|
||||
import { isAdminPage, isOneOfPage } from './pageDefs';
|
||||
import { openWebLink } from './simpleTools';
|
||||
import { serializeJsTypesReplacer } from 'dbgate-tools';
|
||||
|
||||
export const strmid = uuidv1();
|
||||
|
||||
@@ -177,7 +178,7 @@ export async function apiCall(
|
||||
'Content-Type': 'application/json',
|
||||
...resolveApiHeaders(),
|
||||
},
|
||||
body: JSON.stringify(args),
|
||||
body: JSON.stringify(args, serializeJsTypesReplacer),
|
||||
});
|
||||
|
||||
if (resp.status == 401 && !apiDisabled) {
|
||||
|
||||
@@ -21,6 +21,11 @@ const logger = getLogger('postreDriver');
|
||||
pg.types.setTypeParser(1082, 'text', val => val); // date
|
||||
pg.types.setTypeParser(1114, 'text', val => val); // timestamp without timezone
|
||||
pg.types.setTypeParser(1184, 'text', val => val); // timestamp
|
||||
pg.types.setTypeParser(20, 'text', val => {
|
||||
const parsed = parseInt(val);
|
||||
if (Number.isSafeInteger(parsed)) return parsed;
|
||||
return BigInt(val);
|
||||
}); // timestamp
|
||||
|
||||
function extractGeographyDate(value) {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user