Daniele Teti 2022-08-09 13:02:29 +02:00
parent 2e91fb631e
commit 31dee93a3e
7 changed files with 89 additions and 62 deletions

View File

@ -528,6 +528,8 @@ The current beta release is named 3.2.2-nitrogen. If you want to stay on the-edg
- ✅ Improved! Now `TMVCStaticFileMiddleware` is able to manage high-level criteria to show/hide/mask specific files in the documetn web root. Check [Issue 548](https://github.com/danieleteti/delphimvcframework/issues/548) and the updated sample `samples\middleware_staticfiles\` for more info.
- ✅ Improved! In case of multiple MVCPath, Swagger consider only the first one (Thanks to V. Ferri and our sponsors)
- ⚡New! Mechanism to customize the JWT claims setup using the client request as suggested in [issue495](https://github.com/danieleteti/delphimvcframework/issues/495)
- ⚡New! Added `TMVCActiveRecord.Merge<T>(CurrentListOfT, ChangesOfT)` to allow merge between two lists of `TMVCActiveRecord` descendants using `UnitOfWork` design pattern. Check the button "Merge" in demo "activerecord_showcase".
@ -707,6 +709,8 @@ The current beta release is named 3.2.2-nitrogen. If you want to stay on the-edg
- Fix https://github.com/danieleteti/delphimvcframework/issues/570 (Thanks [Marcos Nielsen](https://github.com/marcosnielsen))
- Fix https://github.com/danieleteti/delphimvcframework/issues/565
- Merged [PR#543](https://github.com/danieleteti/delphimvcframework/pull/543) (Now the `PathInfo` is trimmed so the router convert this "http://myserver.com/one " to this "http://myserver.com/one")
- Fix for nil objects in lists during serialization

View File

@ -23,9 +23,9 @@ procedure CreateMySQLPrivateConnDef(AIsPooled: boolean);
var
LParams: TStringList;
begin
{
docker run --detach --env MARIADB_USER=example-user --env MARIADB_PASSWORD=my_cool_secret --env MARIADB_ROOT_PASSWORD=root -p 3306:3306 mariadb:latest
}
{
docker run --detach --env MARIADB_USER=example-user --env MARIADB_PASSWORD=my_cool_secret --env MARIADB_ROOT_PASSWORD=root -p 3306:3306 mariadb:latest
}
LParams := TStringList.Create;
try
@ -35,7 +35,7 @@ begin
LParams.Add('User_Name=root');
LParams.Add('Password=root');
LParams.Add('TinyIntFormat=Boolean'); { it's the default }
LParams.Add('CharacterSet=utf8mb4'); //not utf8!!
LParams.Add('CharacterSet=utf8mb4'); // not utf8!!
if AIsPooled then
begin
LParams.Add('Pooled=True');
@ -55,9 +55,9 @@ procedure CreateMSSQLServerPrivateConnDef(AIsPooled: boolean);
var
LParams: TStringList;
begin
{
docker run -e "ACCEPT_EULA=Y" -e "SA_PASSWORD=!SA_password!" -p 1433:1433 -d mcr.microsoft.com/mssql/server:2019-latest
}
{
docker run -e "ACCEPT_EULA=Y" -e "SA_PASSWORD=!SA_password!" -p 1433:1433 -d mcr.microsoft.com/mssql/server:2019-latest
}
// [ACTIVERECORDB_SQLSERVER]
// Database=activerecorddb
@ -69,10 +69,10 @@ begin
LParams := TStringList.Create;
try
LParams.Add('Database=activerecorddb');
// LParams.Add('OSAuthent=Yes');
LParams.Add('User_Name=sa');
LParams.Add('Password=!SA_password!');
LParams.Add('Server=DANIELETETI');
LParams.Add('OSAuthent=Yes');
// LParams.Add('User_Name=sa');
// LParams.Add('Password=sa');
LParams.Add('Server=DANIELETETI\SQLEXPRESS');
// LParams.Add('TinyIntFormat=Boolean'); { it's the default }
if AIsPooled then
begin
@ -95,7 +95,8 @@ var
begin
LParams := TStringList.Create;
try
LParams.Add('Database=' + TPath.GetFullPath(TPath.Combine('..', 'data\ACTIVERECORDDB.FDB')));
LParams.Add('Database=' + TPath.GetFullPath(TPath.Combine('..',
'data\ACTIVERECORDDB.FDB')));
LParams.Add('Protocol=TCPIP');
LParams.Add('Server=localhost');
LParams.Add('User_Name=sysdba');
@ -122,7 +123,8 @@ var
begin
LParams := TStringList.Create;
try
LParams.Add('Database=' + TPath.GetFullPath(TPath.Combine('..\..', 'data\ACTIVERECORDDB.IB')));
LParams.Add('Database=' + TPath.GetFullPath(TPath.Combine('..\..',
'data\ACTIVERECORDDB.IB')));
LParams.Add('Protocol=TCPIP');
LParams.Add('Server=localhost');
LParams.Add('User_Name=sysdba');
@ -179,7 +181,8 @@ var
begin
LParams := TStringList.Create;
try
lFName := TPath.Combine(TPath.GetDirectoryName(ParamStr(0)), '..\..\data\activerecorddb.db');
lFName := TPath.Combine(TPath.GetDirectoryName(ParamStr(0)),
'..\..\data\activerecorddb.db');
LParams.Add('Database=' + lFName);
LParams.Add('StringFormat=Unicode');
if AIsPooled then

View File

@ -1008,6 +1008,7 @@ const
cRQL2 = 'and(eq(City,"Rome"),or(contains(CompanyName,"GAS"),contains(CompanyName,"Motors")))';
begin
LoadCustomers;
Log('** RQL Queries Test');
Log('>> RQL Query (1) - ' + cRQL1);
lList := TMVCActiveRecord.SelectRQL(TCustomer, cRQL1, 20);

View File

@ -1,3 +1,4 @@
and(eq(City,"Rome"),or(contains(CompanyName,"GAS"),contains(CompanyName,"Motors")))
starts(nome,"J")
out(name,["daniele","scott"])
out ( value , [ 1 , 2 , 3 ] )

View File

@ -3280,53 +3280,6 @@ begin
begin
Result := Result + ';' + lRQLSortingAndLimitPart;
end;
//
// var Pieces := RQL.Split([';']);
// if Pieces[0].Trim.Length > 0 then
// begin
// Result := 'and('+fDefaultRQLFilter + ',' + Pieces[0] + ');' + string.Join(';', Pieces, 1, Length(Pieces)-1);
// end
// else
// begin
// Result := fDefaultRQLFilter + ';' + string.Join(';', Pieces, 1, Length(Pieces)-1);
// end;
// end
//
//
//
// if not fDefaultRQLFilter.IsEmpty then
// begin
// if RQL.Contains(';') then
// begin
// var Pieces := RQL.Split([';']);
// if Pieces[0].Trim.Length > 0 then
// begin
// Result := 'and('+fDefaultRQLFilter + ',' + Pieces[0] + ');' + string.Join(';', Pieces, 1, Length(Pieces)-1);
// end
// else
// begin
// Result := fDefaultRQLFilter + ';' + string.Join(';', Pieces, 1, Length(Pieces)-1);
// end;
// end
// else
// begin
// if RQL.IsEmpty then
// begin
// Result := fDefaultRQLFilter
// end
// else
// begin
// Result := MergeRQL(Result, fPartitionInfo.RQLFilter);
// end;
// //Result := 'and('+fDefaultRQLFilter + ',' + RQL + ')';
// end;
// end
// else
// begin
// Result := RQL;
// end;
// Result := MergeRQL(Result, fPartitionInfo.RQLFilter);
end;
function TMVCSQLGenerator.MergeSQLFilter(const SQL1, SQL2: String): String;
@ -3430,7 +3383,8 @@ begin
begin
lQry.Connection := Connection;
end;
lQry.SQL.Text := SQL;
// lQry.SQL.Clear;
// lQry.SQL.Add(SQL);
// lQry.Prepare;
if Length(ValueTypes) = 0 then
begin

View File

@ -39,6 +39,7 @@ type
function RQLWhereToSQL(const aRQLWhere: TRQLWhere): string;
function RQLLogicOperatorToSQL(const aRQLFIlter: TRQLLogicOperator): string;
protected
procedure AdjustAST(const aRQLAST: TRQLAbstractSyntaxTree); override;
function RQLCustom2SQL(const aRQLCustom: TRQLCustom): string; override;
end;
@ -49,6 +50,34 @@ uses
{ TRQLMSSQLCompiler }
procedure TRQLMSSQLCompiler.AdjustAST(const aRQLAST: TRQLAbstractSyntaxTree);
var
lLimit, lTmp: TRQLCustom;
lSort: TRQLSort;
begin
inherited;
if aRQLAST.TreeContainsToken(tkLimit, lLimit) then
begin
if TRQLLimit(lLimit).Count = 0 then
begin
raise ERQLException.Create('MSSQL Server do not support "FETCH NEXT 0"');
end;
if not aRQLAST.TreeContainsToken(tkSort, lTmp) then
begin
if aRQLAST.Last is TRQLLimit then
begin
lSort := TRQLSort.Create;
aRQLAST.Insert(aRQLAST.Count-1, lSort);
lSort.Add('+', GetPKFieldName);
end
else
begin
raise ERQLException.Create('Invalid position for RQLLimit');
end;
end;
end;
end;
function TRQLMSSQLCompiler.RQLCustom2SQL(
const aRQLCustom: TRQLCustom): string;
begin

View File

@ -94,6 +94,7 @@ type
function GetDatabaseFieldName(const RQLPropertyName: string; const UsePropertyNameIfAttributeDoesntExists: Boolean = False): string;
function QuoteStringArray(const aStringArray: TArray<string>): TArray<string>;
function RQLCustom2SQL(const aRQLCustom: TRQLCustom): string; virtual; abstract;
procedure AdjustAST(const aRQLAST: TRQLAbstractSyntaxTree); virtual;
public
constructor Create(const Mapping: TMVCFieldsMapping); virtual;
procedure AST2SQL(const aRQLAST: TRQLAbstractSyntaxTree; out aSQL: string); virtual;
@ -104,6 +105,7 @@ type
// or if the field name contains spaces.
function GetFieldNameForSQL(const FieldName: string): string; virtual;
function GetParamNameForSQL(const FieldName: string): string; virtual;
function GetPKFieldName: String;
end;
TRQLCompilerClass = class of TRQLCompiler;
@ -368,6 +370,28 @@ begin
end;
// if fAST.TreeContainsToken(tkLimit, lRQLItem) then
// begin
// if (TRQLLimit(lRQLItem).Count > 0) and (not fAST.TreeContainsToken(tkSort, lRQLItem)) then
// begin
// lSort := TRQLSort.Create;
// lSort.Add('+', '1');
// fAST.Insert(fAST.Count-1, lSort);
// end
// else
// begin
// fAST.Remove(lRQLItem);
// fAST.TreeContainsToken(tk)
// fAST.Add(lAlwaysFalse);
// lAlwaysFalse.OpLeft := '1';
// lAlwaysFalse.OpRight := '2';
// lAlwaysFalse.RightValueType := vtInteger;
// lAlwaysFalse.Token := tkEq;
// end;
// end;
if UseFilterOnly then
{If we need only the filter part, remove sort and limit tokens}
begin
@ -1151,6 +1175,11 @@ end;
{ TRQLCompiler }
procedure TRQLCompiler.AdjustAST(const aRQLAST: TRQLAbstractSyntaxTree);
begin
//do nothing
end;
procedure TRQLCompiler.AST2SQL(const aRQLAST: TRQLAbstractSyntaxTree;
out aSQL: string);
var
@ -1165,6 +1194,7 @@ begin
For MSSQL syntax you need to rearrange in: limit, filters, sort
}
AdjustAST(aRQLAST);
lBuff := TStringBuilder.Create;
try
for lItem in aRQLAST do
@ -1237,6 +1267,11 @@ begin
Result := FieldName.Replace(' ', '_', [rfReplaceAll]);
end;
function TRQLCompiler.GetPKFieldName: String;
begin
Result := fMapping[0].InstanceFieldName;
end;
function TRQLCompiler.GetTableNameForSQL(const TableName: string): string;
begin
if TableName.Contains(' ') then