Daniele Teti 2020-09-30 11:16:10 +02:00
parent c3f10f357f
commit 057519d550
9 changed files with 230 additions and 36 deletions

View File

@ -1,7 +1,7 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{F8576ED6-649F-4E28-B364-1F60687C75F2}</ProjectGuid>
<ProjectVersion>19.0</ProjectVersion>
<ProjectVersion>19.1</ProjectVersion>
<FrameworkType>VCL</FrameworkType>
<MainSource>activerecord_showcase.dpr</MainSource>
<Base>True</Base>
@ -163,13 +163,13 @@
</Excluded_Packages>
</Delphi.Personality>
<Deployment Version="3">
<DeployFile LocalName="bin\activerecord_showcase.exe" Configuration="BUILD" Class="ProjectOutput">
<DeployFile LocalName="bin\activerecord_showcase.exe" Configuration="Debug" Class="ProjectOutput">
<Platform Name="Win32">
<RemoteName>activerecord_showcase.exe</RemoteName>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="bin\activerecord_showcase.exe" Configuration="Debug" Class="ProjectOutput">
<DeployFile LocalName="bin\activerecord_showcase.exe" Configuration="BUILD" Class="ProjectOutput">
<Platform Name="Win32">
<RemoteName>activerecord_showcase.exe</RemoteName>
<Overwrite>true</Overwrite>
@ -590,6 +590,32 @@
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iOS_AppStore1024">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_AppIcon152">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_AppIcon167">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch1024">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
@ -764,6 +790,56 @@
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Notification40">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Setting58">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_SpotLight80">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_AppIcon120">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_AppIcon180">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch1125">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
@ -958,6 +1034,66 @@
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Notification40">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Notification60">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Setting58">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Setting87">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Spotlight120">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Spotlight80">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectAndroidManifest">
<Platform Name="Android">
<Operation>1</Operation>

View File

