refactor WIP

This commit is contained in:
Jan Prochazka
2024-08-19 10:23:02 +02:00
parent b30286cd11
commit d0fa565704
9 changed files with 81 additions and 45 deletions

View File

@@ -0,0 +1,12 @@
import { isTypeNumber, isTypeString, isTypeLogical, isTypeDateTime } from 'dbgate-tools';
import { StructuredFilterType } from 'dbgate-types';
import { DatetimeFilterType, LogicalFilterType, NumberFilterType, StringFilterType } from './filterTypes';
export function detectSqlFilterType(dataType: string): StructuredFilterType {
if (!dataType) return StringFilterType;
if (isTypeNumber(dataType)) return NumberFilterType;
if (isTypeString(dataType)) return StringFilterType;
if (isTypeLogical(dataType)) return LogicalFilterType;
if (isTypeDateTime(dataType)) return DatetimeFilterType;
return StringFilterType;
}

View File

@@ -6,6 +6,8 @@ export const NumberFilterType: StructuredFilterType = {
supportNumberLikeComparison: true, supportNumberLikeComparison: true,
supportNullTesting: true, supportNullTesting: true,
supportSqlCondition: true, supportSqlCondition: true,
allowNumberToken: true,
}; };
export const StringFilterType: StructuredFilterType = { export const StringFilterType: StructuredFilterType = {
@@ -16,6 +18,9 @@ export const StringFilterType: StructuredFilterType = {
supportNumberLikeComparison: true, supportNumberLikeComparison: true,
supportNullTesting: true, supportNullTesting: true,
supportSqlCondition: true, supportSqlCondition: true,
allowStringToken: true,
allowHexString: true,
}; };
export const LogicalFilterType: StructuredFilterType = { export const LogicalFilterType: StructuredFilterType = {
@@ -50,4 +55,6 @@ export const EvalFilterType: StructuredFilterType = {
supportEmpty: true, supportEmpty: true,
supportNumberLikeComparison: true, supportNumberLikeComparison: true,
supportNullTesting: true, supportNullTesting: true,
allowStringToken: true,
}; };

View File

@@ -1,11 +0,0 @@
import { isTypeNumber, isTypeString, isTypeLogical, isTypeDateTime } from 'dbgate-tools';
import { FilterType } from './types';
export function getFilterType(dataType: string): FilterType {
if (!dataType) return 'string';
if (isTypeNumber(dataType)) return 'number';
if (isTypeString(dataType)) return 'string';
if (isTypeLogical(dataType)) return 'logical';
if (isTypeDateTime(dataType)) return 'datetime';
return 'string';
}

View File

@@ -1,3 +1,3 @@
export * from './parseFilter'; export * from './parseFilter';
export * from './getFilterType'; export * from './detectSqlFilterType';
export * from './filterTool'; export * from './filterTool';

View File

@@ -1,11 +1,10 @@
import P from 'parsimmon'; import P from 'parsimmon';
import moment from 'moment';
import { FilterType } from './types';
import { Condition } from 'dbgate-sqltree'; import { Condition } from 'dbgate-sqltree';
import { interpretEscapes, token, word, whitespace } from './common'; import { interpretEscapes, token, word, whitespace } from './common';
import { mongoParser } from './mongoParser'; import { mongoParser } from './mongoParser';
import { datetimeParser } from './datetimeParser'; import { datetimeParser } from './datetimeParser';
import { hexStringToArray } from 'dbgate-tools'; import { hexStringToArray } from 'dbgate-tools';
import { StructuredFilterType } from 'dbgate-types';
const binaryCondition = operator => value => ({ const binaryCondition = operator => value => ({
conditionType: 'binary', conditionType: 'binary',
@@ -78,7 +77,7 @@ const sqlTemplate = templateSql => {
}; };
}; };
const createParser = (filterType: FilterType) => { const createParser = (structuredFilterType: StructuredFilterType) => {
const langDef = { const langDef = {
string1: () => string1: () =>
token(P.regexp(/"((?:\\.|.)*?)"/, 1)) token(P.regexp(/"((?:\\.|.)*?)"/, 1))
@@ -156,32 +155,52 @@ const createParser = (filterType: FilterType) => {
}; };
const allowedValues = []; // 'string1', 'string2', 'number', 'noQuotedString']; const allowedValues = []; // 'string1', 'string2', 'number', 'noQuotedString'];
if (filterType == 'string' || filterType == 'eval') { if (structuredFilterType.allowStringToken) {
allowedValues.push('string1', 'string2', 'noQuotedString'); allowedValues.push('string1', 'string2', 'noQuotedString');
} }
if (filterType == 'number') { if (structuredFilterType.allowNumberToken) {
allowedValues.push('string1Num', 'string2Num', 'number'); allowedValues.push('string1Num', 'string2Num', 'number');
} }
const allowedElements = ['null', 'notNull', 'eq', 'ne', 'ne2', 'sql']; const allowedElements = [];
if (filterType == 'number' || filterType == 'datetime' || filterType == 'eval') {
if (structuredFilterType.supportNullTesting) {
allowedElements.push('null', 'notNull');
}
if (structuredFilterType.supportEquals) {
allowedElements.push('eq', 'ne', 'ne2');
}
if (structuredFilterType.supportSqlCondition) {
allowedElements.push('sql');
}
if (structuredFilterType.supportNumberLikeComparison || structuredFilterType.supportDatetimeComparison) {
allowedElements.push('le', 'ge', 'lt', 'gt'); allowedElements.push('le', 'ge', 'lt', 'gt');
} }
if (filterType == 'string') {
allowedElements.push('empty', 'notEmpty', 'hexTestEq'); if (structuredFilterType.supportEmpty) {
allowedElements.push('empty', 'notEmpty');
} }
if (filterType == 'eval' || filterType == 'string') {
if (structuredFilterType.allowHexString) {
allowedElements.push('hexTestEq');
}
if (structuredFilterType.supportStringInclusion) {
allowedElements.push('startsWith', 'endsWith', 'contains', 'startsWithNot', 'endsWithNot', 'containsNot'); allowedElements.push('startsWith', 'endsWith', 'contains', 'startsWithNot', 'endsWithNot', 'containsNot');
} }
if (filterType == 'logical') { if (structuredFilterType.supportBooleanValues) {
allowedElements.push('true', 'false', 'trueNum', 'falseNum'); if (structuredFilterType.allowNumberToken || structuredFilterType.allowStringToken) {
} allowedElements.push('true', 'false');
if (filterType == 'eval') { } else {
allowedElements.push('true', 'false'); allowedElements.push('true', 'false', 'trueNum', 'falseNum');
}
} }
// must be last // must be last
if (filterType == 'string' || filterType == 'eval') { if (structuredFilterType.allowStringToken) {
allowedElements.push('valueTestStr'); allowedElements.push('valueTestStr');
} else { } else {
allowedElements.push('valueTestEq'); allowedElements.push('valueTestEq');
@@ -190,18 +209,25 @@ const createParser = (filterType: FilterType) => {
return P.createLanguage(langDef); return P.createLanguage(langDef);
}; };
const parsers = { const cachedFilters: { [key: string]: P.Language } = {};
number: createParser('number'),
string: createParser('string'),
logical: createParser('logical'),
eval: createParser('eval'),
mongo: mongoParser,
datetime: datetimeParser,
};
export function parseFilter(value: string, filterType: FilterType): Condition { function getParser(structuredFilterType: StructuredFilterType) {
// console.log('PARSING', value, 'WITH', filterType); if (structuredFilterType.compilerType == 'mongoCondition') {
const ast = parsers[filterType].list.tryParse(value); return mongoParser;
}
if (structuredFilterType.compilerType == 'datetime') {
return datetimeParser;
}
const key = JSON.stringify(structuredFilterType);
if (!cachedFilters[key]) {
cachedFilters[key] = createParser(structuredFilterType);
}
return cachedFilters[key];
}
export function parseFilter(value: string, structuredFilterType: StructuredFilterType): Condition {
const parser = getParser(structuredFilterType);
const ast = parser.list.tryParse(value);
// console.log('AST', ast); // console.log('AST', ast);
return ast; return ast;
} }

View File

@@ -1,7 +1,8 @@
const { parseFilter } = require('./parseFilter'); const { parseFilter } = require('./parseFilter');
const { StringFilterType } = require('./filterTypes');
test('parse string', () => { test('parse string', () => {
const ast = parseFilter('"123"', 'string'); const ast = parseFilter('"123"', StringFilterType);
console.log(JSON.stringify(ast)); console.log(JSON.stringify(ast));
expect(ast).toEqual({ expect(ast).toEqual({
conditionType: 'like', conditionType: 'like',

View File

@@ -1,3 +0,0 @@
// import types from 'dbgate-types';
export type FilterType = 'number' | 'string' | 'datetime' | 'logical' | 'eval' | 'mongo';

View File

@@ -3,6 +3,7 @@ import { QueryResult } from './query';
import { SqlDialect } from './dialect'; import { SqlDialect } from './dialect';
import { SqlDumper } from './dumper'; import { SqlDumper } from './dumper';
import { DatabaseInfo, NamedObjectInfo, TableInfo, ViewInfo, ProcedureInfo, FunctionInfo, TriggerInfo } from './dbinfo'; import { DatabaseInfo, NamedObjectInfo, TableInfo, ViewInfo, ProcedureInfo, FunctionInfo, TriggerInfo } from './dbinfo';
import { StructuredFilterType } from './filter-type';
export interface StreamOptions { export interface StreamOptions {
recordset: (columns) => void; recordset: (columns) => void;
@@ -153,6 +154,7 @@ export interface EngineDriver {
getRedirectAuthUrl(connection, options): Promise<{ url: string; sid: string }>; getRedirectAuthUrl(connection, options): Promise<{ url: string; sid: string }>;
getAuthTokenFromCode(connection, options): Promise<string>; getAuthTokenFromCode(connection, options): Promise<string>;
getAccessTokenFromAuth(connection, req): Promise<string | null>; getAccessTokenFromAuth(connection, req): Promise<string | null>;
getFilterType(dataType: string): StructuredFilterType;
analyserClass?: any; analyserClass?: any;
dumperClass?: any; dumperClass?: any;

View File

@@ -1,4 +1,4 @@
export type FilterParserCompilerType = 'sqlTree' | 'mongoCondition'; export type FilterParserCompilerType = 'sqlTree' | 'mongoCondition' | 'datetime';
export interface StructuredFilterType { export interface StructuredFilterType {
compilerType: FilterParserCompilerType; compilerType: FilterParserCompilerType;
@@ -15,5 +15,7 @@ export interface StructuredFilterType {
supportSqlCondition?: boolean; supportSqlCondition?: boolean;
supportArrayTesting?: boolean; supportArrayTesting?: boolean;
// allowedOperators: Array<{ value: string; label: string }>; allowStringToken?: boolean;
allowNumberToken?: boolean;
allowHexString?: boolean;
} }