mirror of
https://github.com/SigNoz/signoz.git
synced 2025-12-23 10:26:40 +00:00
chore: updated grammer for value, added parsetree for finding current context
This commit is contained in:
parent
e2498863e7
commit
3da7ce5f03
@ -14,10 +14,10 @@ import { Color } from '@signozhq/design-tokens';
|
|||||||
import { copilot } from '@uiw/codemirror-theme-copilot';
|
import { copilot } from '@uiw/codemirror-theme-copilot';
|
||||||
import CodeMirror, {
|
import CodeMirror, {
|
||||||
EditorView,
|
EditorView,
|
||||||
Extension,
|
|
||||||
keymap,
|
keymap,
|
||||||
|
Extension,
|
||||||
} from '@uiw/react-codemirror';
|
} from '@uiw/react-codemirror';
|
||||||
import { Button, Card, Collapse, Popover, Tag } from 'antd';
|
import { Button, Card, Collapse, Popover, Space, Tag, Typography } from 'antd';
|
||||||
import { getKeySuggestions } from 'api/querySuggestions/getKeySuggestions';
|
import { getKeySuggestions } from 'api/querySuggestions/getKeySuggestions';
|
||||||
import { getValueSuggestions } from 'api/querySuggestions/getValueSuggestion';
|
import { getValueSuggestions } from 'api/querySuggestions/getValueSuggestion';
|
||||||
import cx from 'classnames';
|
import cx from 'classnames';
|
||||||
@ -196,7 +196,6 @@ function QuerySearch({
|
|||||||
return op.toUpperCase() === 'IN' || op.toUpperCase() === 'NOT IN';
|
return op.toUpperCase() === 'IN' || op.toUpperCase() === 'NOT IN';
|
||||||
};
|
};
|
||||||
|
|
||||||
// Helper function to format value based on operator type and value type
|
|
||||||
const formatValueForOperator = (
|
const formatValueForOperator = (
|
||||||
value: string,
|
value: string,
|
||||||
operatorToken: string | undefined,
|
operatorToken: string | undefined,
|
||||||
@ -215,7 +214,10 @@ function QuerySearch({
|
|||||||
|
|
||||||
// If we're already inside bracket list for IN operator and it's a string value
|
// If we're already inside bracket list for IN operator and it's a string value
|
||||||
// just wrap in quotes but not brackets (we're already in brackets)
|
// just wrap in quotes but not brackets (we're already in brackets)
|
||||||
if (type === 'value' || type === 'keyword') {
|
if (
|
||||||
|
(type === 'value' || type === 'keyword') &&
|
||||||
|
!/^[a-zA-Z0-9_][a-zA-Z0-9_.\[\]]*$/.test(value)
|
||||||
|
) {
|
||||||
return wrapStringValueInQuotes(value);
|
return wrapStringValueInQuotes(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1054,7 +1056,7 @@ function QuerySearch({
|
|||||||
</Collapse>
|
</Collapse>
|
||||||
</Card>
|
</Card>
|
||||||
)}
|
)}
|
||||||
{/*
|
|
||||||
{queryContext && (
|
{queryContext && (
|
||||||
<Card size="small" title="Current Context" className="query-context">
|
<Card size="small" title="Current Context" className="query-context">
|
||||||
<div className="context-details">
|
<div className="context-details">
|
||||||
@ -1097,7 +1099,7 @@ function QuerySearch({
|
|||||||
</Space>
|
</Space>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
)} */}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@ -2,25 +2,23 @@
|
|||||||
|
|
||||||
import { ParseTreeListener } from 'antlr4';
|
import { ParseTreeListener } from 'antlr4';
|
||||||
|
|
||||||
import {
|
import { QueryContext } from './FilterQueryParser';
|
||||||
AndExpressionContext,
|
import { ExpressionContext } from './FilterQueryParser';
|
||||||
ArrayContext,
|
import { OrExpressionContext } from './FilterQueryParser';
|
||||||
ComparisonContext,
|
import { AndExpressionContext } from './FilterQueryParser';
|
||||||
ExpressionContext,
|
import { UnaryExpressionContext } from './FilterQueryParser';
|
||||||
FullTextContext,
|
import { PrimaryContext } from './FilterQueryParser';
|
||||||
FunctionCallContext,
|
import { ComparisonContext } from './FilterQueryParser';
|
||||||
FunctionParamContext,
|
import { InClauseContext } from './FilterQueryParser';
|
||||||
FunctionParamListContext,
|
import { NotInClauseContext } from './FilterQueryParser';
|
||||||
InClauseContext,
|
import { ValueListContext } from './FilterQueryParser';
|
||||||
KeyContext,
|
import { FullTextContext } from './FilterQueryParser';
|
||||||
NotInClauseContext,
|
import { FunctionCallContext } from './FilterQueryParser';
|
||||||
OrExpressionContext,
|
import { FunctionParamListContext } from './FilterQueryParser';
|
||||||
PrimaryContext,
|
import { FunctionParamContext } from './FilterQueryParser';
|
||||||
QueryContext,
|
import { ArrayContext } from './FilterQueryParser';
|
||||||
UnaryExpressionContext,
|
import { ValueContext } from './FilterQueryParser';
|
||||||
ValueContext,
|
import { KeyContext } from './FilterQueryParser';
|
||||||
ValueListContext,
|
|
||||||
} from './FilterQueryParser';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This interface defines a complete listener for a parse tree produced by
|
* This interface defines a complete listener for a parse tree produced by
|
||||||
@ -32,199 +30,166 @@ export default class FilterQueryListener extends ParseTreeListener {
|
|||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
*/
|
*/
|
||||||
enterQuery?: (ctx: QueryContext) => void;
|
enterQuery?: (ctx: QueryContext) => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exit a parse tree produced by `FilterQueryParser.query`.
|
* Exit a parse tree produced by `FilterQueryParser.query`.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
*/
|
*/
|
||||||
exitQuery?: (ctx: QueryContext) => void;
|
exitQuery?: (ctx: QueryContext) => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enter a parse tree produced by `FilterQueryParser.expression`.
|
* Enter a parse tree produced by `FilterQueryParser.expression`.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
*/
|
*/
|
||||||
enterExpression?: (ctx: ExpressionContext) => void;
|
enterExpression?: (ctx: ExpressionContext) => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exit a parse tree produced by `FilterQueryParser.expression`.
|
* Exit a parse tree produced by `FilterQueryParser.expression`.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
*/
|
*/
|
||||||
exitExpression?: (ctx: ExpressionContext) => void;
|
exitExpression?: (ctx: ExpressionContext) => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enter a parse tree produced by `FilterQueryParser.orExpression`.
|
* Enter a parse tree produced by `FilterQueryParser.orExpression`.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
*/
|
*/
|
||||||
enterOrExpression?: (ctx: OrExpressionContext) => void;
|
enterOrExpression?: (ctx: OrExpressionContext) => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exit a parse tree produced by `FilterQueryParser.orExpression`.
|
* Exit a parse tree produced by `FilterQueryParser.orExpression`.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
*/
|
*/
|
||||||
exitOrExpression?: (ctx: OrExpressionContext) => void;
|
exitOrExpression?: (ctx: OrExpressionContext) => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enter a parse tree produced by `FilterQueryParser.andExpression`.
|
* Enter a parse tree produced by `FilterQueryParser.andExpression`.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
*/
|
*/
|
||||||
enterAndExpression?: (ctx: AndExpressionContext) => void;
|
enterAndExpression?: (ctx: AndExpressionContext) => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exit a parse tree produced by `FilterQueryParser.andExpression`.
|
* Exit a parse tree produced by `FilterQueryParser.andExpression`.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
*/
|
*/
|
||||||
exitAndExpression?: (ctx: AndExpressionContext) => void;
|
exitAndExpression?: (ctx: AndExpressionContext) => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enter a parse tree produced by `FilterQueryParser.unaryExpression`.
|
* Enter a parse tree produced by `FilterQueryParser.unaryExpression`.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
*/
|
*/
|
||||||
enterUnaryExpression?: (ctx: UnaryExpressionContext) => void;
|
enterUnaryExpression?: (ctx: UnaryExpressionContext) => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exit a parse tree produced by `FilterQueryParser.unaryExpression`.
|
* Exit a parse tree produced by `FilterQueryParser.unaryExpression`.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
*/
|
*/
|
||||||
exitUnaryExpression?: (ctx: UnaryExpressionContext) => void;
|
exitUnaryExpression?: (ctx: UnaryExpressionContext) => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enter a parse tree produced by `FilterQueryParser.primary`.
|
* Enter a parse tree produced by `FilterQueryParser.primary`.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
*/
|
*/
|
||||||
enterPrimary?: (ctx: PrimaryContext) => void;
|
enterPrimary?: (ctx: PrimaryContext) => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exit a parse tree produced by `FilterQueryParser.primary`.
|
* Exit a parse tree produced by `FilterQueryParser.primary`.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
*/
|
*/
|
||||||
exitPrimary?: (ctx: PrimaryContext) => void;
|
exitPrimary?: (ctx: PrimaryContext) => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enter a parse tree produced by `FilterQueryParser.comparison`.
|
* Enter a parse tree produced by `FilterQueryParser.comparison`.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
*/
|
*/
|
||||||
enterComparison?: (ctx: ComparisonContext) => void;
|
enterComparison?: (ctx: ComparisonContext) => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exit a parse tree produced by `FilterQueryParser.comparison`.
|
* Exit a parse tree produced by `FilterQueryParser.comparison`.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
*/
|
*/
|
||||||
exitComparison?: (ctx: ComparisonContext) => void;
|
exitComparison?: (ctx: ComparisonContext) => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enter a parse tree produced by `FilterQueryParser.inClause`.
|
* Enter a parse tree produced by `FilterQueryParser.inClause`.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
*/
|
*/
|
||||||
enterInClause?: (ctx: InClauseContext) => void;
|
enterInClause?: (ctx: InClauseContext) => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exit a parse tree produced by `FilterQueryParser.inClause`.
|
* Exit a parse tree produced by `FilterQueryParser.inClause`.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
*/
|
*/
|
||||||
exitInClause?: (ctx: InClauseContext) => void;
|
exitInClause?: (ctx: InClauseContext) => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enter a parse tree produced by `FilterQueryParser.notInClause`.
|
* Enter a parse tree produced by `FilterQueryParser.notInClause`.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
*/
|
*/
|
||||||
enterNotInClause?: (ctx: NotInClauseContext) => void;
|
enterNotInClause?: (ctx: NotInClauseContext) => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exit a parse tree produced by `FilterQueryParser.notInClause`.
|
* Exit a parse tree produced by `FilterQueryParser.notInClause`.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
*/
|
*/
|
||||||
exitNotInClause?: (ctx: NotInClauseContext) => void;
|
exitNotInClause?: (ctx: NotInClauseContext) => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enter a parse tree produced by `FilterQueryParser.valueList`.
|
* Enter a parse tree produced by `FilterQueryParser.valueList`.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
*/
|
*/
|
||||||
enterValueList?: (ctx: ValueListContext) => void;
|
enterValueList?: (ctx: ValueListContext) => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exit a parse tree produced by `FilterQueryParser.valueList`.
|
* Exit a parse tree produced by `FilterQueryParser.valueList`.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
*/
|
*/
|
||||||
exitValueList?: (ctx: ValueListContext) => void;
|
exitValueList?: (ctx: ValueListContext) => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enter a parse tree produced by `FilterQueryParser.fullText`.
|
* Enter a parse tree produced by `FilterQueryParser.fullText`.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
*/
|
*/
|
||||||
enterFullText?: (ctx: FullTextContext) => void;
|
enterFullText?: (ctx: FullTextContext) => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exit a parse tree produced by `FilterQueryParser.fullText`.
|
* Exit a parse tree produced by `FilterQueryParser.fullText`.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
*/
|
*/
|
||||||
exitFullText?: (ctx: FullTextContext) => void;
|
exitFullText?: (ctx: FullTextContext) => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enter a parse tree produced by `FilterQueryParser.functionCall`.
|
* Enter a parse tree produced by `FilterQueryParser.functionCall`.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
*/
|
*/
|
||||||
enterFunctionCall?: (ctx: FunctionCallContext) => void;
|
enterFunctionCall?: (ctx: FunctionCallContext) => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exit a parse tree produced by `FilterQueryParser.functionCall`.
|
* Exit a parse tree produced by `FilterQueryParser.functionCall`.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
*/
|
*/
|
||||||
exitFunctionCall?: (ctx: FunctionCallContext) => void;
|
exitFunctionCall?: (ctx: FunctionCallContext) => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enter a parse tree produced by `FilterQueryParser.functionParamList`.
|
* Enter a parse tree produced by `FilterQueryParser.functionParamList`.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
*/
|
*/
|
||||||
enterFunctionParamList?: (ctx: FunctionParamListContext) => void;
|
enterFunctionParamList?: (ctx: FunctionParamListContext) => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exit a parse tree produced by `FilterQueryParser.functionParamList`.
|
* Exit a parse tree produced by `FilterQueryParser.functionParamList`.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
*/
|
*/
|
||||||
exitFunctionParamList?: (ctx: FunctionParamListContext) => void;
|
exitFunctionParamList?: (ctx: FunctionParamListContext) => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enter a parse tree produced by `FilterQueryParser.functionParam`.
|
* Enter a parse tree produced by `FilterQueryParser.functionParam`.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
*/
|
*/
|
||||||
enterFunctionParam?: (ctx: FunctionParamContext) => void;
|
enterFunctionParam?: (ctx: FunctionParamContext) => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exit a parse tree produced by `FilterQueryParser.functionParam`.
|
* Exit a parse tree produced by `FilterQueryParser.functionParam`.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
*/
|
*/
|
||||||
exitFunctionParam?: (ctx: FunctionParamContext) => void;
|
exitFunctionParam?: (ctx: FunctionParamContext) => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enter a parse tree produced by `FilterQueryParser.array`.
|
* Enter a parse tree produced by `FilterQueryParser.array`.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
*/
|
*/
|
||||||
enterArray?: (ctx: ArrayContext) => void;
|
enterArray?: (ctx: ArrayContext) => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exit a parse tree produced by `FilterQueryParser.array`.
|
* Exit a parse tree produced by `FilterQueryParser.array`.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
*/
|
*/
|
||||||
exitArray?: (ctx: ArrayContext) => void;
|
exitArray?: (ctx: ArrayContext) => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enter a parse tree produced by `FilterQueryParser.value`.
|
* Enter a parse tree produced by `FilterQueryParser.value`.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
*/
|
*/
|
||||||
enterValue?: (ctx: ValueContext) => void;
|
enterValue?: (ctx: ValueContext) => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exit a parse tree produced by `FilterQueryParser.value`.
|
* Exit a parse tree produced by `FilterQueryParser.value`.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
*/
|
*/
|
||||||
exitValue?: (ctx: ValueContext) => void;
|
exitValue?: (ctx: ValueContext) => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enter a parse tree produced by `FilterQueryParser.key`.
|
* Enter a parse tree produced by `FilterQueryParser.key`.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
*/
|
*/
|
||||||
enterKey?: (ctx: KeyContext) => void;
|
enterKey?: (ctx: KeyContext) => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exit a parse tree produced by `FilterQueryParser.key`.
|
* Exit a parse tree produced by `FilterQueryParser.key`.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
|
|||||||
@ -1022,17 +1022,15 @@ export default class FilterQueryParser extends Parser {
|
|||||||
try {
|
try {
|
||||||
this.state = 202;
|
this.state = 202;
|
||||||
this._errHandler.sync(this);
|
this._errHandler.sync(this);
|
||||||
switch (this._input.LA(1)) {
|
switch (this._interp.adaptivePredict(this._input, 12, this._ctx)) {
|
||||||
case 37:
|
case 1:
|
||||||
this.enterOuterAlt(localctx, 1);
|
this.enterOuterAlt(localctx, 1);
|
||||||
{
|
{
|
||||||
this.state = 199;
|
this.state = 199;
|
||||||
this.key();
|
this.key();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 34:
|
case 2:
|
||||||
case 35:
|
|
||||||
case 36:
|
|
||||||
this.enterOuterAlt(localctx, 2);
|
this.enterOuterAlt(localctx, 2);
|
||||||
{
|
{
|
||||||
this.state = 200;
|
this.state = 200;
|
||||||
@ -1046,8 +1044,6 @@ export default class FilterQueryParser extends Parser {
|
|||||||
this.array();
|
this.array();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
|
||||||
throw new NoViableAltException(this);
|
|
||||||
}
|
}
|
||||||
} catch (re) {
|
} catch (re) {
|
||||||
if (re instanceof RecognitionException) {
|
if (re instanceof RecognitionException) {
|
||||||
@ -1099,7 +1095,7 @@ export default class FilterQueryParser extends Parser {
|
|||||||
{
|
{
|
||||||
this.state = 208;
|
this.state = 208;
|
||||||
_la = this._input.LA(1);
|
_la = this._input.LA(1);
|
||||||
if (!(((_la - 34) & ~0x1f) === 0 && ((1 << (_la - 34)) & 7) !== 0)) {
|
if (!(((_la - 34) & ~0x1f) === 0 && ((1 << (_la - 34)) & 15) !== 0)) {
|
||||||
this._errHandler.recoverInline(this);
|
this._errHandler.recoverInline(this);
|
||||||
} else {
|
} else {
|
||||||
this._errHandler.reportMatch(this);
|
this._errHandler.reportMatch(this);
|
||||||
@ -1639,7 +1635,7 @@ export default class FilterQueryParser extends Parser {
|
|||||||
1,
|
1,
|
||||||
0,
|
0,
|
||||||
34,
|
34,
|
||||||
36,
|
37,
|
||||||
227,
|
227,
|
||||||
0,
|
0,
|
||||||
34,
|
34,
|
||||||
@ -3809,6 +3805,9 @@ export class ValueContext extends ParserRuleContext {
|
|||||||
public BOOL(): TerminalNode {
|
public BOOL(): TerminalNode {
|
||||||
return this.getToken(FilterQueryParser.BOOL, 0);
|
return this.getToken(FilterQueryParser.BOOL, 0);
|
||||||
}
|
}
|
||||||
|
public KEY(): TerminalNode {
|
||||||
|
return this.getToken(FilterQueryParser.KEY, 0);
|
||||||
|
}
|
||||||
public get ruleIndex(): number {
|
public get ruleIndex(): number {
|
||||||
return FilterQueryParser.RULE_value;
|
return FilterQueryParser.RULE_value;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,25 +2,23 @@
|
|||||||
|
|
||||||
import { ParseTreeVisitor } from 'antlr4';
|
import { ParseTreeVisitor } from 'antlr4';
|
||||||
|
|
||||||
import {
|
import { QueryContext } from './FilterQueryParser';
|
||||||
AndExpressionContext,
|
import { ExpressionContext } from './FilterQueryParser';
|
||||||
ArrayContext,
|
import { OrExpressionContext } from './FilterQueryParser';
|
||||||
ComparisonContext,
|
import { AndExpressionContext } from './FilterQueryParser';
|
||||||
ExpressionContext,
|
import { UnaryExpressionContext } from './FilterQueryParser';
|
||||||
FullTextContext,
|
import { PrimaryContext } from './FilterQueryParser';
|
||||||
FunctionCallContext,
|
import { ComparisonContext } from './FilterQueryParser';
|
||||||
FunctionParamContext,
|
import { InClauseContext } from './FilterQueryParser';
|
||||||
FunctionParamListContext,
|
import { NotInClauseContext } from './FilterQueryParser';
|
||||||
InClauseContext,
|
import { ValueListContext } from './FilterQueryParser';
|
||||||
KeyContext,
|
import { FullTextContext } from './FilterQueryParser';
|
||||||
NotInClauseContext,
|
import { FunctionCallContext } from './FilterQueryParser';
|
||||||
OrExpressionContext,
|
import { FunctionParamListContext } from './FilterQueryParser';
|
||||||
PrimaryContext,
|
import { FunctionParamContext } from './FilterQueryParser';
|
||||||
QueryContext,
|
import { ArrayContext } from './FilterQueryParser';
|
||||||
UnaryExpressionContext,
|
import { ValueContext } from './FilterQueryParser';
|
||||||
ValueContext,
|
import { KeyContext } from './FilterQueryParser';
|
||||||
ValueListContext,
|
|
||||||
} from './FilterQueryParser';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This interface defines a complete generic visitor for a parse tree produced
|
* This interface defines a complete generic visitor for a parse tree produced
|
||||||
@ -38,112 +36,96 @@ export default class FilterQueryVisitor<
|
|||||||
* @return the visitor result
|
* @return the visitor result
|
||||||
*/
|
*/
|
||||||
visitQuery?: (ctx: QueryContext) => Result;
|
visitQuery?: (ctx: QueryContext) => Result;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Visit a parse tree produced by `FilterQueryParser.expression`.
|
* Visit a parse tree produced by `FilterQueryParser.expression`.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
* @return the visitor result
|
* @return the visitor result
|
||||||
*/
|
*/
|
||||||
visitExpression?: (ctx: ExpressionContext) => Result;
|
visitExpression?: (ctx: ExpressionContext) => Result;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Visit a parse tree produced by `FilterQueryParser.orExpression`.
|
* Visit a parse tree produced by `FilterQueryParser.orExpression`.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
* @return the visitor result
|
* @return the visitor result
|
||||||
*/
|
*/
|
||||||
visitOrExpression?: (ctx: OrExpressionContext) => Result;
|
visitOrExpression?: (ctx: OrExpressionContext) => Result;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Visit a parse tree produced by `FilterQueryParser.andExpression`.
|
* Visit a parse tree produced by `FilterQueryParser.andExpression`.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
* @return the visitor result
|
* @return the visitor result
|
||||||
*/
|
*/
|
||||||
visitAndExpression?: (ctx: AndExpressionContext) => Result;
|
visitAndExpression?: (ctx: AndExpressionContext) => Result;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Visit a parse tree produced by `FilterQueryParser.unaryExpression`.
|
* Visit a parse tree produced by `FilterQueryParser.unaryExpression`.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
* @return the visitor result
|
* @return the visitor result
|
||||||
*/
|
*/
|
||||||
visitUnaryExpression?: (ctx: UnaryExpressionContext) => Result;
|
visitUnaryExpression?: (ctx: UnaryExpressionContext) => Result;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Visit a parse tree produced by `FilterQueryParser.primary`.
|
* Visit a parse tree produced by `FilterQueryParser.primary`.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
* @return the visitor result
|
* @return the visitor result
|
||||||
*/
|
*/
|
||||||
visitPrimary?: (ctx: PrimaryContext) => Result;
|
visitPrimary?: (ctx: PrimaryContext) => Result;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Visit a parse tree produced by `FilterQueryParser.comparison`.
|
* Visit a parse tree produced by `FilterQueryParser.comparison`.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
* @return the visitor result
|
* @return the visitor result
|
||||||
*/
|
*/
|
||||||
visitComparison?: (ctx: ComparisonContext) => Result;
|
visitComparison?: (ctx: ComparisonContext) => Result;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Visit a parse tree produced by `FilterQueryParser.inClause`.
|
* Visit a parse tree produced by `FilterQueryParser.inClause`.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
* @return the visitor result
|
* @return the visitor result
|
||||||
*/
|
*/
|
||||||
visitInClause?: (ctx: InClauseContext) => Result;
|
visitInClause?: (ctx: InClauseContext) => Result;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Visit a parse tree produced by `FilterQueryParser.notInClause`.
|
* Visit a parse tree produced by `FilterQueryParser.notInClause`.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
* @return the visitor result
|
* @return the visitor result
|
||||||
*/
|
*/
|
||||||
visitNotInClause?: (ctx: NotInClauseContext) => Result;
|
visitNotInClause?: (ctx: NotInClauseContext) => Result;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Visit a parse tree produced by `FilterQueryParser.valueList`.
|
* Visit a parse tree produced by `FilterQueryParser.valueList`.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
* @return the visitor result
|
* @return the visitor result
|
||||||
*/
|
*/
|
||||||
visitValueList?: (ctx: ValueListContext) => Result;
|
visitValueList?: (ctx: ValueListContext) => Result;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Visit a parse tree produced by `FilterQueryParser.fullText`.
|
* Visit a parse tree produced by `FilterQueryParser.fullText`.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
* @return the visitor result
|
* @return the visitor result
|
||||||
*/
|
*/
|
||||||
visitFullText?: (ctx: FullTextContext) => Result;
|
visitFullText?: (ctx: FullTextContext) => Result;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Visit a parse tree produced by `FilterQueryParser.functionCall`.
|
* Visit a parse tree produced by `FilterQueryParser.functionCall`.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
* @return the visitor result
|
* @return the visitor result
|
||||||
*/
|
*/
|
||||||
visitFunctionCall?: (ctx: FunctionCallContext) => Result;
|
visitFunctionCall?: (ctx: FunctionCallContext) => Result;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Visit a parse tree produced by `FilterQueryParser.functionParamList`.
|
* Visit a parse tree produced by `FilterQueryParser.functionParamList`.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
* @return the visitor result
|
* @return the visitor result
|
||||||
*/
|
*/
|
||||||
visitFunctionParamList?: (ctx: FunctionParamListContext) => Result;
|
visitFunctionParamList?: (ctx: FunctionParamListContext) => Result;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Visit a parse tree produced by `FilterQueryParser.functionParam`.
|
* Visit a parse tree produced by `FilterQueryParser.functionParam`.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
* @return the visitor result
|
* @return the visitor result
|
||||||
*/
|
*/
|
||||||
visitFunctionParam?: (ctx: FunctionParamContext) => Result;
|
visitFunctionParam?: (ctx: FunctionParamContext) => Result;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Visit a parse tree produced by `FilterQueryParser.array`.
|
* Visit a parse tree produced by `FilterQueryParser.array`.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
* @return the visitor result
|
* @return the visitor result
|
||||||
*/
|
*/
|
||||||
visitArray?: (ctx: ArrayContext) => Result;
|
visitArray?: (ctx: ArrayContext) => Result;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Visit a parse tree produced by `FilterQueryParser.value`.
|
* Visit a parse tree produced by `FilterQueryParser.value`.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
* @return the visitor result
|
* @return the visitor result
|
||||||
*/
|
*/
|
||||||
visitValue?: (ctx: ValueContext) => Result;
|
visitValue?: (ctx: ValueContext) => Result;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Visit a parse tree produced by `FilterQueryParser.key`.
|
* Visit a parse tree produced by `FilterQueryParser.key`.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
|
|||||||
94
frontend/src/parser/analyzeQuery.ts
Normal file
94
frontend/src/parser/analyzeQuery.ts
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
import FilterQueryLexer from './FilterQueryLexer';
|
||||||
|
import FilterQueryParser from './FilterQueryParser';
|
||||||
|
import { ParseTreeWalker, CharStreams, CommonTokenStream, Token } from 'antlr4';
|
||||||
|
import { isOperatorToken } from 'utils/tokenUtils';
|
||||||
|
import FilterQueryListener from './FilterQueryListener';
|
||||||
|
|
||||||
|
import {
|
||||||
|
KeyContext,
|
||||||
|
ValueContext,
|
||||||
|
ComparisonContext,
|
||||||
|
} from './FilterQueryParser';
|
||||||
|
import { IToken } from 'types/antlrQueryTypes';
|
||||||
|
|
||||||
|
// 👇 Define the token classification
|
||||||
|
type TokenClassification = 'Key' | 'Value' | 'Operator';
|
||||||
|
|
||||||
|
interface TokenInfo {
|
||||||
|
text: string;
|
||||||
|
startIndex: number;
|
||||||
|
stopIndex: number;
|
||||||
|
type: TokenClassification;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👇 Custom listener to walk the parse tree
|
||||||
|
class TypeTrackingListener implements FilterQueryListener {
|
||||||
|
public tokens: TokenInfo[] = [];
|
||||||
|
|
||||||
|
enterKey(ctx: KeyContext) {
|
||||||
|
const token = ctx.KEY().symbol;
|
||||||
|
this.tokens.push({
|
||||||
|
text: token.text!,
|
||||||
|
startIndex: token.start,
|
||||||
|
stopIndex: token.stop,
|
||||||
|
type: 'Key',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
enterValue(ctx: ValueContext) {
|
||||||
|
const token = ctx.start;
|
||||||
|
this.tokens.push({
|
||||||
|
text: token.text!,
|
||||||
|
startIndex: token.start,
|
||||||
|
stopIndex: token.stop,
|
||||||
|
type: 'Value',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
enterComparison(ctx: ComparisonContext) {
|
||||||
|
const children = ctx.children || [];
|
||||||
|
for (const child of children) {
|
||||||
|
const token = (child as any).symbol;
|
||||||
|
if (token && isOperatorToken(token.type)) {
|
||||||
|
this.tokens.push({
|
||||||
|
text: token.text!,
|
||||||
|
startIndex: token.start,
|
||||||
|
stopIndex: token.stop,
|
||||||
|
type: 'Operator',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Required no-op stubs
|
||||||
|
enterEveryRule() {}
|
||||||
|
exitEveryRule() {}
|
||||||
|
exitKey() {}
|
||||||
|
exitValue() {}
|
||||||
|
exitComparison() {}
|
||||||
|
visitTerminal() {}
|
||||||
|
visitErrorNode() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👇 Analyze function
|
||||||
|
export function analyzeQuery(input: string, lastToken: IToken) {
|
||||||
|
input = input.trim();
|
||||||
|
const chars = CharStreams.fromString(input);
|
||||||
|
const lexer = new FilterQueryLexer(chars);
|
||||||
|
const tokens = new CommonTokenStream(lexer);
|
||||||
|
const parser = new FilterQueryParser(tokens);
|
||||||
|
|
||||||
|
const tree = parser.query();
|
||||||
|
|
||||||
|
const listener = new TypeTrackingListener();
|
||||||
|
ParseTreeWalker.DEFAULT.walk(listener, tree);
|
||||||
|
|
||||||
|
const currentToken = listener.tokens.find(
|
||||||
|
(token) =>
|
||||||
|
token.text === lastToken.text &&
|
||||||
|
token.startIndex === lastToken.start &&
|
||||||
|
token.stopIndex === lastToken.stop,
|
||||||
|
);
|
||||||
|
|
||||||
|
return currentToken;
|
||||||
|
}
|
||||||
File diff suppressed because one or more lines are too long
@ -93,6 +93,7 @@ value
|
|||||||
: QUOTED_TEXT
|
: QUOTED_TEXT
|
||||||
| NUMBER
|
| NUMBER
|
||||||
| BOOL
|
| BOOL
|
||||||
|
| KEY
|
||||||
;
|
;
|
||||||
|
|
||||||
key
|
key
|
||||||
|
|||||||
@ -3,6 +3,16 @@
|
|||||||
import { CharStreams, CommonTokenStream, Token } from 'antlr4';
|
import { CharStreams, CommonTokenStream, Token } from 'antlr4';
|
||||||
import FilterQueryLexer from 'parser/FilterQueryLexer';
|
import FilterQueryLexer from 'parser/FilterQueryLexer';
|
||||||
import { IQueryContext, IQueryPair, IToken } from 'types/antlrQueryTypes';
|
import { IQueryContext, IQueryPair, IToken } from 'types/antlrQueryTypes';
|
||||||
|
import { analyzeQuery } from 'parser/analyzeQuery';
|
||||||
|
import {
|
||||||
|
isBracketToken,
|
||||||
|
isConjunctionToken,
|
||||||
|
isFunctionToken,
|
||||||
|
isKeyToken,
|
||||||
|
isMultiValueOperator,
|
||||||
|
isOperatorToken,
|
||||||
|
isValueToken,
|
||||||
|
} from './tokenUtils';
|
||||||
|
|
||||||
// Function to normalize multiple spaces to single spaces when not in quotes
|
// Function to normalize multiple spaces to single spaces when not in quotes
|
||||||
function normalizeSpaces(query: string): string {
|
function normalizeSpaces(query: string): string {
|
||||||
@ -69,7 +79,8 @@ export function createContext(
|
|||||||
|
|
||||||
// Helper to determine token type for context
|
// Helper to determine token type for context
|
||||||
function determineTokenContext(
|
function determineTokenContext(
|
||||||
tokenType: number,
|
token: IToken,
|
||||||
|
query: string,
|
||||||
): {
|
): {
|
||||||
isInKey: boolean;
|
isInKey: boolean;
|
||||||
isInOperator: boolean;
|
isInOperator: boolean;
|
||||||
@ -78,57 +89,49 @@ function determineTokenContext(
|
|||||||
isInConjunction: boolean;
|
isInConjunction: boolean;
|
||||||
isInParenthesis: boolean;
|
isInParenthesis: boolean;
|
||||||
} {
|
} {
|
||||||
// Key context
|
let isInKey: boolean = false;
|
||||||
const isInKey = tokenType === FilterQueryLexer.KEY;
|
let isInOperator: boolean = false;
|
||||||
|
let isInValue: boolean = false;
|
||||||
|
let isInFunction: boolean = false;
|
||||||
|
let isInConjunction: boolean = false;
|
||||||
|
let isInParenthesis: boolean = false;
|
||||||
|
|
||||||
// Operator context
|
const tokenType = token.type;
|
||||||
const isInOperator = [
|
const currentTokenContext = analyzeQuery(query, token);
|
||||||
FilterQueryLexer.EQUALS,
|
|
||||||
FilterQueryLexer.NOT_EQUALS,
|
|
||||||
FilterQueryLexer.NEQ,
|
|
||||||
FilterQueryLexer.LT,
|
|
||||||
FilterQueryLexer.LE,
|
|
||||||
FilterQueryLexer.GT,
|
|
||||||
FilterQueryLexer.GE,
|
|
||||||
FilterQueryLexer.LIKE,
|
|
||||||
FilterQueryLexer.NOT_LIKE,
|
|
||||||
FilterQueryLexer.ILIKE,
|
|
||||||
FilterQueryLexer.NOT_ILIKE,
|
|
||||||
FilterQueryLexer.BETWEEN,
|
|
||||||
FilterQueryLexer.EXISTS,
|
|
||||||
FilterQueryLexer.REGEXP,
|
|
||||||
FilterQueryLexer.CONTAINS,
|
|
||||||
FilterQueryLexer.IN,
|
|
||||||
FilterQueryLexer.NOT,
|
|
||||||
].includes(tokenType);
|
|
||||||
|
|
||||||
// Value context
|
if (!currentTokenContext) {
|
||||||
const isInValue = [
|
// Key context
|
||||||
FilterQueryLexer.QUOTED_TEXT,
|
isInKey = isKeyToken(tokenType);
|
||||||
FilterQueryLexer.NUMBER,
|
|
||||||
FilterQueryLexer.BOOL,
|
// Operator context
|
||||||
].includes(tokenType);
|
isInOperator = isOperatorToken(tokenType);
|
||||||
|
|
||||||
|
// Value context
|
||||||
|
isInValue = isValueToken(tokenType);
|
||||||
|
} else {
|
||||||
|
switch (currentTokenContext.type) {
|
||||||
|
case 'Operator':
|
||||||
|
isInOperator = true;
|
||||||
|
break;
|
||||||
|
case 'Value':
|
||||||
|
isInValue = true;
|
||||||
|
break;
|
||||||
|
case 'Key':
|
||||||
|
isInKey = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Function context
|
// Function context
|
||||||
const isInFunction = [
|
isInFunction = isFunctionToken(tokenType);
|
||||||
FilterQueryLexer.HAS,
|
|
||||||
FilterQueryLexer.HASANY,
|
|
||||||
FilterQueryLexer.HASALL,
|
|
||||||
FilterQueryLexer.HASNONE,
|
|
||||||
].includes(tokenType);
|
|
||||||
|
|
||||||
// Conjunction context
|
// Conjunction context
|
||||||
const isInConjunction = [FilterQueryLexer.AND, FilterQueryLexer.OR].includes(
|
isInConjunction = isConjunctionToken(tokenType);
|
||||||
tokenType,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Parenthesis context
|
// Parenthesis context
|
||||||
const isInParenthesis = [
|
isInParenthesis = isBracketToken(tokenType);
|
||||||
FilterQueryLexer.LPAREN,
|
|
||||||
FilterQueryLexer.RPAREN,
|
|
||||||
FilterQueryLexer.LBRACK,
|
|
||||||
FilterQueryLexer.RBRACK,
|
|
||||||
].includes(tokenType);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isInKey,
|
isInKey,
|
||||||
@ -140,61 +143,6 @@ function determineTokenContext(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to check if a token is an operator
|
|
||||||
function isOperatorToken(tokenType: number): boolean {
|
|
||||||
return [
|
|
||||||
FilterQueryLexer.EQUALS,
|
|
||||||
FilterQueryLexer.NOT_EQUALS,
|
|
||||||
FilterQueryLexer.NEQ,
|
|
||||||
FilterQueryLexer.LT,
|
|
||||||
FilterQueryLexer.LE,
|
|
||||||
FilterQueryLexer.GT,
|
|
||||||
FilterQueryLexer.GE,
|
|
||||||
FilterQueryLexer.LIKE,
|
|
||||||
FilterQueryLexer.NOT_LIKE,
|
|
||||||
FilterQueryLexer.ILIKE,
|
|
||||||
FilterQueryLexer.NOT_ILIKE,
|
|
||||||
FilterQueryLexer.BETWEEN,
|
|
||||||
FilterQueryLexer.EXISTS,
|
|
||||||
FilterQueryLexer.REGEXP,
|
|
||||||
FilterQueryLexer.CONTAINS,
|
|
||||||
FilterQueryLexer.IN,
|
|
||||||
FilterQueryLexer.NOT,
|
|
||||||
].includes(tokenType);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper function to check if a token is a value
|
|
||||||
function isValueToken(tokenType: number): boolean {
|
|
||||||
return [
|
|
||||||
FilterQueryLexer.QUOTED_TEXT,
|
|
||||||
FilterQueryLexer.NUMBER,
|
|
||||||
FilterQueryLexer.BOOL,
|
|
||||||
].includes(tokenType);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper function to check if a token is a conjunction
|
|
||||||
function isConjunctionToken(tokenType: number): boolean {
|
|
||||||
return [FilterQueryLexer.AND, FilterQueryLexer.OR].includes(tokenType);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper function to check if a token is a bracket
|
|
||||||
function isBracketToken(tokenType: number): boolean {
|
|
||||||
return [
|
|
||||||
FilterQueryLexer.LPAREN,
|
|
||||||
FilterQueryLexer.RPAREN,
|
|
||||||
FilterQueryLexer.LBRACK,
|
|
||||||
FilterQueryLexer.RBRACK,
|
|
||||||
].includes(tokenType);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper function to check if an operator typically uses bracket values (multi-value operators)
|
|
||||||
function isMultiValueOperator(operatorToken?: string): boolean {
|
|
||||||
if (!operatorToken) return false;
|
|
||||||
|
|
||||||
const upperOp = operatorToken.toUpperCase();
|
|
||||||
return upperOp === 'IN' || upperOp === 'NOT IN';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to determine token context boundaries more precisely
|
// Function to determine token context boundaries more precisely
|
||||||
function determineContextBoundaries(
|
function determineContextBoundaries(
|
||||||
query: string,
|
query: string,
|
||||||
@ -888,7 +836,7 @@ export function getQueryContextAtCursor(
|
|||||||
lastTokenBeforeCursor &&
|
lastTokenBeforeCursor &&
|
||||||
(isAtSpace || isAfterSpace || isTransitionPoint)
|
(isAtSpace || isAfterSpace || isTransitionPoint)
|
||||||
) {
|
) {
|
||||||
const lastTokenContext = determineTokenContext(lastTokenBeforeCursor.type);
|
const lastTokenContext = determineTokenContext(lastTokenBeforeCursor, input);
|
||||||
|
|
||||||
// Apply the context progression logic: key → operator → value → conjunction → key
|
// Apply the context progression logic: key → operator → value → conjunction → key
|
||||||
if (lastTokenContext.isInKey) {
|
if (lastTokenContext.isInKey) {
|
||||||
@ -984,7 +932,7 @@ export function getQueryContextAtCursor(
|
|||||||
// FIXED: Consider the case where the cursor is at the end of a token
|
// FIXED: Consider the case where the cursor is at the end of a token
|
||||||
// with no space yet (user is actively typing)
|
// with no space yet (user is actively typing)
|
||||||
if (exactToken && adjustedCursorIndex === exactToken.stop + 1) {
|
if (exactToken && adjustedCursorIndex === exactToken.stop + 1) {
|
||||||
const tokenContext = determineTokenContext(exactToken.type);
|
const tokenContext = determineTokenContext(exactToken, input);
|
||||||
|
|
||||||
// When the cursor is at the end of a token, return the current token context
|
// When the cursor is at the end of a token, return the current token context
|
||||||
return {
|
return {
|
||||||
@ -1011,7 +959,7 @@ export function getQueryContextAtCursor(
|
|||||||
|
|
||||||
// Regular token-based context detection (when cursor is directly on a token)
|
// Regular token-based context detection (when cursor is directly on a token)
|
||||||
if (exactToken?.channel === 0) {
|
if (exactToken?.channel === 0) {
|
||||||
const tokenContext = determineTokenContext(exactToken.type);
|
const tokenContext = determineTokenContext(exactToken, input);
|
||||||
|
|
||||||
// Get relevant tokens based on current pair
|
// Get relevant tokens based on current pair
|
||||||
const keyFromPair = currentPair?.key || '';
|
const keyFromPair = currentPair?.key || '';
|
||||||
@ -1044,7 +992,7 @@ export function getQueryContextAtCursor(
|
|||||||
|
|
||||||
// If we're between tokens but not after a space, use previous token to determine context
|
// If we're between tokens but not after a space, use previous token to determine context
|
||||||
if (previousToken?.channel === 0) {
|
if (previousToken?.channel === 0) {
|
||||||
const prevContext = determineTokenContext(previousToken.type);
|
const prevContext = determineTokenContext(previousToken, input);
|
||||||
|
|
||||||
// Get relevant tokens based on current pair
|
// Get relevant tokens based on current pair
|
||||||
const keyFromPair = currentPair?.key || '';
|
const keyFromPair = currentPair?.key || '';
|
||||||
@ -1221,7 +1169,10 @@ export function extractQueryPairs(query: string): IQueryPair[] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If token is a KEY, start a new pair
|
// If token is a KEY, start a new pair
|
||||||
if (token.type === FilterQueryLexer.KEY) {
|
if (
|
||||||
|
token.type === FilterQueryLexer.KEY &&
|
||||||
|
!(currentPair && currentPair.key)
|
||||||
|
) {
|
||||||
// If we have an existing incomplete pair, add it to the result
|
// If we have an existing incomplete pair, add it to the result
|
||||||
if (currentPair && currentPair.key) {
|
if (currentPair && currentPair.key) {
|
||||||
queryPairs.push({
|
queryPairs.push({
|
||||||
|
|||||||
70
frontend/src/utils/tokenUtils.ts
Normal file
70
frontend/src/utils/tokenUtils.ts
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
import FilterQueryLexer from 'parser/FilterQueryLexer';
|
||||||
|
|
||||||
|
export function isKeyToken(tokenType: number): boolean {
|
||||||
|
return tokenType === FilterQueryLexer.KEY;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to check if a token is an operator
|
||||||
|
export function isOperatorToken(tokenType: number): boolean {
|
||||||
|
return [
|
||||||
|
FilterQueryLexer.EQUALS,
|
||||||
|
FilterQueryLexer.NOT_EQUALS,
|
||||||
|
FilterQueryLexer.NEQ,
|
||||||
|
FilterQueryLexer.LT,
|
||||||
|
FilterQueryLexer.LE,
|
||||||
|
FilterQueryLexer.GT,
|
||||||
|
FilterQueryLexer.GE,
|
||||||
|
FilterQueryLexer.LIKE,
|
||||||
|
FilterQueryLexer.NOT_LIKE,
|
||||||
|
FilterQueryLexer.ILIKE,
|
||||||
|
FilterQueryLexer.NOT_ILIKE,
|
||||||
|
FilterQueryLexer.BETWEEN,
|
||||||
|
FilterQueryLexer.EXISTS,
|
||||||
|
FilterQueryLexer.REGEXP,
|
||||||
|
FilterQueryLexer.CONTAINS,
|
||||||
|
FilterQueryLexer.IN,
|
||||||
|
FilterQueryLexer.NOT,
|
||||||
|
].includes(tokenType);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to check if a token is a value
|
||||||
|
export function isValueToken(tokenType: number): boolean {
|
||||||
|
return [
|
||||||
|
FilterQueryLexer.QUOTED_TEXT,
|
||||||
|
FilterQueryLexer.NUMBER,
|
||||||
|
FilterQueryLexer.BOOL,
|
||||||
|
FilterQueryLexer.KEY,
|
||||||
|
].includes(tokenType);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to check if a token is a conjunction
|
||||||
|
export function isConjunctionToken(tokenType: number): boolean {
|
||||||
|
return [FilterQueryLexer.AND, FilterQueryLexer.OR].includes(tokenType);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to check if a token is a bracket
|
||||||
|
export function isBracketToken(tokenType: number): boolean {
|
||||||
|
return [
|
||||||
|
FilterQueryLexer.LPAREN,
|
||||||
|
FilterQueryLexer.RPAREN,
|
||||||
|
FilterQueryLexer.LBRACK,
|
||||||
|
FilterQueryLexer.RBRACK,
|
||||||
|
].includes(tokenType);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to check if an operator typically uses bracket values (multi-value operators)
|
||||||
|
export function isMultiValueOperator(operatorToken?: string): boolean {
|
||||||
|
if (!operatorToken) return false;
|
||||||
|
|
||||||
|
const upperOp = operatorToken.toUpperCase();
|
||||||
|
return upperOp === 'IN' || upperOp === 'NOT IN';
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isFunctionToken(tokenType: number): boolean {
|
||||||
|
return [
|
||||||
|
FilterQueryLexer.HAS,
|
||||||
|
FilterQueryLexer.HASANY,
|
||||||
|
FilterQueryLexer.HASALL,
|
||||||
|
FilterQueryLexer.HASNONE,
|
||||||
|
].includes(tokenType);
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user