Skip to content

Commit

Permalink
https://github.com/danieleteti/delphimvcframework/issues/631
Browse files Browse the repository at this point in the history
  • Loading branch information
danieleteti committed Jan 29, 2023
1 parent c033150 commit 0023ebe
Show file tree
Hide file tree
Showing 12 changed files with 2,636 additions and 70 deletions.
10 changes: 8 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1423,16 +1423,22 @@ The current beta release is named 3.2.3-radium-beta. If you want to stay on the-

- mid-air-collision handling now uses SHA1 instead of MD5

- Added `MVCFramework.Commons.MVC_HTTP_STATUS_CODES` const array containing all the HTTP status codes with its `ReasonString`
- Added `MVCFramework.Commons.MVC_HTTP_STATUS_CODES` const array containing all the HTTP status codes with its `ReasonString`.

- Support for `TObject` descendants in JSONRPC APIs (not only for JSONObject and JSONArray).

- New global configuration variable `MVCSerializeNulls`.
When MVCSerializeNulls = True (default) empty nullables and nil are serialized as json null.
When MVCSerializeNulls = False empty nullables and nil are not serialized at all.

- Nullable types now have `Equal` support and a better "equality check" strategy.
- Nullable types now have `Equal` method support, the new method `TryHasValue(out Value)` works like `HasValue` but returns the contained value if present. Also there is a better "equality check" strategy.

- Unit tests now are always executed for Win32 and Win64 bit (both client and server).

- Added `TMVCActiveRecord.Refresh` method

- Unit test suites generates one NUnit XML output file for each platform

- New built-in profiler (usable with Delphi 10.4+) - to profile a block of code, write the following

