diff --git a/samples/activerecord_showcase/activerecord_showcase.dproj b/samples/activerecord_showcase/activerecord_showcase.dproj index 7fcddbf3..92078257 100644 --- a/samples/activerecord_showcase/activerecord_showcase.dproj +++ b/samples/activerecord_showcase/activerecord_showcase.dproj @@ -1,7 +1,7 @@  {F8576ED6-649F-4E28-B364-1F60687C75F2} - 19.0 + 19.1 VCL activerecord_showcase.dpr True @@ -163,13 +163,13 @@ - + activerecord_showcase.exe true - + activerecord_showcase.exe true @@ -590,6 +590,32 @@ 0 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + 1 @@ -764,6 +790,56 @@ 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + 1 @@ -958,6 +1034,66 @@ 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + 1 diff --git a/sources/MVCFramework.ActiveRecord.pas b/sources/MVCFramework.ActiveRecord.pas index 9297d185..9c00c6f7 100644 --- a/sources/MVCFramework.ActiveRecord.pas +++ b/sources/MVCFramework.ActiveRecord.pas @@ -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; diff --git a/sources/MVCFramework.Commons.pas b/sources/MVCFramework.Commons.pas index 55f0428c..ff1be2ac 100644 --- a/sources/MVCFramework.Commons.pas +++ b/sources/MVCFramework.Commons.pas @@ -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 diff --git a/sources/MVCFramework.SQLGenerators.Firebird.pas b/sources/MVCFramework.SQLGenerators.Firebird.pas index e86efc48..de39919e 100644 --- a/sources/MVCFramework.SQLGenerators.Firebird.pas +++ b/sources/MVCFramework.SQLGenerators.Firebird.pas @@ -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; diff --git a/sources/MVCFramework.SQLGenerators.MSSQL.pas b/sources/MVCFramework.SQLGenerators.MSSQL.pas index fac99445..0bfe6a09 100644 --- a/sources/MVCFramework.SQLGenerators.MSSQL.pas +++ b/sources/MVCFramework.SQLGenerators.MSSQL.pas @@ -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; diff --git a/sources/MVCFramework.SQLGenerators.MySQL.pas b/sources/MVCFramework.SQLGenerators.MySQL.pas index d3ab9b82..37e977a5 100644 --- a/sources/MVCFramework.SQLGenerators.MySQL.pas +++ b/sources/MVCFramework.SQLGenerators.MySQL.pas @@ -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; diff --git a/sources/MVCFramework.SQLGenerators.PostgreSQL.pas b/sources/MVCFramework.SQLGenerators.PostgreSQL.pas index 6e802246..b2ad0d12 100644 --- a/sources/MVCFramework.SQLGenerators.PostgreSQL.pas +++ b/sources/MVCFramework.SQLGenerators.PostgreSQL.pas @@ -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; diff --git a/sources/MVCFramework.SQLGenerators.Sqlite.pas b/sources/MVCFramework.SQLGenerators.Sqlite.pas index ef64c8a6..9703b3ee 100644 --- a/sources/MVCFramework.SQLGenerators.Sqlite.pas +++ b/sources/MVCFramework.SQLGenerators.Sqlite.pas @@ -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; diff --git a/unittests/general/Several/ActiveRecordTestsU.pas b/unittests/general/Several/ActiveRecordTestsU.pas index 98dad90d..8c94d211 100644 --- a/unittests/general/Several/ActiveRecordTestsU.pas +++ b/unittests/general/Several/ActiveRecordTestsU.pas @@ -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; +const + RQL1 = 'or(eq(City, "Rome"),eq(City, "London"))'; +begin + Assert.AreEqual(Int64(0), TMVCActiveRecord.Count(TCustomer)); + LoadData; + lCustomers := TMVCActiveRecord.SelectRQL(RQL1, MAXINT); + try + Assert.AreEqual(240, lCustomers.Count); + finally + lCustomers.Free; + end; + + lCustomers := TMVCActiveRecord.SelectRQL(RQL1, 20); + try + Assert.AreEqual(20, lCustomers.Count); + finally + lCustomers.Free; + end; + + lCustomers := TMVCActiveRecord.SelectRQL(RQL1, 1); + try + Assert.AreEqual(1, lCustomers.Count); + finally + lCustomers.Free; + end; + + lCustomers := TMVCActiveRecord.SelectRQL(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;