@ -101,7 +101,7 @@ type
constructor Create;
procedure EndUpdates;
property WritableFieldsCount: Integer read fWritableFieldsCount;
property ReadableFieldsCount: Integer read fWritableFieldsCount;
property ReadableFieldsCount: Integer read fReadableFieldsCount;
function GetInfoByFieldName(const FieldName: string): TFieldInfo;
end;
@ -425,7 +425,7 @@ type
fCompiler: TRQLCompiler;
fRQL2SQL: TRQL2SQL;
protected
function GetRQLParser: TRQL2SQL;
function GetRQLParser(const MaxRecordCount: UInt32): TRQL2SQL;
function GetCompiler: TRQLCompiler;
function GetCompilerClass: TRQLCompilerClass; virtual; abstract;
function GetMapping: TMVCFieldsMapping;
@ -438,7 +438,8 @@ type
function HasReturning: Boolean; virtual;
// end-capabilities
function CreateSQLWhereByRQL(const RQL: string; const Mapping: TMVCFieldsMapping;
const UseArtificialLimit: Boolean = True; const UseFilterOnly: Boolean = false): string; virtual; abstract;
const UseArtificialLimit: Boolean = True; const UseFilterOnly: Boolean = false;
const MaxRecordCount: UInt32 = TMVCConstants.MAX_RECORD_COUNT): string; virtual; abstract;
function CreateSelectSQL(const TableName: string; const Map: TFieldsMap; const PKFieldName: string;
const PKOptions: TMVCActiveRecordFieldOptions): string; virtual; abstract;
function CreateSelectByPKSQL(const TableName: string; const Map: TFieldsMap; const PKFieldName: string;
@ -1309,7 +1310,8 @@ function TMVCActiveRecord.CheckAction(const aEntityAction: TMVCEntityAction; con
begin
Result := aEntityAction in fEntityAllowedActions;
if (not Result) and aRaiseException then
raise EMVCActiveRecord.CreateFmt('Action [%s] not allowed on entity [%s]. [HINT] Add the entity action in MVCEntityActions attribute.',
raise EMVCActiveRecord.CreateFmt
('Action [%s] not allowed on entity [%s]. [HINT] Add the entity action in MVCEntityActions attribute.',
[GetEnumName(TypeInfo(TMVCEntityAction), Ord(aEntityAction)), ClassName]);
end;
@ -2110,7 +2112,12 @@ var
begin
lAR := T.Create;
try
lSQL := lAR.SQLGenerator.CreateSQLWhereByRQL(RQL, lAR.GetMapping).Trim;
lSQL := lAR.SQLGenerator.CreateSQLWhereByRQL(
RQL,
lAR.GetMapping,
MaxRecordCount > -1,
False,
MaxRecordCount).Trim;
// LogD(Format('RQL [%s] => SQL [%s]', [RQL, lSQL]));
if lSQL.StartsWith('where', True) then
lSQL := lSQL.Remove(0, 5).Trim;
@ -2746,11 +2753,11 @@ begin
Result := fCompiler.GetFieldNameForSQL(FieldName);
end;
function TMVCSQLGenerator.GetRQLParser: TRQL2SQL;
function TMVCSQLGenerator.GetRQLParser(const MaxRecordCount: UInt32): TRQL2SQL;
begin
if fRQL2SQL = nil then
begin
fRQL2SQL := TRQL2SQL.Create; // (20);
fRQL2SQL := TRQL2SQL.Create(MaxRecordCount);
end;
Result := fRQL2SQL;
end;

View File

@ -123,6 +123,7 @@ type
DEFAULT_MAX_REQUEST_SIZE = OneMiB * 5; // 5 MiB
HATEOAS_PROP_NAME = 'links';
X_HTTP_Method_Override = 'X-HTTP-Method-Override';
MAX_RECORD_COUNT = 20;
end;
HATEOAS = record

View File

@ -72,7 +72,8 @@ type
function CreateSQLWhereByRQL(
const RQL: string; const Mapping: TMVCFieldsMapping;
const UseArtificialLimit: Boolean = True;
const UseFilterOnly: Boolean = False): string; override;
const UseFilterOnly: Boolean = False;
const MaxRecordCount: UInt32 = TMVCConstants.MAX_RECORD_COUNT): string; override;
function CreateSelectCount(
const TableName: string): string; override;
end;
@ -158,14 +159,15 @@ end;
function TMVCSQLGeneratorFirebird.CreateSQLWhereByRQL(
const RQL: string; const Mapping: TMVCFieldsMapping;
const UseArtificialLimit: Boolean;
const UseFilterOnly: Boolean): string;
const UseArtificialLimit: Boolean = True;
const UseFilterOnly: Boolean = False;
const MaxRecordCount: UInt32 = TMVCConstants.MAX_RECORD_COUNT): string;
var
lFirebirdCompiler: TRQLFirebirdCompiler;
begin
lFirebirdCompiler := TRQLFirebirdCompiler.Create(Mapping);
try
GetRQLParser.Execute(RQL, Result, lFirebirdCompiler, UseArtificialLimit, UseFilterOnly);
GetRQLParser(MaxRecordCount).Execute(RQL, Result, lFirebirdCompiler, UseArtificialLimit, UseFilterOnly);
finally
lFirebirdCompiler.Free;
end;

View File

@ -67,7 +67,8 @@ type
function CreateSQLWhereByRQL(
const RQL: string; const Mapping: TMVCFieldsMapping;
const UseArtificialLimit: Boolean = True;
const UseFilterOnly: Boolean = False): string; override;
const UseFilterOnly: Boolean = False;
const MaxRecordCount: UInt32 = TMVCConstants.MAX_RECORD_COUNT): string; override;
function CreateSelectCount(
const TableName: string): string; override;
function CreateDeleteAllSQL(
@ -153,14 +154,15 @@ end;
function TMVCSQLGeneratorMSSQL.CreateSQLWhereByRQL(
const RQL: string; const Mapping: TMVCFieldsMapping;
const UseArtificialLimit: Boolean;
const UseFilterOnly: Boolean): string;
const UseArtificialLimit: Boolean = True;
const UseFilterOnly: Boolean = False;
const MaxRecordCount: UInt32 = TMVCConstants.MAX_RECORD_COUNT): string;
var
lMSSQLCompiler: TRQLMSSQLCompiler;
begin
lMSSQLCompiler := TRQLMSSQLCompiler.Create(Mapping);
try
GetRQLParser.Execute(RQL, Result, lMSSQLCompiler, UseArtificialLimit, UseFilterOnly);
GetRQLParser(MaxRecordCount).Execute(RQL, Result, lMSSQLCompiler, UseArtificialLimit, UseFilterOnly);
finally
lMSSQLCompiler.Free;
end;

