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,13 @@
program FMClient;
uses
FMX.Forms,
FMMain in 'FMMain.pas' {Form1};
{$R *.res}
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.

View File

@@ -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

View File

@@ -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.

View File

@@ -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.

View File

@@ -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

View File

@@ -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.

View File

@@ -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}
]

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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>&lt;small&gt;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>

View File

@@ -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}

View File

@@ -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://*/*&#13;&#10;https://*/*&#13;&#10;tel:*&#13;&#10;sms:*&#13;&#10;mailto:*&#13;&#10;geo:*&#13;&#10;</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>

View File

@@ -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.

View File

@@ -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.

View File

@@ -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

View File

@@ -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.

View File

@@ -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

View File

@@ -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.

View File

@@ -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.