Almost completed merge method for tmvcactiverecord

This commit is contained in:
Daniele Teti 2021-04-29 22:52:28 +02:00
parent d9ebea3d0f
commit 962bd6fbf3
6 changed files with 704 additions and 189 deletions

View File

@ -442,7 +442,7 @@ begin
Result := '';
if PKIsNull then
Result := '<null>';
Result := Format('[ID: %6s][CODE: %6s][CompanyName: %15s][City: %10s][Rating: %3d][Note: %s]',[
Result := Format('[ID: %6s][CODE: %6s][CompanyName: %18s][City: %16s][Rating: %3d][Note: %s]',[
Result, fCode.ValueOrDefault, fCompanyName.ValueOrDefault, fCity, fRating.ValueOrDefault, fNote]);
end;

View File

@ -72,7 +72,6 @@ type
private
procedure Log(const Value: string);
procedure LoadCustomers;
function Merge<T: TMVCActiveRecord>(CurrentList, NewList: TObjectList<T>): IMVCMultiExecutor<T>;
public
{ Public declarations }
end;
@ -441,36 +440,74 @@ var
lCustomersChanges: TObjectList<TCustomer>;
lMultiExecutor: IMVCMultiExecutor<TCustomer>;
begin
Log('** IMVCMultiExecutor demo');
TMVCActiveRecord.DeleteAll(TCustomer);
LoadCustomers;
lCustomers := TMVCActiveRecord.All<TCustomer>;
lCustomers := TMVCActiveRecord.SelectRQL<TCustomer>('eq(rating,1)', 1000);
try
lCustomersChanges := TMVCActiveRecord.SelectRQL<TCustomer>('eq(city,"Rome")', 1000);
lCustomersChanges := TObjectList<TCustomer>.Create(True);
try
lCustomersChanges.Delete(0);
lCustomersChanges[1].CompanyName := 'Changed';
//these 2 customers will be updated
lCustomer := TCustomer.Create;
lCustomersChanges.Add(lCustomer);
lCustomer.ID := lCustomers[0].ID;
lCustomer.Code := 'C8765';
lCustomer.CompanyName := 'New Company';
lCustomer.City := 'New City';
lCustomer.Rating := 3;
lCustomer.CompanyName := '(changed) Company1';
lCustomer.City := '(changed) City';
lCustomer.Rating := 1;
lCustomer := TCustomer.Create;
lCustomersChanges.Add(lCustomer);
lCustomer.ID := lCustomers[1].ID;
lCustomer.Code := lCustomers[1].Code;
lCustomer.CompanyName := '(changed) Company2';
lCustomer.City := '(changed) City';
lCustomer.Rating := 1;
//these 2 customer will be created
lCustomer := TCustomer.Create;
lCustomersChanges.Add(lCustomer);
lCustomer.Code := 'C9898';
lCustomer.CompanyName := 'New Company2';
lCustomer.City := 'New City2';
lCustomer.Rating := 5;
lCustomer.CompanyName := '(new) Company3';
lCustomer.City := '(new) New City2';
lCustomer.Rating := 1;
lMultiExecutor := Merge<TCustomer>(lCustomers, lCustomersChanges);
lMultiExecutor.Apply;
lCustomer := TCustomer.Create;
lCustomersChanges.Add(lCustomer);
lCustomer.Code := 'C2343';
lCustomer.CompanyName := '(new) Company4';
lCustomer.City := '(new) New City2';
lCustomer.Rating := 1;
//all the other customers will be deleted
//calculate the unitofwork to merge the lists
TMVCActiveRecord.Merge<TCustomer>(lCustomers, lCustomersChanges).Apply(
procedure (const Customer: TCustomer; const EntityAction: TMVCEntityAction; var Handled: Boolean)
begin
Handled := False; //set it to true to execute action manually
case EntityAction of
eaCreate: Log('Inserting Customer : ' + Customer.ToString);
eaUpdate: Log('Updating Customer : ' + Customer.ToString);
eaDelete: Log('Deleting Customer : ' + Customer.ToString);
end;
end);
finally
lCustomers.Free;
end;
finally
lCustomersChanges.Free;
end;
lCustomers := TMVCActiveRecord.SelectRQL<TCustomer>('eq(rating,1)', 1000);
try
Assert(lCustomers.Count = 4, 'Expected 4 customers, got ' + lCustomers.Count.ToString);
finally
lCustomers.Free;
end;
end;
procedure TMainForm.btnMultiThreadingClick(Sender: TObject);
@ -1326,57 +1363,5 @@ begin
Memo1.Update;
end;
function TMainForm.Merge<T>(CurrentList, NewList: TObjectList<T>): IMVCMultiExecutor<T>;
var
I: Integer;
lFoundAtIndex: Integer;
lCurrPKValue: Integer;
lPKValue: TValue;
lUnitOfWork: IMVCUnitOfWork<T>;
begin
lUnitOfWork := TMVCUnitOfWork<T>.Create;
lUnitOfWork.RegisterDelete(CurrentList);
for I := 0 to NewList.Count - 1 do
begin
if NewList[I].PKIsNull then
begin
lUnitOfWork.RegisterInsert(NewList[I]);
Continue;
end;
lCurrPKValue := NewList[I].GetPK.AsInteger;
if TMVCUnitOfWork<T>.KeyExists(CurrentList, lCurrPKValue, lFoundAtIndex) then
begin
// update
lUnitOfWork.RegisterUpdate(NewList[I]);
// if KeyExists<T>(lToDelete, lCurrPKValue, lFoundAtIndex) then
// begin
// lUnitOfWork.UnregisterDelete(NewList[I]);
// end
// else
// begin
// raise EMVCActiveRecordNotFound.CreateFmt
// ('Cannot update a non existent record [PK: %s]', [lCurrPKValue.ToString]);
// end;
end
else
begin
// insert
lUnitOfWork.RegisterInsert(NewList[I]);
end;
end;
Result := lUnitOfWork as IMVCMultiExecutor<T>;
// for I := 0 to lToInsert.Count - 1 do
// begin
// Log('INSERT: ' + lToInsert[I].ToString);
// end;
// for I := 0 to lToUpdate.Count - 1 do
// begin
// Log('UPDATE: ' + lToUpdate[I].ToString);
// end;
// for I := 0 to lToDelete.Count - 1 do
// begin
// Log('DELETE: ' + lToDelete[I].ToString);
// end;
end;
end.

View File

@ -58,6 +58,7 @@ type
end;
TMVCActiveRecordClass = class of TMVCActiveRecord;
TMVCActiveRecord = class;
TMVCActiveRecordFieldOption = (foPrimaryKey, { it's the primary key of the mapped table }
foAutoGenerated, { not written, read - similar to readonly }
foTransient, { not written, not read }
@ -83,6 +84,25 @@ type
const id: Integer; var Handled: Boolean);
end;
IMVCUnitOfWork<T: TMVCActiveRecord> = interface
['{68B55DD3-57F6-4CC0-A4DE-BFDE7C3AA287}']
procedure RegisterDelete(const Value: T); overload;
procedure RegisterDelete(const Enumerable: TEnumerable<T>); overload;
procedure RegisterUpdate(const Value: T);
procedure RegisterInsert(const Value: T);
procedure UnregisterDelete(const Value: T);
procedure UnregisterUpdate(const Value: T);
procedure UnregisterInsert(const Value: T);
end;
TMVCItemApplyAction<T: TMVCActiveRecord> = reference to procedure (const Obj: T; const EntityAction: TMVCEntityAction; var Handled: Boolean);
IMVCMultiExecutor<T: TMVCActiveRecord> = interface
['{C815246B-19CA-4F6C-AA67-8E491F809340}']
procedure Apply(const ItemApplyAction: TMVCItemApplyAction<T> = nil);
end;
TFieldInfo = class
public
// TableName: string;
@ -135,8 +155,6 @@ type
end;
TMVCActiveRecord = class;
TMVCSQLGenerator = class;
TMVCActiveRecordList = class(TObjectList<TMVCActiveRecord>)
@ -170,8 +188,6 @@ type
fPropsAttributes: TArray<TCustomAttribute>;
fTableName: string;
fMap: TFieldsMap;
// fMapNonTransientFields: TFieldsMap;
// fMapFieldDataTypes: TDictionary<string, string>;
fPrimaryKey: TRTTIField;
fBackendDriver: string;
fMapping: TMVCFieldsMapping;
@ -353,6 +369,8 @@ type
class function GetFirstByWhere<T: TMVCActiveRecord, constructor>(const SQLWhere: string;
const Params: array of Variant; const ParamTypes: array of TFieldType;
const RaiseExceptionIfNotFound: Boolean = True): T; overload;
class function Merge<T: TMVCActiveRecord>(CurrentList,
NewList: TObjectList<T>): IMVCMultiExecutor<T>;
end;
IMVCEntitiesRegistry = interface
@ -489,32 +507,14 @@ type
function GetSQLGenerator(const aBackend: string): TMVCSQLGeneratorClass;
end;
IMVCUnitOfWork<T: TMVCActiveRecord> = interface
['{68B55DD3-57F6-4CC0-A4DE-BFDE7C3AA287}']
procedure RegisterDelete(const Value: T); overload;
procedure RegisterDelete(const Enumerable: TEnumerable<T>); overload;
procedure RegisterUpdate(const Value: T);
procedure RegisterInsert(const Value: T);
procedure UnregisterDelete(const Value: T);
procedure UnregisterUpdate(const Value: T);
procedure UnregisterInsert(const Value: T);
end;
IMVCMultiExecutor<T: TMVCActiveRecord> = interface
['{C815246B-19CA-4F6C-AA67-8E491F809340}']
procedure Apply;
end;
TMVCUnitOfWork<T: TMVCActiveRecord> = class(TInterfacedObject, IMVCUnitOfWork<T>, IMVCMultiExecutor<T>)
private
fListToDelete: TObjectList<T>;
fListToUpdate: TObjectList<T>;
fListToInsert: TObjectList<T>;
protected
//multiexecutor
procedure Apply;
procedure Apply(const ItemApplyAction: TMVCItemApplyAction<T> = nil);
//unitofwork
procedure RegisterDelete(const Value: T); overload;
procedure RegisterDelete(const Enumerable: TEnumerable<T>); overload;
@ -524,10 +524,9 @@ type
procedure UnregisterUpdate(const Value: T);
procedure UnregisterInsert(const Value: T);
//other methods
function GetListToDelete: TList<T>;
function GetListToUpdate: TList<T>;
function GetListToInsert: TList<T>;
//events
procedure DoItemApplyAction(const Obj: TMVCActiveRecord; const EntityAction: TMVCEntityAction; const ItemApplyAction: TMVCItemApplyAction<T>; var Handled: Boolean);
class function KeyExists(const NewList: TObjectList<T>; const KeyValue: Integer;
out Index: Integer): Boolean;
public
@ -536,9 +535,7 @@ type
end;
function ActiveRecordConnectionsRegistry: IMVCActiveRecordConnections;
function ActiveRecordMappingRegistry: IMVCEntitiesRegistry;
function GetBackEndByConnection(aConnection: TFDConnection): string;
implementation
@ -2592,6 +2589,61 @@ class function TMVCActiveRecordHelper.Where<T>(const SQLWhere: string; const Par
begin
Result := Where<T>(SQLWhere, Params, []);
end;
class function TMVCActiveRecordHelper.Merge<T>(CurrentList, NewList: TObjectList<T>): IMVCMultiExecutor<T>;
var
I: Integer;
lFoundAtIndex: Integer;
lCurrPKValue: Integer;
lPKValue: TValue;
lUnitOfWork: IMVCUnitOfWork<T>;
begin
lUnitOfWork := TMVCUnitOfWork<T>.Create;
lUnitOfWork.RegisterDelete(CurrentList);
for I := 0 to NewList.Count - 1 do
begin
if NewList[I].PKIsNull then
begin
lUnitOfWork.RegisterInsert(NewList[I]);
Continue;
end;
lCurrPKValue := NewList[I].GetPK.AsInteger;
if TMVCUnitOfWork<T>.KeyExists(CurrentList, lCurrPKValue, lFoundAtIndex) then
begin
// update
lUnitOfWork.RegisterUpdate(NewList[I]);
// if KeyExists<T>(lToDelete, lCurrPKValue, lFoundAtIndex) then
// begin
// lUnitOfWork.UnregisterDelete(NewList[I]);
// end
// else
// begin
// raise EMVCActiveRecordNotFound.CreateFmt
// ('Cannot update a non existent record [PK: %s]', [lCurrPKValue.ToString]);
// end;
end
else
begin
// insert
lUnitOfWork.RegisterInsert(NewList[I]);
end;
end;
Result := lUnitOfWork as IMVCMultiExecutor<T>;
// for I := 0 to lToInsert.Count - 1 do
// begin
// Log('INSERT: ' + lToInsert[I].ToString);
// end;
// for I := 0 to lToUpdate.Count - 1 do
// begin
// Log('UPDATE: ' + lToUpdate[I].ToString);
// end;
// for I := 0 to lToDelete.Count - 1 do
// begin
// Log('DELETE: ' + lToDelete[I].ToString);
// end;
end;
{ PrimaryKeyAttribute }
// constructor MVCPrimaryKeyAttribute.Create(const aFieldName: string);
@ -2965,21 +3017,37 @@ end;
{ TMVCUnitOfWork<T> }
procedure TMVCUnitOfWork<T>.Apply;
procedure TMVCUnitOfWork<T>.Apply(const ItemApplyAction: TMVCItemApplyAction<T>);
var
I: UInt32;
lHandled: Boolean;
begin
for I := 0 to fListToInsert.Count - 1 do
begin
fListToInsert[I].Insert;
lHandled := False;
DoItemApplyAction(fListToInsert[I], eaCreate, ItemApplyAction, lHandled);
if not lHandled then
begin
fListToInsert[I].Insert;
end;
end;
for I := 0 to fListToUpdate.Count - 1 do
begin
fListToUpdate[I].Update;
lHandled := False;
DoItemApplyAction(fListToUpdate[I], eaUpdate, ItemApplyAction, lHandled);
if not lHandled then
begin
fListToUpdate[I].Update;
end;
end;
for I := 0 to fListToDelete.Count - 1 do
begin
fListToDelete[I].Delete;
lHandled := False;
DoItemApplyAction(fListToDelete[I], eaDelete, ItemApplyAction, lHandled);
if not lHandled then
begin
fListToDelete[I].Delete;
end;
end;
end;
@ -2999,20 +3067,31 @@ begin
inherited;
end;
function TMVCUnitOfWork<T>.GetListToDelete: TList<T>;
procedure TMVCUnitOfWork<T>.DoItemApplyAction(const Obj: TMVCActiveRecord;
const EntityAction: TMVCEntityAction;
const ItemApplyAction: TMVCItemApplyAction<T>;
var Handled: Boolean);
begin
Result := fListToDelete;
if Assigned(ItemApplyAction) then
begin
ItemApplyAction(Obj, EntityAction, Handled);
end;
end;
function TMVCUnitOfWork<T>.GetListToInsert: TList<T>;
begin
Result := fListToInsert;
end;
function TMVCUnitOfWork<T>.GetListToUpdate: TList<T>;
begin
Result := fListToUpdate;
end;
//function TMVCUnitOfWork<T>.GetListToDelete: TList<T>;
//begin
// Result := fListToDelete;
//end;
//
//function TMVCUnitOfWork<T>.GetListToInsert: TList<T>;
//begin
// Result := fListToInsert;
//end;
//
//function TMVCUnitOfWork<T>.GetListToUpdate: TList<T>;
//begin
// Result := fListToUpdate;
//end;
class function TMVCUnitOfWork<T>.KeyExists(const NewList: TObjectList<T>;
const KeyValue: Integer; out Index: Integer): Boolean;
@ -3032,17 +3111,17 @@ end;
procedure TMVCUnitOfWork<T>.RegisterDelete(const Value: T);
begin
GetListToDelete.Add(Value);
fListToDelete.Add(Value);
end;
procedure TMVCUnitOfWork<T>.RegisterDelete(const Enumerable: TEnumerable<T>);
begin
GetListToDelete.AddRange(Enumerable);
fListToDelete.AddRange(Enumerable);
end;
procedure TMVCUnitOfWork<T>.RegisterInsert(const Value: T);
begin
GetListToInsert.Add(Value);
fListToInsert.Add(Value);
end;
procedure TMVCUnitOfWork<T>.RegisterUpdate(const Value: T);
@ -3050,7 +3129,7 @@ var
lCurrPKValue: Integer;
lFoundAtIndex: Integer;
begin
GetListToUpdate.Add(Value);
fListToUpdate.Add(Value);
lCurrPKValue := Value.GetPK.AsInteger;
if KeyExists(fListToDelete, lCurrPKValue, lFoundAtIndex) then
begin
@ -3060,17 +3139,17 @@ end;
procedure TMVCUnitOfWork<T>.UnregisterDelete(const Value: T);
begin
GetListToDelete.Remove(Value);
fListToDelete.Remove(Value);
end;
procedure TMVCUnitOfWork<T>.UnregisterInsert(const Value: T);
begin
GetListToInsert.Remove(Value);
fListToInsert.Remove(Value);
end;
procedure TMVCUnitOfWork<T>.UnregisterUpdate(const Value: T);
begin
GetListToUpdate.Remove(Value);
fListToUpdate.Remove(Value);
end;
initialization

View File

@ -1,7 +1,7 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{ABDCF3F4-55C9-4C93-9DA7-7E7D35B0FE68}</ProjectGuid>
<ProjectVersion>18.8</ProjectVersion>
<ProjectVersion>19.2</ProjectVersion>
<FrameworkType>VCL</FrameworkType>
<MainSource>MVCAREntitiesGenerator.dpr</MainSource>
<Base>True</Base>
@ -326,6 +326,16 @@
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon192">
<Platform Name="Android">
<RemoteDir>res\drawable-xxxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-xxxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon36">
<Platform Name="Android">
<RemoteDir>res\drawable-ldpi</RemoteDir>
@ -577,6 +587,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>
@ -709,6 +745,16 @@
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch2x">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch768">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
@ -731,6 +777,66 @@
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_LaunchDark2x">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
<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>
@ -830,6 +936,16 @@
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch2x">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch320">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
@ -841,6 +957,16 @@
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch3x">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch640">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
@ -885,6 +1011,86 @@
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_LaunchDark2x">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_LaunchDark3x">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
<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>
@ -932,6 +1138,16 @@
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSLaunchScreen">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen</RemoteDir>
<Operation>64</Operation>
</Platform>
<Platform Name="iOSSimulator">
<RemoteDir>..\$(PROJECTNAME).launchscreen</RemoteDir>
<Operation>64</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSResource">
<Platform Name="iOSDevice32">
<Operation>1</Operation>

View File

@ -3,7 +3,7 @@ object MainForm: TMainForm
Top = 0
Caption = '[DMVCFramework] MVCActiveRecord Entity Generator'
ClientHeight = 630
ClientWidth = 863
ClientWidth = 909
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
@ -18,7 +18,7 @@ object MainForm: TMainForm
object Splitter1: TSplitter
Left = 0
Top = 207
Width = 863
Width = 909
Height = 3
Cursor = crVSplit
Align = alTop
@ -28,13 +28,14 @@ object MainForm: TMainForm
object Panel1: TPanel
Left = 0
Top = 0
Width = 863
Width = 909
Height = 39
Align = alTop
TabOrder = 0
ExplicitWidth = 863
object Label1: TLabel
AlignWithMargins = True
Left = 497
Left = 543
Top = 11
Width = 190
Height = 17
@ -45,11 +46,12 @@ object MainForm: TMainForm
Align = alRight
Caption = 'Select a FireDAC Connection Definitions'
Layout = tlCenter
ExplicitLeft = 497
ExplicitHeight = 13
end
object cboConnectionDefs: TComboBox
AlignWithMargins = True
Left = 707
Left = 753
Top = 11
Width = 145
Height = 21
@ -60,12 +62,13 @@ object MainForm: TMainForm
Align = alRight
TabOrder = 0
OnChange = cboConnectionDefsChange
ExplicitLeft = 707
end
end
object Panel2: TPanel
Left = 0
Top = 39
Width = 863
Width = 909
Height = 168
Align = alTop
Caption = 'Panel1'
@ -76,11 +79,12 @@ object MainForm: TMainForm
Font.Style = []
ParentFont = False
TabOrder = 1
ExplicitWidth = 863
object Label2: TLabel
AlignWithMargins = True
Left = 4
Top = 4
Width = 855
Width = 901
Height = 13
Align = alTop
Caption = 'FireDAC connection parameters'
@ -90,7 +94,7 @@ object MainForm: TMainForm
AlignWithMargins = True
Left = 4
Top = 23
Width = 489
Width = 535
Height = 141
Align = alClient
Font.Charset = ANSI_CHARSET
@ -103,9 +107,10 @@ object MainForm: TMainForm
TabOrder = 0
WordWrap = False
OnChange = mmConnectionParamsChange
ExplicitWidth = 489
end
object Panel6: TPanel
Left = 496
Left = 542
Top = 20
Width = 366
Height = 147
@ -114,6 +119,7 @@ object MainForm: TMainForm
Caption = 'Panel6'
ShowCaption = False
TabOrder = 1
ExplicitLeft = 496
object GroupBox1: TGroupBox
AlignWithMargins = True
Left = 3
@ -166,28 +172,69 @@ object MainForm: TMainForm
object Panel3: TPanel
Left = 0
Top = 210
Width = 863
Width = 909
Height = 420
Align = alClient
Caption = 'Panel3'
TabOrder = 2
ExplicitWidth = 863
object Panel4: TPanel
Left = 1
Top = 1
Width = 861
Height = 41
Width = 907
Height = 120
Align = alTop
BevelOuter = bvNone
Caption = 'Panel4'
ShowCaption = False
TabOrder = 0
ExplicitWidth = 861
DesignSize = (
907
120)
object SpeedButton1: TSpeedButton
AlignWithMargins = True
Left = 140
Top = 4
Width = 100
Height = 29
Margins.Top = 2
Margins.Right = 2
Margins.Bottom = 2
Caption = 'Select All'
OnClick = SpeedButton1Click
end
object SpeedButton2: TSpeedButton
AlignWithMargins = True
Left = 245
Top = 4
Width = 100
Height = 29
Margins.Top = 2
Margins.Right = 2
Margins.Bottom = 2
Caption = 'Select None'
OnClick = SpeedButton2Click
end
object SpeedButton3: TSpeedButton
AlignWithMargins = True
Left = 350
Top = 4
Width = 100
Height = 29
Margins.Top = 2
Margins.Right = 2
Margins.Bottom = 2
Caption = 'Invert Selection'
OnClick = SpeedButton3Click
end
object btnGenEntities: TButton
AlignWithMargins = True
Left = 129
Top = 3
Left = 774
Top = 82
Width = 120
Height = 35
Align = alLeft
Anchors = [akRight, akBottom]
Caption = 'Generate Entities'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
@ -204,7 +251,6 @@ object MainForm: TMainForm
Top = 3
Width = 120
Height = 35
Align = alLeft
Caption = 'Get Tables'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
@ -216,42 +262,87 @@ object MainForm: TMainForm
OnClick = btnGetTablesClick
end
object chGenerateMapping: TCheckBox
Left = 255
Top = 12
Width = 514
Height = 17
AlignWithMargins = True
Left = 470
Top = -2
Width = 262
Height = 48
Caption =
'Register entities in ActiveRecordMappingRegistry (needed by TMVC' +
'ActiveRecordController)'
Checked = True
State = cbChecked
TabOrder = 2
WordWrap = True
end
object RadioGroup1: TRadioGroup
Left = 7
Top = 47
Width = 443
Height = 70
Caption = 'MVCNameCase'
Columns = 3
ItemIndex = 0
Items.Strings = (
'LowerCase'
'UpperCase'
'CamelCase'
'PascalCase'
'SnakeCase'
'AsIs')
TabOrder = 3
end
end
object PageControl1: TPageControl
AlignWithMargins = True
Left = 4
Top = 45
Width = 855
Height = 371
Top = 124
Width = 901
Height = 292
ActivePage = TabSheet1
Align = alClient
TabOrder = 1
ExplicitTop = 45
ExplicitWidth = 855
ExplicitHeight = 371
object TabSheet1: TTabSheet
Caption = 'Tables'
object DBGrid1: TDBGrid
Left = 0
Top = 0
Width = 847
Height = 343
Width = 893
Height = 264
Align = alClient
DataSource = dsrcTablesMapping
DefaultDrawing = False
TabOrder = 0
TitleFont.Charset = DEFAULT_CHARSET
TitleFont.Color = clWindowText
TitleFont.Height = -11
TitleFont.Name = 'Tahoma'
TitleFont.Style = []
OnCellClick = DBGrid1CellClick
OnDrawColumnCell = DBGrid1DrawColumnCell
Columns = <
item
Expanded = False
FieldName = 'GENERATE'
PickList.Strings = (
'yes'
'no')
Width = 58
Visible = True
end
item
Expanded = False
FieldName = 'TABLE_NAME'
Visible = True
end
item
Expanded = False
FieldName = 'CLASS_NAME'
Visible = True
end>
end
end
object TabSheet2: TTabSheet
@ -261,8 +352,8 @@ object MainForm: TMainForm
AlignWithMargins = True
Left = 3
Top = 44
Width = 841
Height = 296
Width = 887
Height = 217
Align = alClient
BevelInner = bvNone
BevelOuter = bvNone
@ -277,16 +368,19 @@ object MainForm: TMainForm
ScrollBars = ssBoth
TabOrder = 0
WordWrap = False
ExplicitWidth = 841
ExplicitHeight = 296
end
object Panel5: TPanel
Left = 0
Top = 0
Width = 847
Width = 893
Height = 41
Align = alTop
Caption = 'Panel5'
ShowCaption = False
TabOrder = 1
ExplicitWidth = 847
object btnSaveCode: TButton
AlignWithMargins = True
Left = 4
@ -325,7 +419,7 @@ object MainForm: TMainForm
Top = 152
end
object FDPhysFBDriverLink1: TFDPhysFBDriverLink
Left = 616
Left = 504
Top = 496
end
object FDGUIxWaitCursor1: TFDGUIxWaitCursor
@ -334,8 +428,8 @@ object MainForm: TMainForm
Top = 104
end
object FDPhysMSSQLDriverLink1: TFDPhysMSSQLDriverLink
Left = 752
Top = 360
Left = 784
Top = 568
end
object FileSaveDialog1: TFileSaveDialog
FavoriteLinks = <>
@ -345,35 +439,51 @@ object MainForm: TMainForm
FileMask = '*.pas'
end>
Options = []
Left = 424
Top = 320
Left = 328
Top = 416
end
object FDPhysMySQLDriverLink1: TFDPhysMySQLDriverLink
Left = 752
Top = 496
Left = 616
Top = 568
end
object FDPhysPgDriverLink1: TFDPhysPgDriverLink
Left = 752
Top = 424
Left = 784
Top = 496
end
object FDPhysFBDriverLink2: TFDPhysFBDriverLink
Left = 616
Top = 424
Top = 408
end
object FDPhysIBDriverLink1: TFDPhysIBDriverLink
Left = 752
Top = 280
Left = 616
Top = 496
end
object FDPhysMySQLDriverLink2: TFDPhysMySQLDriverLink
Left = 616
Top = 360
Left = 504
Top = 568
end
object FDPhysSQLiteDriverLink1: TFDPhysSQLiteDriverLink
Left = 608
Top = 280
Left = 504
Top = 408
end
object dsTablesMapping: TFDMemTable
Active = True
FieldDefs = <
item
Name = 'TABLE_NAME'
DataType = ftString
Size = 100
end
item
Name = 'CLASS_NAME'
DataType = ftString
Size = 100
end
item
Name = 'GENERATE'
DataType = ftBoolean
end>
IndexDefs = <>
FetchOptions.AssignedValues = [evMode]
FetchOptions.Mode = fmAll
ResourceOptions.AssignedValues = [rvSilentMode]
@ -381,8 +491,13 @@ object MainForm: TMainForm
UpdateOptions.AssignedValues = [uvCheckRequired, uvAutoCommitUpdates]
UpdateOptions.CheckRequired = False
UpdateOptions.AutoCommitUpdates = True
Left = 48
Top = 304
StoreDefs = True
Left = 96
Top = 504
object dsTablesMappingGENERATE: TBooleanField
DisplayLabel = 'Generate?'
FieldName = 'GENERATE'
end
object dsTablesMappingTABLE_NAME: TStringField
DisplayLabel = 'Table Name'
DisplayWidth = 60
@ -398,7 +513,7 @@ object MainForm: TMainForm
end
object dsrcTablesMapping: TDataSource
DataSet = dsTablesMapping
Left = 48
Top = 368
Left = 96
Top = 448
end
end

View File

@ -49,9 +49,11 @@ uses
FireDAC.Phys.IB,
FireDAC.Stan.ExprFuncs,
FireDAC.Phys.SQLiteDef,
FireDAC.Phys.SQLite, Vcl.DBGrids, FireDAC.Phys.SQLiteWrapper.Stat;
FireDAC.Phys.SQLite, Vcl.DBGrids, FireDAC.Phys.SQLiteWrapper.Stat, Vcl.Buttons;
type
TSelectionType = (stAll, stNone, stInverse);
TMainForm = class(TForm)
FDConnection1: TFDConnection;
Panel1: TPanel;
@ -93,6 +95,11 @@ type
btnRefreshCatalog: TButton;
Label1: TLabel;
chGenerateMapping: TCheckBox;
dsTablesMappingGENERATE: TBooleanField;
SpeedButton1: TSpeedButton;
SpeedButton2: TSpeedButton;
SpeedButton3: TSpeedButton;
RadioGroup1: TRadioGroup;
procedure btnGenEntitiesClick(Sender: TObject);
procedure btnGetTablesClick(Sender: TObject);
procedure btnSaveCodeClick(Sender: TObject);
@ -103,22 +110,30 @@ type
procedure btnRefreshCatalogClick(Sender: TObject);
procedure mmConnectionParamsChange(Sender: TObject);
procedure lstSchemaDblClick(Sender: TObject);
procedure DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect;
DataCol: Integer; Column: TColumn; State: TGridDrawState);
procedure DBGrid1CellClick(Column: TColumn);
procedure SpeedButton2Click(Sender: TObject);
procedure SpeedButton3Click(Sender: TObject);
procedure SpeedButton1Click(Sender: TObject);
private
fCatalog: string;
fSchema: string;
fIntfBuff, fImplBuff, fInitializationBuff: TStringStream;
FHistoryFileName: string;
lTypesName: TArray<string>;
fBookmark: TArray<Byte>;
procedure EmitHeaderComments;
function GetClassName(const aTableName: string): string;
procedure EmitUnit;
procedure EmitUnitEnd;
procedure EmitProperty(F: TField);
procedure EmitField(F: TField; const IsPK: Boolean);
procedure EmitClass(const aTableName, aClassName: string);
procedure EmitClass(const aTableName, aClassName, aNameCase: string);
procedure EmitClassEnd;
function GetDelphiType(FT: TFieldType): string;
function GetFieldName(const Value: string): string;
procedure DoSelection(const SelectionType: TSelectionType);
public
{ Public declarations }
end;
@ -126,10 +141,13 @@ type
var
MainForm: TMainForm;
const
LOG_TAG = 'generator';
implementation
uses
System.IOUtils, System.TypInfo, System.DateUtils;
System.IOUtils, System.TypInfo, System.DateUtils, LoggerPro.GlobalLogger;
{$R *.dfm}
@ -146,6 +164,7 @@ var
lFieldsName: TArray<string>;
lKeyFields: TStringList;
begin
Log.Info('Starting entities generation', LOG_TAG);
fIntfBuff.Clear;
fImplBuff.Clear;
fInitializationBuff.Clear;
@ -157,11 +176,24 @@ begin
I := 0;
while not dsTablesMapping.Eof do
begin
if not dsTablesMappingGENERATE.Value then
begin
Log.Info('Skipping table %s', [dsTablesMappingTABLE_NAME.AsString], LOG_TAG);
dsTablesMapping.Next;
Continue;
end;
lTableName := dsTablesMappingTABLE_NAME.AsString;
Log.Info('Generating entity %s for table %s', [dsTablesMappingCLASS_NAME.AsString,
dsTablesMappingTABLE_NAME.AsString], LOG_TAG);
lClassName := dsTablesMappingCLASS_NAME.AsString;
EmitClass(lTableName, lClassName);
EmitClass(lTableName, lClassName, RadioGroup1.Items[RadioGroup1.ItemIndex]);
lKeyFields.Clear;
qry.Close;
qry.Open('select * from ' + lTableName + ' where 1=0');
FDConnection1.GetKeyFieldNames(fCatalog, fSchema, lTableName, '', lKeyFields);
try
FDConnection1.GetKeyFieldNames(fCatalog, fSchema, lTableName, '', lKeyFields);
except
end;
lFieldsName := [];
lTypesName := [];
fIntfBuff.WriteString(INDENT + 'private' + sLineBreak);
@ -185,7 +217,8 @@ begin
fImplBuff.WriteString(' inherited Create;' + sLineBreak);
for F := low(lFieldsName) to high(lFieldsName) do
begin
fImplBuff.WriteString(' ' + lFieldsName[F] + ' := ' + lTypesName[F] + '.Create;' + sLineBreak);
fImplBuff.WriteString(' ' + lFieldsName[F] + ' := ' + lTypesName[F] + '.Create;' +
sLineBreak);
end;
fImplBuff.WriteString('end;' + sLineBreak + sLineBreak);
@ -208,7 +241,8 @@ begin
dsTablesMapping.Next;
end;
EmitUnitEnd;
mmOutput.Lines.Text := fIntfBuff.DataString + fImplBuff.DataString + fInitializationBuff.DataString;
mmOutput.Lines.Text := fIntfBuff.DataString + fImplBuff.DataString +
fInitializationBuff.DataString;
finally
lKeyFields.Free;
@ -248,7 +282,7 @@ begin
for lTable in lTables do
begin
lClassName := GetClassName(lTable);
dsTablesMapping.AppendRecord([lTable, lClassName]);
dsTablesMapping.AppendRecord([True, lTable, lClassName]);
end;
dsTablesMapping.First;
finally
@ -286,15 +320,74 @@ begin
FDConnection1.Params.Text := mmConnectionParams.Text;
end;
procedure TMainForm.EmitClass(const aTableName, aClassName: string);
procedure TMainForm.DBGrid1CellClick(Column: TColumn);
begin
fIntfBuff.WriteString(INDENT + '[MVCNameCase(ncLowerCase)]' + sLineBreak);
if Column.FieldName = 'GENERATE' then
begin
if not(dsTablesMapping.State = dsEdit) then
begin
dsTablesMapping.Edit;
end;
dsTablesMappingGENERATE.Value := not dsTablesMappingGENERATE.Value;
end;
end;
procedure TMainForm.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect;
DataCol: Integer; Column: TColumn; State: TGridDrawState);
const
IsChecked: array [Boolean] of Integer = (DFCS_BUTTONCHECK, DFCS_BUTTONCHECK or DFCS_CHECKED);
var
DrawState: Integer;
DrawRect: TRect;
begin
if (Column.Field.FieldName = 'GENERATE') then
begin
DrawRect := Rect;
InflateRect(DrawRect, -1, -1);
DrawState := IsChecked[Column.Field.AsBoolean];
DBGrid1.Canvas.FillRect(Rect);
DrawFrameControl(DBGrid1.Canvas.Handle, DrawRect,
DFC_BUTTON, DrawState);
end
else
begin
DBGrid1.DefaultDrawColumnCell(Rect, DataCol, Column, State);
end;
end;
procedure TMainForm.DoSelection(const SelectionType: TSelectionType);
begin
dsTablesMapping.DisableControls;
try
fBookmark := dsTablesMapping.GetBookmark;
dsTablesMapping.First;
while not dsTablesMapping.Eof do
begin
dsTablesMapping.Edit;
case SelectionType of
stAll: dsTablesMappingGENERATE.Value := True;
stNone: dsTablesMappingGENERATE.Value := False;
stInverse: dsTablesMappingGENERATE.Value := not dsTablesMappingGENERATE.Value;
end;
dsTablesMapping.Post;
dsTablesMapping.Next;
end;
dsTablesMapping.Bookmark := fBookmark;
finally
dsTablesMapping.EnableControls;
end;
end;
procedure TMainForm.EmitClass(const aTableName, aClassName, aNameCase: string);
begin
fIntfBuff.WriteString(INDENT + '[MVCNameCase(nc' + aNameCase + ')]' + sLineBreak);
fIntfBuff.WriteString(INDENT + Format('[MVCTable(''%s'')]', [aTableName]) + sLineBreak);
if trim(aClassName) = '' then
raise Exception.Create('Invalid class name');
fIntfBuff.WriteString(INDENT + aClassName + ' = class(TMVCActiveRecord)' + sLineBreak);
if chGenerateMapping.Checked then
fInitializationBuff.WriteString(INDENT + Format('ActiveRecordMappingRegistry.AddEntity(''%s'',%s);',
fInitializationBuff.WriteString
(INDENT + Format('ActiveRecordMappingRegistry.AddEntity(''%s'',%s);',
[aTableName.ToLower, aClassName]) + sLineBreak);
end;
@ -332,30 +425,40 @@ end;
procedure TMainForm.EmitHeaderComments;
begin
fIntfBuff.WriteString('// *************************************************************************** }' +
fIntfBuff.WriteString
('// *************************************************************************** }' +
sLineBreak);
fIntfBuff.WriteString('//' + sLineBreak);
fIntfBuff.WriteString('// Delphi MVC Framework' + sLineBreak);
fIntfBuff.WriteString('//' + sLineBreak);
fIntfBuff.WriteString('// Copyright (c) 2010-' + YearOf(Date).ToString + ' Daniele Teti and the DMVCFramework Team' + sLineBreak);
fIntfBuff.WriteString('// Copyright (c) 2010-' + YearOf(Date).ToString +
' Daniele Teti and the DMVCFramework Team' + sLineBreak);
fIntfBuff.WriteString('//' + sLineBreak);
fIntfBuff.WriteString('// https://github.com/danieleteti/delphimvcframework' + sLineBreak);
fIntfBuff.WriteString('//' + sLineBreak);
fIntfBuff.WriteString('// ***************************************************************************' + sLineBreak);
fIntfBuff.WriteString
('// ***************************************************************************' + sLineBreak);
fIntfBuff.WriteString('//' + sLineBreak);
fIntfBuff.WriteString('// Licensed under the Apache License, Version 2.0 (the "License");' + sLineBreak);
fIntfBuff.WriteString('// you may not use this file except in compliance with the License.' + sLineBreak);
fIntfBuff.WriteString('// Licensed under the Apache License, Version 2.0 (the "License");' +
sLineBreak);
fIntfBuff.WriteString('// you may not use this file except in compliance with the License.' +
sLineBreak);
fIntfBuff.WriteString('// You may obtain a copy of the License at' + sLineBreak);
fIntfBuff.WriteString('//' + sLineBreak);
fIntfBuff.WriteString('// http://www.apache.org/licenses/LICENSE-2.0' + sLineBreak);
fIntfBuff.WriteString('//' + sLineBreak);
fIntfBuff.WriteString('// Unless required by applicable law or agreed to in writing, software' + sLineBreak);
fIntfBuff.WriteString('// distributed under the License is distributed on an "AS IS" BASIS,' + sLineBreak);
fIntfBuff.WriteString('// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.' + sLineBreak);
fIntfBuff.WriteString('// See the License for the specific language governing permissions and' + sLineBreak);
fIntfBuff.WriteString('// Unless required by applicable law or agreed to in writing, software' +
sLineBreak);
fIntfBuff.WriteString('// distributed under the License is distributed on an "AS IS" BASIS,' +
sLineBreak);
fIntfBuff.WriteString
('// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.' + sLineBreak);
fIntfBuff.WriteString('// See the License for the specific language governing permissions and' +
sLineBreak);
fIntfBuff.WriteString('// limitations under the License.' + sLineBreak);
fIntfBuff.WriteString('//' + sLineBreak);
fIntfBuff.WriteString('// ***************************************************************************' + sLineBreak);
fIntfBuff.WriteString
('// ***************************************************************************' + sLineBreak);
fIntfBuff.WriteString(sLineBreak);
end;
@ -368,7 +471,8 @@ begin
lProp := Format('[MVCNameAs(''%s'')]', [F.FieldName]) + sLineBreak + INDENT + INDENT;
end;
lProp := lProp + 'property ' + GetFieldName(F.FieldName).Substring(1) { remove f } + ': ' +
GetDelphiType(F.DataType) + ' read ' + GetFieldName(F.FieldName) + ' write ' + GetFieldName(F.FieldName) + ';' +
GetDelphiType(F.DataType) + ' read ' + GetFieldName(F.FieldName) + ' write ' +
GetFieldName(F.FieldName) + ';' +
sLineBreak;
if GetDelphiType(F.DataType).ToUpper.Contains('UNSUPPORTED TYPE') then
@ -418,7 +522,8 @@ begin
fIntfBuff := TStringStream.Create;
fImplBuff := TStringStream.Create;
fInitializationBuff := TStringStream.Create;
FHistoryFileName := TPath.Combine(TPath.GetDocumentsPath, TPath.GetFileNameWithoutExtension(ParamStr(0)) +
FHistoryFileName := TPath.Combine(TPath.GetDocumentsPath,
TPath.GetFileNameWithoutExtension(ParamStr(0)) +
'.history');
try
if TFile.Exists(FHistoryFileName) then
@ -532,4 +637,19 @@ begin
lstCatalog.Clear;
end;
procedure TMainForm.SpeedButton1Click(Sender: TObject);
begin
DoSelection(stAll);
end;
procedure TMainForm.SpeedButton2Click(Sender: TObject);
begin
DoSelection(stNone);
end;
procedure TMainForm.SpeedButton3Click(Sender: TObject);
begin
DoSelection(stInverse);
end;
end.