source upload

This commit is contained in:
Razor12911
2022-01-17 22:16:47 +02:00
parent 12936d065b
commit 098e8c48de
1778 changed files with 1206749 additions and 0 deletions

View File

@@ -0,0 +1,4 @@
xcopy ..\..\..\CrossPlatform\SynCrossPlatformSpecific.pas "c:\ProgramData\Optimale Systemer AS\Smart Mobile Studio\Libraries" /Y
xcopy ..\..\..\CrossPlatform\SynCrossPlatformCrypto.pas "c:\ProgramData\Optimale Systemer AS\Smart Mobile Studio\Libraries" /Y
xcopy ..\..\..\CrossPlatform\SynCrossPlatformREST.pas "c:\ProgramData\Optimale Systemer AS\Smart Mobile Studio\Libraries" /Y
pause

View File

@@ -0,0 +1,5 @@
rem To be used to synchronize units modified within SMS IDE
xcopy "c:\ProgramData\Optimale Systemer AS\Smart Mobile Studio\Libraries\SynCrossPlatformSpecific.pas" ..\..\..\CrossPlatform /Y
xcopy "c:\ProgramData\Optimale Systemer AS\Smart Mobile Studio\Libraries\SynCrossPlatformCrypto.pas" ..\..\..\CrossPlatform /Y
xcopy "c:\ProgramData\Optimale Systemer AS\Smart Mobile Studio\Libraries\SynCrossPlatformREST.pas" ..\..\..\CrossPlatform /Y
pause

View File

@@ -0,0 +1,113 @@
unit LoginForm;
interface
uses
SmartCL.System, SmartCL.Graphics, SmartCL.Components, SmartCL.Forms,
SmartCL.Fonts, SmartCL.Borders, SmartCL.Application,
SynCrossPlatformREST, SmartTests,
SmartCL.Controls.Label, SmartCL.Controls.Editbox, SmartCL.Controls.Panel,
SmartCL.Controls.Button, w3c.date;
type
TLoginForm=class(TW3form)
procedure W3Button1Click(Sender: TObject);
procedure ConnectClick(Sender: TObject);
private
{$I 'LoginForm:intf'}
protected
procedure InitializeForm; override;
procedure InitializeObject; override;
procedure Resize; override;
end;
implementation
uses
mORMotClient; // unit generated by the server!
{ TLoginForm }
procedure TLoginForm.InitializeForm;
begin
inherited;
// this is a good place to initialize components
end;
procedure TLoginForm.InitializeObject;
begin
inherited;
{$I 'LoginForm:impl'}
LogonPassword.InputType := itPassword;
end;
procedure TLoginForm.ConnectClick(Sender: TObject);
var model: TSQLModel;
begin
BrowserAPI.console.time('ORM');
writeln('Creating Data Model');
model := GetModel;
model.GetTableIndexExisting(TSQLRecordPeople);
var people := new TSQLRecordPeople;
var s := model.InfoExisting(people.RecordClass).ToJSONAdd(nil,people,true,'');
assert(s='{"RowID":0,"FirstName":"","LastName":"","YearOfBirth":0,"YearOfDeath":0,'+
'"Sexe":0,"Simple":{"F":"","G":[],"H":{"H1":0,"H2":"","H3":{"H3a":false,"H3b":null}},"I":"","J":[]}}');
s := '{"RowID":10,"FirstName":"ab\"c","LastName":"def","YearOfBirth":20,"YearOfDeath":30,'+
'"Sexe":1,"Simple":{"F":"","G":[],"H":{"H1":0,"H2":"","H3":{"H3a":false,"H3b":null}},"I":"","J":['+
'{"J1":1,"J2":"","J3":"reLast"}]}}';
assert(people.FromJSON(s));
assert(people.ID=10);
assert(people.FirstName='ab"c');
assert(people.LastName='def');
assert(people.YearOfBirth=20);
assert(people.YearOfDeath=30);
assert(people.Sexe=sMale);
assert(people.Simple.J.Count=1);
assert(people.Simple.J[0].J1=1);
assert(people.Simple.J[0].J3=reLast);
writeln('Connecting to the server at '+ServerAddress.Text+':888');
GetClient(ServerAddress.Text,LogonName.Text,LogonPassword.Text,
lambda(client)
client.LogToRemoteServer(LOG_VERBOSE,'localhost');
writeln('Safely connected with SessionID='+IntToStr(client.Authentication.SessionID));
people := TSQLRecordPeople.Create(client,1);
assert(people.ID=1);
writeln(people.ToJSON(client.Model,'*'));
writeln('Testing remote CRUD methods');
ORMTest(client);
BrowserAPI.console.timeEnd('ORM');
BrowserAPI.console.time('SOA');
writeln('Testing SOA remote access');
SOATest(client,
lambda
writeln('Disconnect from server');
client.Free;
BrowserAPI.console.timeEnd('SOA');
end,
lambda
writeln('ERROR!');
writeln('Disconnect from server');
client.Free;
BrowserAPI.console.timeEnd('SOA');
end);
end,
lambda
ShowMessage('Impossible to connect to the server');
writeln('ERROR at GetClient');
BrowserAPI.console.timeEnd('ORM');
end);
end;
procedure TLoginForm.W3Button1Click(Sender: TObject);
begin
BrowserAPI.console.time('LowLevel');
TestSMS;
BrowserAPI.console.timeEnd('LowLevel');
end;
procedure TLoginForm.Resize;
begin
inherited;
end;
end.

