mirror of
https://github.com/danieleteti/delphimvcframework.git
synced 2024-11-15 07:45:54 +01:00
Merge branch 'master' of https://github.com/pedrooliveira01/delphimvcframework
All conflicts have been fixed
This commit is contained in:
commit
efd170d9ba
22
README.md
22
README.md
@ -130,16 +130,34 @@ Render(lPerson, False,
|
||||
- Added! New overloads for all the Log\* calls. Now it is possibile to call `LogD(lMyObject)` to get logged `lMyObject` as JSON (custom type serializers not supported in log).
|
||||
- Fixed! [issue164](https://github.com/danieleteti/delphimvcframework/issues/164)
|
||||
- Fixed! [issue182](https://github.com/danieleteti/delphimvcframework/issues/182)
|
||||
- New! `Dict(array of string, array of string)` function allows to render a dictionary of strings in a really simple way.
|
||||
- New! `StrDict(array of string, array of string)` function allows to render a dictionary of strings in a really simple way. See the following action sample.
|
||||
```delphi
|
||||
procedure TMy.GetPeople(const Value: Integer);
|
||||
begin
|
||||
if Value mod 2 <> 0 then
|
||||
begin
|
||||
raise EMVCException.Create(HTTP_STATUS.NotAcceptable, 'We don''t like odd numbers');
|
||||
end;
|
||||
Render(
|
||||
StrDict(
|
||||
['id', 'message'],
|
||||
['123', 'We like even numbers, thank you for your ' + Value.ToString]
|
||||
));
|
||||
end;
|
||||
```
|
||||
- New! Custom Exception Handling (Based on work of [David Moorhouse](https://github.com/fastbike)). Sample "custom_exception_handling" show how to use it.
|
||||
- Improved! Exceptions rendering while using MIME types different to `application/json`.
|
||||
- Improved! JSONRPC Automatic Object Publishing can not invoke inherited methods if not explicitely defined with `MVCInheritable` attribute.
|
||||
- Improved! Datasets serialization speed improvement. In some case the performace [improves of 2 order of magnitude](https://github.com/danieleteti/delphimvcframework/issues/205#issuecomment-479513158). (Thanks to https://github.com/pedrooliveira01)
|
||||
- New! Added `in` operator in RQL parser (Thank you [João Antônio Duarte](https://github.com/joaoduarte19))
|
||||
- New! Added `in` operator in RQL parser (Thank you to [João Antônio Duarte](https://github.com/joaoduarte19) for his initial work on this)
|
||||
- New! Added `TMVCActiveRecord.Count<T>(RQL)` to count record based on RQL criteria
|
||||
- New! Calling `<jsonrpcendpoint>/describe` returns the methods list available for that endpoint.
|
||||
- New! Experimental (alpha stage) support for Android servers!
|
||||
- New! Added support for `X-HTTP-Method-Override` to work behind corporate firewalls.
|
||||
- New Sample! Server in DLL
|
||||
- Improved! Now Firebird RQL' SQLGenerator can include primary key in "createinsert" if not autogenerated.
|
||||
- New! Added support for `TArray<String>` and `TArray<Integer>` in default json serializer (Thank you [Pedro Oliveira](https://github.com/pedrooliveira01))
|
||||
- Improved! DMVCFramework now has 130+ unit tests that checks its funtionalities at every build!
|
||||
- New Installation procedure! Just open the project group, build all and install the design-time package (which is `dmvcframeworkDT`)
|
||||
|
||||
|
||||
|
@ -10,8 +10,8 @@ uses
|
||||
MVCFramework.Logger,
|
||||
Winapi.Windows,
|
||||
System.Classes,
|
||||
MainWebModuleUnit in '..\winecellarserver\MainWebModuleUnit.pas' {wm: TWebModule},
|
||||
MainDataModuleUnit in '..\winecellarserver\MainDataModuleUnit.pas' {WineCellarDataModule: TDataModule},
|
||||
MainWebModuleUnit in '..\winecellarserver\MainWebModuleUnit.pas' {wm: TWebModule} ,
|
||||
MainDataModuleUnit in '..\winecellarserver\MainDataModuleUnit.pas' {WineCellarDataModule: TDataModule} ,
|
||||
WineCellarAppControllerU in '..\winecellarserver\WineCellarAppControllerU.pas',
|
||||
WinesBO in '..\winecellarserver\WinesBO.pas';
|
||||
|
||||
@ -41,6 +41,10 @@ var
|
||||
exports
|
||||
GModuleData name 'dmvc_module';
|
||||
|
||||
{
|
||||
Navigate to http://localhost/winecellar/
|
||||
}
|
||||
|
||||
begin
|
||||
CoInitFlags := COINIT_MULTITHREADED;
|
||||
Web.ApacheApp.InitApplication(@GModuleData);
|
||||
@ -48,5 +52,4 @@ begin
|
||||
Application.WebModuleClass := WebModuleClass;
|
||||
Application.Run;
|
||||
|
||||
|
||||
end.
|
||||
|
@ -1,7 +1,7 @@
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{61ADE231-72F2-4E11-8EDD-62C5AFEF0463}</ProjectGuid>
|
||||
<ProjectVersion>18.4</ProjectVersion>
|
||||
<ProjectVersion>18.6</ProjectVersion>
|
||||
<FrameworkType>VCL</FrameworkType>
|
||||
<MainSource>mod_dmvc.dpr</MainSource>
|
||||
<Base>True</Base>
|
||||
@ -141,7 +141,6 @@
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Win32">
|
||||
<RemoteDir>Contents\MacOS</RemoteDir>
|
||||
<Operation>0</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
@ -151,6 +150,12 @@
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="AndroidFileProvider">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\xml</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="AndroidGDBServer">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
|
||||
@ -188,6 +193,12 @@
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="AndroidSplashStylesV21">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\values-v21</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_DefaultAppIcon">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable</RemoteDir>
|
||||
@ -264,6 +275,10 @@
|
||||
<Operation>1</Operation>
|
||||
<Extensions>.framework</Extensions>
|
||||
</Platform>
|
||||
<Platform Name="OSX64">
|
||||
<Operation>1</Operation>
|
||||
<Extensions>.framework</Extensions>
|
||||
</Platform>
|
||||
<Platform Name="Win32">
|
||||
<Operation>0</Operation>
|
||||
</Platform>
|
||||
@ -273,6 +288,10 @@
|
||||
<Operation>1</Operation>
|
||||
<Extensions>.dylib</Extensions>
|
||||
</Platform>
|
||||
<Platform Name="OSX64">
|
||||
<Operation>1</Operation>
|
||||
<Extensions>.dylib</Extensions>
|
||||
</Platform>
|
||||
<Platform Name="Win32">
|
||||
<Operation>0</Operation>
|
||||
<Extensions>.dll;.bpl</Extensions>
|
||||
@ -295,6 +314,10 @@
|
||||
<Operation>1</Operation>
|
||||
<Extensions>.dylib</Extensions>
|
||||
</Platform>
|
||||
<Platform Name="OSX64">
|
||||
<Operation>1</Operation>
|
||||
<Extensions>.dylib</Extensions>
|
||||
</Platform>
|
||||
<Platform Name="Win32">
|
||||
<Operation>0</Operation>
|
||||
<Extensions>.bpl</Extensions>
|
||||
@ -316,6 +339,9 @@
|
||||
<Platform Name="OSX32">
|
||||
<Operation>0</Operation>
|
||||
</Platform>
|
||||
<Platform Name="OSX64">
|
||||
<Operation>0</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Win32">
|
||||
<Operation>0</Operation>
|
||||
</Platform>
|
||||
@ -426,6 +452,7 @@
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="ProjectOSXDebug"/>
|
||||
<DeployClass Name="ProjectOSXEntitlements"/>
|
||||
<DeployClass Name="ProjectOSXInfoPList"/>
|
||||
<DeployClass Name="ProjectOSXResource">
|
||||
@ -433,6 +460,10 @@
|
||||
<RemoteDir>Contents\Resources</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="OSX64">
|
||||
<RemoteDir>Contents\Resources</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Required="true" Name="ProjectOutput">
|
||||
<Platform Name="Android">
|
||||
@ -454,6 +485,9 @@
|
||||
<Platform Name="OSX32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="OSX64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Win32">
|
||||
<Operation>0</Operation>
|
||||
</Platform>
|
||||
@ -493,6 +527,7 @@
|
||||
<ProjectRoot Platform="Linux64" Name="$(PROJECTNAME)"/>
|
||||
<ProjectRoot Platform="OSX32" Name="$(PROJECTNAME)"/>
|
||||
<ProjectRoot Platform="Android" Name="$(PROJECTNAME)"/>
|
||||
<ProjectRoot Platform="OSX64" Name="$(PROJECTNAME)"/>
|
||||
<ProjectRoot Platform="iOSSimulator" Name="$(PROJECTNAME).app"/>
|
||||
</Deployment>
|
||||
<Platforms>
|
||||
|
@ -747,6 +747,7 @@ begin
|
||||
FHTTP.HandleRedirects := False; // DT 2016/09/16
|
||||
FHTTP.OnRedirect := OnHTTPRedirect; // DT 2016/09/16
|
||||
FHTTP.ReadTimeOut := 20000;
|
||||
FHTTP.Request.UserAgent := 'Mozilla/3.0 (compatible; IndyLibrary)'; // Resolve 403 Forbidden error in REST API SSL
|
||||
|
||||
if (AIOHandler <> nil) then
|
||||
FHTTP.IOHandler := AIOHandler
|
||||
|
@ -94,12 +94,18 @@ begin
|
||||
lSB.Append('INSERT INTO ' + TableName + '(');
|
||||
for lKeyValue in Map do
|
||||
lSB.Append(lKeyValue.value + ',');
|
||||
|
||||
if (not (TMVCActiveRecordFieldOption.foAutoGenerated in PKOptions))and(PKFieldName<>'') then
|
||||
lSB.Append(PKFieldName + ',');
|
||||
|
||||
lSB.Remove(lSB.Length - 1, 1);
|
||||
lSB.Append(') values (');
|
||||
for lKeyValue in Map do
|
||||
begin
|
||||
lSB.Append(':' + lKeyValue.value + ',');
|
||||
end;
|
||||
|
||||
if (not (TMVCActiveRecordFieldOption.foAutoGenerated in PKOptions))and(PKFieldName<>'') then
|
||||
lSB.Append(':' +PKFieldName + ',');
|
||||
|
||||
lSB.Remove(lSB.Length - 1, 1);
|
||||
lSB.Append(')');
|
||||
|
||||
|
@ -96,6 +96,7 @@ type
|
||||
const AIgnoredFields: TMVCIgnoredList; const ANameCase: TMVCNameCase);
|
||||
procedure JsonArrayToDataSet(const AJsonArray: TJDOJsonArray; const ADataSet: TDataSet;
|
||||
const AIgnoredFields: TMVCIgnoredList; const ANameCase: TMVCNameCase);
|
||||
function JsonArrayToArray(const AJsonArray: TJDOJsonArray):TValue;
|
||||
{ IMVCSerializer }
|
||||
function SerializeObject(const AObject: TObject; const AType: TMVCSerializationType = stDefault;
|
||||
const AIgnoredAttributes: TMVCIgnoredList = [];
|
||||
@ -189,6 +190,7 @@ var
|
||||
ChildList: IMVCList;
|
||||
ValueTypeAtt: MVCValueAsTypeAttribute;
|
||||
CastValue, CastedValue: TValue;
|
||||
i:integer;
|
||||
begin
|
||||
if AValue.IsEmpty then
|
||||
begin
|
||||
@ -340,8 +342,23 @@ begin
|
||||
|
||||
tkArray, tkDynArray:
|
||||
begin
|
||||
raise EMVCSerializationException.CreateFmt
|
||||
('Cannot serialize %s of TypeKind tkArray or tkDynArray.', [AName]);
|
||||
if aValue.getarraylength>0 then
|
||||
Begin
|
||||
for i := 0 to aValue.getarraylength-1 do
|
||||
Begin
|
||||
case aValue.GetArrayElement(i).Kind of
|
||||
tkChar, tkString, tkWChar, tkLString, tkWString, tkUString:
|
||||
AJsonObject.A[AName].Add(aValue.GetArrayElement(i).AsString);
|
||||
tkInteger:
|
||||
AJsonObject.A[AName].Add(aValue.GetArrayElement(i).AsInteger);
|
||||
tkInt64:
|
||||
AJsonObject.A[AName].Add(aValue.GetArrayElement(i).AsInt64);
|
||||
else
|
||||
raise EMVCSerializationException.CreateFmt
|
||||
('Cannot serialize %s of TypeKind tkArray or tkDynArray.', [AName]);
|
||||
end;
|
||||
End;
|
||||
End;
|
||||
end;
|
||||
|
||||
tkUnknown:
|
||||
@ -571,6 +588,24 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
function TMVCJsonDataObjectsSerializer.JsonArrayToArray(
|
||||
const AJsonArray: TJDOJsonArray):TValue;
|
||||
var i:integer;
|
||||
lStrArr:TArray<String>;
|
||||
lIntArr:TArray<Integer>;
|
||||
begin
|
||||
for I := 0 to Pred(AJsonArray.Count) do
|
||||
case AJsonArray.types[0] of
|
||||
jdtString : lStrArr := lStrArr + [AJsonArray.Items[i].Value];
|
||||
jdtInt : lIntArr := lIntArr + [AJsonArray.Items[i].Value.ToInteger];
|
||||
end;
|
||||
|
||||
if Length(lStrArr)>0 then
|
||||
result := TValue.From<TArray<String>>(lStrArr)
|
||||
else
|
||||
result := TValue.From<TArray<Integer>>(lIntArr);
|
||||
end;
|
||||
|
||||
procedure TMVCJsonDataObjectsSerializer.JsonArrayToDataSet(const AJsonArray: TJDOJsonArray;
|
||||
const ADataSet: TDataSet;
|
||||
const AIgnoredFields: TMVCIgnoredList; const ANameCase: TMVCNameCase);
|
||||
@ -716,7 +751,11 @@ begin
|
||||
raise EMVCDeserializationException.CreateFmt
|
||||
('You can not deserialize a list %s without the MVCListOf attribute.', [AName]);
|
||||
end;
|
||||
end;
|
||||
end
|
||||
else if AValue.isArray then
|
||||
Begin
|
||||
AValue := JsonArrayToArray(AJsonObject.A[AName]);
|
||||
End;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
@ -273,6 +273,17 @@ type
|
||||
property NotesAsString: TStringStream read FNotesAsString write FNotesAsString;
|
||||
end;
|
||||
|
||||
TEntityWithArray = class
|
||||
private
|
||||
FId: Int64;
|
||||
FNames: TArray<String>;
|
||||
FValues: TArray<Integer>;
|
||||
public
|
||||
property Id: Int64 read FId write FId;
|
||||
property Names: TArray<String> read FNames write FNames;
|
||||
property Values: TArray<Integer> read FValues write FValues;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
|
||||
|
@ -64,6 +64,8 @@ type
|
||||
[Test]
|
||||
procedure TestSerializeEntityUpperCaseNames;
|
||||
[Test]
|
||||
procedure TestSerializeEntityWithArray;
|
||||
[Test]
|
||||
procedure TestSerializeEntityLowerCaseNames;
|
||||
[Test]
|
||||
procedure TestSerializeEntityNameAs;
|
||||
@ -77,8 +79,6 @@ type
|
||||
procedure TestSerializeCollection;
|
||||
[Test]
|
||||
procedure TestSerializeDataSet;
|
||||
[Test]
|
||||
procedure TestSerializeEmptyDataSet;
|
||||
{ deserialize declarations }
|
||||
[Test]
|
||||
procedure TestDeserializeEntity;
|
||||
@ -94,6 +94,10 @@ type
|
||||
procedure TestDeserializeCollection;
|
||||
[Test]
|
||||
procedure TestDeserializeDataSet;
|
||||
[Test]
|
||||
procedure TestSerializeEmptyDataSet;
|
||||
[Test]
|
||||
procedure TestDeserializeEntityWithArray;
|
||||
{ full cycle }
|
||||
[Test]
|
||||
procedure TestSerializeDeSerializeEntityWithEnums;
|
||||
@ -620,6 +624,35 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TMVCTestSerializerJsonDataObjects.TestDeserializeEntityWithArray;
|
||||
procedure CheckObject(const AEntity: TEntityWithArray);
|
||||
begin
|
||||
Assert.isTrue(AEntity.Id = 1);
|
||||
Assert.isTrue(AEntity.Names[0] = 'Pedro');
|
||||
Assert.isTrue(AEntity.Names[1] = 'Oliveira');
|
||||
Assert.isTrue(AEntity.Values[0] = 1);
|
||||
Assert.isTrue(AEntity.Values[1] = 2);
|
||||
end;
|
||||
|
||||
const
|
||||
JSON_WITH_ARRAY =
|
||||
'{' +
|
||||
'"Id":1,' +
|
||||
'"Names":["Pedro","Oliveira"],' +
|
||||
'"Values":[1,2]' +
|
||||
'}';
|
||||
var
|
||||
O: TEntityWithArray;
|
||||
begin
|
||||
O := TEntityWithArray.Create;
|
||||
try
|
||||
FSerializer.DeserializeObject(JSON_WITH_ARRAY, O);
|
||||
CheckObject(O);
|
||||
finally
|
||||
O.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TMVCTestSerializerJsonDataObjects.TestSerializeCollection;
|
||||
const
|
||||
JSON =
|
||||
@ -863,7 +896,7 @@ begin
|
||||
try
|
||||
Dm.Entity.EmptyDataSet;
|
||||
S := FSerializer.SerializeDataSet(Dm.Entity);
|
||||
Assert.AreEqual('[]', S);
|
||||
Assert.areEqual('[]', S);
|
||||
finally
|
||||
Dm.Free;
|
||||
end;
|
||||
@ -1215,6 +1248,31 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TMVCTestSerializerJsonDataObjects.TestSerializeEntityWithArray;
|
||||
const
|
||||
JSON_WITH_ARRAY =
|
||||
'{' +
|
||||
'"Id":1,' +
|
||||
'"Names":["Pedro","Oliveira"],' +
|
||||
'"Values":[1,2]' +
|
||||
'}';
|
||||
var
|
||||
O: TEntityWithArray;
|
||||
S: string;
|
||||
begin
|
||||
O := TEntityWithArray.Create;
|
||||
try
|
||||
O.Id := 1;
|
||||
O.Names := ['Pedro', 'Oliveira'];
|
||||
O.Values := [1, 2];
|
||||
|
||||
S := FSerializer.SerializeObject(O);
|
||||
Assert.areEqual(JSON_WITH_ARRAY, S);
|
||||
finally
|
||||
O.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TMVCTestSerializerJsonDataObjects.TestSerializeNil;
|
||||
begin
|
||||
Assert.areEqual('null', FSerializer.SerializeObject(nil));
|
||||
|
Loading…
Reference in New Issue
Block a user