```delphi
Expand Down
9 changes: 9 additions & 0 deletions samples/activerecord_showcase/MainFormU.dfm
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,15 @@ object MainForm: TMainForm
TabOrder = 24
OnClick = btnSpeedClick
end
object btnRefresh: TButton
Left = 144
Top = 442
Width = 121
Height = 34
Caption = 'Manual Refresh'
TabOrder = 25
OnClick = btnRefreshClick
end
object FDConnection1: TFDConnection
Left = 312
Top = 40
Expand Down
40 changes: 40 additions & 0 deletions samples/activerecord_showcase/MainFormU.pas
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ TMainForm = class(TForm)
btnOOP: TButton;
btnReadOnly: TButton;
btnSpeed: TButton;
btnRefresh: TButton;
procedure btnCRUDClick(Sender: TObject);
procedure btnInheritanceClick(Sender: TObject);
procedure btnMultiThreadingClick(Sender: TObject);
Expand Down Expand Up @@ -84,6 +85,7 @@ TMainForm = class(TForm)
procedure btnOOPClick(Sender: TObject);
procedure btnReadOnlyClick(Sender: TObject);
procedure btnSpeedClick(Sender: TObject);
procedure btnRefreshClick(Sender: TObject);
private
procedure Log(const Value: string);
procedure LoadCustomers;
Expand Down Expand Up @@ -1467,6 +1469,44 @@ procedure TMainForm.btnReadOnlyFieldsClick(Sender: TObject);
end;
end;

procedure TMainForm.btnRefreshClick(Sender: TObject);
var
lCustomer: TCustomer;
lID: Integer;
begin
Log('** Refresh test');
lCustomer := TCustomer.Create;
try
Log('Entity ' + TCustomer.ClassName + ' is mapped to table ' + lCustomer.TableName);
lCustomer.CompanyName := 'Google Inc.';
lCustomer.City := 'Montain View, CA';
lCustomer.Note := 'Μῆνιν ἄειδε θεὰ Πηληϊάδεω Ἀχιλῆος οὐλομένην 😁';
lCustomer.Insert;
Assert('Montain View, CA' = lCustomer.City);
Assert('Μῆνιν ἄειδε θεὰ Πηληϊάδεω Ἀχιλῆος οὐλομένην 😁' = lCustomer.Note);
lCustomer.City := '';
lCustomer.Note := '';
Log('Refreshing the customer');
lCustomer.Refresh;
Assert('Montain View, CA' = lCustomer.City);
Assert('Μῆνιν ἄειδε θεὰ Πηληϊάδεω Ἀχιλῆος οὐλομένην 😁' = lCustomer.Note);
lID := lCustomer.ID;
finally
lCustomer.Free;
end;

lCustomer := TCustomer.Create;
try
Log('Loading customer using Refresh');
lCustomer.ID := lID;
lCustomer.Refresh;
Assert('Montain View, CA' = lCustomer.City);
Assert('Μῆνιν ἄειδε θεὰ Πηληϊάδεω Ἀχιλῆος οὐλομένην 😁' = lCustomer.Note);
finally
lCustomer.Free;
end;
end;

procedure TMainForm.btnValidationClick(Sender: TObject);
var
lCustomer: TCustomerWithLogic;
Expand Down
2 changes: 1 addition & 1 deletion samples/renders/renders.dproj
Original file line number Diff line number Diff line change
Expand Up @@ -220,12 +220,12 @@
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="$(BDS)\Redist\iossimulator\libPCRE.dylib" Class="DependencyModule"/>
<DeployFile LocalName="$(BDS)\Redist\iossimulator\libpcre.dylib" Class="DependencyModule">
<Platform Name="iOSSimulator">
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="$(BDS)\Redist\iossimulator\libPCRE.dylib" Class="DependencyModule"/>
<DeployFile LocalName="$(BDS)\Redist\osx32\libcgsqlite3.dylib" Class="DependencyModule"/>
<DeployFile LocalName="$(BDS)\Redist\osx32\libcgunwind.1.0.dylib" Class="DependencyModule">
<Platform Name="OSX32">
Expand Down
79 changes: 36 additions & 43 deletions sources/MVCFramework.ActiveRecord.pas
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,6 @@ TMVCTableMap = class
fDefaultRQLFilter: string;
fMap: TFieldsMap;
fPrimaryKey: TRTTIField;
//fBackendDriver: string;
fMapping: TMVCFieldsMapping;
fPropsAttributes: TArray<TCustomAttribute>;
fProps: TArray<TRTTIField>;
Expand Down Expand Up @@ -224,25 +223,7 @@ TMVCActiveRecord = class
procedure SetAttributes(const AttrName: string; const Value: TValue);
function GetTableName: string;
protected
// fPrimaryKeyFieldName: string;
// fPrimaryKeyOptions: TMVCActiveRecordFieldOptions;
// fPrimaryKeySequenceName: string;
// fPrimaryKeyFieldType: TFieldType;
// fEntityAllowedActions: TMVCEntityActions;
// fRTTIType: TRttiInstanceType;
// fObjAttributes: TArray<TCustomAttribute>;
// fTableName: string;
// fDefaultRQLFilter: string;
// fMap: TFieldsMap;
// fPrimaryKey: TRTTIField;
fBackendDriver: string;
// fMapping: TMVCFieldsMapping;
// fPropsAttributes: TArray<TCustomAttribute>;
// fProps: TArray<TRTTIField>;

// fPartitionInfoInternal: TPartitionInfo;
// fPartitionClause: String;

fTableMap: TMVCTableMap;
function GetPartitionInfo: TPartitionInfo;
function GetBackEnd: string;
Expand Down Expand Up @@ -280,6 +261,7 @@ TMVCActiveRecord = class
class function GetByPK(aActiveRecord: TMVCActiveRecord; const aValue: string; const aFieldType: TFieldType;
const RaiseExceptionIfNotFound: Boolean): TMVCActiveRecord; overload;


// load events
/// <summary>
/// Called everywhere before persist object into database
Expand Down Expand Up @@ -364,6 +346,10 @@ TMVCActiveRecord = class
/// Executes an Insert (pk is null) or an Update (pk is not null)
/// </summary>
procedure Store;
/// <summary>
/// Reload the current instance from database if the primary key is not empty.
/// </summary>
procedure Refresh; virtual;
function CheckAction(const aEntityAction: TMVCEntityAction;
const aRaiseException: Boolean = True): Boolean;
procedure Insert;
Expand Down Expand Up @@ -2381,6 +2367,29 @@ procedure TMVCActiveRecord.OnValidation(const EntityAction: TMVCEntityAction);
// do nothing
end;

procedure TMVCActiveRecord.Refresh;
begin
if not GetPK.IsEmpty then
begin
case GetPrimaryKeyFieldType of
ftLargeInt: begin
LoadByPK(GetPK.AsInt64);
end;
ftInteger: begin
LoadByPK(GetPK.AsInteger);
end;
ftString: begin
LoadByPK(GetPK.AsString);
end;
ftGuid: begin
LoadByPK(GetPK.AsType<TGUID>);
end;
else
raise EMVCActiveRecord.Create('Unknown primary key type');
end;
end;
end;

procedure TMVCActiveRecord.RemoveChildren(const ChildObject: TObject);
begin
if fChildren <> nil then
Expand Down Expand Up @@ -2885,51 +2894,35 @@ function TMVCActiveRecord.TryGetPKValue(var Value: TValue; out IsNullableType: B
begin
if Value.IsType<NullableInt32>() then
begin
Result := Value.AsType<NullableInt32>().HasValue;
if Result then
Value := Value.AsType<NullableInt32>().Value;
Result := Value.AsType<NullableInt32>().TryHasValue(Value);
end
else if Value.IsType<NullableInt64>() then
begin
Result := Value.AsType<NullableInt64>().HasValue;
if Result then
Value := Value.AsType<NullableInt64>().Value;
Result := Value.AsType<NullableInt64>().TryHasValue(Value)
end
else if Value.IsType<NullableUInt32>() then
begin
Result := Value.AsType<NullableUInt32>().HasValue;
if Result then
Value := Value.AsType<NullableUInt32>().Value;
Result := Value.AsType<NullableUInt32>().TryHasValue(Value)
end
else if Value.IsType<NullableUInt64>() then
begin
Result := Value.AsType<NullableUInt64>().HasValue;
if Result then
Value := Value.AsType<NullableUInt64>().Value;
Result := Value.AsType<NullableUInt64>().TryHasValue(Value)
end
else if Value.IsType<NullableInt16>() then
begin
Result := Value.AsType<NullableInt16>().HasValue;
if Result then
Value := Value.AsType<NullableInt16>().Value;
Result := Value.AsType<NullableInt16>().TryHasValue(Value)
end
else if Value.IsType<NullableUInt16>() then
begin
Result := Value.AsType<NullableUInt16>().HasValue;
if Result then
Value := Value.AsType<NullableUInt16>().Value;
Result := Value.AsType<NullableUInt16>().TryHasValue(Value)
end
else if Value.IsType<NullableString>() then
begin
Result := Value.AsType<NullableString>().HasValue;
if Result then
Value := Value.AsType<NullableString>().Value;
Result := Value.AsType<NullableString>().TryHasValue(Value)
end
else if Value.IsType<NullableTGUID>() then
begin
Result := Value.AsType<NullableTGUID>().HasValue;
if Result then
Value := TValue.From<TGuid>(Value.AsType<NullableTGUID>().Value);
Result := Value.AsType<NullableTGUID>().TryHasValue(Value)
end
else
raise EMVCActiveRecord.Create
Expand Down
Loading

0 comments on commit 0023ebe

Please sign in to comment.