View File

@@ -0,0 +1,109 @@
<SMART>
<Form version="2" subversion="1">
<Created>2014-06-17T10:47:09.864</Created>
<Modified>2014-07-18T15:32:06.707</Modified>
<object type="TW3Form">
<Caption>mORMot Web Test</Caption>
<Name>LoginForm</Name>
<object type="TW3Label">
<Caption>&lt;b&gt;&lt;i&gt;mORMot&lt;/i&gt; Web Test&lt;/b&gt;</Caption>
<Width>184</Width>
<Top>8</Top>
<StyleClass>h1</StyleClass>
<Left>32</Left>
<Height>32</Height>
<Transparent>True</Transparent>
<Name>W3Label1</Name>
</object>
<object type="TW3Panel">
<Width>192</Width>
<Top>40</Top>
<Left>24</Left>
<Height>264</Height>
<Name>W3Panel1</Name>
<object type="TW3EditBox">
<Value></Value>
<Text>User</Text>
<Range></Range>
<Width>128</Width>
<Top>104</Top>
<Left>16</Left>
<Height>32</Height>
<Name>LogonName</Name>
</object>
<object type="TW3Label">
<Caption>Name</Caption>
<Width>56</Width>
<Top>80</Top>
<Left>16</Left>
<Height>24</Height>
<Name>W3Label3</Name>
</object>
<object type="TW3Label">
<Caption>Password</Caption>
<Width>128</Width>
<Top>136</Top>
<Left>16</Left>
<Height>32</Height>
<Name>W3Label4</Name>
</object>
<object type="TW3EditBox">
<Value></Value>
<Text>synopse</Text>
<Range></Range>
<Width>128</Width>
<Top>168</Top>
<Left>16</Left>
<Height>32</Height>
<Name>LogonPassword</Name>
</object>
<object type="TW3Button">
<Caption>Remote Tests</Caption>
<Width>160</Width>
<Top>208</Top>
<Left>16</Left>
<Height>40</Height>
<Name>Connect</Name>
<OnClick>ConnectClick</OnClick>
</object>
<object type="TW3EditBox">
<Value></Value>
<Text>127.0.0.1</Text>
<Range></Range>
<Width>128</Width>
<Top>160</Top>
<Left>240</Left>
<Height>32</Height>
<Name>W3EditBox1</Name>
</object>
<object type="TW3Label">
<Caption>Server</Caption>
<Width>128</Width>
<Top>8</Top>
<Left>16</Left>
<Height>32</Height>
<Name>W3Label2</Name>
</object>
<object type="TW3EditBox">
<Value></Value>
<Text>127.0.0.1</Text>
<Range></Range>
<Width>128</Width>
<Top>40</Top>
<Left>16</Left>
<Height>32</Height>
<Name>ServerAddress</Name>
</object>
</object>
<object type="TW3Button">
<Caption>Offline Tests</Caption>
<Width>160</Width>
<Top>312</Top>
<Left>40</Left>
<Height>40</Height>
<Name>W3Button1</Name>
<OnClick>W3Button1Click</OnClick>
</object>
</object>
</Form>
</SMART>

View File

@@ -0,0 +1,36 @@
unit MainUnit;
interface
uses
SmartCL.System, SmartCL.Components, SmartCL.Forms, SmartCL.Application,
SynCrossPlatformCrypto, SynCrossPlatformSpecific, SynCrossPlatformREST,
SmartTests,
LoginForm;
type
TApplication = class(TW3CustomApplication)
private
FForm1: TLoginForm;
protected
procedure ApplicationStarting; override;
public
end;
implementation
{ TApplication}
procedure TApplication.ApplicationStarting;
begin
FForm1 := TLoginForm.Create(Display.View);
FForm1.Name := 'Form1';
RegisterFormInstance(FForm1, True);
// register other forms here
inherited;
end;
end.

View File

@@ -0,0 +1,31 @@
SmartMobileStudio Client to mORMot
==================================
Please ensure you first copied the latest version of those files
from CrossPlatform folder into the SMS shared library folder, i.e.
c:\ProgramData\Optimale Systemer AS\Smart Mobile Studio\Libraries\
- SynCrossPlatformCrypto.pas
- SynCrossPlatformRest.pas
- SynCrossPlatformSpecific.pas
For this, simply run CopySynCrossPlatformUnits.bat
Those units are needed as external content, to compile the
demo application.
As an alternative, you may copy those units to the projects root
folder, but you forget to synchronize the units from the official
source code repository later.
### Server Needed
In order to let this client sample application run as exepected,
you need to compile and run the RegressionTestsServer.dpr program,
as available in "27 - CrossPlatform Clients" folder.
This server will publish TSQLRecordPeople remote ORM access,
with TSQLRestServerAuthenticationDefault authentication.

View File

