diff --git a/README.md b/README.md index 29dd8b4b..e4ca3f18 100644 --- a/README.md +++ b/README.md @@ -459,6 +459,31 @@ The current beta release is named 3.2.2-nitrogen. If you want to stay on the-edg - ⚡New! Added `TMVCActiveRecord.Merge(CurrentListOfT, ChangesOfT)` to allow merge between two lists of `TMVCActiveRecord` descendants using `UnitOfWork` design pattern. Check the button "Merge" in demo "activerecord_showcase". +- ⚡New! Added default filtering for `TMVCActiveRecord descendants` (more info ASAP) + +- ⚡New! Added partitioning for `TMVCActiveRecord descendants` (more info ASAP) + +- ⚡Improved! After a big refactoring (*"I love to delete code" -- cit. Daniele Teti*), support a new SQLGenerator is just 2 (two) methods away! Just as example, this is the current version of `TMVCSQLGeneratorPostgreSQL` + + ```delphi + type + TMVCSQLGeneratorPostgreSQL = class(TMVCSQLGenerator) + protected + function GetCompilerClass: TRQLCompilerClass; override; + public + function CreateInsertSQL( + const TableName: string; + const Map: TFieldsMap; + const PKFieldName: string; + const PKOptions: TMVCActiveRecordFieldOptions): string; override; + function GetSequenceValueSQL(const PKFieldName: string; + const SequenceName: string; + const Step: Integer = 1): string; override; + end; + ``` + + + - ⚡New! Added new default parameter to `TMVCActiveRecord.RemoveDefaultConnection` and `TMVCActiveRecord.RemoveConnection` to avoid exceptions in case of not initialized connection. - ⚡New! Added the new `MVCOwned` attribute which allows to auto-create nested objects in the deserialization phase. This will not change the current behavior, you ned to explocitly define a property (or a field) as `MVCOwned` to allows the serialization to create or destroy object for you. diff --git a/samples/activerecord_showcase/FDConnectionConfigU.pas b/samples/activerecord_showcase/FDConnectionConfigU.pas index 51689186..687600a4 100644 --- a/samples/activerecord_showcase/FDConnectionConfigU.pas +++ b/samples/activerecord_showcase/FDConnectionConfigU.pas @@ -23,6 +23,10 @@ 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 +} + LParams := TStringList.Create; try LParams.Add('Database=activerecorddb'); @@ -31,7 +35,7 @@ begin LParams.Add('User_Name=root'); LParams.Add('Password=root'); LParams.Add('TinyIntFormat=Boolean'); { it's the default } - LParams.Add('CharacterSet=utf8'); + LParams.Add('CharacterSet=utf8mb4'); //not utf8!! if AIsPooled then begin LParams.Add('Pooled=True'); @@ -51,6 +55,10 @@ 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 +} + // [ACTIVERECORDB_SQLSERVER] // Database=activerecorddb // OSAuthent=Yes @@ -61,8 +69,10 @@ begin LParams := TStringList.Create; try LParams.Add('Database=activerecorddb'); - LParams.Add('OSAuthent=Yes'); - LParams.Add('Server=DANIELETETI\SQLEXPRESS'); +// LParams.Add('OSAuthent=Yes'); + LParams.Add('User_Name=sa'); + LParams.Add('Password=!SA_password!'); + LParams.Add('Server=DANIELETETI'); // LParams.Add('TinyIntFormat=Boolean'); { it's the default } if AIsPooled then begin diff --git a/samples/activerecord_showcase/MainFormU.pas b/samples/activerecord_showcase/MainFormU.pas index ad53f70e..db617239 100644 --- a/samples/activerecord_showcase/MainFormU.pas +++ b/samples/activerecord_showcase/MainFormU.pas @@ -215,7 +215,7 @@ begin Log('Entity ' + TCustomer.ClassName + ' is mapped to table ' + lCustomer.TableName); lCustomer.CompanyName := 'Google Inc.'; lCustomer.City := 'Montain View, CA'; - lCustomer.Note := 'Μῆνιν ἄειδε θεὰ Πηληϊάδεω Ἀχιλῆος οὐλομένην'; + lCustomer.Note := 'Μῆνιν ἄειδε θεὰ Πηληϊάδεω Ἀχιλῆος οὐλομένην 😁'; lCustomer.Insert; lID := lCustomer.ID; Log('Just inserted Customer ' + lID.ToString); diff --git a/samples/data/activerecorddb_mssqlserver_script.sql b/samples/data/activerecorddb_mssqlserver_script.sql index 051e93eb..e8047767 100644 --- a/samples/data/activerecorddb_mssqlserver_script.sql +++ b/samples/data/activerecorddb_mssqlserver_script.sql @@ -1,15 +1,15 @@ CREATE TABLE articles ( id integer IDENTITY(1, 1) , - description varchar(100) NOT NULL, + description nvarchar(100) NOT NULL, price integer NOT NULL, CONSTRAINT articles_pkey PRIMARY KEY (id) ); CREATE TABLE customers ( id integer IDENTITY(1, 1) , - code varchar(20), - description varchar(200), - city varchar(200), + code nvarchar(20), + description nvarchar(200), + city nvarchar(200), rating INTEGER, NOTE nvarchar(max), CONSTRAINT customers_pk PRIMARY KEY (id) @@ -17,18 +17,20 @@ CREATE TABLE customers ( CREATE TABLE customers_plain ( id integer NOT NULL, - code varchar(20), - description varchar(200), - city varchar(200), + code nvarchar(20), + description nvarchar(200), + city nvarchar(200), note nvarchar(max), rating smallint, + creation_time time, + creation_date date, CONSTRAINT customers_plain_pk PRIMARY KEY (id) ); CREATE TABLE customers_with_code ( - code varchar(20) NOT null primary key, - description varchar(200), - city varchar(200), + code nvarchar(20) NOT null primary key, + description nvarchar(200), + city nvarchar(200), NOTE nvarchar(max), rating smallint ); @@ -40,7 +42,7 @@ CREATE TABLE order_details ( unit_price numeric(18,2) NOT NULL, discount integer DEFAULT 0 NOT NULL , quantity integer NOT NULL, - description varchar(200) NOT NULL, + description nvarchar(200) NOT NULL, total numeric(18,2) NOT NULL, CONSTRAINT order_details_pkey PRIMARY KEY (id) ); @@ -56,10 +58,10 @@ CREATE TABLE orders ( CREATE TABLE people ( id integer IDENTITY(1, 1) , - last_name varchar(100) NOT NULL, - first_name varchar(100) NOT NULL, + last_name nvarchar(100) NOT NULL, + first_name nvarchar(100) NOT NULL, dob date NOT NULL, - full_name varchar(80) NOT NULL, + full_name nvarchar(80) NOT NULL, is_male bit DEFAULT 1 NOT NULL, note nvarchar(max), photo VARBINARY(MAX), @@ -68,11 +70,27 @@ CREATE TABLE people ( create table phones ( id integer IDENTITY(1, 1) , - phone_number varchar(200) not null, - number_type varchar(200) not null, + phone_number nvarchar(200) not null, + number_type nvarchar(200) not null, dob date, id_person integer not null references people(id) ); ALTER TABLE orders ADD CONSTRAINT orders_customers_fk FOREIGN KEY (id_customer) REFERENCES customers(id) ON DELETE CASCADE ON UPDATE CASCADE; ALTER TABLE order_details ADD CONSTRAINT order_details_orders_fk FOREIGN KEY (id_order) REFERENCES orders(id) ON DELETE CASCADE ON UPDATE CASCADE; + +CREATE TABLE nullables_test ( + f_int2 smallint, + f_int8 bigint, + f_int4 integer, + f_string nvarchar(200), + f_bool bit, + f_date date, + f_time time, + f_datetime datetime, + f_float4 real, + f_float8 double precision, + f_currency numeric(18,4), + f_blob varchar(max) +); + diff --git a/samples/data/activerecorddb_mysql_script.sql b/samples/data/activerecorddb_mysql_script.sql index 3c56ceb8..b4e8bbd4 100644 --- a/samples/data/activerecorddb_mysql_script.sql +++ b/samples/data/activerecorddb_mysql_script.sql @@ -1,5 +1,5 @@ CREATE TABLE articles ( - id integer GENERATED BY DEFAULT AS IDENTITY, + id integer NOT NULL AUTO_INCREMENT, description varchar(100) NOT NULL, price integer NOT NULL, CONSTRAINT articles_pkey PRIMARY KEY (id) @@ -23,12 +23,12 @@ CREATE TABLE nullables_test ( CREATE TABLE customers ( - id integer GENERATED BY DEFAULT AS IDENTITY, - code varchar(20) NOT NULL, + id integer NOT NULL AUTO_INCREMENT, + code varchar(20) NULL, description varchar(200), city varchar(200), rating INTEGER NULL, - note text DEFAULT NULL, + note text character set "utf8mb4" collate "utf8mb4_unicode_ci" DEFAULT NULL, CONSTRAINT customers_pk PRIMARY KEY (id) ); @@ -54,7 +54,7 @@ CREATE TABLE customers_with_code ( ); CREATE TABLE order_details ( - id integer GENERATED BY DEFAULT AS IDENTITY, + id integer NOT NULL AUTO_INCREMENT, id_order integer NOT NULL, id_article integer NOT NULL, unit_price numeric(18,2) NOT NULL, @@ -66,7 +66,7 @@ CREATE TABLE order_details ( ); CREATE TABLE orders ( - id integer GENERATED BY DEFAULT AS IDENTITY, + id integer NOT NULL AUTO_INCREMENT, id_customer integer NOT NULL, order_date date NOT NULL, total numeric(18,4) NOT NULL, @@ -75,19 +75,19 @@ CREATE TABLE orders ( CREATE TABLE people ( - id integer GENERATED BY DEFAULT AS IDENTITY, + id integer NOT NULL AUTO_INCREMENT, last_name varchar(100) NOT NULL, first_name varchar(100) NOT NULL, dob date NOT NULL, full_name varchar(80) NOT NULL, is_male BOOLEAN DEFAULT TRUE NOT NULL, - note blob sub_type TEXT, - photo blob sub_type binary, + note TEXT, + photo BLOB, CONSTRAINT people_pkey PRIMARY KEY (id) ); create table phones ( - id integer GENERATED BY DEFAULT AS IDENTITY, + id integer NOT NULL auto_increment primary key, phone_number varchar(200) not null, number_type varchar(200) not null, dob date, diff --git a/sources/MVCFramework.ActiveRecord.pas b/sources/MVCFramework.ActiveRecord.pas index f21a6c10..506abc1a 100644 --- a/sources/MVCFramework.ActiveRecord.pas +++ b/sources/MVCFramework.ActiveRecord.pas @@ -554,29 +554,32 @@ type function HasSequences: Boolean; virtual; function HasReturning: Boolean; virtual; // end-capabilities + + // abstract SQL generator methods function CreateSQLWhereByRQL(const RQL: string; const Mapping: TMVCFieldsMapping; const UseArtificialLimit: Boolean = True; const UseFilterOnly: Boolean = false; - const MaxRecordCount: Int32 = TMVCConstants.MAX_RECORD_COUNT): string; virtual; abstract; + const MaxRecordCount: Int32 = TMVCConstants.MAX_RECORD_COUNT): string; 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; - const PKOptions: TMVCActiveRecordFieldOptions): string; virtual; abstract; + const PKOptions: TMVCActiveRecordFieldOptions): string; virtual; function CreateInsertSQL(const TableName: string; const Map: TFieldsMap; const PKFieldName: string; const PKOptions: TMVCActiveRecordFieldOptions): string; virtual; abstract; - function CreateUpdateSQL(const TableName: string; const Map: TFieldsMap; + + // virtual methods with default implementation + function CreateSelectByPKSQL(const TableName: string; const Map: TFieldsMap; const PKFieldName: string; - const PKOptions: TMVCActiveRecordFieldOptions): string; virtual; abstract; + const PKOptions: TMVCActiveRecordFieldOptions): string; virtual; function CreateDeleteSQL(const TableName: string; const Map: TFieldsMap; const PKFieldName: string; - const PKOptions: TMVCActiveRecordFieldOptions): string; virtual; abstract; - function CreateDeleteAllSQL(const TableName: string): string; virtual; abstract; - function CreateSelectCount(const TableName: string): string; virtual; abstract; + const PKOptions: TMVCActiveRecordFieldOptions): string; virtual; + function CreateDeleteAllSQL(const TableName: string): string; virtual; + function CreateSelectCount(const TableName: string): string; virtual; + function CreateUpdateSQL(const TableName: string; const Map: TFieldsMap; + const PKFieldName: string; + const PKOptions: TMVCActiveRecordFieldOptions): string; virtual; function GetSequenceValueSQL(const PKFieldName: string; const SequenceName: string; - const Step: Integer = 1) - : string; virtual; + const Step: Integer = 1): string; virtual; // Overwritten by descendant if the SQL syntaxt requires more than the simple table name // or if the table name contains spaces. @@ -3062,6 +3065,83 @@ begin Result := fCompiler.GetParamNameForSQL(FieldName); end; +function TMVCSQLGenerator.CreateDeleteAllSQL(const TableName: string): string; +begin + Result := 'DELETE FROM ' + GetTableNameForSQL(TableName); +end; + +function TMVCSQLGenerator.CreateDeleteSQL(const TableName: string; + const Map: TFieldsMap; const PKFieldName: string; + const PKOptions: TMVCActiveRecordFieldOptions): string; +begin + Result := CreateDeleteAllSQL(TableName) + ' WHERE ' + GetFieldNameForSQL(PKFieldName) + '=:' + + GetParamNameForSQL(PKFieldName); +end; + +function TMVCSQLGenerator.CreateSelectByPKSQL(const TableName: string; + const Map: TFieldsMap; const PKFieldName: string; + const PKOptions: TMVCActiveRecordFieldOptions): string; +begin + if PKFieldName.IsEmpty then + begin + raise EMVCActiveRecord.Create('No primary key provided. [HINT] Define a primary key field adding foPrimaryKey in field options.'); + end; + + Result := CreateSelectSQL(TableName, Map, PKFieldName, PKOptions) + ' WHERE ' + + GetFieldNameForSQL(PKFieldName) + '= :' + GetParamNameForSQL(PKFieldName) + + GetDefaultSQLFilter(False, True); +end; + +function TMVCSQLGenerator.CreateSelectCount(const TableName: string): string; +begin + {do not add SQLFilter here!} + Result := 'SELECT count(*) FROM ' + GetTableNameForSQL(TableName); +end; + +function TMVCSQLGenerator.CreateSelectSQL(const TableName: string; + const Map: TFieldsMap; const PKFieldName: string; + const PKOptions: TMVCActiveRecordFieldOptions): string; +begin + Result := 'SELECT ' + TableFieldsDelimited(Map, PKFieldName, ',') + ' FROM ' + GetTableNameForSQL(TableName); +end; + +function TMVCSQLGenerator.CreateSQLWhereByRQL(const RQL: string; + const Mapping: TMVCFieldsMapping; const UseArtificialLimit, + UseFilterOnly: Boolean; const MaxRecordCount: Int32): string; +begin + GetRQLParser.Execute(MergeDefaultRQLFilter(RQL), Result, GetCompiler, UseArtificialLimit, UseFilterOnly, MaxRecordCount); +end; + +function TMVCSQLGenerator.CreateUpdateSQL(const TableName: string; + const Map: TFieldsMap; const PKFieldName: string; + const PKOptions: TMVCActiveRecordFieldOptions): string; +var + lPair: TPair; + I: Integer; +begin + Result := 'UPDATE ' + GetTableNameForSQL(TableName) + ' SET '; + for lPair in Map do + begin + if lPair.Value.Writeable then + begin + Result := Result + GetFieldNameForSQL(lPair.Value.FieldName) + ' = :' + + GetParamNameForSQL(lPair.Value.FieldName) + ','; + end; + end; + {partition} + for I := 0 to fPartitionInfo.FieldNames.Count - 1 do + begin + Result := Result + GetFieldNameForSQL(fPartitionInfo.FieldNames[I]) + ' = :' + + GetParamNameForSQL(fPartitionInfo.FieldNames[I]) + ','; + end; + {end-partitioning} + Result[Length(Result)] := ' '; + if not PKFieldName.IsEmpty then + begin + Result := Result + ' where ' + GetFieldNameForSQL(PKFieldName) + '= :' + GetParamNameForSQL(PKFieldName); + end; +end; + destructor TMVCSQLGenerator.Destroy; begin fCompiler.Free; diff --git a/sources/MVCFramework.RQL.AST2FirebirdSQL.pas b/sources/MVCFramework.RQL.AST2FirebirdSQL.pas index 5a13dad9..0032ba43 100644 --- a/sources/MVCFramework.RQL.AST2FirebirdSQL.pas +++ b/sources/MVCFramework.RQL.AST2FirebirdSQL.pas @@ -136,7 +136,7 @@ begin else lValue := aRQLFIlter.OpRight; - lDBFieldName := GetDatabaseFieldName(aRQLFIlter.OpLeft); + lDBFieldName := GetDatabaseFieldName(aRQLFIlter.OpLeft, True); case aRQLFIlter.Token of tkEq: @@ -262,7 +262,7 @@ begin begin if I > 0 then Result := Result + ','; - Result := Result + ' ' + GetDatabaseFieldName(aRQLSort.Fields[I]); + Result := Result + ' ' + GetDatabaseFieldName(aRQLSort.Fields[I], True); if aRQLSort.Signs[I] = '+' then Result := Result + ' ASC' else diff --git a/sources/MVCFramework.RQL.AST2MSSQL.pas b/sources/MVCFramework.RQL.AST2MSSQL.pas index e8c22700..cb82d686 100644 --- a/sources/MVCFramework.RQL.AST2MSSQL.pas +++ b/sources/MVCFramework.RQL.AST2MSSQL.pas @@ -101,7 +101,7 @@ begin else lValue := aRQLFIlter.OpRight; - lDBFieldName := GetDatabaseFieldName(aRQLFIlter.OpLeft); + lDBFieldName := GetDatabaseFieldName(aRQLFIlter.OpLeft, True); case aRQLFIlter.Token of tkEq: @@ -227,7 +227,7 @@ begin begin if I > 0 then Result := Result + ','; - Result := Result + ' ' + GetDatabaseFieldName(aRQLSort.Fields[I]); + Result := Result + ' ' + GetDatabaseFieldName(aRQLSort.Fields[I], True); if aRQLSort.Signs[I] = '+' then Result := Result + ' ASC' else @@ -245,8 +245,8 @@ procedure TRQLMSSQLCompiler.AST2SQL(const aRQLAST: TRQLAbstractSyntaxTree; var lBuff: TStringBuilder; lItem: TRQLCustom; - LFoundSort: Boolean; - LitemSort: TRQLSort; + lFoundSort: Boolean; + lItemSort: TRQLSort; begin inherited; @@ -264,16 +264,19 @@ begin if (lItem is TRQLLimit) and (not LFoundSort) then begin - LitemSort := TRQLSort.Create; - LitemSort.Add('+', FMapping[0].InstanceFieldName); - lBuff.Append(RQLCustom2SQL(LitemSort)); + lItemSort := TRQLSort.Create; + try + lItemSort.Add('+', FMapping[0].InstanceFieldName); + lBuff.Append(RQLCustom2SQL(LitemSort)); + finally + lItemSort.Free; + end; end; lBuff.Append(RQLCustom2SQL(lItem)); if (lItem is TRQLSort) then LFoundSort := True; - end; aSQL := lBuff.ToString; finally diff --git a/sources/MVCFramework.RQL.AST2MySQL.pas b/sources/MVCFramework.RQL.AST2MySQL.pas index 576a1374..f9de1cf4 100644 --- a/sources/MVCFramework.RQL.AST2MySQL.pas +++ b/sources/MVCFramework.RQL.AST2MySQL.pas @@ -92,7 +92,7 @@ begin else lValue := aRQLFIlter.OpRight; - lDBFieldName := GetDatabaseFieldName(aRQLFIlter.OpLeft); + lDBFieldName := GetDatabaseFieldName(aRQLFIlter.OpLeft, True); case aRQLFIlter.Token of tkEq: @@ -218,7 +218,7 @@ begin begin if I > 0 then Result := Result + ','; - Result := Result + ' ' + GetDatabaseFieldName(aRQLSort.Fields[I]); + Result := Result + ' ' + GetDatabaseFieldName(aRQLSort.Fields[I], True); if aRQLSort.Signs[I] = '+' then Result := Result + ' ASC' else diff --git a/sources/MVCFramework.RQL.AST2PostgreSQL.pas b/sources/MVCFramework.RQL.AST2PostgreSQL.pas index f5ddce95..467a2351 100644 --- a/sources/MVCFramework.RQL.AST2PostgreSQL.pas +++ b/sources/MVCFramework.RQL.AST2PostgreSQL.pas @@ -219,7 +219,7 @@ begin begin if I > 0 then Result := Result + ','; - Result := Result + ' ' + GetFieldNameForSQL(GetDatabaseFieldName(aRQLSort.Fields[I])); + Result := Result + ' ' + GetFieldNameForSQL(GetDatabaseFieldName(aRQLSort.Fields[I], True)); if aRQLSort.Signs[I] = '+' then Result := Result + ' ASC' else diff --git a/sources/MVCFramework.RQL.AST2SQLite.pas b/sources/MVCFramework.RQL.AST2SQLite.pas index 1cf002f9..6523a650 100644 --- a/sources/MVCFramework.RQL.AST2SQLite.pas +++ b/sources/MVCFramework.RQL.AST2SQLite.pas @@ -87,7 +87,7 @@ begin else lValue := aRQLFIlter.OpRight; - lDBFieldName := GetDatabaseFieldName(aRQLFIlter.OpLeft); + lDBFieldName := GetDatabaseFieldName(aRQLFIlter.OpLeft, True); case aRQLFIlter.Token of tkEq: @@ -213,7 +213,7 @@ begin begin if I > 0 then Result := Result + ','; - Result := Result + ' ' + GetDatabaseFieldName(aRQLSort.Fields[I]); + Result := Result + ' ' + GetDatabaseFieldName(aRQLSort.Fields[I], True); if aRQLSort.Signs[I] = '+' then Result := Result + ' ASC' else diff --git a/sources/MVCFramework.SQLGenerators.Firebird.pas b/sources/MVCFramework.SQLGenerators.Firebird.pas index 62be3d2f..bbada015 100644 --- a/sources/MVCFramework.SQLGenerators.Firebird.pas +++ b/sources/MVCFramework.SQLGenerators.Firebird.pas @@ -41,41 +41,14 @@ type protected function GetCompilerClass: TRQLCompilerClass; override; public - function GetSequenceValueSQL( - const PKFieldName: string; const SequenceName: string; const Step: Integer): string; override; - function CreateSelectSQL( - const TableName: string; - const Map: TFieldsMap; - const PKFieldName: string; - const PKOptions: TMVCActiveRecordFieldOptions): string; override; function CreateInsertSQL( const TableName: string; const Map: TFieldsMap; const PKFieldName: string; const PKOptions: TMVCActiveRecordFieldOptions): string; override; - function CreateUpdateSQL( - const TableName: string; - const Map: TFieldsMap; - const PKFieldName: string; - const PKOptions: TMVCActiveRecordFieldOptions): string; override; - function CreateDeleteSQL( - const TableName: string; - const Map: TFieldsMap; - const PKFieldName: string; - const PKOptions: TMVCActiveRecordFieldOptions): string; override; - function CreateDeleteAllSQL( - const TableName: string): string; override; - function CreateSelectByPKSQL( - const TableName: string; - const Map: TFieldsMap; const PKFieldName: string; - const PKOptions: TMVCActiveRecordFieldOptions): string; override; - function CreateSQLWhereByRQL( - const RQL: string; const Mapping: TMVCFieldsMapping; - const UseArtificialLimit: Boolean = True; - const UseFilterOnly: Boolean = False; - const MaxRecordCount: Int32 = TMVCConstants.MAX_RECORD_COUNT): string; override; - function CreateSelectCount( - const TableName: string): string; override; + function GetSequenceValueSQL(const PKFieldName: string; + const SequenceName: string; + const Step: Integer = 1): string; override; end; implementation @@ -90,6 +63,7 @@ var lKeyValue: TPair; lSB: TStringBuilder; lPKInInsert: Boolean; + lFieldName: String; begin lPKInInsert := (not PKFieldName.IsEmpty) and (not(TMVCActiveRecordFieldOption.foAutoGenerated in PKOptions)); lPKInInsert := lPKInInsert and (not(TMVCActiveRecordFieldOption.foReadOnly in PKOptions)); @@ -100,8 +74,17 @@ begin begin lSB.Append(GetFieldNameForSQL(PKFieldName) + ','); end; + + {partition} + for lFieldName in fPartitionInfo.FieldNames do + begin + lSB.Append(GetFieldNameForSQL(lFieldName) + ','); + end; + {end-partition} + for lKeyValue in Map do begin + // if not(foTransient in lKeyValue.Value.FieldOptions) then if lKeyValue.Value.Writeable then begin lSB.Append(GetFieldNameForSQL(lKeyValue.Value.FieldName) + ','); @@ -114,6 +97,14 @@ begin begin lSB.Append(':' + GetParamNameForSQL(PKFieldName) + ','); end; + + {partition} + for lFieldName in fPartitionInfo.FieldNames do + begin + lSB.Append(':' + GetParamNameForSQL(lFieldName) + ','); + end; + {end-partition} + for lKeyValue in Map do begin if lKeyValue.Value.Writeable then @@ -135,65 +126,6 @@ begin end; end; -function TMVCSQLGeneratorFirebird.CreateSelectByPKSQL( - const TableName: string; - const Map: TFieldsMap; const PKFieldName: string; - const PKOptions: TMVCActiveRecordFieldOptions): string; -begin - Result := CreateSelectSQL(TableName, Map, PKFieldName, PKOptions) + ' WHERE ' + - GetFieldNameForSQL(PKFieldName) + '= :' + GetParamNameForSQL(PKFieldName); // IntToStr(PrimaryKeyValue); -end; - -function TMVCSQLGeneratorFirebird.CreateSelectCount( - const TableName: string): string; -begin - Result := 'SELECT count(*) FROM ' + GetTableNameForSQL(TableName); -end; - -function TMVCSQLGeneratorFirebird.CreateSelectSQL(const TableName: string; - const Map: TFieldsMap; const PKFieldName: string; - const PKOptions: TMVCActiveRecordFieldOptions): string; -begin - Result := 'SELECT ' + TableFieldsDelimited(Map, PKFieldName, ',') + ' FROM ' + GetTableNameForSQL(TableName); -end; - -function TMVCSQLGeneratorFirebird.CreateSQLWhereByRQL( - const RQL: string; const Mapping: TMVCFieldsMapping; - const UseArtificialLimit: Boolean = True; - const UseFilterOnly: Boolean = False; - const MaxRecordCount: Int32 = TMVCConstants.MAX_RECORD_COUNT): string; -var - lFirebirdCompiler: TRQLFirebirdCompiler; -begin - lFirebirdCompiler := TRQLFirebirdCompiler.Create(Mapping); - try - GetRQLParser.Execute(RQL, Result, lFirebirdCompiler, - UseArtificialLimit, UseFilterOnly, MaxRecordCount); - finally - lFirebirdCompiler.Free; - end; -end; - -function TMVCSQLGeneratorFirebird.CreateUpdateSQL(const TableName: string; const Map: TFieldsMap; - const PKFieldName: string; const PKOptions: TMVCActiveRecordFieldOptions): string; -var - lKeyValue: TPair; -begin - Result := 'UPDATE ' + GetTableNameForSQL(TableName) + ' SET '; - for lKeyValue in Map do - begin - if lKeyValue.Value.Writeable then - begin - Result := Result + GetFieldNameForSQL(lKeyValue.Value.FieldName) + ' = :' + GetParamNameForSQL(lKeyValue.Value.FieldName) + ','; - end; - end; - Result[Length(Result)] := ' '; - if not PKFieldName.IsEmpty then - begin - Result := Result + ' where ' + GetFieldNameForSQL(PKFieldName) + '= :' + GetParamNameForSQL(PKFieldName); - end; -end; - function TMVCSQLGeneratorFirebird.GetCompilerClass: TRQLCompilerClass; begin Result := TRQLFirebirdCompiler; @@ -205,18 +137,6 @@ begin Result := Format('select gen_id(%s,%d) %s from rdb$database', [GetFieldNameForSQL(SequenceName), Step, GetFieldNameForSQL(PKFieldName)]); end; -function TMVCSQLGeneratorFirebird.CreateDeleteAllSQL( - const TableName: string): string; -begin - Result := 'DELETE FROM ' + GetTableNameForSQL(TableName); -end; - -function TMVCSQLGeneratorFirebird.CreateDeleteSQL(const TableName: string; const Map: TFieldsMap; - const PKFieldName: string; const PKOptions: TMVCActiveRecordFieldOptions): string; -begin - Result := CreateDeleteAllSQL(TableName) + ' WHERE ' + GetFieldNameForSQL(PKFieldName) + '=:' + GetParamNameForSQL(PKFieldName); -end; - initialization TMVCSQLGeneratorRegistry.Instance.RegisterSQLGenerator('firebird', TMVCSQLGeneratorFirebird); diff --git a/sources/MVCFramework.SQLGenerators.MSSQL.pas b/sources/MVCFramework.SQLGenerators.MSSQL.pas index 08f8bda0..68db63cf 100644 --- a/sources/MVCFramework.SQLGenerators.MSSQL.pas +++ b/sources/MVCFramework.SQLGenerators.MSSQL.pas @@ -40,39 +40,11 @@ type protected function GetCompilerClass: TRQLCompilerClass; override; public - function CreateSelectSQL( - const TableName: string; - const Map: TFieldsMap; - const PKFieldName: string; - const PKOptions: TMVCActiveRecordFieldOptions): string; override; function CreateInsertSQL( const TableName: string; const Map: TFieldsMap; const PKFieldName: string; const PKOptions: TMVCActiveRecordFieldOptions): string; override; - function CreateUpdateSQL( - const TableName: string; - const Map: TFieldsMap; - const PKFieldName: string; - const PKOptions: TMVCActiveRecordFieldOptions): string; override; - function CreateDeleteSQL( - const TableName: string; - const Map: TFieldsMap; - const PKFieldName: string; - const PKOptions: TMVCActiveRecordFieldOptions): string; override; - function CreateSelectByPKSQL( - const TableName: string; - const Map: TFieldsMap; const PKFieldName: string; - const PKOptions: TMVCActiveRecordFieldOptions): string; override; - function CreateSQLWhereByRQL( - const RQL: string; const Mapping: TMVCFieldsMapping; - const UseArtificialLimit: Boolean = True; - const UseFilterOnly: Boolean = False; - const MaxRecordCount: Int32 = TMVCConstants.MAX_RECORD_COUNT): string; override; - function CreateSelectCount( - const TableName: string): string; override; - function CreateDeleteAllSQL( - const TableName: string): string; override; end; implementation @@ -87,6 +59,7 @@ var lKeyValue: TPair; lSB: TStringBuilder; lPKInInsert: Boolean; + lFieldName: String; begin lPKInInsert := (not PKFieldName.IsEmpty) and (not(TMVCActiveRecordFieldOption.foAutoGenerated in PKOptions)); lPKInInsert := lPKInInsert and (not(TMVCActiveRecordFieldOption.foReadOnly in PKOptions)); @@ -97,6 +70,14 @@ begin begin lSB.Append(PKFieldName + ','); end; + + {partition} + for lFieldName in fPartitionInfo.FieldNames do + begin + lSB.Append(GetFieldNameForSQL(lFieldName) + ','); + end; + {end-partition} + for lKeyValue in Map do begin if lKeyValue.Value.Writeable then @@ -110,6 +91,14 @@ begin begin lSB.Append(':' + PKFieldName + ','); end; + + {partition} + for lFieldName in fPartitionInfo.FieldNames do + begin + lSB.Append(':' + GetParamNameForSQL(lFieldName) + ','); + end; + {end-partition} + for lKeyValue in Map do begin if lKeyValue.Value.Writeable then @@ -130,84 +119,11 @@ begin end; end; -function TMVCSQLGeneratorMSSQL.CreateSelectByPKSQL( - const TableName: string; - const Map: TFieldsMap; const PKFieldName: string; - const PKOptions: TMVCActiveRecordFieldOptions): string; -begin - Result := CreateSelectSQL(TableName, Map, PKFieldName, PKOptions) + ' WHERE ' + - PKFieldName + '= :' + PKFieldName; // IntToStr(PrimaryKeyValue); -end; - -function TMVCSQLGeneratorMSSQL.CreateSelectCount( - const TableName: string): string; -begin - Result := 'SELECT count(*) FROM ' + TableName; -end; - -function TMVCSQLGeneratorMSSQL.CreateSelectSQL(const TableName: string; - const Map: TFieldsMap; const PKFieldName: string; - const PKOptions: TMVCActiveRecordFieldOptions): string; -begin - Result := 'SELECT ' + TableFieldsDelimited(Map, PKFieldName, ',') + ' FROM ' + TableName; -end; - -function TMVCSQLGeneratorMSSQL.CreateSQLWhereByRQL( - const RQL: string; const Mapping: TMVCFieldsMapping; - const UseArtificialLimit: Boolean = True; - const UseFilterOnly: Boolean = False; - const MaxRecordCount: Int32 = TMVCConstants.MAX_RECORD_COUNT): string; -var - lMSSQLCompiler: TRQLMSSQLCompiler; -begin - lMSSQLCompiler := TRQLMSSQLCompiler.Create(Mapping); - try - GetRQLParser.Execute(RQL, Result, lMSSQLCompiler, UseArtificialLimit, UseFilterOnly, MaxRecordCount); - finally - lMSSQLCompiler.Free; - end; -end; - -function TMVCSQLGeneratorMSSQL.CreateUpdateSQL(const TableName: string; const Map: TFieldsMap; - const PKFieldName: string; const PKOptions: TMVCActiveRecordFieldOptions): string; -var - lKeyValue: TPair; -begin - Result := 'UPDATE ' + TableName + ' SET '; - for lKeyValue in Map do - begin - if lKeyValue.Value.Writeable then - begin - Result := Result + lKeyValue.Value.FieldName + ' = :' + lKeyValue.Value.FieldName + ','; - end; - end; - Result[Length(Result)] := ' '; - if not PKFieldName.IsEmpty then - begin - Result := Result + ' where ' + PKFieldName + '= :' + PKFieldName; - end; -end; - function TMVCSQLGeneratorMSSQL.GetCompilerClass: TRQLCompilerClass; begin Result := TRQLMSSQLCompiler; end; -function TMVCSQLGeneratorMSSQL.CreateDeleteAllSQL( - const TableName: string): string; -begin - Result := 'DELETE FROM ' + TableName; -end; - -function TMVCSQLGeneratorMSSQL.CreateDeleteSQL( - const TableName: string; - const Map: TFieldsMap; - const PKFieldName: string; - const PKOptions: TMVCActiveRecordFieldOptions): string; -begin - Result := 'DELETE FROM ' + TableName + ' WHERE ' + PKFieldName + '=:' + PKFieldName; -end; - initialization TMVCSQLGeneratorRegistry.Instance.RegisterSQLGenerator('mssql', TMVCSQLGeneratorMSSQL); diff --git a/sources/MVCFramework.SQLGenerators.MySQL.pas b/sources/MVCFramework.SQLGenerators.MySQL.pas index b8a7daf2..d883288f 100644 --- a/sources/MVCFramework.SQLGenerators.MySQL.pas +++ b/sources/MVCFramework.SQLGenerators.MySQL.pas @@ -40,39 +40,11 @@ type protected function GetCompilerClass: TRQLCompilerClass; override; public - function CreateSelectSQL( - const TableName: string; - const Map: TFieldsMap; - const PKFieldName: string; - const PKOptions: TMVCActiveRecordFieldOptions): string; override; function CreateInsertSQL( const TableName: string; const Map: TFieldsMap; const PKFieldName: string; const PKOptions: TMVCActiveRecordFieldOptions): string; override; - function CreateUpdateSQL( - const TableName: string; - const Map: TFieldsMap; - const PKFieldName: string; - const PKOptions: TMVCActiveRecordFieldOptions): string; override; - function CreateDeleteSQL( - const TableName: string; - const Map: TFieldsMap; - const PKFieldName: string; - const PKOptions: TMVCActiveRecordFieldOptions): string; override; - function CreateDeleteAllSQL( - const TableName: string): string; override; - function CreateSelectByPKSQL( - const TableName: string; - const Map: TFieldsMap; const PKFieldName: string; - const PKOptions: TMVCActiveRecordFieldOptions): string; override; - function CreateSQLWhereByRQL( - const RQL: string; const Mapping: TMVCFieldsMapping; - const UseArtificialLimit: Boolean = True; - const UseFilterOnly: Boolean = False; - const MaxRecordCount: Int32 = TMVCConstants.MAX_RECORD_COUNT): string; override; - function CreateSelectCount( - const TableName: string): string; override; end; implementation @@ -87,6 +59,7 @@ var lKeyValue: TPair; lSB: TStringBuilder; lPKInInsert: Boolean; + lFieldName: String; begin lPKInInsert := (not PKFieldName.IsEmpty) and (not(TMVCActiveRecordFieldOption.foAutoGenerated in PKOptions)); lPKInInsert := lPKInInsert and (not(TMVCActiveRecordFieldOption.foReadOnly in PKOptions)); @@ -97,6 +70,14 @@ begin begin lSB.Append(PKFieldName + ','); end; + + {partition} + for lFieldName in fPartitionInfo.FieldNames do + begin + lSB.Append(GetFieldNameForSQL(lFieldName) + ','); + end; + {end-partition} + for lKeyValue in Map do begin if lKeyValue.Value.Writeable then @@ -111,6 +92,14 @@ begin begin lSB.Append(':' + PKFieldName + ','); end; + + {partition} + for lFieldName in fPartitionInfo.FieldNames do + begin + lSB.Append(':' + GetParamNameForSQL(lFieldName) + ','); + end; + {end-partition} + for lKeyValue in Map do begin if lKeyValue.Value.Writeable then @@ -131,81 +120,11 @@ begin end; end; -function TMVCSQLGeneratorMySQL.CreateSelectByPKSQL( - const TableName: string; - const Map: TFieldsMap; const PKFieldName: string; - const PKOptions: TMVCActiveRecordFieldOptions): string; -begin - Result := CreateSelectSQL(TableName, Map, PKFieldName, PKOptions) + ' WHERE ' + - PKFieldName + '= :' + PKFieldName; // IntToStr(PrimaryKeyValue); -end; - -function TMVCSQLGeneratorMySQL.CreateSelectCount( - const TableName: string): string; -begin - Result := 'SELECT count(*) FROM ' + TableName; -end; - -function TMVCSQLGeneratorMySQL.CreateSelectSQL(const TableName: string; - const Map: TFieldsMap; const PKFieldName: string; - const PKOptions: TMVCActiveRecordFieldOptions): string; -begin - Result := 'SELECT ' + TableFieldsDelimited(Map, PKFieldName, ',') + ' FROM ' + TableName; -end; - -function TMVCSQLGeneratorMySQL.CreateSQLWhereByRQL( - const RQL: string; const Mapping: TMVCFieldsMapping; - const UseArtificialLimit: Boolean = True; - const UseFilterOnly: Boolean = False; - const MaxRecordCount: Int32 = TMVCConstants.MAX_RECORD_COUNT): string; -var - lMySQLCompiler: TRQLMySQLCompiler; -begin - lMySQLCompiler := TRQLMySQLCompiler.Create(Mapping); - try - GetRQLParser.Execute(RQL, Result, lMySQLCompiler, UseArtificialLimit, UseFilterOnly, MaxRecordCount); - finally - lMySQLCompiler.Free; - end; -end; - -function TMVCSQLGeneratorMySQL.CreateUpdateSQL(const TableName: string; const Map: TFieldsMap; - const PKFieldName: string; const PKOptions: TMVCActiveRecordFieldOptions): string; -var - lKeyValue: TPair; -begin - Result := 'UPDATE ' + TableName + ' SET '; - for lKeyValue in Map do - begin - if lKeyValue.Value.Writeable then - begin - Result := Result + lKeyValue.Value.FieldName + ' = :' + lKeyValue.Value.FieldName + ','; - end; - end; - Result[Length(Result)] := ' '; - if not PKFieldName.IsEmpty then - begin - Result := Result + ' where ' + PKFieldName + '= :' + PKFieldName; - end; -end; - function TMVCSQLGeneratorMySQL.GetCompilerClass: TRQLCompilerClass; begin Result := TRQLMySQLCompiler; end; -function TMVCSQLGeneratorMySQL.CreateDeleteAllSQL( - const TableName: string): string; -begin - Result := 'DELETE FROM ' + TableName; -end; - -function TMVCSQLGeneratorMySQL.CreateDeleteSQL(const TableName: string; const Map: TFieldsMap; - const PKFieldName: string; const PKOptions: TMVCActiveRecordFieldOptions): string; -begin - Result := CreateDeleteAllSQL(TableName) + ' WHERE ' + PKFieldName + '=:' + PKFieldName; -end; - initialization TMVCSQLGeneratorRegistry.Instance.RegisterSQLGenerator('mysql', TMVCSQLGeneratorMySQL); diff --git a/sources/MVCFramework.SQLGenerators.PostgreSQL.pas b/sources/MVCFramework.SQLGenerators.PostgreSQL.pas index da2530db..54a3f006 100644 --- a/sources/MVCFramework.SQLGenerators.PostgreSQL.pas +++ b/sources/MVCFramework.SQLGenerators.PostgreSQL.pas @@ -29,8 +29,6 @@ interface uses System.Rtti, System.Generics.Collections, - FireDAC.Phys.FB, - FireDAC.Phys.FBDef, MVCFramework.ActiveRecord, MVCFramework.Commons, MVCFramework.RQL.Parser; @@ -40,40 +38,11 @@ type protected function GetCompilerClass: TRQLCompilerClass; override; public - function CreateSelectSQL( - const TableName: string; - const Map: TFieldsMap; - const PKFieldName: string; - const PKOptions: TMVCActiveRecordFieldOptions): string; override; function CreateInsertSQL( const TableName: string; const Map: TFieldsMap; const PKFieldName: string; const PKOptions: TMVCActiveRecordFieldOptions): string; override; - function CreateUpdateSQL( - const TableName: string; - const Map: TFieldsMap; - const PKFieldName: string; - const PKOptions: TMVCActiveRecordFieldOptions): string; override; - function CreateDeleteSQL( - const TableName: string; - const Map: TFieldsMap; - const PKFieldName: string; - const PKOptions: TMVCActiveRecordFieldOptions): string; override; - function CreateDeleteAllSQL( - const TableName: string): string; override; - function CreateSelectByPKSQL( - const TableName: string; - const Map: TFieldsMap; const PKFieldName: string; - const PKOptions: TMVCActiveRecordFieldOptions): string; override; - function CreateSQLWhereByRQL( - const RQL: string; - const Mapping: TMVCFieldsMapping; - const UseArtificialLimit: Boolean; - const UseFilterOnly: Boolean; - const MaxRecordCount: Int32 = TMVCConstants.MAX_RECORD_COUNT): string; override; - function CreateSelectCount( - const TableName: string): string; override; function GetSequenceValueSQL(const PKFieldName: string; const SequenceName: string; const Step: Integer = 1): string; override; @@ -159,82 +128,6 @@ begin end; end; -function TMVCSQLGeneratorPostgreSQL.CreateSelectByPKSQL( - const TableName: string; - const Map: TFieldsMap; const PKFieldName: string; - const PKOptions: TMVCActiveRecordFieldOptions): string; -begin - if PKFieldName.IsEmpty then - begin - raise EMVCActiveRecord.Create('No primary key provided. [HINT] Define a primary key field adding foPrimaryKey in field options.'); - end; - - Result := CreateSelectSQL(TableName, Map, PKFieldName, PKOptions) + ' WHERE ' + - GetFieldNameForSQL(PKFieldName) + '= :' + GetParamNameForSQL(PKFieldName) + - GetDefaultSQLFilter(False, True); // IntToStr(PrimaryKeyValue); -end; - -function TMVCSQLGeneratorPostgreSQL.CreateSelectCount( - const TableName: string): string; -begin - {do not add SQLFilter here!} - Result := 'SELECT count(*) FROM ' + GetTableNameForSQL(TableName); // + GetDefaultSQLFilter(True); -end; - -function TMVCSQLGeneratorPostgreSQL.CreateSelectSQL(const TableName: string; - const Map: TFieldsMap; const PKFieldName: string; - const PKOptions: TMVCActiveRecordFieldOptions): string; -begin - Result := 'SELECT ' + TableFieldsDelimited(Map, PKFieldName, ',') + ' FROM ' + GetTableNameForSQL(TableName); -end; - -function TMVCSQLGeneratorPostgreSQL.CreateSQLWhereByRQL( - const RQL: string; - const Mapping: TMVCFieldsMapping; - const UseArtificialLimit: Boolean; - const UseFilterOnly: Boolean; - const MaxRecordCount: Int32): string; -var - lPostgreSQLCompiler: TRQLPostgreSQLCompiler; -begin - lPostgreSQLCompiler := TRQLPostgreSQLCompiler.Create(Mapping); - try - GetRQLParser.Execute(MergeDefaultRQLFilter(RQL), Result, lPostgreSQLCompiler, - UseArtificialLimit, UseFilterOnly, MaxRecordCount); - finally - lPostgreSQLCompiler.Free; - end; -end; - -function TMVCSQLGeneratorPostgreSQL.CreateUpdateSQL(const TableName: string; const Map: TFieldsMap; - const PKFieldName: string; const PKOptions: TMVCActiveRecordFieldOptions): string; -var - lPair: TPair; - I: Integer; -begin - Result := 'UPDATE ' + GetTableNameForSQL(TableName) + ' SET '; - for lPair in Map do - begin - if lPair.Value.Writeable then - begin - Result := Result + GetFieldNameForSQL(lPair.Value.FieldName) + ' = :' + - GetParamNameForSQL(lPair.Value.FieldName) + ','; - end; - end; - {partition} - for I := 0 to fPartitionInfo.FieldNames.Count - 1 do - begin - Result := Result + GetFieldNameForSQL(fPartitionInfo.FieldNames[I]) + ' = :' + - GetParamNameForSQL(fPartitionInfo.FieldNames[I]) + ','; - end; - {end-partitioning} - Result[Length(Result)] := ' '; - if not PKFieldName.IsEmpty then - begin - Result := Result + ' where ' + GetFieldNameForSQL(PKFieldName) + '= :' + GetParamNameForSQL(PKFieldName); - end; -end; - function TMVCSQLGeneratorPostgreSQL.GetCompilerClass: TRQLCompilerClass; begin Result := TRQLPostgreSQLCompiler; @@ -246,19 +139,6 @@ begin Result := Format('SELECT nextval(''%s'') %s', [SequenceName, GetFieldNameForSQL(PKFieldName)]); end; -function TMVCSQLGeneratorPostgreSQL.CreateDeleteAllSQL( - const TableName: string): string; -begin - Result := 'DELETE FROM ' + GetTableNameForSQL(TableName); // + GetDefaultSQLFilter(True); -end; - -function TMVCSQLGeneratorPostgreSQL.CreateDeleteSQL(const TableName: string; const Map: TFieldsMap; - const PKFieldName: string; const PKOptions: TMVCActiveRecordFieldOptions): string; -begin - Result := CreateDeleteAllSQL(TableName) + ' WHERE ' + GetFieldNameForSQL(PKFieldName) + '=:' + - GetParamNameForSQL(PKFieldName); -end; - initialization TMVCSQLGeneratorRegistry.Instance.RegisterSQLGenerator('postgresql', TMVCSQLGeneratorPostgreSQL); diff --git a/sources/MVCFramework.SQLGenerators.Sqlite.pas b/sources/MVCFramework.SQLGenerators.Sqlite.pas index ab687b10..11889913 100644 --- a/sources/MVCFramework.SQLGenerators.Sqlite.pas +++ b/sources/MVCFramework.SQLGenerators.Sqlite.pas @@ -38,21 +38,8 @@ type protected function GetCompilerClass: TRQLCompilerClass; override; public - function CreateSelectSQL(const TableName: string; const Map: TFieldsMap; - const PKFieldName: string; const PKOptions: TMVCActiveRecordFieldOptions): string; override; function CreateInsertSQL(const TableName: string; const Map: TFieldsMap; const PKFieldName: string; const PKOptions: TMVCActiveRecordFieldOptions): string; override; - function CreateUpdateSQL(const TableName: string; const Map: TFieldsMap; - const PKFieldName: string; const PKOptions: TMVCActiveRecordFieldOptions): string; override; - function CreateDeleteSQL(const TableName: string; const Map: TFieldsMap; - const PKFieldName: string; const PKOptions: TMVCActiveRecordFieldOptions): string; override; - function CreateDeleteAllSQL(const TableName: string): string; override; - function CreateSelectByPKSQL(const TableName: string; const Map: TFieldsMap; - const PKFieldName: string; const PKOptions: TMVCActiveRecordFieldOptions): string; override; - function CreateSQLWhereByRQL(const RQL: string; const Mapping: TMVCFieldsMapping; - const UseArtificialLimit: Boolean = True; const UseFilterOnly: Boolean = False; - const MaxRecordCount: Int32 = TMVCConstants.MAX_RECORD_COUNT): string; override; - function CreateSelectCount(const TableName: string): string; override; function HasSequences: Boolean; override; end; @@ -68,6 +55,7 @@ var lKeyValue: TPair; lSB: TStringBuilder; lPKInInsert: Boolean; + lFieldName: String; begin lPKInInsert := (not PKFieldName.IsEmpty) and (not(TMVCActiveRecordFieldOption.foAutoGenerated in PKOptions)); @@ -79,6 +67,14 @@ begin begin lSB.Append(GetFieldNameForSQL(PKFieldName) + ','); end; + + {partition} + for lFieldName in fPartitionInfo.FieldNames do + begin + lSB.Append(GetFieldNameForSQL(lFieldName) + ','); + end; + {end-partition} + for lKeyValue in Map do begin if lKeyValue.Value.Writeable then @@ -92,6 +88,14 @@ begin begin lSB.Append(':' + GetParamNameForSQL(PKFieldName) + ','); end; + + {partition} + for lFieldName in fPartitionInfo.FieldNames do + begin + lSB.Append(':' + GetParamNameForSQL(lFieldName) + ','); + end; + {end-partition} + for lKeyValue in Map do begin if lKeyValue.Value.Writeable then @@ -112,64 +116,6 @@ begin end; end; -function TMVCSQLGeneratorSQLite.CreateSelectByPKSQL(const TableName: string; const Map: TFieldsMap; - const PKFieldName: string; const PKOptions: TMVCActiveRecordFieldOptions): string; -begin - Result := CreateSelectSQL(TableName, Map, PKFieldName, PKOptions) + ' WHERE ' + - GetFieldNameForSQL(PKFieldName) + '= :' + GetParamNameForSQL(PKFieldName); - // IntToStr(PrimaryKeyValue); -end; - -function TMVCSQLGeneratorSQLite.CreateSelectCount(const TableName: string): string; -begin - Result := 'SELECT count(*) FROM ' + GetTableNameForSQL(TableName); -end; - -function TMVCSQLGeneratorSQLite.CreateSelectSQL(const TableName: string; const Map: TFieldsMap; - const PKFieldName: string; const PKOptions: TMVCActiveRecordFieldOptions): string; -begin - Result := 'SELECT ' + TableFieldsDelimited(Map, PKFieldName, ',') + ' FROM ' + - GetTableNameForSQL(TableName); -end; - -function TMVCSQLGeneratorSQLite.CreateSQLWhereByRQL(const RQL: string; - const Mapping: TMVCFieldsMapping; const UseArtificialLimit: Boolean = True; - const UseFilterOnly: Boolean = False; - const MaxRecordCount: Int32 = TMVCConstants.MAX_RECORD_COUNT): string; -var - lSQLiteCompiler: TRQLSQLiteCompiler; -begin - lSQLiteCompiler := TRQLSQLiteCompiler.Create(Mapping); - try - GetRQLParser.Execute(RQL, Result, lSQLiteCompiler, - UseArtificialLimit, UseFilterOnly, MaxRecordCount); - finally - lSQLiteCompiler.Free; - end; -end; - -function TMVCSQLGeneratorSQLite.CreateUpdateSQL(const TableName: string; const Map: TFieldsMap; - const PKFieldName: string; const PKOptions: TMVCActiveRecordFieldOptions): string; -var - lKeyValue: TPair; -begin - Result := 'UPDATE ' + GetTableNameForSQL(TableName) + ' SET '; - for lKeyValue in Map do - begin - if lKeyValue.Value.Writeable then - begin - Result := Result + GetFieldNameForSQL(lKeyValue.Value.FieldName) + ' = :' + - GetParamNameForSQL(lKeyValue.Value.FieldName) + ','; - end; - end; - Result[Length(Result)] := ' '; - if not PKFieldName.IsEmpty then - begin - Result := Result + ' where ' + GetFieldNameForSQL(PKFieldName) + '= :' + - GetParamNameForSQL(PKFieldName); - end; -end; - function TMVCSQLGeneratorSQLite.GetCompilerClass: TRQLCompilerClass; begin Result := TRQLSQLiteCompiler; @@ -180,18 +126,6 @@ begin Result := False; end; -function TMVCSQLGeneratorSQLite.CreateDeleteAllSQL(const TableName: string): string; -begin - Result := 'DELETE FROM ' + GetTableNameForSQL(TableName); -end; - -function TMVCSQLGeneratorSQLite.CreateDeleteSQL(const TableName: string; const Map: TFieldsMap; - const PKFieldName: string; const PKOptions: TMVCActiveRecordFieldOptions): string; -begin - Result := CreateDeleteAllSQL(TableName) + ' WHERE ' + GetFieldNameForSQL(PKFieldName) + '=:' + - GetParamNameForSQL(PKFieldName); -end; - initialization TMVCSQLGeneratorRegistry.Instance.RegisterSQLGenerator('sqlite', TMVCSQLGeneratorSQLite); diff --git a/unittests/general/Several/ActiveRecordTestsU.pas b/unittests/general/Several/ActiveRecordTestsU.pas index 9bcc9355..eca5bd6f 100644 --- a/unittests/general/Several/ActiveRecordTestsU.pas +++ b/unittests/general/Several/ActiveRecordTestsU.pas @@ -1203,7 +1203,7 @@ procedure TTestActiveRecordBase.TestPartitioningCRUD; var lRMCustomer: TRomeBasedCustomer; lNYCustomer: TNewYorkBasedCustomer; - lIDRome, lIDNewYork: Integer; + lIDRome: Integer; begin Assert.AreEqual(Int64(0), TMVCActiveRecord.Count()); lRMCustomer := TRomeBasedCustomer.Create; @@ -1221,7 +1221,6 @@ begin lNYCustomer.CompanyName := 'bit Time Professionals NY'; lRMCustomer.Note := 'note2'; lNYCustomer.Insert; - lIDNewYork := lNYCustomer.ID; finally lNYCustomer.Free; end; @@ -1263,10 +1262,10 @@ end; procedure TTestActiveRecordBase.TestPartitioningDelete; begin TMVCActiveRecord.DeleteAll(TCustomer); - var lID1 := CreateACustomer('Daniele', 'Rome', 1); - var lID2 := CreateACustomer('Jack', 'Rome', 2); - var lID3 := CreateACustomer('Bruce', 'Tokyo', 3); - var lID4 := CreateACustomer('John', 'New York', 4); + CreateACustomer('Daniele', 'Rome', 1); + CreateACustomer('Jack', 'Rome', 2); + CreateACustomer('Bruce', 'Tokyo', 3); + CreateACustomer('John', 'New York', 4); var lID5 := CreateACustomer('Scott', 'New York', 5); var lGoodNewYorkCustomer := TMVCActiveRecord.GetByPK(lID5); @@ -1286,11 +1285,11 @@ end; procedure TTestActiveRecordBase.TestPartitioningDeleteByRQL; begin TMVCActiveRecord.DeleteAll(TCustomer); - var lID1 := CreateACustomer('Daniele', 'Rome', 1); - var lID2 := CreateACustomer('Jack', 'Rome', 2); - var lID3 := CreateACustomer('Bruce', 'Tokyo', 3); - var lID4 := CreateACustomer('John', 'New York', 4); - var lID5 := CreateACustomer('Scott', 'New York', 5); + CreateACustomer('Daniele', 'Rome', 1); + CreateACustomer('Jack', 'Rome', 2); + CreateACustomer('Bruce', 'Tokyo', 3); + CreateACustomer('John', 'New York', 4); + CreateACustomer('Scott', 'New York', 5); Assert.AreEqual(Int64(2), TMVCActiveRecord.Count(TNewYorkBasedCustomer)); TMVCActiveRecord.DeleteRQL(TNewYorkBasedCustomer, 'eq(CompanyName,"John")'); @@ -1304,9 +1303,9 @@ procedure TTestActiveRecordBase.TestPartitioningGetByPK; begin TMVCActiveRecord.DeleteAll(TCustomer); var lID1 := CreateACustomer('Daniele', 'Rome', 1); - var lID2 := CreateACustomer('Jack', 'Rome', 2); - var lID3 := CreateACustomer('Bruce', 'Tokyo', 3); - var lID4 := CreateACustomer('John', 'New York', 4); + CreateACustomer('Jack', 'Rome', 2); + CreateACustomer('Bruce', 'Tokyo', 3); + CreateACustomer('John', 'New York', 4); var lID5 := CreateACustomer('Scott', 'New York', 5); var lRomeCustomer := TMVCActiveRecord.GetByPK(lID1); @@ -1380,10 +1379,6 @@ begin end; procedure TTestActiveRecordBase.TestPartitioningSelectByWhere; -var - lRMCustomer: TRomeBasedCustomer; - lNYCustomer: TNewYorkBasedCustomer; - lIDRome, lIDNewYork: Integer; begin Assert.AreEqual(Int64(0), TMVCActiveRecord.Count()); CreateACustomer('Daniele','Rome',1); diff --git a/unittests/general/Several/DMVCFrameworkTests.dpr b/unittests/general/Several/DMVCFrameworkTests.dpr index 9c6f7318..fe3ceb6c 100644 --- a/unittests/general/Several/DMVCFrameworkTests.dpr +++ b/unittests/general/Several/DMVCFrameworkTests.dpr @@ -54,7 +54,19 @@ uses MVCFramework.Commons in '..\..\..\sources\MVCFramework.Commons.pas', MVCFramework.Serializer.JsonDataObjects.CustomTypes in '..\..\..\sources\MVCFramework.Serializer.JsonDataObjects.CustomTypes.pas', MVCFramework.SQLGenerators.Firebird in '..\..\..\sources\MVCFramework.SQLGenerators.Firebird.pas', - MVCFramework.Utils in '..\..\..\sources\MVCFramework.Utils.pas'; + MVCFramework.Utils in '..\..\..\sources\MVCFramework.Utils.pas', + MVCFramework.SQLGenerators.Interbase in '..\..\..\sources\MVCFramework.SQLGenerators.Interbase.pas', + MVCFramework.SQLGenerators.MSSQL in '..\..\..\sources\MVCFramework.SQLGenerators.MSSQL.pas', + MVCFramework.SQLGenerators.MySQL in '..\..\..\sources\MVCFramework.SQLGenerators.MySQL.pas', + MVCFramework.SQLGenerators.PostgreSQL in '..\..\..\sources\MVCFramework.SQLGenerators.PostgreSQL.pas', + MVCFramework.SQLGenerators.Sqlite in '..\..\..\sources\MVCFramework.SQLGenerators.Sqlite.pas', + MVCFramework.RQL.AST2FirebirdSQL in '..\..\..\sources\MVCFramework.RQL.AST2FirebirdSQL.pas', + MVCFramework.RQL.AST2InterbaseSQL in '..\..\..\sources\MVCFramework.RQL.AST2InterbaseSQL.pas', + MVCFramework.RQL.AST2MSSQL in '..\..\..\sources\MVCFramework.RQL.AST2MSSQL.pas', + MVCFramework.RQL.AST2MySQL in '..\..\..\sources\MVCFramework.RQL.AST2MySQL.pas', + MVCFramework.RQL.AST2PostgreSQL in '..\..\..\sources\MVCFramework.RQL.AST2PostgreSQL.pas', + MVCFramework.RQL.AST2SQLite in '..\..\..\sources\MVCFramework.RQL.AST2SQLite.pas', + MVCFramework.RQL.Parser in '..\..\..\sources\MVCFramework.RQL.Parser.pas'; {$R *.RES} diff --git a/unittests/general/Several/DMVCFrameworkTests.dproj b/unittests/general/Several/DMVCFrameworkTests.dproj index 0319a6f2..41622ad9 100644 --- a/unittests/general/Several/DMVCFrameworkTests.dproj +++ b/unittests/general/Several/DMVCFrameworkTests.dproj @@ -219,6 +219,18 @@ + + + + + + + + + + + + Base @@ -309,7 +321,7 @@ - + DMVCFrameworkTests.exe true @@ -333,13 +345,13 @@ true - - + + true - - + + true @@ -361,7 +373,7 @@ true - + DMVCFrameworkTests.exe true