mirror of
https://gitlab.com/freepascal.org/fpc/pas2js.git
synced 2025-08-27 11:50:14 +02:00
* Allow LIKE in filters
This commit is contained in:
parent
91021a0107
commit
5013439753
@ -24,9 +24,9 @@ interface
|
|||||||
|
|
||||||
uses
|
uses
|
||||||
{$IFDEF FPC_DOTTEDUNITS}
|
{$IFDEF FPC_DOTTEDUNITS}
|
||||||
System.Classes, System.SysUtils, System.Contnrs;
|
System.Classes, System.SysUtils, System.Contnrs, JSApi.JS;
|
||||||
{$ELSE}
|
{$ELSE}
|
||||||
Classes, SysUtils, contnrs;
|
Classes, SysUtils, contnrs, js;
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
|
|
||||||
Type
|
Type
|
||||||
@ -35,7 +35,7 @@ Type
|
|||||||
ttMod, ttMul, ttLeft, ttRight, ttLessThanEqual,
|
ttMod, ttMul, ttLeft, ttRight, ttLessThanEqual,
|
||||||
ttLargerThanEqual, ttunequal, ttNumber, ttString, ttIdentifier,
|
ttLargerThanEqual, ttunequal, ttNumber, ttString, ttIdentifier,
|
||||||
ttComma, ttAnd, ttOr, ttXor, ttTrue, ttFalse, ttNot, ttif,
|
ttComma, ttAnd, ttOr, ttXor, ttTrue, ttFalse, ttNot, ttif,
|
||||||
ttCase, ttPower, ttEOF); // keep ttEOF last
|
ttCase, ttPower, ttLike, ttEOF); // keep ttEOF last
|
||||||
|
|
||||||
TExprFloat = Double;
|
TExprFloat = Double;
|
||||||
|
|
||||||
@ -45,7 +45,7 @@ Const
|
|||||||
ttunequal, ttPower];
|
ttunequal, ttPower];
|
||||||
ttComparisons = [ttLargerThan,ttLessthan,
|
ttComparisons = [ttLargerThan,ttLessthan,
|
||||||
ttLargerThanEqual,ttLessthanEqual,
|
ttLargerThanEqual,ttLessthanEqual,
|
||||||
ttEqual,ttUnequal];
|
ttEqual,ttUnequal, ttLike];
|
||||||
|
|
||||||
Type
|
Type
|
||||||
|
|
||||||
@ -66,6 +66,7 @@ Type
|
|||||||
FToken : String;
|
FToken : String;
|
||||||
FTokenType : TTokenType;
|
FTokenType : TTokenType;
|
||||||
private
|
private
|
||||||
|
FAllowLike: Boolean;
|
||||||
function GetCurrentChar: Char;
|
function GetCurrentChar: Char;
|
||||||
procedure ScanError(Msg: String);
|
procedure ScanError(Msg: String);
|
||||||
protected
|
protected
|
||||||
@ -88,6 +89,7 @@ Type
|
|||||||
Property Source : String Read FSource Write SetSource;
|
Property Source : String Read FSource Write SetSource;
|
||||||
Property Pos : Integer Read FPos;
|
Property Pos : Integer Read FPos;
|
||||||
Property CurrentChar : Char Read GetCurrentChar;
|
Property CurrentChar : Char Read GetCurrentChar;
|
||||||
|
Property AllowLike : Boolean Read FAllowLike Write FAllowLike;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
EExprScanner = Class(Exception);
|
EExprScanner = Class(Exception);
|
||||||
@ -131,7 +133,7 @@ Type
|
|||||||
Protected
|
Protected
|
||||||
Procedure CheckSameNodeTypes;
|
Procedure CheckSameNodeTypes;
|
||||||
Public
|
Public
|
||||||
Constructor Create(ALeft,ARight : TFPExprNode);
|
Constructor Create(ALeft,ARight : TFPExprNode); virtual;
|
||||||
Destructor Destroy; override;
|
Destructor Destroy; override;
|
||||||
Procedure InitAggregate; override;
|
Procedure InitAggregate; override;
|
||||||
Procedure UpdateAggregate; override;
|
Procedure UpdateAggregate; override;
|
||||||
@ -196,6 +198,21 @@ Type
|
|||||||
Function AsString : string ; override;
|
Function AsString : string ; override;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ TFPEqualOperation }
|
||||||
|
|
||||||
|
{ TFPLikeOperation }
|
||||||
|
|
||||||
|
TFPLikeOperation = Class(TFPBooleanResultOperation)
|
||||||
|
Protected
|
||||||
|
FRE : TJSRegexp;
|
||||||
|
FLast : String;
|
||||||
|
Function GetNodeValue : TFPExpressionResult; override;
|
||||||
|
Public
|
||||||
|
procedure check; override;
|
||||||
|
Function AsString : string ; override;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
{ TFPUnequalOperation }
|
{ TFPUnequalOperation }
|
||||||
|
|
||||||
TFPUnequalOperation = Class(TFPEqualOperation)
|
TFPUnequalOperation = Class(TFPEqualOperation)
|
||||||
@ -712,10 +729,12 @@ Type
|
|||||||
function GetAsCurrency: Currency;
|
function GetAsCurrency: Currency;
|
||||||
function GetAsInteger: NativeInt;
|
function GetAsInteger: NativeInt;
|
||||||
function GetAsString: String;
|
function GetAsString: String;
|
||||||
|
function GetAllowLike: Boolean;
|
||||||
function MatchNodes(Todo, Match: TFPExprNode): TFPExprNode;
|
function MatchNodes(Todo, Match: TFPExprNode): TFPExprNode;
|
||||||
procedure CheckNodes(var Left, Right: TFPExprNode);
|
procedure CheckNodes(var Left, Right: TFPExprNode);
|
||||||
procedure SetBuiltIns(const AValue: TBuiltInCategories);
|
procedure SetBuiltIns(const AValue: TBuiltInCategories);
|
||||||
procedure SetIdentifiers(const AValue: TFPExprIdentifierDefs);
|
procedure SetIdentifiers(const AValue: TFPExprIdentifierDefs);
|
||||||
|
procedure SetAllowLike(AValue: Boolean);
|
||||||
Protected
|
Protected
|
||||||
procedure ParserError(Msg: String);
|
procedure ParserError(Msg: String);
|
||||||
procedure SetExpression(const AValue: String); virtual;
|
procedure SetExpression(const AValue: String); virtual;
|
||||||
@ -751,6 +770,7 @@ Type
|
|||||||
Function HasAggregate : Boolean;
|
Function HasAggregate : Boolean;
|
||||||
Procedure InitAggregate;
|
Procedure InitAggregate;
|
||||||
Procedure UpdateAggregate;
|
Procedure UpdateAggregate;
|
||||||
|
Property AllowLike : Boolean Read GetAllowLike Write SetAllowLike;
|
||||||
Property AsFloat : TExprFloat Read GetAsFloat;
|
Property AsFloat : TExprFloat Read GetAsFloat;
|
||||||
Property AsCurrency : Currency Read GetAsCurrency;
|
Property AsCurrency : Currency Read GetAsCurrency;
|
||||||
Property AsInteger : NativeInt Read GetAsInteger;
|
Property AsInteger : NativeInt Read GetAsInteger;
|
||||||
@ -876,6 +896,7 @@ Resourcestring
|
|||||||
SErrCaseLabelNotAConst = 'Case label %d "%s" is not a constant expression';
|
SErrCaseLabelNotAConst = 'Case label %d "%s" is not a constant expression';
|
||||||
SErrCaseLabelType = 'Case label %d "%s" needs type %s, but has type %s';
|
SErrCaseLabelType = 'Case label %d "%s" needs type %s, but has type %s';
|
||||||
SErrCaseValueType = 'Case value %d "%s" needs type %s, but has type %s';
|
SErrCaseValueType = 'Case value %d "%s" needs type %s, but has type %s';
|
||||||
|
SErrStringTypeRequired = 'Expression requires string type, got type "%s" for %s';
|
||||||
|
|
||||||
{ ---------------------------------------------------------------------
|
{ ---------------------------------------------------------------------
|
||||||
Auxiliary functions
|
Auxiliary functions
|
||||||
@ -1243,14 +1264,14 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Procedure TFPExpressionScanner.SkipWhiteSpace;
|
procedure TFPExpressionScanner.SkipWhiteSpace;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
While (FChar in WhiteSpace) and (FPos<=LSource) do
|
While (FChar in WhiteSpace) and (FPos<=LSource) do
|
||||||
NextPos;
|
NextPos;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Function TFPExpressionScanner.DoDelimiter : TTokenType;
|
function TFPExpressionScanner.DoDelimiter: TTokenType;
|
||||||
|
|
||||||
Var
|
Var
|
||||||
B : Boolean;
|
B : Boolean;
|
||||||
@ -1293,13 +1314,14 @@ begin
|
|||||||
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Procedure TFPExpressionScanner.ScanError(Msg : String);
|
procedure TFPExpressionScanner.ScanError(Msg: String);
|
||||||
|
|
||||||
begin
|
begin
|
||||||
Raise EExprScanner.Create(Msg)
|
Raise EExprScanner.Create(Msg)
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Function TFPExpressionScanner.DoString : TTokenType;
|
|
||||||
|
function TFPExpressionScanner.DoString: TTokenType;
|
||||||
|
|
||||||
Function TerminatingChar(C : Char) : boolean;
|
Function TerminatingChar(C : Char) : boolean;
|
||||||
|
|
||||||
@ -1351,7 +1373,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
{$endif}
|
{$endif}
|
||||||
|
|
||||||
Function TFPExpressionScanner.DoNumber(AKind: TNumberKind) : TTokenType;
|
function TFPExpressionScanner.DoNumber(AKind: TNumberKind): TTokenType;
|
||||||
|
|
||||||
Var
|
Var
|
||||||
C : Char;
|
C : Char;
|
||||||
@ -1402,7 +1424,7 @@ begin
|
|||||||
Result:=ttNumber;
|
Result:=ttNumber;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Function TFPExpressionScanner.DoIdentifier : TTokenType;
|
function TFPExpressionScanner.DoIdentifier: TTokenType;
|
||||||
|
|
||||||
Var
|
Var
|
||||||
C : Char;
|
C : Char;
|
||||||
@ -1445,11 +1467,13 @@ begin
|
|||||||
Result:=ttcase
|
Result:=ttcase
|
||||||
else if (S='mod') then
|
else if (S='mod') then
|
||||||
Result:=ttMod
|
Result:=ttMod
|
||||||
|
else if (S='like') and AllowLike then
|
||||||
|
Result:=ttLike
|
||||||
else
|
else
|
||||||
Result:=ttIdentifier;
|
Result:=ttIdentifier;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Function TFPExpressionScanner.GetToken : TTokenType;
|
function TFPExpressionScanner.GetToken: TTokenType;
|
||||||
|
|
||||||
Var
|
Var
|
||||||
C : Char;
|
C : Char;
|
||||||
@ -1588,6 +1612,11 @@ begin
|
|||||||
FIdentifiers.Assign(AValue)
|
FIdentifiers.Assign(AValue)
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TFPExpressionParser.SetAllowLike(AValue: Boolean);
|
||||||
|
begin
|
||||||
|
FScanner.AllowLike:=aValue;
|
||||||
|
end;
|
||||||
|
|
||||||
function TFPExpressionParser.Evaluate: TFPExpressionResult;
|
function TFPExpressionParser.Evaluate: TFPExpressionResult;
|
||||||
begin
|
begin
|
||||||
If (FExpression='') then
|
If (FExpression='') then
|
||||||
@ -1598,12 +1627,12 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
procedure TFPExpressionParser.EvaluateExpression(Out Result: TFPExpressionResult);
|
procedure TFPExpressionParser.EvaluateExpression(out Result: TFPExpressionResult);
|
||||||
begin
|
begin
|
||||||
Result:=Evaluate;
|
Result:=Evaluate;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TFPExpressionParser.ExtractNode(Var N : TFPExprNode) : Boolean;
|
function TFPExpressionParser.ExtractNode(var N: TFPExprNode): Boolean;
|
||||||
begin
|
begin
|
||||||
Result:=Assigned(FExprNode);
|
Result:=Assigned(FExprNode);
|
||||||
if Result then
|
if Result then
|
||||||
@ -1619,7 +1648,7 @@ begin
|
|||||||
Raise EExprParser.Create(Msg);
|
Raise EExprParser.Create(Msg);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Class function TFPExpressionParser.ConvertNode(Todo : TFPExprNode; ToType : TResultType): TFPExprNode;
|
class function TFPExpressionParser.ConvertNode(Todo: TFPExprNode; ToType: TResultType): TFPExprNode;
|
||||||
begin
|
begin
|
||||||
Result:=ToDo;
|
Result:=ToDo;
|
||||||
Case ToDo.NodeType of
|
Case ToDo.NodeType of
|
||||||
@ -1714,6 +1743,11 @@ begin
|
|||||||
Result:=String(Res.resValue);
|
Result:=String(Res.resValue);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TFPExpressionParser.GetAllowLike: Boolean;
|
||||||
|
begin
|
||||||
|
Result:=FScanner.AllowLike;
|
||||||
|
end;
|
||||||
|
|
||||||
{
|
{
|
||||||
Checks types of todo and match. If ToDO can be converted to it matches
|
Checks types of todo and match. If ToDO can be converted to it matches
|
||||||
the type of match, then a node is inserted.
|
the type of match, then a node is inserted.
|
||||||
@ -1824,6 +1858,7 @@ begin
|
|||||||
ttLargerThanEqual : C:=TFPGreaterThanEqualOperation;
|
ttLargerThanEqual : C:=TFPGreaterThanEqualOperation;
|
||||||
ttEqual : C:=TFPEqualOperation;
|
ttEqual : C:=TFPEqualOperation;
|
||||||
ttUnequal : C:=TFPUnequalOperation;
|
ttUnequal : C:=TFPUnequalOperation;
|
||||||
|
ttLike : C:=TFPLikeOperation;
|
||||||
Else
|
Else
|
||||||
ParserError(SErrUnknownComparison)
|
ParserError(SErrUnknownComparison)
|
||||||
end;
|
end;
|
||||||
@ -3238,6 +3273,56 @@ begin
|
|||||||
Result.ResultType:=rtBoolean;
|
Result.ResultType:=rtBoolean;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ TFPLikeOperation }
|
||||||
|
|
||||||
|
function TFPLikeOperation.GetNodeValue: TFPExpressionResult;
|
||||||
|
|
||||||
|
const
|
||||||
|
RESpecials = '([\$\+\[\]\(\)\\\.\*\^\?\|])';
|
||||||
|
|
||||||
|
Var
|
||||||
|
S: String;
|
||||||
|
RE : TJSRegexp;
|
||||||
|
|
||||||
|
begin
|
||||||
|
// We need to recreate a regexp every time, since the RE can change any time the right-hand expression changes
|
||||||
|
S:=String(Right.NodeValue.resValue);
|
||||||
|
if (FLast<>'') and (S=FLast) then
|
||||||
|
RE:=FRE
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
FLast:=S;
|
||||||
|
S:=TJSString(S).replace(TJSRegexp.new(RESpecials,'g'),'\$1');
|
||||||
|
S:=StringReplace(S,'%','(.*)',[rfReplaceAll]);
|
||||||
|
S:=StringReplace(S,'_','(.)',[rfReplaceAll]);
|
||||||
|
try
|
||||||
|
// Writeln('Ex: ',FLast,' -> ',S);
|
||||||
|
FRE:=TJSRegexp.New(S,'i');
|
||||||
|
Re:=FRe;
|
||||||
|
except
|
||||||
|
Result.resValue:=False;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
Result.resValue:=RE.Test(String(Left.NodeValue.resValue));
|
||||||
|
// Writeln('Checking : ',flast,' (',FRE.Source,') on ',Left.NodeValue.resValue,' : ', Result.resValue);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TFPLikeOperation.check;
|
||||||
|
begin
|
||||||
|
if Left.NodeType<>rtString then
|
||||||
|
RaiseParserError(SErrStringTypeRequired,[ResultTypeName(Left.NodeType),Left.AsString]);
|
||||||
|
if Right.NodeType<>rtString then
|
||||||
|
RaiseParserError(SErrStringTypeRequired,[ResultTypeName(Right.NodeType),Right.AsString]);
|
||||||
|
inherited check;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TFPLikeOperation.AsString: string;
|
||||||
|
begin
|
||||||
|
Result:=Left.AsString+' LIKE '+Right.AsString;
|
||||||
|
end;
|
||||||
|
|
||||||
{ TFPUnequalOperation }
|
{ TFPUnequalOperation }
|
||||||
|
|
||||||
function TFPUnequalOperation.AsString: string;
|
function TFPUnequalOperation.AsString: string;
|
||||||
|
@ -1392,6 +1392,7 @@ Var
|
|||||||
|
|
||||||
begin
|
begin
|
||||||
Result:=FilterExpressionClass.Create(Self);
|
Result:=FilterExpressionClass.Create(Self);
|
||||||
|
Result.AllowLike:=True;
|
||||||
for I:=0 to Fields.Count-1 do
|
for I:=0 to Fields.Count-1 do
|
||||||
if not (Fields[i].DataType in [ftBlob,ftMemo]) then
|
if not (Fields[i].DataType in [ftBlob,ftMemo]) then
|
||||||
Result.Identifiers.AddVariable(Fields[i].FieldName,FieldTypeToExpressionType(Fields[i].DataType),@GetFilterField);
|
Result.Identifiers.AddVariable(Fields[i].FieldName,FieldTypeToExpressionType(Fields[i].DataType),@GetFilterField);
|
||||||
|
Loading…
Reference in New Issue
Block a user