@@ -0,0 +1,271 @@
unit SmartTests;
interface
uses
SmartCL.System,
System.Types,
ECMA.Date,
System.Date,
SynCrossPlatformSpecific,
SynCrossPlatformREST,
SynCrossPlatformCrypto;
procedure TestSMS;
procedure ORMTest(client: TSQLRestClientURI);
procedure SOATest(client: TSQLRestClientURI; onSuccess, onError: TSQLRestEvent);
implementation
uses
mORMotClient; // unit generated by the server!
const
MSecsPerDay = 86400000;
OneSecDateTime = 1/SecsPerDay;
procedure TestsIso8601DateTime;
procedure Test(D: TDateTime);
var s: string;
procedure One(D: TDateTime);
var E: TDateTime;
V: TTimeLog;
J: JDate;
begin
J := new JDate;
J.AsDateTime := D;
E := J.AsDateTime;
assert(Abs(D-E)<OneSecDateTime);
s := DateTimeToIso8601(D);
E := Iso8601ToDateTime(s);
assert(Abs(D-E)<OneSecDateTime);
V := DateTimeToTTimeLog(D);
E := TTimeLogToDateTime(V);
assert(Abs(D-E)<OneSecDateTime);
assert(UrlDecode(UrlEncode(s))=s);
end;
begin
One(D);
assert(length(s)=19);
One(Trunc(D));
assert(length(s)=10);
One(Frac(D));
assert(length(s)=9);
end;
var D: TDateTime;
i: integer;
s,x: string;
T: TTimeLog;
begin
s := '2014-06-28T11:50:22';
D := Iso8601ToDateTime(s);
assert(DateTimeToIso8601(D)=s);
assert(Abs(D-41818.40997685185)<OneSecDateTime);
x := TTimeLogToIso8601(135181810838);
assert(x=s);
T := DateTimeToTTimeLog(D);
assert(T=135181810838);
D := Now/20+Random*20; // some starting random date/time
for i := 1 to 2000 do begin
Test(D);
D := D+Random*57; // go further a little bit: change date/time
end;
end;
procedure TestSMS;
var doc: TJSONVariantData;
begin
assert(crc32ascii(0,'abcdefghijklmnop')=$943AC093);
assert(SHA256('abc')='ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad');
assert(VariantType(123)=jvUndefined);
assert(VariantType(null)=jvUndefined);
assert(VariantType(TVariant.CreateObject)=jvObject);
assert(VariantType(new JObject)=jvObject);
assert(VariantType(TVariant.CreateArray)=jvArray);
doc := TJSONVariantData.Create('{"a":1,"b":"B"}');
assert(doc.Kind=jvObject);
assert(doc.Count=2);
assert(doc.Names[0]='a');
assert(doc.Names[1]='b');
assert(doc.Values[0]=1);
assert(doc.Values[1]='B');
doc := TJSONVariantData.Create('["a",2]');
assert(doc.Kind=jvArray);
assert(doc.Count=2);
assert(doc.Names.Count=0);
assert(doc.Values[0]='a');
assert(doc.Values[1]=2);
TestsIso8601DateTime;
end;
procedure ORMTest(client: TSQLRestClientURI);
var people: TSQLRecordPeople;
Call: TSQLRestURIParams;
res: TIntegerDynArray;
i,id: integer;
begin // all this is run in synchronous mode -> only 200 records in the set
client.CallBackGet('DropTable',[],Call,TSQLRecordPeople);
assert(client.InternalState>0);
assert(Call.OutStatus=HTTP_SUCCESS);
client.BatchStart(TSQLRecordPeople);
people := TSQLRecordPeople.Create;
assert(people.InternalState=0);
for i := 1 to 200 do begin
people.FirstName := 'First'+IntToStr(i);
people.LastName := 'Last'+IntToStr(i);
people.YearOfBirth := i+1800;
people.YearOfDeath := i+1825;
assert(client.BatchAdd(people,true)=i-1);
assert(people.InternalState=0);
end;
assert(client.BatchSend(res)=HTTP_SUCCESS);
assert(length(res)=200);
for i := 1 to 200 do
assert(res[i-1]=i);
people := TSQLRecordPeople.CreateAndFillPrepare(client,'','',[]);
assert(people.InternalState=0);
id := 0;
while people.FillOne do begin
assert(people.InternalState=client.InternalState);
inc(id);
assert(people.ID=id);
assert(people.FirstName='First'+IntToStr(id));
assert(people.LastName='Last'+IntToStr(id));
assert(people.YearOfBirth=id+1800);
assert(people.YearOfDeath=id+1825);
end;
assert(id=200);
people.Free; // release all memory used by the request
people := TSQLRecordPeople.CreateAndFillPrepare(client,
'YearOFBIRTH,Yearofdeath,id','',[]);
assert(people.InternalState=0);
id := 0;
while people.FillOne do begin
assert(people.InternalState=client.InternalState);
inc(id);
assert(people.ID=id);
assert(people.FirstName='');
assert(people.LastName='');
assert(people.YearOfBirth=id+1800);
assert(people.YearOfDeath=id+1825);
end;
assert(id=200);
people.Free; // release all memory used by the request
people := TSQLRecordPeople.CreateAndFillPrepare(client,'',
'yearofbirth=?',[1900]);
id := 0;
while people.FillOne do begin
assert(people.InternalState=client.InternalState);
inc(id);
assert(people.ID=100);
assert(people.FirstName='First100');
assert(people.LastName='Last100');
assert(people.YearOfBirth=1900);
assert(people.YearOfDeath=1925);
end;
assert(id=1);
for i := 1 to 200 do
if i and 15=0 then
client.Delete(TSQLRecordPeople,i) else
if i mod 82=0 then begin
people := TSQLRecordPeople.Create;
id := i+1;
people.ID := i;
people.FirstName := 'neversent';
people.LastName := 'neitherthisone';
people.YearOfBirth := id+1800;
people.YearOfDeath := id+1825;
assert(people.InternalState=0);
assert(client.Update(people,'YEarOFBIRTH,YEarOfDeath'));
assert(people.InternalState=client.InternalState);
end;
people := new TSQLRecordPeople;
assert(people.InternalState=0);
for i := 1 to 200 do begin
var read = client.Retrieve(i,people);
if i and 15=0 then
assert(not read) else begin
assert(read);
assert(people.InternalState=client.InternalState);
if i mod 82=0 then
id := i+1 else
id := i;
assert(people.ID=i);
assert(people.FirstName='First'+IntToStr(i));
assert(people.LastName='Last'+IntToStr(i));
assert(people.YearOfBirth=id+1800);
assert(people.YearOfDeath=id+1825);
end;
end;
people.Free;
end;
procedure SOATest(client: TSQLRestClientURI; onSuccess, onError: TSQLRestEvent);
var Calc: TServiceCalculator;
i: integer;
const SEX_TEXT: array[0..1] of string = ('Miss','Mister');
ITERATIONS = 50;
begin
Calc := TServiceCalculator.Create(client); // no need to free instance on SMS
assert(Calc.InstanceImplementation=sicShared);
assert(Calc.ServiceName='Calculator');
// first test synchronous / blocking mode
for i := 1 to ITERATIONS do
assert(calc._Add(i,i+1)=i*2+1);
for i := 1 to ITERATIONS do begin
var sex := TPeopleSexe(i and 1);
var name := 'Smith';
calc._ToText(i,'$',sex,name);
assert(sex=sFemale);
assert(name=format('$ %d for %s Smith',[i,SEX_TEXT[i and 1]]));
end;
var j: integer;
var rec: TTestCustomJSONArraySimpleArray;
for i := 1 to ITERATIONS do begin
var name := calc._RecordToText(rec);
if i=1 then
assert(name='{"F":"","G":[],"H":{"H1":0,"H2":"","H3":{"H3a":false,"H3b":null}},"I":"","J":[]}');
assert(length(Rec.F)=i);
for j := 1 to length(Rec.F) do
assert(Rec.F[j]='!');
assert(length(Rec.G)=i);
for j := 0 to high(Rec.G) do
assert(Rec.G[j]=IntToStr(j+1));
assert(Rec.H.H1=i);
assert(length(Rec.J)=i-1);
for j := 0 to high(Rec.J) do begin
assert(Rec.J[j].J1=j);
assert(Rec.J[j].J2<>'');
assert(Rec.J[j].J3=TRecordEnum(j mod (ord(high(TRecordEnum))+1)));
end;
end;
// code below is asynchronous, so more difficult to follow than synchronous !
i := 1; // need two Calc*Asynch() inlined lambdas to access var i
procedure CalcToTextAsynch(sexe: TPeopleSexe; name: string);
begin
assert(sexe=sFemale);
assert(name=format('$ %d for %s Smith',[i,SEX_TEXT[i and 1]]));
inc(i);
sexe := TPeopleSexe(i and 1);
name := 'Smith';
if i<=ITERATIONS then // recursive for i := 1 to ITERATIONS
Calc.ToText(i,'$',sexe,name,CalcToTextAsynch,onError) else
onSuccess(client);
end;
procedure CalcAddAsynch(res: integer);
begin
assert(res=i*2+1);
inc(i);
if i<=ITERATIONS then // recursive for i := 1 to ITERATIONS
Calc.Add(i,i+1,CalcAddAsynch,onError) else begin
i := 1;
Calc.ToText(i,'$',TPeopleSexe(i and 1),'Smith',CalcToTextAsynch,onError);
end;
end;
Calc.Add(i,i+1,CalcAddAsynch,onError);
end;
end.