View File

@ -69,7 +69,8 @@ type
function CreateSQLWhereByRQL(
const RQL: string; const Mapping: TMVCFieldsMapping;
const UseArtificialLimit: Boolean = True;
const UseFilterOnly: Boolean = False): string; override;
const UseFilterOnly: Boolean = False;
const MaxRecordCount: UInt32 = TMVCConstants.MAX_RECORD_COUNT): string; override;
function CreateSelectCount(
const TableName: string): string; override;
end;
@ -154,14 +155,15 @@ end;
function TMVCSQLGeneratorMySQL.CreateSQLWhereByRQL(
const RQL: string; const Mapping: TMVCFieldsMapping;
const UseArtificialLimit: Boolean;
const UseFilterOnly: Boolean): string;
const UseArtificialLimit: Boolean = True;
const UseFilterOnly: Boolean = False;
const MaxRecordCount: UInt32 = TMVCConstants.MAX_RECORD_COUNT): string;
var
lMySQLCompiler: TRQLMySQLCompiler;
begin
lMySQLCompiler := TRQLMySQLCompiler.Create(Mapping);
try
GetRQLParser.Execute(RQL, Result, lMySQLCompiler, UseArtificialLimit, UseFilterOnly);
GetRQLParser(MaxRecordCount).Execute(RQL, Result, lMySQLCompiler, UseArtificialLimit, UseFilterOnly);
finally
lMySQLCompiler.Free;
end;

View File

@ -69,8 +69,9 @@ type
function CreateSQLWhereByRQL(
const RQL: string;
const Mapping: TMVCFieldsMapping;
const UseArtificialLimit: Boolean = True;
const UseFilterOnly: Boolean = False): string; override;
const UseArtificialLimit: Boolean;
const UseFilterOnly: Boolean;
const MaxRecordCount: UInt32 = TMVCConstants.MAX_RECORD_COUNT): string; override;
function CreateSelectCount(
const TableName: string): string; override;
function GetSequenceValueSQL(const PKFieldName: string;
@ -173,13 +174,14 @@ function TMVCSQLGeneratorPostgreSQL.CreateSQLWhereByRQL(
const RQL: string;
const Mapping: TMVCFieldsMapping;
const UseArtificialLimit: Boolean;
const UseFilterOnly: Boolean): string;
const UseFilterOnly: Boolean;
const MaxRecordCount: UInt32): string;
var
lPostgreSQLCompiler: TRQLPostgreSQLCompiler;
begin
lPostgreSQLCompiler := TRQLPostgreSQLCompiler.Create(Mapping);
try
GetRQLParser.Execute(RQL, Result, lPostgreSQLCompiler, UseArtificialLimit, UseFilterOnly);
GetRQLParser(MaxRecordCount).Execute(RQL, Result, lPostgreSQLCompiler, UseArtificialLimit, UseFilterOnly);
finally
lPostgreSQLCompiler.Free;
end;

View File

