mirror of
https://github.com/danieleteti/delphimvcframework.git
synced 2024-11-15 15:55:54 +01:00
Merge pull request #168 from joaoduarte19/rqlparser
Changes in the RQL parser
This commit is contained in:
commit
00f51f8c81
@ -113,6 +113,10 @@ begin
|
||||
begin
|
||||
Result := Format('(%s != %s)', [lDBFieldName, lValue]);
|
||||
end;
|
||||
tkContains:
|
||||
begin
|
||||
Result := Format('(LOWER(%s) LIKE ''%%%s%%'')', [lDBFieldName, lValue.DeQuotedString.ToLower ])
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
217
sources/MVCFramework.RQL.AST2PostgreSQL.pas
Normal file
217
sources/MVCFramework.RQL.AST2PostgreSQL.pas
Normal file
@ -0,0 +1,217 @@
|
||||
// *************************************************************************** }
|
||||
//
|
||||
// Delphi MVC Framework
|
||||
//
|
||||
// Copyright (c) 2010-2018 Daniele Teti and the DMVCFramework Team
|
||||
//
|
||||
// https://github.com/danieleteti/delphimvcframework
|
||||
//
|
||||
// ***************************************************************************
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// ***************************************************************************
|
||||
|
||||
unit MVCFramework.RQL.AST2PostgreSQL;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
MVCFramework.RQL.Parser;
|
||||
|
||||
type
|
||||
TRQLPostgreSQLCompiler = class(TRQLCompiler)
|
||||
private
|
||||
function RQLFilterToSQL(const aRQLFIlter: TRQLFilter): string;
|
||||
function RQLSortToSQL(const aRQLSort: TRQLSort): string;
|
||||
function RQLLimitToSQL(const aRQLLimit: TRQLLimit): string;
|
||||
function RQLWhereToSQL(const aRQLWhere: TRQLWhere): string;
|
||||
function RQLLogicOperatorToSQL(const aRQLFIlter: TRQLLogicOperator): string;
|
||||
function RQLCustom2SQL(const aRQLCustom: TRQLCustom): string;
|
||||
public
|
||||
procedure AST2SQL(const aRQLAST: TRQLAbstractSyntaxTree; out aSQL: string); override;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
System.SysUtils,
|
||||
MVCFramework.RQL.AST2FirebirdSQL;
|
||||
|
||||
{ TRQLPostgreSQLCompiler }
|
||||
|
||||
function TRQLPostgreSQLCompiler.RQLCustom2SQL(
|
||||
const aRQLCustom: TRQLCustom): string;
|
||||
begin
|
||||
if aRQLCustom is TRQLFilter then
|
||||
begin
|
||||
Result := RQLFilterToSQL(TRQLFilter(aRQLCustom));
|
||||
end
|
||||
else if aRQLCustom is TRQLLogicOperator then
|
||||
begin
|
||||
Result := RQLLogicOperatorToSQL(TRQLLogicOperator(aRQLCustom));
|
||||
end
|
||||
else if aRQLCustom is TRQLSort then
|
||||
begin
|
||||
Result := RQLSortToSQL(TRQLSort(aRQLCustom));
|
||||
end
|
||||
else if aRQLCustom is TRQLLimit then
|
||||
begin
|
||||
Result := RQLLimitToSQL(TRQLLimit(aRQLCustom));
|
||||
end
|
||||
else if aRQLCustom is TRQLWhere then
|
||||
begin
|
||||
Result := RQLWhereToSQL(TRQLWhere(aRQLCustom));
|
||||
end
|
||||
else
|
||||
raise ERQLException.CreateFmt('Unknown token in compiler: %s', [aRQLCustom.ClassName]);
|
||||
end;
|
||||
|
||||
function TRQLPostgreSQLCompiler.RQLFilterToSQL(const aRQLFIlter: TRQLFilter): string;
|
||||
var
|
||||
lValue, lDBFieldName: string;
|
||||
begin
|
||||
if aRQLFIlter.RightIsString then
|
||||
lValue := aRQLFIlter.OpRight.QuotedString('''')
|
||||
else
|
||||
lValue := aRQLFIlter.OpRight;
|
||||
|
||||
lDBFieldName := GetDatabaseFieldName(aRQLFIlter.OpLeft);
|
||||
|
||||
case aRQLFIlter.Token of
|
||||
tkEq:
|
||||
begin
|
||||
Result := Format('(%s = %s)', [lDBFieldName, lValue]);
|
||||
end;
|
||||
tkLt:
|
||||
begin
|
||||
Result := Format('(%s < %s)', [lDBFieldName, lValue]);
|
||||
end;
|
||||
tkLe:
|
||||
begin
|
||||
Result := Format('(%s <= %s)', [lDBFieldName, lValue]);
|
||||
end;
|
||||
tkGt:
|
||||
begin
|
||||
Result := Format('(%s > %s)', [lDBFieldName, lValue]);
|
||||
end;
|
||||
tkGe:
|
||||
begin
|
||||
Result := Format('(%s >= %s)', [lDBFieldName, lValue]);
|
||||
end;
|
||||
tkNe:
|
||||
begin
|
||||
Result := Format('(%s != %s)', [lDBFieldName, lValue]);
|
||||
end;
|
||||
tkContains:
|
||||
begin
|
||||
Result := Format('(LOWER(%s) LIKE ''%%%s%%'')', [lDBFieldName, lValue.DeQuotedString.ToLower ])
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TRQLPostgreSQLCompiler.RQLLimitToSQL(const aRQLLimit: TRQLLimit): string;
|
||||
begin
|
||||
Result := Format(' LIMIT %d OFFSET %d', [aRQLLimit.Count, aRQLLimit.Start]);
|
||||
end;
|
||||
|
||||
function TRQLPostgreSQLCompiler.RQLLogicOperatorToSQL(const aRQLFIlter: TRQLLogicOperator): string;
|
||||
var
|
||||
lJoin: string;
|
||||
lRQLCustom: TRQLCustom;
|
||||
lFirst: Boolean;
|
||||
begin
|
||||
case aRQLFIlter.Token of
|
||||
tkAnd:
|
||||
begin
|
||||
lJoin := ' and ';
|
||||
end;
|
||||
tkOr:
|
||||
begin
|
||||
lJoin := ' or ';
|
||||
end;
|
||||
else
|
||||
raise ERQLException.Create('Invalid token in RQLLogicOperator');
|
||||
end;
|
||||
|
||||
Result := '';
|
||||
lFirst := True;
|
||||
for lRQLCustom in aRQLFIlter.FilterAST do
|
||||
begin
|
||||
if not lFirst then
|
||||
begin
|
||||
Result := Result + lJoin;
|
||||
end;
|
||||
lFirst := False;
|
||||
Result := Result + RQLCustom2SQL(lRQLCustom);
|
||||
end;
|
||||
Result := '(' + Result + ')';
|
||||
end;
|
||||
|
||||
function TRQLPostgreSQLCompiler.RQLSortToSQL(const aRQLSort: TRQLSort): string;
|
||||
var
|
||||
I: Integer;
|
||||
begin
|
||||
Result := ' ORDER BY';
|
||||
for I := 0 to aRQLSort.Fields.Count - 1 do
|
||||
begin
|
||||
if I > 0 then
|
||||
Result := Result + ',';
|
||||
Result := Result + ' ' + GetDatabaseFieldName(aRQLSort.Fields[I]);
|
||||
if aRQLSort.Signs[I] = '+' then
|
||||
Result := Result + ' ASC'
|
||||
else
|
||||
Result := Result + ' DESC';
|
||||
end;
|
||||
end;
|
||||
|
||||
function TRQLPostgreSQLCompiler.RQLWhereToSQL(const aRQLWhere: TRQLWhere): string;
|
||||
begin
|
||||
Result := ' WHERE ';
|
||||
end;
|
||||
|
||||
procedure TRQLPostgreSQLCompiler.AST2SQL(const aRQLAST: TRQLAbstractSyntaxTree;
|
||||
out aSQL: string);
|
||||
var
|
||||
lBuff: TStringBuilder;
|
||||
lItem: TRQLCustom;
|
||||
begin
|
||||
inherited;
|
||||
|
||||
{
|
||||
Here you can rearrange tokens in the list, for example:
|
||||
For firebird and mysql syntax you have: filters, sort, limit (default)
|
||||
For MSSQL syntax you need to rearrange in: limit, filters, sort
|
||||
}
|
||||
|
||||
lBuff := TStringBuilder.Create;
|
||||
try
|
||||
for lItem in aRQLAST do
|
||||
begin
|
||||
lBuff.Append(RQLCustom2SQL(lItem));
|
||||
end;
|
||||
aSQL := lBuff.ToString;
|
||||
finally
|
||||
lBuff.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
initialization
|
||||
|
||||
TRQLCompilerRegistry.Instance.RegisterCompiler('postgresql', TRQLPostgreSQLCompiler);
|
||||
|
||||
finalization
|
||||
|
||||
TRQLCompilerRegistry.Instance.UnRegisterCompiler('postgresql');
|
||||
|
||||
end.
|
@ -76,8 +76,8 @@ uses
|
||||
|
||||
type
|
||||
TRQLToken = (tkEq, tkLt, tkLe, tkGt, tkGe, tkNe, tkAnd, tkOr, tkSort, tkLimit, { RQL } tkAmpersand, tkEOF, tkOpenPar, tkClosedPar,
|
||||
tkComma, tkSemicolon, tkPlus, tkMinus, tkDblQuote, tkQuote, tkSpace, tkUnknown);
|
||||
|
||||
tkComma, tkSemicolon, tkPlus, tkMinus, tkDblQuote, tkQuote, tkSpace, tkContains, tkUnknown);
|
||||
|
||||
TRQLCustom = class;
|
||||
|
||||
TRQLAbstractSyntaxTree = class(TObjectList<TRQLCustom>)
|
||||
@ -486,6 +486,12 @@ begin
|
||||
fCurrToken := tkLimit;
|
||||
Exit(fCurrToken);
|
||||
end;
|
||||
if (lChar = 'c') and (C(1) = 'o') and (C(2) = 'n') and (C(3) = 't') and (C(4) = 'a') and (C(5) = 'i') and (C(6) = 'n') and (C(7) = 's') then
|
||||
begin
|
||||
Skip(8);
|
||||
fCurrToken := tkContains;
|
||||
Exit(fCurrToken);
|
||||
end;
|
||||
if (lChar = ' ') then
|
||||
begin
|
||||
fCurrToken := tkSpace;
|
||||
@ -562,7 +568,7 @@ begin
|
||||
Result := True;
|
||||
lTk := GetToken;
|
||||
case lTk of
|
||||
tkEq, tkLt, tkLe, tkGt, tkGe, tkNe:
|
||||
tkEq, tkLt, tkLe, tkGt, tkGe, tkNe, tkContains:
|
||||
begin
|
||||
ParseBinOperator(lTk, fAST);
|
||||
end;
|
||||
@ -640,7 +646,7 @@ begin
|
||||
EatWhiteSpaces;
|
||||
lToken := GetToken;
|
||||
case lToken of
|
||||
tkEq, tkLt, tkLe, tkGt, tkGe, tkNe:
|
||||
tkEq, tkLt, tkLe, tkGt, tkGe, tkNe, tkContains:
|
||||
begin
|
||||
ParseBinOperator(lToken, lLogicOp.FilterAST);
|
||||
end;
|
||||
|
@ -1,3 +1,4 @@
|
||||
contains(nome,"João")
|
||||
sort(+last_name);limit(0,1)
|
||||
limit(1,5)
|
||||
sort(+nome, -cognome)
|
||||
|
@ -6,7 +6,8 @@ uses
|
||||
MVCFramework.RQL.AST2FirebirdSQL in '..\..\sources\MVCFramework.RQL.AST2FirebirdSQL.pas',
|
||||
MVCFramework.RQL.Parser in '..\..\sources\MVCFramework.RQL.Parser.pas',
|
||||
MVCFramework.RQL.AST2MySQL in '..\..\sources\MVCFramework.RQL.AST2MySQL.pas',
|
||||
MVCFramework.RQL.AST2InterbaseSQL in '..\..\sources\MVCFramework.RQL.AST2InterbaseSQL.pas';
|
||||
MVCFramework.RQL.AST2InterbaseSQL in '..\..\sources\MVCFramework.RQL.AST2InterbaseSQL.pas',
|
||||
MVCFramework.RQL.AST2PostgreSQL in '..\..\sources\MVCFramework.RQL.AST2PostgreSQL.pas';
|
||||
|
||||
{$R *.res}
|
||||
|
||||
|
@ -110,6 +110,7 @@
|
||||
<DCCReference Include="..\..\sources\MVCFramework.RQL.Parser.pas"/>
|
||||
<DCCReference Include="..\..\sources\MVCFramework.RQL.AST2MySQL.pas"/>
|
||||
<DCCReference Include="..\..\sources\MVCFramework.RQL.AST2InterbaseSQL.pas"/>
|
||||
<DCCReference Include="..\..\sources\MVCFramework.RQL.AST2PostgreSQL.pas"/>
|
||||
<BuildConfiguration Include="Release">
|
||||
<Key>Cfg_2</Key>
|
||||
<CfgParent>Base</CfgParent>
|
||||
@ -572,3 +573,11 @@
|
||||
<Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/>
|
||||
<Import Project="$(MSBuildProjectName).deployproj" Condition="Exists('$(MSBuildProjectName).deployproj')"/>
|
||||
</Project>
|
||||
|
||||
<!-- EurekaLog First Line
|
||||
[Exception Log]
|
||||
EurekaLog Version=7007
|
||||
Activate=0
|
||||
DeleteMapAfterCompile=0
|
||||
Encrypt Password=""
|
||||
EurekaLog Last Line -->
|
||||
|
Loading…
Reference in New Issue
Block a user