View File

@@ -0,0 +1,125 @@
<SMART>
<Project version="2" subversion="2">
<Name>WebForm</Name>
<Created>T00:00:00.000</Created>
<Modified>2016-07-27T16:44:14.890</Modified>
<Author>A. Bouchez</Author>
<Company>Synopse</Company>
<Version>
<Major>1</Major>
<Minor>18</Minor>
<Revision>0</Revision>
</Version>
<VendorSpecific>
<Apple>
<FormatDetection>0</FormatDetection>
<StatusBarStyle>default</StatusBarStyle>
<WebAppCapable>1</WebAppCapable>
</Apple>
<ChromeApp>
<Kiosk>0</Kiosk>
<KioskOnly>1</KioskOnly>
<OfflineEnabled>1</OfflineEnabled>
</ChromeApp>
<Cordova>
<WidgetID>com.smartmobilestudio.app</WidgetID>
<AllowIntent>http://*/*&#13;&#10;https://*/*&#13;&#10;tel:*&#13;&#10;sms:*&#13;&#10;mailto:*&#13;&#10;geo:*</AllowIntent>
</Cordova>
</VendorSpecific>
<Options>
<PostBuild>
<Enabled>0</Enabled>
<Script>//CopyFile(&apos;.\www\index.html&apos;,&apos;.\www\debug\index.html&apos;,true);</Script>
</PostBuild>
<Compiler>
<Assertions>1</Assertions>
<Optimize>1</Optimize>
<HintsLevel>1</HintsLevel>
</Compiler>
<Codegen>
<Obfuscation>0</Obfuscation>
<RangeChecking>0</RangeChecking>
<InstanceChecking>0</InstanceChecking>
<ConditionChecking>1</ConditionChecking>
<LoopChecking>1</LoopChecking>
<InlineMagics>1</InlineMagics>
<IgnorePublishedInImplementation>0</IgnorePublishedInImplementation>
<EmitSourceLocation>1</EmitSourceLocation>
<EmitRTTI>0</EmitRTTI>
<Devirtualize>1</Devirtualize>
<MainBody>1</MainBody>
<CodePacking>0</CodePacking>
<SmartLinking>1</SmartLinking>
<Verbosity>1</Verbosity>
</Codegen>
<ConditionalDefines>
<HandleExceptions>1</HandleExceptions>
<AutoRefresh>0</AutoRefresh>
<LegacySupportForIE>0</LegacySupportForIE>
</ConditionalDefines>
<Linker>
<SourceMap>0</SourceMap>
<CompressCSS>1</CompressCSS>
<GenerateAppCacheManifest>1</GenerateAppCacheManifest>
<GenerateChromeAppManifest>0</GenerateChromeAppManifest>
<GenerateFireFoxManifest>0</GenerateFireFoxManifest>
<GenerateWebAppManifest>1</GenerateWebAppManifest>
<GenerateWidgetPackageConfigXML>0</GenerateWidgetPackageConfigXML>
<GenerateCordovaConfigXML>1</GenerateCordovaConfigXML>
<ExternalCSS>0</ExternalCSS>
<Theme>default.css</Theme>
<CustomTheme>0</CustomTheme>
<EmbedJavaScript>1</EmbedJavaScript>
</Linker>
<Output>
<HtmlFileName>index.html</HtmlFileName>
<OutputFilePath>www\</OutputFilePath>
</Output>
<Import />
<Execute>
<ServeManifest>0</ServeManifest>
<Server>1</Server>
<CustomFile></CustomFile>
<LoadCustomFile>0</LoadCustomFile>
<PauseAfterExecution>0</PauseAfterExecution>
<ExecuteType>1</ExecuteType>
<ExecuteableParams>%output%</ExecuteableParams>
</Execute>
</Options>
<Files>
<File type="main">
<Name>WebForm</Name>
<Created>2014-07-11T23:12:17.628Z</Created>
<Modified>2014-07-11T23:12:17.629</Modified>
<Filename>WebForm.pas</Filename>
</File>
<File type="unit">
<Name>MainUnit</Name>
<Created>2014-06-17T10:47:09.813Z</Created>
<Modified>2014-07-11T23:12:17.619</Modified>
<Filename>MainUnit.pas</Filename>
</File>
<File type="form">
<Name>LoginForm</Name>
<Created>2014-06-17T10:47:09.813Z</Created>
<Modified>2014-09-08T18:00:47.737</Modified>
<Filename>LoginForm.pas</Filename>
<AutoCreate>
<IsAutoCreate>1</IsAutoCreate>
<IsMainForm>1</IsMainForm>
<Order>1</Order>
</AutoCreate>
</File>
</Files>
<Target>Browser</Target>
<Generator>Visual Component Project</Generator>
<Statistics>
<BackgroundCompilations>36</BackgroundCompilations>
<EditTime>00:03:35.206</EditTime>
<CompileTime>00:00:34.311</CompileTime>
<TotalTime>01:24:55.433</TotalTime>
<DesigningTime>00:04:05.595</DesigningTime>
<RunningTime>00:44:02.193</RunningTime>
</Statistics>
</Project>
</SMART>