@ -67,7 +67,8 @@ type
function CreateSQLWhereByRQL(
const RQL: string; const Mapping: TMVCFieldsMapping;
const UseArtificialLimit: Boolean = True;
const UseFilterOnly: Boolean = False): string; override;
const UseFilterOnly: Boolean = False;
const MaxRecordCount: UInt32 = TMVCConstants.MAX_RECORD_COUNT): string; override;
function CreateSelectCount(
const TableName: string): string; override;
function HasSequences: Boolean; override;
@ -152,14 +153,15 @@ end;
function TMVCSQLGeneratorSQLite.CreateSQLWhereByRQL(
const RQL: string; const Mapping: TMVCFieldsMapping;
const UseArtificialLimit: Boolean;
const UseFilterOnly: Boolean): string;
const UseArtificialLimit: Boolean = True;
const UseFilterOnly: Boolean = False;
const MaxRecordCount: UInt32 = TMVCConstants.MAX_RECORD_COUNT): string;
var
lSQLiteCompiler: TRQLSQLiteCompiler;
begin
lSQLiteCompiler := TRQLSQLiteCompiler.Create(Mapping);
try
GetRQLParser.Execute(RQL, Result, lSQLiteCompiler, UseArtificialLimit, UseFilterOnly);
GetRQLParser(MaxRecordCount).Execute(RQL, Result, lSQLiteCompiler, UseArtificialLimit, UseFilterOnly);
finally
lSQLiteCompiler.Free;
end;

View File

@ -61,6 +61,8 @@ type
[Test]
procedure TestRQL;
[Test]
procedure TestIssue424;
[Test]
procedure TestMultiThreading;
[Test]
procedure TestNullables;
@ -92,11 +94,11 @@ var
procedure TTestActiveRecordSQLite.AfterDataLoad;
begin
{TODO -oDanieleT -cGeneral : Hot to reset a sqlite autoincrement field?}
//https://sqlite.org/fileformat2.html#seqtab
//https://stackoverflow.com/questions/5586269/how-can-i-reset-a-autoincrement-sequence-number-in-sqlite/14298431
// TMVCActiveRecord.CurrentConnection.ExecSQL('delete from sqlite_sequence where name=''customers''');
// TMVCActiveRecord.CurrentConnection.ExecSQL('delete from sqlite_sequence where name=''customers2''');
{ TODO -oDanieleT -cGeneral : Hot to reset a sqlite autoincrement field? }
// https://sqlite.org/fileformat2.html#seqtab
// https://stackoverflow.com/questions/5586269/how-can-i-reset-a-autoincrement-sequence-number-in-sqlite/14298431
// TMVCActiveRecord.CurrentConnection.ExecSQL('delete from sqlite_sequence where name=''customers''');
// TMVCActiveRecord.CurrentConnection.ExecSQL('delete from sqlite_sequence where name=''customers2''');
TMVCActiveRecord.CurrentConnection.ExecSQL('drop table if exists sqlite_sequence');
end;
@ -318,6 +320,44 @@ begin
end;
end;
{ https://github.com/danieleteti/delphimvcframework/issues/424 }
procedure TTestActiveRecordSQLite.TestIssue424;
var
lCustomers: TObjectList<TCustomer>;
const
RQL1 = 'or(eq(City, "Rome"),eq(City, "London"))';
begin
Assert.AreEqual(Int64(0), TMVCActiveRecord.Count(TCustomer));
LoadData;
lCustomers := TMVCActiveRecord.SelectRQL<TCustomer>(RQL1, MAXINT);
try
Assert.AreEqual(240, lCustomers.Count);
finally
lCustomers.Free;
end;
lCustomers := TMVCActiveRecord.SelectRQL<TCustomer>(RQL1, 20);
try
Assert.AreEqual(20, lCustomers.Count);
finally
lCustomers.Free;
end;
lCustomers := TMVCActiveRecord.SelectRQL<TCustomer>(RQL1, 1);
try
Assert.AreEqual(1, lCustomers.Count);
finally
lCustomers.Free;
end;
lCustomers := TMVCActiveRecord.SelectRQL<TCustomer>(RQL1, -1);
try
Assert.AreEqual(240, lCustomers.Count);
finally
lCustomers.Free;
end;
end;
procedure TTestActiveRecordSQLite.TestLifeCycle;
var
lCustomer: TCustomerWithLF;
@ -442,7 +482,7 @@ begin
lTest.f_datetime := Now;
lTest.f_float4 := 1234.5678;
lTest.f_float8 := 12345678901234567890.0123456789;
// lTest.f_currency := 1234567890.1234;
// lTest.f_currency := 1234567890.1234;
lTest.Insert;
finally
lTest.Free;