source upload
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
program FMClient;
|
||||
|
||||
uses
|
||||
FMX.Forms,
|
||||
FMMain in 'FMMain.pas' {Form1};
|
||||
|
||||
{$R *.res}
|
||||
|
||||
begin
|
||||
Application.Initialize;
|
||||
Application.CreateForm(TForm1, Form1);
|
||||
Application.Run;
|
||||
end.
|
@@ -0,0 +1,112 @@
|
||||
object Form1: TForm1
|
||||
Left = 0
|
||||
Top = 0
|
||||
Caption = ' mORMot Client using FireMonkey'
|
||||
ClientHeight = 301
|
||||
ClientWidth = 605
|
||||
FormFactor.Width = 320
|
||||
FormFactor.Height = 480
|
||||
FormFactor.Devices = [Desktop, iPhone, iPad]
|
||||
OnCreate = FormCreate
|
||||
OnDestroy = FormDestroy
|
||||
DesignerMobile = False
|
||||
DesignerWidth = 0
|
||||
DesignerHeight = 0
|
||||
DesignerDeviceName = ''
|
||||
DesignerOrientation = 0
|
||||
DesignerOSVersion = ''
|
||||
object lbl1: TLabel
|
||||
AutoSize = True
|
||||
Height = 16.000000000000000000
|
||||
Position.X = 24.000000000000000000
|
||||
Position.Y = 16.000000000000000000
|
||||
Text = 'mORMot Client using FireMonkey'
|
||||
Width = 181.000000000000000000
|
||||
end
|
||||
object edtValue: TEdit
|
||||
Touch.InteractiveGestures = [LongTap, DoubleTap]
|
||||
TabOrder = 1
|
||||
Position.X = 32.000000000000000000
|
||||
Position.Y = 80.000000000000000000
|
||||
Width = 153.000000000000000000
|
||||
Height = 22.000000000000000000
|
||||
OnChangeTracking = edtValueChange
|
||||
end
|
||||
object lbl2: TLabel
|
||||
AutoSize = True
|
||||
Height = 16.000000000000000000
|
||||
Position.X = 32.000000000000000000
|
||||
Position.Y = 56.000000000000000000
|
||||
Text = 'Enter some text:'
|
||||
Width = 86.000000000000000000
|
||||
end
|
||||
object lbl3: TLabel
|
||||
AutoSize = True
|
||||
Height = 16.000000000000000000
|
||||
Position.X = 32.000000000000000000
|
||||
Position.Y = 112.000000000000000000
|
||||
Text = 'Computed JSON:'
|
||||
Width = 91.000000000000000000
|
||||
end
|
||||
object mmoJSON: TMemo
|
||||
Touch.InteractiveGestures = [Pan, LongTap, DoubleTap]
|
||||
Height = 137.000000000000000000
|
||||
Position.X = 32.000000000000000000
|
||||
Position.Y = 136.000000000000000000
|
||||
TabOrder = 4
|
||||
Width = 545.000000000000000000
|
||||
TextSettings.WordWrap = True
|
||||
end
|
||||
object grpTable: TGroupBox
|
||||
Height = 89.000000000000000000
|
||||
Position.X = 240.000000000000000000
|
||||
Position.Y = 32.000000000000000000
|
||||
Text = 'Table'
|
||||
Width = 113.000000000000000000
|
||||
TabOrder = 7
|
||||
object btnRewind: TButton
|
||||
Height = 22.000000000000000000
|
||||
Position.X = 16.000000000000000000
|
||||
Position.Y = 24.000000000000000000
|
||||
TabOrder = 5
|
||||
Text = 'First'
|
||||
Width = 80.000000000000000000
|
||||
OnClick = btnNextClick
|
||||
end
|
||||
object btnNext: TButton
|
||||
Height = 22.000000000000000000
|
||||
Position.X = 16.000000000000000000
|
||||
Position.Y = 54.000000000000000000
|
||||
TabOrder = 6
|
||||
Text = 'Next'
|
||||
Width = 80.000000000000000000
|
||||
OnClick = btnNextClick
|
||||
end
|
||||
end
|
||||
object grpORM: TGroupBox
|
||||
Height = 89.000000000000000000
|
||||
Position.X = 376.000000000000000000
|
||||
Position.Y = 32.000000000000000000
|
||||
Text = 'ORM'
|
||||
Width = 113.000000000000000000
|
||||
TabOrder = 6
|
||||
object btnRewindORM: TButton
|
||||
Height = 22.000000000000000000
|
||||
Position.X = 16.000000000000000000
|
||||
Position.Y = 24.000000000000000000
|
||||
TabOrder = 5
|
||||
Text = 'First'
|
||||
Width = 80.000000000000000000
|
||||
OnClick = btnORMClick
|
||||
end
|
||||
object btnNextORM: TButton
|
||||
Height = 22.000000000000000000
|
||||
Position.X = 16.000000000000000000
|
||||
Position.Y = 54.000000000000000000
|
||||
TabOrder = 6
|
||||
Text = 'Next'
|
||||
Width = 80.000000000000000000
|
||||
OnClick = btnORMClick
|
||||
end
|
||||
end
|
||||
end
|
@@ -0,0 +1,116 @@
|
||||
unit FMMain;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
System.SysUtils, System.Types, System.UITypes, System.Rtti, System.Classes,
|
||||
System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Dialogs,
|
||||
FMX.StdCtrls, FMX.Layouts, FMX.Memo, FMX.Edit,
|
||||
SynCrossPlatformJSON;
|
||||
|
||||
type
|
||||
TForm1 = class(TForm)
|
||||
lbl1: TLabel;
|
||||
edtValue: TEdit;
|
||||
lbl2: TLabel;
|
||||
lbl3: TLabel;
|
||||
mmoJSON: TMemo;
|
||||
grpTable: TGroupBox;
|
||||
btnRewind: TButton;
|
||||
btnNext: TButton;
|
||||
grpORM: TGroupBox;
|
||||
btnRewindORM: TButton;
|
||||
btnNextORM: TButton;
|
||||
procedure edtValueChange(Sender: TObject);
|
||||
procedure FormCreate(Sender: TObject);
|
||||
procedure btnNextClick(Sender: TObject);
|
||||
procedure FormDestroy(Sender: TObject);
|
||||
procedure btnORMClick(Sender: TObject);
|
||||
private
|
||||
public
|
||||
doc: variant;
|
||||
table: TJSONTableObject;
|
||||
end;
|
||||
|
||||
var
|
||||
Form1: TForm1;
|
||||
|
||||
implementation
|
||||
|
||||
{$R *.fmx}
|
||||
|
||||
procedure TForm1.btnNextClick(Sender: TObject);
|
||||
begin
|
||||
if table.Step(Sender=btnRewind) then
|
||||
mmoJSON.Text := JSONVariant(table.RowValues) else
|
||||
mmoJSON.Text := 'null';
|
||||
end;
|
||||
|
||||
type
|
||||
TSQLRecordPeople = class(TPersistent)
|
||||
private
|
||||
fRowID: integer;
|
||||
fData: TByteDynArray;
|
||||
fFirstName: string;
|
||||
fLastName: string;
|
||||
fYearOfBirth: integer;
|
||||
fYearOfDeath: word;
|
||||
published
|
||||
property RowID: integer read fRowID write fRowID;
|
||||
property FirstName: string read fFirstName write fFirstName;
|
||||
property LastName: string read fLastName write fLastName;
|
||||
property Data: TByteDynArray read fData write fData;
|
||||
property YearOfBirth: integer read fYearOfBirth write fYearOfBirth;
|
||||
property YearOfDeath: word read fYearOfDeath write fYearOfDeath;
|
||||
end;
|
||||
|
||||
procedure TForm1.btnORMClick(Sender: TObject);
|
||||
var people: TSQLRecordPeople;
|
||||
begin
|
||||
people := TSQLRecordPeople.Create;
|
||||
try
|
||||
if table.StepObject(people,Sender=btnRewindORM) then
|
||||
mmoJSON.Text := ObjectToJSON(people) else
|
||||
mmoJSON.Text := 'null';
|
||||
finally
|
||||
people.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TForm1.edtValueChange(Sender: TObject);
|
||||
begin
|
||||
doc.value := edtValue.Text;
|
||||
mmoJSON.Text := doc;
|
||||
end;
|
||||
|
||||
procedure TForm1.FormCreate(Sender: TObject);
|
||||
var json: string;
|
||||
FN: TFileName;
|
||||
level: integer;
|
||||
begin
|
||||
doc := JSONVariant('{"test":1234,"name":"Joh\"n\r","zero":0.0}');
|
||||
assert(doc.test=1234);
|
||||
assert(doc.name='Joh"n'#13);
|
||||
assert(doc.name2=null);
|
||||
assert(doc.zero=0);
|
||||
json := doc;
|
||||
assert(json='{"test":1234,"name":"Joh\"n\r","zero":0}');
|
||||
doc.name2 := 3.1415926;
|
||||
doc.name := 'John';
|
||||
json := doc;
|
||||
assert(json='{"test":1234,"name":"John","zero":0,"name2":3.1415926}');
|
||||
FN := 'people.json';
|
||||
for level := 1 to 4 do
|
||||
if FileExists(FN) then
|
||||
break else
|
||||
FN := IncludeTrailingPathDelimiter('..')+FN;
|
||||
table := TJSONTableObject.Create(UTF8FileToString(FN));
|
||||
assert(length(table.FieldNames)=6);
|
||||
end;
|
||||
|
||||
procedure TForm1.FormDestroy(Sender: TObject);
|
||||
begin
|
||||
table.Free;
|
||||
end;
|
||||
|
||||
end.
|
@@ -0,0 +1,15 @@
|
||||
program MobileClient;
|
||||
|
||||
uses
|
||||
System.StartUpCopy,
|
||||
FMX.MobilePreview,
|
||||
FMX.Forms,
|
||||
MobileMain in 'MobileMain.pas' {Form1};
|
||||
|
||||
{$R *.res}
|
||||
|
||||
begin
|
||||
Application.Initialize;
|
||||
Application.CreateForm(TForm1, Form1);
|
||||
Application.Run;
|
||||
end.
|
@@ -0,0 +1,53 @@
|
||||
object Form1: TForm1
|
||||
Left = 0
|
||||
Top = 0
|
||||
Caption = 'Form1'
|
||||
ClientHeight = 548
|
||||
ClientWidth = 320
|
||||
FormFactor.Width = 320
|
||||
FormFactor.Height = 480
|
||||
FormFactor.Devices = [Desktop]
|
||||
OnCreate = FormCreate
|
||||
DesignerMobile = True
|
||||
DesignerWidth = 320
|
||||
DesignerHeight = 568
|
||||
DesignerDeviceName = 'iPhone5'
|
||||
DesignerOrientation = 0
|
||||
DesignerOSVersion = '7'
|
||||
object lbl1: TLabel
|
||||
AutoSize = True
|
||||
Height = 23.000000000000000000
|
||||
Position.X = 16.000000000000000000
|
||||
Position.Y = 16.000000000000000000
|
||||
TextSettings.WordWrap = False
|
||||
Text = 'Enter a value:'
|
||||
Width = 101.000000000000000000
|
||||
end
|
||||
object edtValue: TEdit
|
||||
Touch.InteractiveGestures = [LongTap, DoubleTap]
|
||||
TabOrder = 2
|
||||
Position.X = 16.000000000000000000
|
||||
Position.Y = 40.000000000000000000
|
||||
Width = 233.000000000000000000
|
||||
Height = 30.000000000000000000
|
||||
OnChangeTracking = edtValueChangeTracking
|
||||
end
|
||||
object lbl2: TLabel
|
||||
AutoSize = True
|
||||
Height = 23.000000000000000000
|
||||
Position.X = 16.000000000000000000
|
||||
Position.Y = 96.000000000000000000
|
||||
TextSettings.WordWrap = False
|
||||
Text = 'Computed JSON:'
|
||||
Width = 129.000000000000000000
|
||||
end
|
||||
object mmoJSON: TMemo
|
||||
Touch.InteractiveGestures = [Pan, LongTap, DoubleTap]
|
||||
Anchors = [akLeft, akTop, akRight]
|
||||
Height = 321.000000000000000000
|
||||
Position.X = 16.000000000000000000
|
||||
Position.Y = 128.000000000000000000
|
||||
TabOrder = 4
|
||||
Width = 273.000000000000000000
|
||||
end
|
||||
end
|
@@ -0,0 +1,53 @@
|
||||
unit MobileMain;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
|
||||
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Layouts,
|
||||
FMX.Memo, FMX.StdCtrls, FMX.Edit,
|
||||
SynCrossPlatformJSON;
|
||||
|
||||
type
|
||||
TForm1 = class(TForm)
|
||||
lbl1: TLabel;
|
||||
edtValue: TEdit;
|
||||
lbl2: TLabel;
|
||||
mmoJSON: TMemo;
|
||||
procedure FormCreate(Sender: TObject);
|
||||
procedure edtValueChangeTracking(Sender: TObject);
|
||||
private
|
||||
public
|
||||
doc: variant;
|
||||
end;
|
||||
|
||||
var
|
||||
Form1: TForm1;
|
||||
|
||||
implementation
|
||||
|
||||
{$R *.fmx}
|
||||
|
||||
procedure TForm1.edtValueChangeTracking(Sender: TObject);
|
||||
begin
|
||||
doc.value := edtValue.Text;
|
||||
mmoJSON.Text := doc;
|
||||
end;
|
||||
|
||||
procedure TForm1.FormCreate(Sender: TObject);
|
||||
var json: string;
|
||||
begin
|
||||
doc := JSONVariant('{"test":1234,"name":"Joh\"n\r","zero":0.0}');
|
||||
assert(doc.test=1234);
|
||||
assert(doc.name='Joh"n'#13);
|
||||
assert(doc.name2=null);
|
||||
assert(doc.zero=0);
|
||||
json := doc;
|
||||
assert(json='{"test":1234,"name":"Joh\"n\r","zero":0}');
|
||||
doc.name2 := 3.1415926;
|
||||
doc.name := 'John';
|
||||
json := doc;
|
||||
assert(json='{"test":1234,"name":"John","zero":0,"name2":3.1415926}');
|
||||
end;
|
||||
|
||||
end.
|
@@ -0,0 +1,72 @@
|
||||
[
|
||||
{"RowID":3,"FirstName":"Sergei1","LastName":"Rachmaninoff","Data":"w6l6w6di","YearOfBirth":1800,"YearOfDeath":1943},
|
||||
{"RowID":4,"FirstName":"Alexandre1","LastName":"Dumas","Data":"w6nDp2I=","YearOfBirth":1801,"YearOfDeath":1870},
|
||||
{"RowID":7,"FirstName":"Aldous Leonard1","LastName":"Huxley","Data":"w6nDoA==","YearOfBirth":1802,"YearOfDeath":1963},
|
||||
{"RowID":8,"FirstName":"Claudè1\n\u0007","LastName":"Mônet","Data":"4OnnZHNqZHNCTE9CMjM=","YearOfBirth":1803,"YearOfDeath":1926},
|
||||
{"RowID":9,"FirstName":"Albert1","LastName":"Einstein","Data":"w6nDp3A=","YearOfBirth":1804,"YearOfDeath":1955},
|
||||
{"RowID":11,"FirstName":"Jane1","LastName":"Austèn","Data":"w6fDoMOnbQ==","YearOfBirth":1805,"YearOfDeath":1817},
|
||||
{"RowID":12,"FirstName":"Salvador1","LastName":"Dali","Data":"DAAAAA==","YearOfBirth":1806,"YearOfDeath":1989},
|
||||
{"RowID":15,"FirstName":"Alexandre1","LastName":"Dumas","Data":"w6nDp2I=","YearOfBirth":1807,"YearOfDeath":1870},
|
||||
{"RowID":16,"FirstName":"Franz1","LastName":"Schubert","Data":"w6nDoMOnYQ==","YearOfBirth":1808,"YearOfDeath":1828},
|
||||
{"RowID":17,"FirstName":"Leonardo1","LastName":"da Vinçi","Data":"QMOnYg==","YearOfBirth":1809,"YearOfDeath":1519},
|
||||
{"RowID":19,"FirstName":"Claudè1\n\u0007","LastName":"Mônet","Data":"4OnnZHNqZHNCTE9CMjM=","YearOfBirth":1810,"YearOfDeath":1926},
|
||||
{"RowID":20,"FirstName":"Albert1","LastName":"Einstein","Data":"w6nDp3A=","YearOfBirth":1811,"YearOfDeath":1955},
|
||||
{"RowID":21,"FirstName":"Johannes1","LastName":"Gutenberg","Data":"w6ptbHM=","YearOfBirth":1812,"YearOfDeath":1468},
|
||||
{"RowID":23,"FirstName":"Salvador2","LastName":"Dali","Data":"FwAAAA==","YearOfBirth":1813,"YearOfDeath":1989},
|
||||
{"RowID":25,"FirstName":"Sergei2","LastName":"Rachmaninoff","Data":"w6l6w6di","YearOfBirth":1814,"YearOfDeath":1943},
|
||||
{"RowID":27,"FirstName":"Franz2","LastName":"Schubert","Data":"w6nDoMOnYQ==","YearOfBirth":1815,"YearOfDeath":1828},
|
||||
{"RowID":28,"FirstName":"Leonardo2","LastName":"da Vinçi","Data":"QMOnYg==","YearOfBirth":1816,"YearOfDeath":1519},
|
||||
{"RowID":29,"FirstName":"Aldous Leonard2","LastName":"Huxley","Data":"w6nDoA==","YearOfBirth":1817,"YearOfDeath":1963},
|
||||
{"RowID":31,"FirstName":"Albert2","LastName":"Einstein","Data":"w6nDp3A=","YearOfBirth":1818,"YearOfDeath":1955},
|
||||
{"RowID":32,"FirstName":"Johannes2","LastName":"Gutenberg","Data":"w6ptbHM=","YearOfBirth":1819,"YearOfDeath":1468},
|
||||
{"RowID":33,"FirstName":"Jane2","LastName":"Austèn","Data":"w6fDoMOnbQ==","YearOfBirth":1820,"YearOfDeath":1817},
|
||||
{"RowID":36,"FirstName":"Sergei3","LastName":"Rachmaninoff","Data":"w6l6w6di","YearOfBirth":1821,"YearOfDeath":1943},
|
||||
{"RowID":37,"FirstName":"Alexandre3","LastName":"Dumas","Data":"w6nDp2I=","YearOfBirth":1822,"YearOfDeath":1870},
|
||||
{"RowID":39,"FirstName":"Leonardo3","LastName":"da Vinçi","Data":"QMOnYg==","YearOfBirth":1823,"YearOfDeath":1519},
|
||||
{"RowID":40,"FirstName":"Aldous Leonard3","LastName":"Huxley","Data":"w6nDoA==","YearOfBirth":1824,"YearOfDeath":1963},
|
||||
{"RowID":41,"FirstName":"Claudè3\n\u0007","LastName":"Mônet","Data":"4OnnZHNqZHNCTE9CMjM=","YearOfBirth":1825,"YearOfDeath":1926},
|
||||
{"RowID":43,"FirstName":"Johannes3","LastName":"Gutenberg","Data":"w6ptbHM=","YearOfBirth":1826,"YearOfDeath":1468},
|
||||
{"RowID":44,"FirstName":"Jane3","LastName":"Austèn","Data":"w6fDoMOnbQ==","YearOfBirth":1827,"YearOfDeath":1817},
|
||||
{"RowID":47,"FirstName":"Sergei4","LastName":"Rachmaninoff","Data":"w6l6w6di","YearOfBirth":1828,"YearOfDeath":1943},
|
||||
{"RowID":48,"FirstName":"Alexandre4","LastName":"Dumas","Data":"w6nDp2I=","YearOfBirth":1829,"YearOfDeath":1870},
|
||||
{"RowID":49,"FirstName":"Franz4","LastName":"Schubert","Data":"w6nDoMOnYQ==","YearOfBirth":1830,"YearOfDeath":1828},
|
||||
{"RowID":51,"FirstName":"Aldous Leonard4","LastName":"Huxley","Data":"w6nDoA==","YearOfBirth":1831,"YearOfDeath":1963},
|
||||
{"RowID":52,"FirstName":"Claudè4\n\u0007","LastName":"Mônet","Data":"4OnnZHNqZHNCTE9CMjM=","YearOfBirth":1832,"YearOfDeath":1926},
|
||||
{"RowID":53,"FirstName":"Albert4","LastName":"Einstein","Data":"w6nDp3A=","YearOfBirth":1833,"YearOfDeath":1955},
|
||||
{"RowID":55,"FirstName":"Jane4","LastName":"Austèn","Data":"w6fDoMOnbQ==","YearOfBirth":1834,"YearOfDeath":1817},
|
||||
{"RowID":57,"FirstName":"Samuel Finley Breese5","LastName":"Morse","Data":"YcOpw6DDpw==","YearOfBirth":1835,"YearOfDeath":1872},
|
||||
{"RowID":59,"FirstName":"Alexandre5","LastName":"Dumas","Data":"w6nDp2I=","YearOfBirth":1836,"YearOfDeath":1870},
|
||||
{"RowID":60,"FirstName":"Franz5","LastName":"Schubert","Data":"w6nDoMOnYQ==","YearOfBirth":1837,"YearOfDeath":1828},
|
||||
{"RowID":61,"FirstName":"Leonardo5","LastName":"da Vinçi","Data":"QMOnYg==","YearOfBirth":1838,"YearOfDeath":1519},
|
||||
{"RowID":63,"FirstName":"Claudè5\n\u0007","LastName":"Mônet","Data":"4OnnZHNqZHNCTE9CMjM=","YearOfBirth":1839,"YearOfDeath":1926},
|
||||
{"RowID":64,"FirstName":"Albert5","LastName":"Einstein","Data":"w6nDp3A=","YearOfBirth":1840,"YearOfDeath":1955},
|
||||
{"RowID":65,"FirstName":"Johannes5","LastName":"Gutenberg","Data":"w6ptbHM=","YearOfBirth":1841,"YearOfDeath":1468},
|
||||
{"RowID":68,"FirstName":"Samuel Finley Breese6","LastName":"Morse","Data":"YcOpw6DDpw==","YearOfBirth":1842,"YearOfDeath":1872},
|
||||
{"RowID":69,"FirstName":"Sergei6","LastName":"Rachmaninoff","Data":"w6l6w6di","YearOfBirth":1843,"YearOfDeath":1943},
|
||||
{"RowID":71,"FirstName":"Franz6","LastName":"Schubert","Data":"w6nDoMOnYQ==","YearOfBirth":1844,"YearOfDeath":1828},
|
||||
{"RowID":72,"FirstName":"Leonardo6","LastName":"da Vinçi","Data":"QMOnYg==","YearOfBirth":1845,"YearOfDeath":1519},
|
||||
{"RowID":73,"FirstName":"Aldous Leonard6","LastName":"Huxley","Data":"w6nDoA==","YearOfBirth":1846,"YearOfDeath":1963},
|
||||
{"RowID":75,"FirstName":"Albert6","LastName":"Einstein","Data":"w6nDp3A=","YearOfBirth":1847,"YearOfDeath":1955},
|
||||
{"RowID":76,"FirstName":"Johannes6","LastName":"Gutenberg","Data":"w6ptbHM=","YearOfBirth":1848,"YearOfDeath":1468},
|
||||
{"RowID":79,"FirstName":"Samuel Finley Breese7","LastName":"Morse","Data":"YcOpw6DDpw==","YearOfBirth":1849,"YearOfDeath":1872},
|
||||
{"RowID":80,"FirstName":"Sergei7","LastName":"Rachmaninoff","Data":"w6l6w6di","YearOfBirth":1850,"YearOfDeath":1943},
|
||||
{"RowID":81,"FirstName":"Alexandre7","LastName":"Dumas","Data":"w6nDp2I=","YearOfBirth":1851,"YearOfDeath":1870},
|
||||
{"RowID":83,"FirstName":"Leonardo7","LastName":"da Vinçi","Data":"QMOnYg==","YearOfBirth":1852,"YearOfDeath":1519},
|
||||
{"RowID":84,"FirstName":"Aldous Leonard7","LastName":"Huxley","Data":"w6nDoA==","YearOfBirth":1853,"YearOfDeath":1963},
|
||||
{"RowID":85,"FirstName":"Claudè7\n\u0007","LastName":"Mônet","Data":"4OnnZHNqZHNCTE9CMjM=","YearOfBirth":1854,"YearOfDeath":1926},
|
||||
{"RowID":87,"FirstName":"Johannes7","LastName":"Gutenberg","Data":"w6ptbHM=","YearOfBirth":1855,"YearOfDeath":1468},
|
||||
{"RowID":89,"FirstName":"Salvador8","LastName":"Dali","Data":"WQAAAA==","YearOfBirth":1856,"YearOfDeath":1989},
|
||||
{"RowID":91,"FirstName":"Sergei8","LastName":"Rachmaninoff","Data":"w6l6w6di","YearOfBirth":1857,"YearOfDeath":1943},
|
||||
{"RowID":92,"FirstName":"Alexandre8","LastName":"Dumas","Data":"w6nDp2I=","YearOfBirth":1858,"YearOfDeath":1870},
|
||||
{"RowID":93,"FirstName":"Franz8","LastName":"Schubert","Data":"w6nDoMOnYQ==","YearOfBirth":1859,"YearOfDeath":1828},
|
||||
{"RowID":95,"FirstName":"Aldous Leonard8","LastName":"Huxley","Data":"w6nDoA==","YearOfBirth":1860,"YearOfDeath":1963},
|
||||
{"RowID":96,"FirstName":"Claudè8\n\u0007","LastName":"Mônet","Data":"4OnnZHNqZHNCTE9CMjM=","YearOfBirth":1861,"YearOfDeath":1926},
|
||||
{"RowID":97,"FirstName":"Albert8","LastName":"Einstein","Data":"w6nDp3A=","YearOfBirth":1862,"YearOfDeath":1955},
|
||||
{"RowID":100,"FirstName":"Salvador9","LastName":"Dali","Data":"ZAAAAA==","YearOfBirth":1863,"YearOfDeath":1989},
|
||||
{"RowID":101,"FirstName":"Samuel Finley Breese9","LastName":"Morse","Data":"YcOpw6DDpw==","YearOfBirth":1864,"YearOfDeath":1872},
|
||||
{"RowID":103,"FirstName":"Alexandre9","LastName":"Dumas","Data":"w6nDp2I=","YearOfBirth":1865,"YearOfDeath":1870},
|
||||
{"RowID":104,"FirstName":"Franz9","LastName":"Schubert","Data":"w6nDoMOnYQ==","YearOfBirth":1866,"YearOfDeath":1828},
|
||||
{"RowID":105,"FirstName":"Leonardo9","LastName":"da Vinçi","Data":"QMOnYg==","YearOfBirth":1867,"YearOfDeath":1519},
|
||||
{"RowID":107,"FirstName":"Claudè9\n\u0007","LastName":"Mônet","Data":"4OnnZHNqZHNCTE9CMjM=","YearOfBirth":1868,"YearOfDeath":1926},
|
||||
{"RowID":108,"FirstName":"Albert9","LastName":"Einstein","Data":"w6nDp3A=","YearOfBirth":1869,"YearOfDeath":1955}
|
||||
]
|
@@ -0,0 +1,267 @@
|
||||
unit PeopleServer;
|
||||
|
||||
interface
|
||||
|
||||
{$define TESTRECORD}
|
||||
|
||||
uses
|
||||
SynCommons,
|
||||
mORMot,
|
||||
mORMotHttpServer,
|
||||
mORMotWrappers,
|
||||
SynMustache,
|
||||
SysUtils;
|
||||
|
||||
type
|
||||
{$ifdef TESTRECORD}
|
||||
TRecordEnum = (reOne, reTwo, reLast);
|
||||
|
||||
TTestCustomJSONArraySimpleArray = packed record
|
||||
F: RawUTF8;
|
||||
G: array of RawUTF8;
|
||||
H: record
|
||||
H1: integer;
|
||||
H2: WideString;
|
||||
H3: record
|
||||
H3a: boolean;
|
||||
H3b: RawByteString;
|
||||
end;
|
||||
end;
|
||||
I: TDateTime;
|
||||
J: array of packed record
|
||||
J1: byte;
|
||||
J2: TGUID;
|
||||
J3: TRecordEnum;
|
||||
end;
|
||||
end;
|
||||
{$endif TESTRECORD}
|
||||
|
||||
{
|
||||
TRecB=packed record
|
||||
a1:array of packed record
|
||||
v1,v2:integer;
|
||||
end;
|
||||
a2:array of integer;
|
||||
v1:integer;
|
||||
end;
|
||||
}
|
||||
|
||||
TPeopleSexe = (sFemale, sMale);
|
||||
|
||||
TPeopleSexeDynArray = array of TPeopleSexe;
|
||||
|
||||
TSimpleRecord = packed record
|
||||
A,B: integer;
|
||||
C: RawUTF8;
|
||||
end;
|
||||
|
||||
TSimpleRecordDynArray = array of TSimpleRecord;
|
||||
|
||||
TSQLRecordPeople = class(TSQLRecord)
|
||||
protected
|
||||
fData: TSQLRawBlob;
|
||||
fFirstName: RawUTF8;
|
||||
fLastName: RawUTF8;
|
||||
fYearOfBirth: integer;
|
||||
fYearOfDeath: word;
|
||||
fAnother: TSQLRecordPeople;
|
||||
{$ifdef TESTRECORD}
|
||||
fSexe: TPeopleSexe;
|
||||
fSimple: TTestCustomJSONArraySimpleArray;
|
||||
public
|
||||
class procedure InternalRegisterCustomProperties(Props: TSQLRecordProperties); override;
|
||||
{$endif}
|
||||
published
|
||||
property FirstName: RawUTF8 read fFirstName write fFirstName;
|
||||
property LastName: RawUTF8 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 Another: TSQLRecordPeople read fAnother write fAnother;
|
||||
{$ifdef TESTRECORD}
|
||||
property Sexe: TPeopleSexe read fSexe write fSexe;
|
||||
public
|
||||
property Simple: TTestCustomJSONArraySimpleArray read fSimple;
|
||||
{$endif}
|
||||
end;
|
||||
|
||||
ICalculator = interface(IInvokable)
|
||||
['{9A60C8ED-CEB2-4E09-87D4-4A16F496E5FE}']
|
||||
function Add(n1,n2: integer): integer;
|
||||
procedure ToText(Value: Currency; const Curr: RawUTF8;
|
||||
var Sexe: TPeopleSexe; var Name: RawUTF8);
|
||||
{$ifdef TESTRECORD}
|
||||
function RecordToText(var Rec: TTestCustomJSONArraySimpleArray): string;
|
||||
{$endif}
|
||||
function GetPeople(id: TID; out People: TSQLRecordPeople;
|
||||
out Sexes: TPeopleSexeDynArray; var arr: TSimpleRecordDynArray): boolean;
|
||||
// var rec: TRecB): boolean;
|
||||
//function Test(toto: integer): TServiceCustomAnswer;
|
||||
end;
|
||||
|
||||
TCustomServer = class(TSQLRestServerFullMemory)
|
||||
published
|
||||
procedure DropTable(Ctxt: TSQLRestServerURIContext);
|
||||
end;
|
||||
|
||||
TPeopleServerAuthentication = (psaNone,psaWeak,psaDefault);
|
||||
|
||||
|
||||
procedure StartServer(auth: TPeopleServerAuthentication);
|
||||
|
||||
procedure StopServer;
|
||||
|
||||
|
||||
implementation
|
||||
|
||||
{ TServiceCalculator }
|
||||
|
||||
type
|
||||
TServiceCalculator = class(TInterfacedObject, ICalculator)
|
||||
public
|
||||
function Add(n1,n2: integer): integer;
|
||||
procedure ToText(Value: Currency; const Curr: RawUTF8;
|
||||
var Sexe: TPeopleSexe; var Name: RawUTF8);
|
||||
{$ifdef TESTRECORD}
|
||||
function RecordToText(var Rec: TTestCustomJSONArraySimpleArray): string;
|
||||
{$endif}
|
||||
function GetPeople(id: TID; out People: TSQLRecordPeople;
|
||||
out Sexes: TPeopleSexeDynArray; var arr: TSimpleRecordDynArray): boolean;
|
||||
// var rec: TRecB): boolean;
|
||||
function Test(toto: integer): TServiceCustomAnswer;
|
||||
end;
|
||||
|
||||
function TServiceCalculator.Add(n1, n2: integer): integer;
|
||||
begin
|
||||
result := n1+n2;
|
||||
end;
|
||||
|
||||
procedure TServiceCalculator.ToText(Value: Currency; const Curr: RawUTF8;
|
||||
var Sexe: TPeopleSexe; var Name: RawUTF8);
|
||||
const SEX_TEXT: array[TPeopleSexe] of RawUTF8 = ('Miss','Mister');
|
||||
begin
|
||||
Name := FormatUTF8('% % for % %',[Curr,Value,SEX_TEXT[Sexe],Name]);
|
||||
Sexe := sFemale;
|
||||
end;
|
||||
|
||||
function TServiceCalculator.GetPeople(id: TID;
|
||||
out People: TSQLRecordPeople; out Sexes: TPeopleSexeDynArray;
|
||||
var arr: TSimpleRecordDynArray{; var rec: TRecB}): boolean;
|
||||
var n: integer;
|
||||
begin
|
||||
result := ServiceContext.Request.Server.Retrieve(id,People);
|
||||
n := length(arr);
|
||||
SetLength(arr,n+1);
|
||||
arr[n].A := id;
|
||||
arr[n].C := People.FirstName;
|
||||
end;
|
||||
|
||||
|
||||
{$ifdef TESTRECORD}
|
||||
|
||||
function TServiceCalculator.RecordToText(var Rec: TTestCustomJSONArraySimpleArray): string;
|
||||
var n: integer;
|
||||
begin
|
||||
result := UTF8ToString(RecordSaveJSON(Rec,TypeInfo(TTestCustomJSONArraySimpleArray)));
|
||||
Rec.F := Rec.F+'!';
|
||||
n := length(Rec.G);
|
||||
SetLength(Rec.G,n+1);
|
||||
Rec.G[n] := UInt32ToUtf8(n+1);
|
||||
inc(Rec.H.H1);
|
||||
if n=0 then
|
||||
exit; // first return J[] with nothing
|
||||
n := length(Rec.J);
|
||||
SetLength(Rec.J,n+1);
|
||||
Rec.J[n].J1 := n;
|
||||
Rec.J[n].J2.D2 := n;
|
||||
Rec.J[n].J3 := TRecordEnum(n mod (ord(high(TRecordEnum))+1));
|
||||
end;
|
||||
|
||||
{$endif}
|
||||
|
||||
{ TCustomServer }
|
||||
|
||||
procedure TCustomServer.DropTable(Ctxt: TSQLRestServerURIContext);
|
||||
begin
|
||||
if (Ctxt.Method=mGET) and (Ctxt.TableIndex>=0) then begin
|
||||
TSQLRestStorageInMemory(fStaticData[Ctxt.TableIndex]).DropValues;
|
||||
Ctxt.Success;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
var Model: TSQLModel;
|
||||
DB: TCustomServer;
|
||||
Server: TSQLHttpServer;
|
||||
|
||||
procedure StartServer(auth: TPeopleServerAuthentication);
|
||||
begin
|
||||
StopServer;
|
||||
//TSQLLog.Family.Level := LOG_VERBOSE;
|
||||
Model := TSQLModel.Create([TSQLAuthUser,TSQLAuthGroup,TSQLRecordPeople]);
|
||||
DB := TCustomServer.Create(Model);
|
||||
Server := TSQLHttpServer.Create('888',DB);
|
||||
Server.AccessControlAllowOrigin := '*';
|
||||
case auth of
|
||||
psaDefault:
|
||||
DB.AuthenticationRegister(TSQLRestServerAuthenticationDefault);
|
||||
psaWeak:
|
||||
DB.AuthenticationRegister(TSQLRestServerAuthenticationNone);
|
||||
end;
|
||||
if DB.TableRowCount(TSQLRecordPeople)=0 then
|
||||
// we expect at least one record
|
||||
if DB.AddSimple(TSQLRecordPeople,['First1','Last1',1801,1826,1{$ifdef TESTRECORD},0,''{$endif}])=0 then
|
||||
writeln('StartServer DB.Add(TSQLRecordPeople) Error');
|
||||
// in all cases, client will call DropTable method-based service
|
||||
AddToServerWrapperMethod(DB,['..\..\..\CrossPlatform\templates',
|
||||
'..\..\..\..\CrossPlatform\templates']);
|
||||
{$ifndef FPC}
|
||||
DB.ServiceRegister(TServiceCalculator,[TypeInfo(ICalculator)],sicShared);
|
||||
{$endif}
|
||||
end;
|
||||
|
||||
procedure StopServer;
|
||||
begin
|
||||
FreeAndNil(Server);
|
||||
FreeAndNil(DB);
|
||||
FreeAndNil(Model);
|
||||
end;
|
||||
|
||||
{$ifdef TESTRECORD}
|
||||
|
||||
{ TSQLRecordPeople }
|
||||
|
||||
const
|
||||
__TTestCustomJSONArraySimpleArray =
|
||||
'F RawUTF8 G array of RawUTF8 '+
|
||||
'H {H1 integer H2 WideString H3{H3a boolean H3b RawByteString}} I TDateTime '+
|
||||
'J [J1 byte J2 TGUID J3 TRecordEnum]';
|
||||
__TSimpleRecord = 'A,B:integer C: RawUTF8';
|
||||
__TRecB = 'a2:array of integer v1:integer';
|
||||
// __TRecB = 'a1 [v1,v2:integer] a2:array of integer v1:integer';
|
||||
|
||||
class procedure TSQLRecordPeople.InternalRegisterCustomProperties(
|
||||
Props: TSQLRecordProperties);
|
||||
begin
|
||||
Props.RegisterCustomPropertyFromRTTI(Self,TypeInfo(TTestCustomJSONArraySimpleArray),
|
||||
'Simple',@TSQLRecordPeople(nil).fSimple);
|
||||
end;
|
||||
|
||||
function TServiceCalculator.Test(toto: integer): TServiceCustomAnswer;
|
||||
begin
|
||||
result.Header := TEXT_CONTENT_TYPE_HEADER;
|
||||
result.Content := Int32ToUtf8(toto);
|
||||
result.Status := HTTP_SUCCESS;
|
||||
end;
|
||||
|
||||
initialization
|
||||
TTextWriter.RegisterCustomJSONSerializerFromTextSimpleType(TypeInfo(TRecordEnum));
|
||||
TTextWriter.RegisterCustomJSONSerializerFromText(
|
||||
TypeInfo(TTestCustomJSONArraySimpleArray),__TTestCustomJSONArraySimpleArray);
|
||||
TTextWriter.RegisterCustomJSONSerializerFromText(TypeInfo(TSimpleRecord),__TSimpleRecord);
|
||||
// TTextWriter.RegisterCustomJSONSerializerFromText(TypeInfo(TRecB),__TRecB);
|
||||
|
||||
|
||||
{$endif TESTRECORD}
|
||||
|
||||
end.
|
@@ -0,0 +1,73 @@
|
||||
/// this server will demonstrate how to publish code generation wrappers
|
||||
program Project14ServerHttpWrapper;
|
||||
|
||||
{$APPTYPE CONSOLE}
|
||||
|
||||
uses
|
||||
{$I SynDprUses.inc} // use FastMM4 on older Delphi, or set FPC threads
|
||||
SysUtils,
|
||||
Classes,
|
||||
SynCommons,
|
||||
SynTable,
|
||||
SynLog,
|
||||
mORMot,
|
||||
mORMotHttpServer,
|
||||
mORMotWrappers,
|
||||
Project14Interface in '..\14 - Interface based services\Project14Interface.pas';
|
||||
|
||||
type
|
||||
TServiceCalculator = class(TInterfacedObject, ICalculator)
|
||||
public
|
||||
function Add(n1,n2: integer): integer;
|
||||
end;
|
||||
|
||||
function TServiceCalculator.Add(n1, n2: integer): integer;
|
||||
begin
|
||||
result := n1+n2;
|
||||
end;
|
||||
|
||||
var
|
||||
aModel: TSQLModel;
|
||||
aServer: TSQLRestServer;
|
||||
aHTTPServer: TSQLHttpServer;
|
||||
url: RawUTF8;
|
||||
begin
|
||||
// define the log level
|
||||
with TSQLLog.Family do begin
|
||||
Level := LOG_VERBOSE;
|
||||
//EchoToConsole := LOG_VERBOSE; // log all events to the console
|
||||
end;
|
||||
// create a Data Model
|
||||
aModel := TSQLModel.Create([],ROOT_NAME);
|
||||
try
|
||||
// initialize a TObjectList-based database engine
|
||||
aServer := TSQLRestServerFullMemory.Create(aModel,'test.json',{binary=}false,{auth=}false);
|
||||
try
|
||||
// add the http://localhost:888/root/wrapper code generation web page
|
||||
AddToServerWrapperMethod(aServer,
|
||||
['..\..\..\CrossPlatform\templates','..\..\..\..\CrossPlatform\templates']);
|
||||
// register our ICalculator service on the server side
|
||||
aServer.ServiceDefine(TServiceCalculator,[ICalculator],sicShared)
|
||||
.ResultAsJSONObjectWithoutResult := true;
|
||||
// launch the HTTP server
|
||||
aHTTPServer := TSQLHttpServer.Create(PORT_NAME,[aServer]);
|
||||
try
|
||||
aHTTPServer.AccessControlAllowOrigin := '*'; // for AJAX requests to work
|
||||
writeln(#10'Background server is running.'#10);
|
||||
url := 'http://localhost:'+PORT_NAME+'/'+ROOT_NAME+'/wrapper';
|
||||
writeln('Cross-Platform wrappers are available at: ',url);
|
||||
writeln('- you may also check:');
|
||||
writeln(' http://petstore.swagger.io/?url=',url,'/Swagger/mORMotClient.json.txt');
|
||||
writeln(#10'Press [Enter] to close the server.'#10);
|
||||
ConsoleWaitForEnterKey;
|
||||
finally
|
||||
aHTTPServer.Free;
|
||||
end;
|
||||
finally
|
||||
aServer.Free;
|
||||
end;
|
||||
finally
|
||||
aModel.Free;
|
||||
end;
|
||||
writeln('Server is now down');
|
||||
end.
|
@@ -0,0 +1,78 @@
|
||||
program RegressionTests;
|
||||
|
||||
{$i SynCrossPlatform.inc} // define e.g. HASINLINE
|
||||
|
||||
{$APPTYPE CONSOLE}
|
||||
|
||||
{$ifdef MSWINDOWS}
|
||||
{$ifndef FPC} // under FPC, please run program RegressionTestsServer.dpr
|
||||
{$define RUNSERVER}
|
||||
{$endif}
|
||||
{$endif}
|
||||
|
||||
{$ifdef ISDELPHI5OROLDER}
|
||||
{$undef RUNSERVER} // mORMot.pas not available prior to Delphi 6
|
||||
{$endif}
|
||||
|
||||
uses
|
||||
{$I SynDprUses.inc} // use FastMM4 on older Delphi, or set FPC threads
|
||||
SynCrossPlatformJSON,
|
||||
SynCrossPlatformSpecific,
|
||||
SynCrossPlatformREST,
|
||||
SynCrossPlatformCrypto,
|
||||
SynCrossPlatformTests,
|
||||
{$ifdef RUNSERVER}
|
||||
PeopleServer,
|
||||
{$endif}
|
||||
SysUtils;
|
||||
|
||||
var
|
||||
TotalFailed: cardinal = 0;
|
||||
|
||||
procedure TestWithAuth(aAuth: SynCrossPlatformREST.TSQLRestServerAuthenticationClass);
|
||||
begin
|
||||
with TSynCrossPlatformClient.Create(aAuth) do
|
||||
try
|
||||
Ident := 'Cross Platform Client for mORMot';
|
||||
if aAuth=nil then
|
||||
Ident := Ident+' without authentication' else
|
||||
Ident := Ident+' using '+string(aAuth.ClassName);
|
||||
{$ifdef RUNSERVER}
|
||||
try
|
||||
if aAuth=TSQLRestServerAuthenticationDefault then
|
||||
StartServer(psaDefault) else
|
||||
if aAuth=TSQLRestServerAuthenticationNone then
|
||||
StartServer(psaWeak) else
|
||||
StartServer(psaNone);
|
||||
{$endif}
|
||||
Run(true);
|
||||
inc(TotalFailed,Failed);
|
||||
{$ifdef RUNSERVER}
|
||||
finally
|
||||
StopServer;
|
||||
end;
|
||||
{$endif}
|
||||
finally
|
||||
Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
begin
|
||||
with TSynCrossPlatformTests.Create('Cross Platform Units for mORMot') do
|
||||
try
|
||||
Run(true);
|
||||
finally
|
||||
Free;
|
||||
end;
|
||||
writeln;
|
||||
{$ifdef RUNSERVER} // only last one should be tested for server-less FPC
|
||||
TestWithAuth(nil);
|
||||
TestWithAuth(TSQLRestServerAuthenticationNone);
|
||||
{$endif}
|
||||
TestWithAuth(TSQLRestServerAuthenticationDefault);
|
||||
if TotalFailed>0 then
|
||||
writeln(#10'Some tests failed... please fix it ASAP!');
|
||||
write(#10'Press [Enter] to quit');
|
||||
readln;
|
||||
end.
|
||||
|
@@ -0,0 +1,31 @@
|
||||
program RegressionTestsServer;
|
||||
|
||||
{$i Synopse.inc} // define e.g. HASINLINE
|
||||
|
||||
{$APPTYPE CONSOLE}
|
||||
|
||||
uses
|
||||
{$I SynDprUses.inc}
|
||||
PeopleServer,
|
||||
SynCommons,
|
||||
SynLog,
|
||||
mORMot,
|
||||
SysUtils;
|
||||
|
||||
begin
|
||||
// define the log level
|
||||
if false then
|
||||
with TSQLLog.Family do begin
|
||||
Level := LOG_VERBOSE; // LOG_STACKTRACE;
|
||||
//EchoToConsole := LOG_VERBOSE; // events to the console
|
||||
PerThreadLog := ptIdentifiedInOnFile;
|
||||
end;
|
||||
Writeln('Running Cross-Platform mORMot Server on port 888'#13#10+
|
||||
'Using TSQLRestServerAuthenticationDefault'#13#10#10+
|
||||
'You can now run FPC or SMS client applications'#13#10':)');
|
||||
StartServer(psaDefault);
|
||||
writeln(#13#10'Press [Enter] to quit');
|
||||
readln;
|
||||
StopServer;
|
||||
end.
|
||||
|
@@ -0,0 +1,93 @@
|
||||
unit Form1;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
SmartCL.System, SmartCL.Graphics, SmartCL.Components, SmartCL.Forms,
|
||||
SmartCL.Fonts, SmartCL.Borders, SmartCL.Application, SmartCL.Controls.Panel,
|
||||
SmartCL.Controls.Label, SmartCL.Controls.EditBox, SmartCL.Controls.Button,
|
||||
SynCrossPlatformREST, mORMotClient;
|
||||
|
||||
type
|
||||
TForm1 = class(TW3Form)
|
||||
procedure BtnComputeSynchClick(Sender: TObject);
|
||||
procedure BtnComputeAsynchClick(Sender: TObject);
|
||||
procedure BtnConnectClick(Sender: TObject);
|
||||
private
|
||||
{$I 'Form1:intf'}
|
||||
protected
|
||||
Client: TSQLRestClientURI;
|
||||
procedure InitializeForm; override;
|
||||
procedure InitializeObject; override;
|
||||
procedure Resize; override;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
{ TForm1 }
|
||||
|
||||
procedure TForm1.BtnConnectClick(Sender: TObject);
|
||||
begin
|
||||
if Client=nil then
|
||||
GetClient('127.0.0.1','User','synopse',
|
||||
lambda (aClient: TSQLRestClientURI)
|
||||
PanelCompute.Visible := true;
|
||||
W3Label1.Visible := true;
|
||||
W3Label2.Visible := true;
|
||||
LabelConnect.Caption := '';
|
||||
BtnConnect.Caption := 'Disconnect';
|
||||
LabelResult.Caption := '';
|
||||
Client := aClient;
|
||||
end,
|
||||
lambda
|
||||
ShowMessage('Impossible to connect to the server!');
|
||||
end)
|
||||
else begin
|
||||
PanelCompute.Visible := false;
|
||||
BtnConnect.Caption := 'Server Connect';
|
||||
Client.Free;
|
||||
Client := nil;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TForm1.BtnComputeAsynchClick(Sender: TObject);
|
||||
begin
|
||||
TServiceCalculator.Create(Client).Add(
|
||||
StrToInt(EditA.Text),StrToInt(EditB.Text),
|
||||
lambda (res: integer)
|
||||
LabelResult.Caption := format('Result = %d',[res]);
|
||||
end,
|
||||
lambda
|
||||
ShowMessage('Error calling the method!');
|
||||
end);
|
||||
end;
|
||||
|
||||
procedure TForm1.BtnComputeSynchClick(Sender: TObject);
|
||||
begin
|
||||
LabelResult.Caption := format('Result = %d',
|
||||
[TServiceCalculator.Create(Client)._Add(
|
||||
StrToInt(EditA.Text),StrToInt(EditB.Text))]);
|
||||
end;
|
||||
|
||||
procedure TForm1.InitializeForm;
|
||||
begin
|
||||
inherited;
|
||||
// this is a good place to initialize components
|
||||
EditA.InputType := itNumber;
|
||||
EditB.InputType := itNumber;
|
||||
end;
|
||||
|
||||
procedure TForm1.InitializeObject;
|
||||
begin
|
||||
inherited;
|
||||
{$I 'Form1:impl'}
|
||||
end;
|
||||
|
||||
procedure TForm1.Resize;
|
||||
begin
|
||||
inherited;
|
||||
end;
|
||||
|
||||
initialization
|
||||
Forms.RegisterForm({$I %FILE%}, TForm1);
|
||||
end.
|
@@ -0,0 +1,96 @@
|
||||
<SMART>
|
||||
<Form version="2" subversion="1">
|
||||
<Created>2014-08-10T14:52:31.247</Created>
|
||||
<Modified>2014-08-10T16:08:54.867</Modified>
|
||||
<object type="TW3Form">
|
||||
<Caption>W3Form</Caption>
|
||||
<Name>Form1</Name>
|
||||
<object type="TW3Panel">
|
||||
<Width>264</Width>
|
||||
<Visible>False</Visible>
|
||||
<Top>96</Top>
|
||||
<Left>40</Left>
|
||||
<Height>264</Height>
|
||||
<Name>PanelCompute</Name>
|
||||
<object type="TW3Label">
|
||||
<Caption>A =</Caption>
|
||||
<Width>32</Width>
|
||||
<Top>32</Top>
|
||||
<Left>56</Left>
|
||||
<Height>32</Height>
|
||||
<Name>W3Label1</Name>
|
||||
</object>
|
||||
<object type="TW3EditBox">
|
||||
<Value></Value>
|
||||
<Text>1</Text>
|
||||
<Range></Range>
|
||||
<Width>128</Width>
|
||||
<Top>32</Top>
|
||||
<Left>88</Left>
|
||||
<Height>32</Height>
|
||||
<Name>EditA</Name>
|
||||
</object>
|
||||
<object type="TW3Label">
|
||||
<Caption>B =</Caption>
|
||||
<Width>32</Width>
|
||||
<Top>72</Top>
|
||||
<Left>56</Left>
|
||||
<Height>32</Height>
|
||||
<Name>W3Label2</Name>
|
||||
</object>
|
||||
<object type="TW3EditBox">
|
||||
<Value></Value>
|
||||
<Text>1</Text>
|
||||
<Range></Range>
|
||||
<Width>128</Width>
|
||||
<Top>72</Top>
|
||||
<Left>88</Left>
|
||||
<Height>32</Height>
|
||||
<Name>EditB</Name>
|
||||
</object>
|
||||
<object type="TW3Button">
|
||||
<Caption>Compute Asynch</Caption>
|
||||
<Width>168</Width>
|
||||
<Top>112</Top>
|
||||
<Left>48</Left>
|
||||
<Height>40</Height>
|
||||
<Name>BtnComputeAsynch</Name>
|
||||
<OnClick>BtnComputeAsynchClick</OnClick>
|
||||
</object>
|
||||
<object type="TW3Label">
|
||||
<Width>152</Width>
|
||||
<Top>208</Top>
|
||||
<Left>64</Left>
|
||||
<Height>32</Height>
|
||||
<Name>LabelResult</Name>
|
||||
</object>
|
||||
<object type="TW3Button">
|
||||
<Caption>Compute Synch</Caption>
|
||||
<Width>168</Width>
|
||||
<Top>160</Top>
|
||||
<Left>48</Left>
|
||||
<Height>40</Height>
|
||||
<Name>BtnComputeSynch</Name>
|
||||
<OnClick>BtnComputeSynchClick</OnClick>
|
||||
</object>
|
||||
</object>
|
||||
<object type="TW3Label">
|
||||
<Caption><small>Project14ServerHttpWrapper should be running!</Caption>
|
||||
<Width>376</Width>
|
||||
<Top>16</Top>
|
||||
<Left>24</Left>
|
||||
<Height>32</Height>
|
||||
<Name>LabelConnect</Name>
|
||||
</object>
|
||||
<object type="TW3Button">
|
||||
<Caption>Server Connect</Caption>
|
||||
<Width>176</Width>
|
||||
<Top>48</Top>
|
||||
<Left>40</Left>
|
||||
<Height>40</Height>
|
||||
<Name>BtnConnect</Name>
|
||||
<OnClick>BtnConnectClick</OnClick>
|
||||
</object>
|
||||
</object>
|
||||
</Form>
|
||||
</SMART>
|
@@ -0,0 +1,21 @@
|
||||
uses Unit1;
|
||||
|
||||
{$IFDEF SMART_INTERNAL_AUTO_REFRESH}
|
||||
uses SmartCL.AutoRefresh;
|
||||
TW3AutoRefresh.Create.Start;
|
||||
{$ENDIF}
|
||||
|
||||
var Application: TApplication;
|
||||
|
||||
{$IFDEF SMART_INTERNAL_HANDLE_EXCEPTIONS}
|
||||
uses SmartCL.System;
|
||||
try
|
||||
{$ENDIF}
|
||||
Application := TApplication.Create;
|
||||
Application.RunApp;
|
||||
{$IFDEF SMART_INTERNAL_HANDLE_EXCEPTIONS}
|
||||
except
|
||||
on e: Exception do
|
||||
ShowMessage(e.Message);
|
||||
end;
|
||||
{$ENDIF}
|
@@ -0,0 +1,120 @@
|
||||
<SMART>
|
||||
<Project version="2" subversion="2">
|
||||
<Name>Project14Client</Name>
|
||||
<Created>T00:00:00.000</Created>
|
||||
<Modified>2016-01-25T11:36:04.339</Modified>
|
||||
<Author>Arnaud 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>0</WebAppCapable>
|
||||
</Apple>
|
||||
<ChromeApp>
|
||||
<Kiosk>0</Kiosk>
|
||||
<KioskOnly>1</KioskOnly>
|
||||
<OfflineEnabled>1</OfflineEnabled>
|
||||
</ChromeApp>
|
||||
<Cordova>
|
||||
<WidgetID></WidgetID>
|
||||
<AllowIntent>http://*/* https://*/* tel:* sms:* mailto:* geo:* </AllowIntent>
|
||||
</Cordova>
|
||||
</VendorSpecific>
|
||||
<Options>
|
||||
<Compiler>
|
||||
<Assertions>1</Assertions>
|
||||
<Optimize>1</Optimize>
|
||||
<HintsLevel>1</HintsLevel>
|
||||
</Compiler>
|
||||
<Codegen>
|
||||
<Obfuscation>1</Obfuscation>
|
||||
<RangeChecking>0</RangeChecking>
|
||||
<InstanceChecking>0</InstanceChecking>
|
||||
<ConditionChecking>1</ConditionChecking>
|
||||
<LoopChecking>1</LoopChecking>
|
||||
<InlineMagics>1</InlineMagics>
|
||||
<IgnorePublishedInImplementation>0</IgnorePublishedInImplementation>
|
||||
<EmitSourceLocation>0</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>0</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>Project14Client</Name>
|
||||
<Created>2014-08-10T14:52:31.247Z</Created>
|
||||
<Modified>2014-08-10T14:55:37.144</Modified>
|
||||
<Filename>Project14Client.spr</Filename>
|
||||
</File>
|
||||
<File type="unit">
|
||||
<Name>Unit1</Name>
|
||||
<Created>2014-08-10T14:52:31.247Z</Created>
|
||||
<Modified>2014-08-10T14:52:31.247</Modified>
|
||||
<Filename>Unit1.pas</Filename>
|
||||
</File>
|
||||
<File type="form">
|
||||
<Name>Form1</Name>
|
||||
<Created>2014-08-10T14:52:31.247Z</Created>
|
||||
<Modified>2014-08-10T16:07:43.657</Modified>
|
||||
<Filename>Form1.pas</Filename>
|
||||
<AutoCreate>
|
||||
<IsAutoCreate>1</IsAutoCreate>
|
||||
<IsMainForm>1</IsMainForm>
|
||||
<Order>1</Order>
|
||||
</AutoCreate>
|
||||
</File>
|
||||
</Files>
|
||||
<Target>Browser</Target>
|
||||
<Statistics>
|
||||
<BackgroundCompilations>8</BackgroundCompilations>
|
||||
<EditTime>00:00:10.144</EditTime>
|
||||
<CompileTime>00:00:06.404</CompileTime>
|
||||
<TotalTime>00:11:51.417</TotalTime>
|
||||
<DesigningTime>00:00:00.089</DesigningTime>
|
||||
<RunningTime>00:10:45.657</RunningTime>
|
||||
</Statistics>
|
||||
</Project>
|
||||
</SMART>
|
@@ -0,0 +1,16 @@
|
||||
unit Unit1;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Pseudo.CreateForms, // auto-generated unit that creates forms during startup
|
||||
System.Types, SmartCL.System, SmartCL.Components, SmartCL.Forms,
|
||||
SmartCL.Application, Form1;
|
||||
|
||||
type
|
||||
TApplication = class(TW3CustomApplication)
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
end.
|
@@ -0,0 +1,130 @@
|
||||
/// remote access to a mORMot server using SmartMobileStudio
|
||||
// - retrieved from http://localhost:888/root/wrapper/SmartMobileStudio/mORMotClient.pas
|
||||
// at 2014-12-10 21:54:15 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
|
||||
/// 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;
|
||||
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);
|
||||
|
||||
|
||||
implementation
|
||||
|
||||
|
||||
function GetModel: TSQLModel;
|
||||
begin
|
||||
result := TSQLModel.Create([TSQLAuthUser,TSQLAuthGroup],'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 := '1FC2AE72D7E2C88D';
|
||||
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;
|
||||
|
||||
|
||||
|
||||
end.
|
@@ -0,0 +1,7 @@
|
||||
CACHE MANIFEST
|
||||
# Offline cache version 0.0.1
|
||||
# id:69550
|
||||
|
||||
CACHE:
|
||||
index.html
|
||||
res/app.css
|
File diff suppressed because one or more lines are too long
@@ -0,0 +1,13 @@
|
||||
program VCLClient;
|
||||
|
||||
uses
|
||||
Forms,
|
||||
VCLMain in 'VCLMain.pas' {Form1};
|
||||
|
||||
{$R *.res}
|
||||
|
||||
begin
|
||||
Application.Initialize;
|
||||
Application.CreateForm(TForm1, Form1);
|
||||
Application.Run;
|
||||
end.
|
@@ -0,0 +1,99 @@
|
||||
object Form1: TForm1
|
||||
Left = 317
|
||||
Top = 279
|
||||
Width = 490
|
||||
Height = 244
|
||||
Caption = ' mORMot Client using VCL'
|
||||
Color = clBtnFace
|
||||
Font.Charset = DEFAULT_CHARSET
|
||||
Font.Color = clWindowText
|
||||
Font.Height = -11
|
||||
Font.Name = 'Tahoma'
|
||||
Font.Style = []
|
||||
OldCreateOrder = False
|
||||
OnCreate = FormCreate
|
||||
OnDestroy = FormDestroy
|
||||
PixelsPerInch = 96
|
||||
TextHeight = 13
|
||||
object lbl1: TLabel
|
||||
Left = 16
|
||||
Top = 16
|
||||
Width = 87
|
||||
Height = 13
|
||||
Caption = 'Enter some value:'
|
||||
end
|
||||
object lbl2: TLabel
|
||||
Left = 16
|
||||
Top = 88
|
||||
Width = 82
|
||||
Height = 13
|
||||
Caption = 'Computed JSON:'
|
||||
end
|
||||
object edtValue: TEdit
|
||||
Left = 16
|
||||
Top = 32
|
||||
Width = 121
|
||||
Height = 21
|
||||
TabOrder = 0
|
||||
OnChange = edtValueChange
|
||||
end
|
||||
object mmoJSON: TMemo
|
||||
Left = 16
|
||||
Top = 104
|
||||
Width = 425
|
||||
Height = 81
|
||||
TabOrder = 1
|
||||
end
|
||||
object grpTable: TGroupBox
|
||||
Left = 184
|
||||
Top = 8
|
||||
Width = 89
|
||||
Height = 81
|
||||
Caption = ' TJSONTable '
|
||||
TabOrder = 2
|
||||
object btnTableRewind: TButton
|
||||
Left = 6
|
||||
Top = 16
|
||||
Width = 75
|
||||
Height = 25
|
||||
Caption = 'First'
|
||||
TabOrder = 0
|
||||
OnClick = btnTableNextClick
|
||||
end
|
||||
object btnTableNext: TButton
|
||||
Left = 6
|
||||
Top = 48
|
||||
Width = 75
|
||||
Height = 25
|
||||
Caption = 'Next'
|
||||
TabOrder = 1
|
||||
OnClick = btnTableNextClick
|
||||
end
|
||||
end
|
||||
object grpORM: TGroupBox
|
||||
Left = 296
|
||||
Top = 8
|
||||
Width = 89
|
||||
Height = 81
|
||||
Caption = ' ORM '
|
||||
TabOrder = 3
|
||||
object btnORMFirst: TButton
|
||||
Left = 6
|
||||
Top = 16
|
||||
Width = 75
|
||||
Height = 25
|
||||
Caption = 'First'
|
||||
TabOrder = 0
|
||||
OnClick = ORMClick
|
||||
end
|
||||
object btnORMNext: TButton
|
||||
Left = 6
|
||||
Top = 48
|
||||
Width = 75
|
||||
Height = 25
|
||||
Caption = 'Next'
|
||||
TabOrder = 1
|
||||
OnClick = ORMClick
|
||||
end
|
||||
end
|
||||
end
|
@@ -0,0 +1,103 @@
|
||||
unit VCLMain;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
|
||||
Dialogs, StdCtrls,
|
||||
SynCrossPlatformJSON, SynCrossPlatformREST;
|
||||
|
||||
type
|
||||
TForm1 = class(TForm)
|
||||
lbl1: TLabel;
|
||||
edtValue: TEdit;
|
||||
lbl2: TLabel;
|
||||
mmoJSON: TMemo;
|
||||
grpTable: TGroupBox;
|
||||
btnTableRewind: TButton;
|
||||
btnTableNext: TButton;
|
||||
grpORM: TGroupBox;
|
||||
btnORMFirst: TButton;
|
||||
btnORMNext: TButton;
|
||||
procedure FormCreate(Sender: TObject);
|
||||
procedure edtValueChange(Sender: TObject);
|
||||
procedure FormDestroy(Sender: TObject);
|
||||
procedure btnTableNextClick(Sender: TObject);
|
||||
procedure ORMClick(Sender: TObject);
|
||||
private
|
||||
public
|
||||
doc: variant;
|
||||
table: TJSONTableObject;
|
||||
end;
|
||||
|
||||
var
|
||||
Form1: TForm1;
|
||||
|
||||
implementation
|
||||
|
||||
{$R *.dfm}
|
||||
|
||||
procedure TForm1.FormCreate(Sender: TObject);
|
||||
var FN: TFileName;
|
||||
level: integer;
|
||||
begin
|
||||
doc := JSONVariant('{"test":1234,"name":"Joh\"n\r","zero":0.0}');
|
||||
FN := 'people.json';
|
||||
for level := 1 to 4 do
|
||||
if FileExists(FN) then
|
||||
break else
|
||||
FN := '..\'+FN;
|
||||
table := TJSONTableObject.Create(UTF8FileToString(FN));
|
||||
assert(length(table.FieldNames)=6);
|
||||
end;
|
||||
|
||||
procedure TForm1.edtValueChange(Sender: TObject);
|
||||
begin
|
||||
doc.value := edtValue.Text;
|
||||
mmoJSON.Text := doc;
|
||||
end;
|
||||
|
||||
procedure TForm1.FormDestroy(Sender: TObject);
|
||||
begin
|
||||
table.Free;
|
||||
end;
|
||||
|
||||
procedure TForm1.btnTableNextClick(Sender: TObject);
|
||||
begin
|
||||
if table.Step(Sender=btnTableRewind) then
|
||||
mmoJSON.Text := JSONVariant(table.RowValues) else
|
||||
mmoJSON.Text := 'null';
|
||||
end;
|
||||
|
||||
type
|
||||
TSQLRecordPeople = class(TPersistent)
|
||||
private
|
||||
fRowID: integer;
|
||||
fData: TByteDynArray;
|
||||
fFirstName: string;
|
||||
fLastName: string;
|
||||
fYearOfBirth: integer;
|
||||
fYearOfDeath: word;
|
||||
published
|
||||
property RowID: integer read fRowID write fRowID;
|
||||
property FirstName: string read fFirstName write fFirstName;
|
||||
property LastName: string read fLastName write fLastName;
|
||||
property Data: TByteDynArray read fData write fData;
|
||||
property YearOfBirth: integer read fYearOfBirth write fYearOfBirth;
|
||||
property YearOfDeath: word read fYearOfDeath write fYearOfDeath;
|
||||
end;
|
||||
|
||||
procedure TForm1.ORMClick(Sender: TObject);
|
||||
var people: TSQLRecordPeople;
|
||||
begin
|
||||
people := TSQLRecordPeople.Create;
|
||||
try
|
||||
if table.StepObject(people,Sender=btnORMFirst) then
|
||||
mmoJSON.Text := ObjectToJSON(people) else
|
||||
mmoJSON.Text := 'null';
|
||||
finally
|
||||
people.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
end.
|
@@ -0,0 +1,340 @@
|
||||
/// remote access to a mORMot server using SynCrossPlatform* units
|
||||
// - retrieved from http://localhost:888/root/wrapper/CrossPlatform/mORMotClient.pas
|
||||
// at 2014-12-10 21:28:46 using "CrossPlatform.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 Delphi 6 and later, under all supported platforms
|
||||
(including MacOSX, and NextGen iPhone/iPad), and the Free Pascal Compiler.
|
||||
}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
SynCrossPlatformJSON,
|
||||
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;
|
||||
public
|
||||
property Simple: TTestCustomJSONArraySimpleArray read fSimple write fSimple;
|
||||
published
|
||||
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;
|
||||
end;
|
||||
|
||||
/// service implemented by TServiceCalculator
|
||||
// - you can access this service as such:
|
||||
// !var aCalculator: ICalculator;
|
||||
// !begin
|
||||
// ! aCalculator := TCalculator.Create(aClient);
|
||||
// ! // now you can use aCalculator methods
|
||||
// !...
|
||||
ICalculator = interface(IServiceAbstract)
|
||||
['{9A60C8ED-CEB2-4E09-87D4-4A16F496E5FE}']
|
||||
function Add(const n1: Integer; const n2: Integer): Integer;
|
||||
procedure ToText(const Value: Currency; const Curr: String; var Sexe: TPeopleSexe; var Name: String);
|
||||
function RecordToText(var Rec: TTestCustomJSONArraySimpleArray): String;
|
||||
function GetPeople(const id: TID; out People: TSQLRecordPeople; out Sexes: TPeopleSexeDynArray; var arr: TSimpleRecordDynArray): Boolean;
|
||||
end;
|
||||
|
||||
/// implements ICalculator from http://localhost:888/root/Calculator
|
||||
// - this service will run in sicShared mode
|
||||
TServiceCalculator = class(TServiceClientAbstract,ICalculator)
|
||||
public
|
||||
constructor Create(aClient: TSQLRestClientURI); override;
|
||||
function Add(const n1: Integer; const n2: Integer): Integer;
|
||||
procedure ToText(const Value: Currency; const Curr: String; var Sexe: TPeopleSexe; var Name: String);
|
||||
function RecordToText(var Rec: TTestCustomJSONArraySimpleArray): String;
|
||||
function GetPeople(const id: TID; out People: TSQLRecordPeople; out 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 - on connection or authentication error,
|
||||
// this function will raise a corresponding exception
|
||||
function GetClient(const aServerAddress, aUserName,aPassword: string;
|
||||
aServerPort: integer=SERVER_PORT): TSQLRestClientHTTP;
|
||||
|
||||
// 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(_variant: variant): TTestCustomJSONArraySimpleArray;
|
||||
function TTestCustomJSONArraySimpleArray2Variant(const _record: TTestCustomJSONArraySimpleArray): variant;
|
||||
function Variant2TSimpleRecord(_variant: variant): TSimpleRecord;
|
||||
function TSimpleRecord2Variant(const _record: 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 }
|
||||
|
||||
function Variant2TPeopleSexe(const _variant: variant): TPeopleSexe;
|
||||
begin
|
||||
result := TPeopleSexe(VariantToEnum(_variant,['sFemale','sMale']));
|
||||
end;
|
||||
|
||||
function Variant2TRecordEnum(const _variant: variant): TRecordEnum;
|
||||
begin
|
||||
result := TRecordEnum(VariantToEnum(_variant,['reOne','reTwo','reLast']));
|
||||
end;
|
||||
|
||||
|
||||
{ Some helpers for record types }
|
||||
|
||||
function Variant2TTestCustomJSONArraySimpleArray(_variant: variant): TTestCustomJSONArraySimpleArray;
|
||||
var _a: integer;
|
||||
_arr: PJSONVariantData;
|
||||
begin
|
||||
result.F := _variant.F;
|
||||
_arr := JSONVariantDataSafe(_variant.G,jvArray);
|
||||
SetLength(result.G,_arr^.Count);
|
||||
for _a := 0 to high(result.G) do
|
||||
result.G[_a] := _arr^.Values[_a];
|
||||
result.H.H1 := _variant.H.H1;
|
||||
result.H.H2 := _variant.H.H2;
|
||||
result.H.H3.H3a := _variant.H.H3.H3a;
|
||||
result.H.H3.H3b := VariantToBlob(_variant.H.H3.H3b);
|
||||
result.I := Iso8601ToDateTime(_variant.I);
|
||||
_arr := JSONVariantDataSafe(_variant.J,jvArray);
|
||||
SetLength(result.J,_arr^.Count);
|
||||
for _a := 0 to high(result.J) do
|
||||
with result.J[_a] do begin
|
||||
J1 := _arr^.Values[_a].J1;
|
||||
J2 := VariantToGUID(_arr^.Values[_a].J2);
|
||||
J3 := Variant2TRecordEnum(_arr^.Values[_a].J3);
|
||||
end;
|
||||
end;
|
||||
|
||||
function TTestCustomJSONArraySimpleArray2Variant(const _record: TTestCustomJSONArraySimpleArray): variant;
|
||||
var i: integer;
|
||||
res: TJSONVariantData;
|
||||
begin
|
||||
res.Init;
|
||||
res.SetPath('F',_record.F);
|
||||
with res.EnsureData('G')^ do
|
||||
for i := 0 to high(_record.G) do
|
||||
AddValue(_record.G[i]);
|
||||
res.SetPath('H.H1',_record.H.H1);
|
||||
res.SetPath('H.H2',_record.H.H2);
|
||||
res.SetPath('H.H3.H3a',_record.H.H3.H3a);
|
||||
res.SetPath('H.H3.H3b',BlobToVariant(_record.H.H3.H3b));
|
||||
res.SetPath('I',DateTimeToIso8601(_record.I));
|
||||
with res.EnsureData('J')^ do
|
||||
for i := 0 to high(_record.J) do
|
||||
with AddItem^, _record.J[i] do begin
|
||||
AddNameValue('J1',J1);
|
||||
AddNameValue('J2',GUIDToVariant(J2));
|
||||
AddNameValue('J3',ord(J3));
|
||||
end;
|
||||
result := variant(res);
|
||||
end;
|
||||
|
||||
function Variant2TSimpleRecord(_variant: variant): TSimpleRecord;
|
||||
begin
|
||||
result.A := _variant.A;
|
||||
result.B := _variant.B;
|
||||
result.C := _variant.C;
|
||||
end;
|
||||
|
||||
function TSimpleRecord2Variant(const _record: TSimpleRecord): variant;
|
||||
var res: TJSONVariantData;
|
||||
begin
|
||||
res.Init;
|
||||
res.SetPath('A',_record.A);
|
||||
res.SetPath('B',_record.B);
|
||||
res.SetPath('C',_record.C);
|
||||
result := variant(res);
|
||||
end;
|
||||
|
||||
|
||||
{ Some helpers for dynamic array types }
|
||||
|
||||
function Variant2TPeopleSexeDynArray(const _variant: variant): TPeopleSexeDynArray;
|
||||
var i: integer;
|
||||
arr: PJSONVariantData;
|
||||
begin
|
||||
arr := JSONVariantDataSafe(_variant,jvArray);
|
||||
SetLength(result,arr^.Count);
|
||||
for i := 0 to arr^.Count-1 do
|
||||
result[i] := (arr^.Values[i]);
|
||||
end;
|
||||
|
||||
function TPeopleSexeDynArray2Variant(const _array: TPeopleSexeDynArray): variant;
|
||||
var i: integer;
|
||||
res: TJSONVariantData;
|
||||
begin
|
||||
res.Init;
|
||||
for i := 0 to high(_array) do
|
||||
res.AddValue((_array[i]));
|
||||
result := variant(res);
|
||||
end;
|
||||
|
||||
function Variant2TSimpleRecordDynArray(const _variant: variant): TSimpleRecordDynArray;
|
||||
var i: integer;
|
||||
arr: PJSONVariantData;
|
||||
begin
|
||||
arr := JSONVariantDataSafe(_variant,jvArray);
|
||||
SetLength(result,arr^.Count);
|
||||
for i := 0 to arr^.Count-1 do
|
||||
result[i] := Variant2TSimpleRecord(arr^.Values[i]);
|
||||
end;
|
||||
|
||||
function TSimpleRecordDynArray2Variant(const _array: TSimpleRecordDynArray): variant;
|
||||
var i: integer;
|
||||
res: TJSONVariantData;
|
||||
begin
|
||||
res.Init;
|
||||
for i := 0 to high(_array) do
|
||||
res.AddValue(TSimpleRecord2Variant(_array[i]));
|
||||
result := variant(res);
|
||||
end;
|
||||
|
||||
|
||||
function GetModel: TSQLModel;
|
||||
begin
|
||||
result := TSQLModel.Create([TSQLAuthUser,TSQLAuthGroup,TSQLRecordPeople],'root');
|
||||
end;
|
||||
|
||||
function GetClient(const aServerAddress, aUserName,aPassword: string;
|
||||
aServerPort: integer): TSQLRestClientHTTP;
|
||||
begin
|
||||
result := TSQLRestClientHTTP.Create(aServerAddress,aServerPort,GetModel,true); // aOwnModel=true
|
||||
try
|
||||
if (not result.Connect) or (result.ServerTimeStamp=0) then
|
||||
raise ERestException.CreateFmt('Impossible to connect to %s:%d server',
|
||||
[aServerAddress,aServerPort]);
|
||||
if not result.SetUser(TSQLRestServerAuthenticationDefault,aUserName,aPassword) then
|
||||
raise ERestException.CreateFmt('%s:%d server rejected "%s" credentials',
|
||||
[aServerAddress,aServerPort,aUserName]);
|
||||
except
|
||||
result.Free;
|
||||
raise;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
{ TServiceCalculator }
|
||||
|
||||
constructor TServiceCalculator.Create(aClient: TSQLRestClientURI);
|
||||
begin
|
||||
fServiceName := 'Calculator';
|
||||
fServiceURI := 'Calculator';
|
||||
fInstanceImplementation := sicShared;
|
||||
fContractExpected := '814F1362B19B2F4D';
|
||||
inherited Create(aClient);
|
||||
end;
|
||||
|
||||
function TServiceCalculator.Add(const n1: Integer; const n2: Integer): Integer;
|
||||
var res: TVariantDynArray;
|
||||
begin
|
||||
fClient.CallRemoteService(self,'Add',1, // raise EServiceException on error
|
||||
[n1,n2],res);
|
||||
Result := res[0];
|
||||
end;
|
||||
|
||||
procedure TServiceCalculator.ToText(const Value: Currency; const Curr: String; var Sexe: TPeopleSexe; var Name: String);
|
||||
var res: TVariantDynArray;
|
||||
begin
|
||||
fClient.CallRemoteService(self,'ToText',2, // raise EServiceException on error
|
||||
[Value,Curr,ord(Sexe),Name],res);
|
||||
Sexe := Variant2TPeopleSexe(res[0]);
|
||||
Name := res[1];
|
||||
end;
|
||||
|
||||
function TServiceCalculator.RecordToText(var Rec: TTestCustomJSONArraySimpleArray): String;
|
||||
var res: TVariantDynArray;
|
||||
begin
|
||||
fClient.CallRemoteService(self,'RecordToText',2, // raise EServiceException on error
|
||||
[TTestCustomJSONArraySimpleArray2Variant(Rec)],res);
|
||||
Rec := Variant2TTestCustomJSONArraySimpleArray(res[0]);
|
||||
Result := res[1];
|
||||
end;
|
||||
|
||||
function TServiceCalculator.GetPeople(const id: TID; out People: TSQLRecordPeople; out Sexes: TPeopleSexeDynArray; var arr: TSimpleRecordDynArray): Boolean;
|
||||
var res: TVariantDynArray;
|
||||
begin
|
||||
fClient.CallRemoteService(self,'GetPeople',4, // raise EServiceException on error
|
||||
[id,TSimpleRecordDynArray2Variant(arr)],res);
|
||||
People := TSQLRecordPeople.CreateFromVariant(res[0]);
|
||||
Sexes := Variant2TPeopleSexeDynArray(res[1]);
|
||||
arr := Variant2TSimpleRecordDynArray(res[2]);
|
||||
Result := res[3];
|
||||
end;
|
||||
|
||||
|
||||
end.
|
Reference in New Issue
Block a user