View File

@@ -0,0 +1,26 @@
uses MainUnit;
{$IFDEF SMART_INTERNAL_HANDLE_EXCEPTIONS}
uses W3System;
{$ENDIF}
{$IFDEF SMART_INTERNAL_AUTO_REFRESH}
uses W3AutoRefresh;
TW3AutoRefresh.Create.Start;
{$ENDIF}
var Application: TApplication;
{$IFDEF SMART_INTERNAL_HANDLE_EXCEPTIONS}
try
{$ENDIF}
Application := TApplication.Create;
Application.RunApp;
{$IFDEF SMART_INTERNAL_HANDLE_EXCEPTIONS}
except
on e: Exception do
ShowMessage(e.Message);
end;
{$ENDIF}

View File

@@ -0,0 +1,436 @@
/// remote access to a mORMot server using SmartMobileStudio
// - retrieved from http://localhost:888/root/wrapper/SmartMobileStudio/mORMotClient.pas
// at 2014-12-10 21:44:23 using "SmartMobileStudio.pas.mustache" template
unit mORMotClient;
{
WARNING:
This unit has been generated by a mORMot 1.18.626 server.
Any manual modification of this file may be lost after regeneration.
Synopse mORMot framework. Copyright (C) 2014 Arnaud Bouchez
Synopse Informatique - https://synopse.info
This unit is released under a MPL/GPL/LGPL tri-license,
and therefore may be freely included in any application.
This unit would work on Smart Mobile Studio 2.1.1 and later.
}
interface
uses
SmartCL.System,
System.Types,
SynCrossPlatformSpecific,
SynCrossPlatformREST;
type // define some enumeration types, used below
TPeopleSexe = (sFemale, sMale);
TRecordEnum = (reOne, reTwo, reLast);
type // define some record types, used as properties below
TTestCustomJSONArraySimpleArray = record
F: String;
G: array of String;
H: record
H1: Integer;
H2: String;
H3: record
H3a: Boolean;
H3b: TSQLRawBlob;
end;
end;
I: TDateTime;
J: array of record
J1: Byte;
J2: TGUID;
J3: TRecordEnum;
end;
end;
TSimpleRecord = record
A: Integer;
B: Integer;
C: String;
end;
type // define some dynamic array types, used as properties below
TPeopleSexeDynArray = array of Byte;
TSimpleRecordDynArray = array of TSimpleRecord;
type
/// map "People" table
TSQLRecordPeople = class(TSQLRecord)
protected
fFirstName: String;
fLastName: String;
fData: TSQLRawBlob;
fYearOfBirth: Integer;
fYearOfDeath: Word;
fSexe: TPeopleSexe;
fSimple: TTestCustomJSONArraySimpleArray;
// those overriden methods will emulate the needed RTTI
class function ComputeRTTI: TRTTIPropInfos; override;
procedure SetProperty(FieldIndex: integer; const Value: variant); override;
function GetProperty(FieldIndex: integer): variant; override;
public
property FirstName: String read fFirstName write fFirstName;
property LastName: String read fLastName write fLastName;
property Data: TSQLRawBlob read fData write fData;
property YearOfBirth: Integer read fYearOfBirth write fYearOfBirth;
property YearOfDeath: Word read fYearOfDeath write fYearOfDeath;
property Sexe: TPeopleSexe read fSexe write fSexe;
property Simple: TTestCustomJSONArraySimpleArray read fSimple write fSimple;
end;
/// service accessible via http://localhost:888/root/Calculator
// - this service will run in sicShared mode
// - synchronous and asynchronous methods are available, depending on use case
// - synchronous _*() methods will block the browser execution, so won't be
// appropriate for long process - on error, they may raise EServiceException
TServiceCalculator = class(TServiceClientAbstract)
public
/// will initialize an access to the remote service
constructor Create(aClient: TSQLRestClientURI); override;
procedure Add(n1: Integer; n2: Integer;
onSuccess: procedure(Result: Integer); onError: TSQLRestEvent);
function _Add(const n1: Integer; const n2: Integer): Integer;
procedure ToText(Value: Currency; Curr: String; Sexe: TPeopleSexe; Name: String;
onSuccess: procedure(Sexe: TPeopleSexe; Name: String); onError: TSQLRestEvent);
procedure _ToText(const Value: Currency; const Curr: RawUTF8; var Sexe: TPeopleSexe; var Name: RawUTF8);
procedure RecordToText(Rec: TTestCustomJSONArraySimpleArray;
onSuccess: procedure(Rec: TTestCustomJSONArraySimpleArray; Result: String); onError: TSQLRestEvent);
function _RecordToText(var Rec: TTestCustomJSONArraySimpleArray): String;
procedure GetPeople(id: TID; arr: TSimpleRecordDynArray;
onSuccess: procedure(People: TSQLRecordPeople; Sexes: TPeopleSexeDynArray; arr: TSimpleRecordDynArray; Result: Boolean); onError: TSQLRestEvent);
function _GetPeople(const id: TID; var People: TSQLRecordPeople; var Sexes: TPeopleSexeDynArray; var arr: TSimpleRecordDynArray): Boolean;
end;
const
/// the server port, corresponding to http://localhost:888
SERVER_PORT = 888;
/// return the database Model corresponding to this server
function GetModel: TSQLModel;
/// create a TSQLRestClientHTTP instance and connect to the server
// - it will use by default port 888
// - secure connection will be established via TSQLRestServerAuthenticationDefault
// with the supplied credentials
// - request will be asynchronous, and trigger onSuccess or onError event
procedure GetClient(const aServerAddress, aUserName,aPassword: string;
onSuccess, onError: TSQLRestEvent; aServerPort: integer=SERVER_PORT);
// publish some low-level helpers for variant conversion
// - used internally: you should not need those functions in your end-user code
function Variant2TPeopleSexe(const _variant: variant): TPeopleSexe;
function Variant2TRecordEnum(const _variant: variant): TRecordEnum;
function Variant2TTestCustomJSONArraySimpleArray(const Value: variant): TTestCustomJSONArraySimpleArray;
function TTestCustomJSONArraySimpleArray2Variant(const Value: TTestCustomJSONArraySimpleArray): variant;
function Variant2TSimpleRecord(const Value: variant): TSimpleRecord;
function TSimpleRecord2Variant(const Value: TSimpleRecord): variant;
function Variant2TPeopleSexeDynArray(const _variant: variant): TPeopleSexeDynArray;
function TPeopleSexeDynArray2Variant(const _array: TPeopleSexeDynArray): variant;
function Variant2TSimpleRecordDynArray(const _variant: variant): TSimpleRecordDynArray;
function TSimpleRecordDynArray2Variant(const _array: TSimpleRecordDynArray): variant;
implementation
{ Some helpers for enumerates types }
{$HINTS OFF} // for begin asm return ... end; end below
// those functions will use the existing generated string array constant
// defined by the SMS compiler for each enumeration
function Variant2TPeopleSexe(const _variant: variant): TPeopleSexe;
begin
asm return @VariantToEnum(@_variant,@TPeopleSexe); end;
end;
function Variant2TRecordEnum(const _variant: variant): TRecordEnum;
begin
asm return @VariantToEnum(@_variant,@TRecordEnum); end;
end;
{$HINTS ON}
{ Some helpers for record types:
due to potential obfuscation of generated JavaScript, we can't assume
that the JSON used for transmission would match record fields naming }
function Variant2TTestCustomJSONArraySimpleArray(const Value: variant): TTestCustomJSONArraySimpleArray;
begin
result.F := Value.F;
if VariantType(Value.G)=jvArray then
for var i := 0 to integer(Value.G.length)-1 do
result.G.Add(String(Value.G[i]));
result.H.H1 := Value.H.H1;
result.H.H2 := Value.H.H2;
result.H.H3.H3a := Value.H.H3.H3a;
result.H.H3.H3b := VariantToBlob(Value.H.H3.H3b);
result.I := Iso8601ToDateTime(Value.I);
if VariantType(Value.J)=jvArray then begin
var tmp: TTestCustomJSONArraySimpleArray;
tmp.J.SetLength(1);
for var n := 0 to integer(Value.J.length)-1 do begin
var source := Value.J[n];
var dest := tmp.J[0];
dest.J1 := source.J1;
dest.J2 := VariantToGUID(source.J2);
dest.J3 := Variant2TRecordEnum(source.J3);
result.J.Add(dest);
end;
end;
end;
function TTestCustomJSONArraySimpleArray2Variant(const Value: TTestCustomJSONArraySimpleArray): variant;
begin
result := new JObject;
result.F := Value.F;
result.G := variant(Value.G);
result.H := new JObject;
result.H.H1 := Value.H.H1;
result.H.H2 := Value.H.H2;
result.H.H3 := new JObject;
result.H.H3.H3a := Value.H.H3.H3a;
result.H.H3.H3b := BlobToVariant(Value.H.H3.H3b);
result.I := DateTimeToIso8601(Value.I);
result.J := TVariant.CreateArray;
for var source in Value.J do begin
var dest: variant := new JObject;
dest.J1 := source.J1;
dest.J2 := GUIDToVariant(source.J2);
dest.J3 := ord(source.J3);
result.J.push(dest);
end;
end;
function Variant2TSimpleRecord(const Value: variant): TSimpleRecord;
begin
result.A := Value.A;
result.B := Value.B;
result.C := Value.C;
end;
function TSimpleRecord2Variant(const Value: TSimpleRecord): variant;
begin
result := new JObject;
result.A := Value.A;
result.B := Value.B;
result.C := Value.C;
end;
{ Some helpers for dynamic array types }
function Variant2TPeopleSexeDynArray(const _variant: variant): TPeopleSexeDynArray;
var tmp: Byte;
begin
if VariantType(_variant)=jvArray then
for var i := 0 to integer(_variant.Length)-1 do begin
tmp := (_variant[i]);
result.Add(tmp);
end;
end;
function TPeopleSexeDynArray2Variant(const _array: TPeopleSexeDynArray): variant;
var i: integer;
begin
result := TVariant.CreateArray;
for i := 0 to high(_array) do
result.push((_array[i]));
end;
function Variant2TSimpleRecordDynArray(const _variant: variant): TSimpleRecordDynArray;
var tmp: TSimpleRecord;
begin
if VariantType(_variant)=jvArray then
for var i := 0 to integer(_variant.Length)-1 do begin
tmp := Variant2TSimpleRecord(_variant[i]);
result.Add(tmp);
end;
end;
function TSimpleRecordDynArray2Variant(const _array: TSimpleRecordDynArray): variant;
var i: integer;
begin
result := TVariant.CreateArray;
for i := 0 to high(_array) do
result.push(TSimpleRecord2Variant(_array[i]));
end;
{ TSQLRecordPeople }
class function TSQLRecordPeople.ComputeRTTI: TRTTIPropInfos;
begin
result := TRTTIPropInfos.Create(
['FirstName','LastName','Data','YearOfBirth','YearOfDeath','Sexe','Simple'],
[sftUnspecified,sftUnspecified,sftBlob,sftUnspecified,sftUnspecified,sftUnspecified,sftRecord]);
end;
procedure TSQLRecordPeople.SetProperty(FieldIndex: integer; const Value: variant);
begin
case FieldIndex of
0: fID := Value;
1: fFirstName := Value;
2: fLastName := Value;
3: fData := VariantToBlob(Value);
4: fYearOfBirth := Value;
5: fYearOfDeath := Value;
6: fSexe := Variant2TPeopleSexe(Value);
7: fSimple := Variant2TTestCustomJSONArraySimpleArray(Value);
end;
end;
function TSQLRecordPeople.GetProperty(FieldIndex: integer): variant;
begin
case FieldIndex of
0: result := fID;
1: result := fFirstName;
2: result := fLastName;
3: result := BlobToVariant(fData);
4: result := fYearOfBirth;
5: result := fYearOfDeath;
6: result := ord(fSexe);
7: result := TTestCustomJSONArraySimpleArray2Variant(fSimple);
end;
end;
function GetModel: TSQLModel;
begin
result := TSQLModel.Create([TSQLAuthUser,TSQLAuthGroup,TSQLRecordPeople],'root');
end;
procedure GetClient(const aServerAddress, aUserName,aPassword: string;
onSuccess, onError: TSQLRestEvent; aServerPort: integer);
begin
var client := TSQLRestClientHTTP.Create(aServerAddress,aServerPort,GetModel,true);
client.Connect(
lambda
try
if client.ServerTimeStamp=0 then begin
if Assigned(onError) then
onError(client);
exit;
end;
if not client.SetUser(TSQLRestServerAuthenticationDefault,aUserName,aPassword) then begin
if Assigned(onError) then
onError(client);
exit;
end;
if Assigned(onSuccess) then
onSuccess(client);
except
if Assigned(onError) then
onError(client);
end;
end,
onError);
end;
{ TServiceCalculator }
constructor TServiceCalculator.Create(aClient: TSQLRestClientURI);
begin
fServiceName := 'Calculator';
fServiceURI := 'Calculator';
fInstanceImplementation := sicShared;
fContractExpected := '814F1362B19B2F4D';
inherited Create(aClient);
end;
procedure TServiceCalculator.Add(n1: Integer; n2: Integer;
onSuccess: procedure(Result: Integer); onError: TSQLRestEvent);
begin
fClient.CallRemoteServiceAsynch(self,'Add',1,
[n1,n2],
lambda (res: array of Variant)
onSuccess(res[0]);
end, onError);
end;
function TServiceCalculator._Add(const n1: Integer; const n2: Integer): Integer;
begin
var res := fClient.CallRemoteServiceSynch(self,'Add',1,
[n1,n2]);
Result := res[0];
end;
procedure TServiceCalculator.ToText(Value: Currency; Curr: String; Sexe: TPeopleSexe; Name: String;
onSuccess: procedure(Sexe: TPeopleSexe; Name: String); onError: TSQLRestEvent);
begin
fClient.CallRemoteServiceAsynch(self,'ToText',2,
[Value,Curr,ord(Sexe),Name],
lambda (res: array of Variant)
onSuccess(Variant2TPeopleSexe(res[0]),res[1]);
end, onError);
end;
procedure TServiceCalculator._ToText(const Value: Currency; const Curr: RawUTF8; var Sexe: TPeopleSexe; var Name: RawUTF8);
begin
var res := fClient.CallRemoteServiceSynch(self,'ToText',2,
[Value,Curr,ord(Sexe),Name]);
Sexe := Variant2TPeopleSexe(res[0]);
Name := res[1];
end;
procedure TServiceCalculator.RecordToText(Rec: TTestCustomJSONArraySimpleArray;
onSuccess: procedure(Rec: TTestCustomJSONArraySimpleArray; Result: String); onError: TSQLRestEvent);
begin
fClient.CallRemoteServiceAsynch(self,'RecordToText',2,
[TTestCustomJSONArraySimpleArray2Variant(Rec)],
lambda (res: array of Variant)
onSuccess(Variant2TTestCustomJSONArraySimpleArray(res[0]),res[1]);
end, onError);
end;
function TServiceCalculator._RecordToText(var Rec: TTestCustomJSONArraySimpleArray): String;
begin
var res := fClient.CallRemoteServiceSynch(self,'RecordToText',2,
[TTestCustomJSONArraySimpleArray2Variant(Rec)]);
Rec := Variant2TTestCustomJSONArraySimpleArray(res[0]);
Result := res[1];
end;
procedure TServiceCalculator.GetPeople(id: TID; arr: TSimpleRecordDynArray;
onSuccess: procedure(People: TSQLRecordPeople; Sexes: TPeopleSexeDynArray; arr: TSimpleRecordDynArray; Result: Boolean); onError: TSQLRestEvent);
begin
fClient.CallRemoteServiceAsynch(self,'GetPeople',4,
[id,TSimpleRecordDynArray2Variant(arr)],
lambda (res: array of Variant)
onSuccess(TSQLRecordPeople.CreateFromVariant(res[0]),Variant2TPeopleSexeDynArray(res[1]),Variant2TSimpleRecordDynArray(res[2]),res[3]);
end, onError);
end;
function TServiceCalculator._GetPeople(const id: TID; var People: TSQLRecordPeople; var Sexes: TPeopleSexeDynArray; var arr: TSimpleRecordDynArray): Boolean;
begin
var res := fClient.CallRemoteServiceSynch(self,'GetPeople',4,
[id,TSimpleRecordDynArray2Variant(arr)]);
People := TSQLRecordPeople.CreateFromVariant(res[0]);
Sexes := Variant2TPeopleSexeDynArray(res[1]);
arr := Variant2TSimpleRecordDynArray(res[2]);
Result := res[3];
end;
end.