Some slides, as presented during EKON20 conferences, about the mORMot Open Source project, a Delphi/FPC professional framework featuring highly integrated SOA, MVC, ORM, SOLID over SQL and NoSQL databases.
15. Open Source
Started in 2008
6215 checkins since 2010
86 COCOMO years
($ 4,746,754)
http://synopse.info/fossil
http://github.com/synopse/mORMot
http://openhub.net/p/mormot
22. Hall of fame
Alexander (sha)
Alexander (volax)
AlexPirate
Alfred Glaenzer (alf)
Arnaud Bouchez
Aweste
Bas Schouten
BigStar
Cheemeng
CoMPi
Damien (ddemars)
Daniel Kuettner
David Mead (MDW)
Delphinium (louisyeow)
DigDiver
EgorovAlex
Emanuele (lele9)
Eric Grange
Esmond
Esteban Martin (EMartin)
EvaF
Goran Despalatovic (gigo)
Joe (jokusoft)
Jordi Tudela
Leon Oosthuizen
Maciej Izak (hnb)
Mario Moretti
Marius Maximus (mariuszekpl)
Martin Suer
Mazinsw
MChaos
Miab3
Michael (EgonHugeist)
MilesYou
Mingda
Ondrej (reddwarf)
Pavel (mpv)
Pierre le Riche
RalfS
Richard6688
Sabbiolina
Sanyin
Sinisa (sinisav)
Sllimr7139
Stefan (itSDS)
Vadim Orel
Win2014
Wloochacz
Wolfgang Ehrhardt
Zed
23. Hall of fame
Alexander (sha)
Alexander (volax)
AlexPirate
Alfred Glaenzer (alf)
Arnaud Bouchez
Aweste
Bas Schouten
BigStar
Cheemeng
CoMPi
Damien (ddemars)
Daniel Kuettner
David Mead (MDW)
Delphinium (louisyeow)
DigDiver
EgorovAlex
Emanuele (lele9)
Eric Grange
Esmond
Esteban Martin (EMartin)
EvaF
Goran Despalatovic (gigo)
Joe (jokusoft)
Jordi Tudela
Leon Oosthuizen
Maciej Izak (hnb)
Mario Moretti
Marius Maximus (mariuszekpl)
Martin Suer
Mazinsw
MChaos
Miab3
Michael (EgonHugeist)
MilesYou
Mingda
Ondrej (reddwarf)
Pavel (mpv)
Pierre le Riche
RalfS
Richard6688
Sabbiolina
Sanyin
Sinisa (sinisav)
Sllimr7139
Stefan (itSDS)
Vadim Orel
Win2014
Wloochacz
Wolfgang Ehrhardt
Zed
… YOUR NAME ?
24. mORMot & Friends
Open Source
Architecture & Design
Cross-Cutting features
DB Layer
ORM/ODM/SOA/MVC
Cross platform
Q&A
30. Design with Interfaces
Abstraction is your health
Publish classes as services
Test, mock
Write SOLID code
and manage memory for you
unless zeroing weak pointers
32. mORMot & Friends
Open Source
Architecture & Design
Cross-Cutting features
DB Layer
ORM/ODM/SOA/MVC
Cross platform
Q&A
33. Cross Cutting Features
UTF-8 JSON
TDynArray
TDocVariant
Logging
Testing
Compression
Crypto ECC
PDF
Mustache
SpiderMonkey
Uncoupled features: could be used
without the ORM/SOA/MVC framework
34. SynCommons
UTF-8 JSON
From the ground up
With objects, records,
dynamic arrays, variants, any value
Performance and integration
35. SynCommons
TDynArray
Wrapper to an existing dynamic array
TList<> on steroids
e.g. sorting, search,
binary or JSON serialization
using enhanced RTTI if available
38. SynCommons
TDocVariant
var V: variant; // stored as any variant
...
TDocVariant.New(V);
// or slightly slower V := TDocVariant.New;
V.name := 'John';
// property accessed via late-binding
V.year := 1972;
// now V contains {"name":"john","year":1972}
39. SynCommons
TDocVariant
V.name := 'Mark'; // overwrite a property value
writeln(V.name); // will write 'Mark'
V.age := 12; // add a property to the object
writeln(V.age); // will write '12'
writeln(V); // implicit conversion to JSON string
// i.e. '{"name":"Mark","age":12}'
writeln(VariantSaveJSON(V1)); // as RawUTF8
41. TDocVariant + mORMot.pas
property Data: variant read fData write fData;
We store a TDocVariant in Data
to mutate a SQL database
into a NoSQL engine
42. TDocVariant + mORMot.pas
property Data: variant read fData write fData;
We store a TDocVariant in Data
to mutate a SQL database
into a NoSQL engine
43. TDocVariant + mORMot.pas
var aRec: TSQLRecordData;
aID: integer;
begin
// initialization of one record
aRec := TSQLRecordData.Create;
aRec.Name := 'Joe’;
// create a TDocVariant
aRec.data := _JSONFast('{name:"Joe",age:30}');
// or we can use this overloaded constructor
aRec := TSQLRecordData.Create(
['Joe',_ObjFast(['name','Joe','age',30])]);
44. TDocVariant + mORMot.pas
// now we can play with the data, e.g. via late-binding:
writeln(aRec.Name); // will write 'Joe'
writeln(aRec.Data); // write '{"name":"Joe","age":30}
// one year older
aRec.Data.age := aRec.Data.age+1;
// add a property to the schema
aRec.Data.interests := 'football';
aID := aClient.Add(aRec);
// we stored {"name":"Joe","age":31,"interests":"footbal"}
aRec.Free;
// now we can retrieve the data e.g. via aID
end;
46. TDocVariant + mORMot.pas
property Data: variant read fData write fData;
Data will be stored as TEXT
in the underlying RDBMS
Of course, if the database is a MongoDB engine,
the data will be stored as a true BSON document
75. SynDB
Direct RDBMS access layer
Not linked to DB.pas
Multi providers
UTF-8 JSON
Interface based
Knows SQL dialects
SynDBExplorer
76. SynDB
Not linked to DB.pas
Enter the 21th century
Less data types
By-pass slow TDataSet
Unicode even before Delphi 2009
Array binding
Native JSON support
Remote access
78. SynDB
Connect to a DB
var Props: TSQLDBConnectionProperties;
...
Props := TOleDBMSSQLConnectionProperties.Create(
'.SQLEXPRESS','AdventureWorks2008R2','','');
try
UseProps(Props);
finally
Props.Free;
end;
79. SynDB
Execute statements
procedure UseProps(Props: TSQLDBConnectionProperties);
var I: ISQLDBRows;
begin
I := Props.Execute(
'select * from Sales.Customer '+
'where AccountNumber like ?',['AW000001%']);
while I.Step do
assert(Copy(I['AccountNumber'],1,8)='AW000001');
end;
84. SynDB
Remote access via HTTP
http.sys based server
SynLZ compression
Digital signature
Authentication
85. SynDB
Remote access via HTTP
Mutate SQLite3 into a
high performance Client-Server RDBMS
No library to deploy on Client side
Easy remote hosting on Server side
86. SynDB
Remote access via HTTP
Mutate SQLite3 into a
high performance Client-Server RDBMS
No library to deploy on Client side
Easy remote hosting on Server side
87. SynDBExplorer
Manage and request your DBs
Any supported database
High performance grid
Export to CSV or SQLite3
SQLite3 integrated
Remote server or client
105. TSQLModel
Define your data model
function CreateSampleModel: TSQLModel;
begin
result := TSQLModel.Create([TSQLSampleRecord]);
end;
Shared on both Client and Server side
106. Database: TSQLRest
CRUD Operations
procedure TForm1.FindButtonClick(Sender: TObject);
var Rec: TSQLSampleRecord;
begin
Rec := TSQLSampleRecord.Create(
Database,'Name=?',[StringToUTF8(NameEdit.Text)]);
try
if Rec.ID=0 then
QuestionMemo.Text := 'Not found' else
QuestionMemo.Text := UTF8ToString(Rec.Question);
finally
Rec.Free;
end;
end;
107. Database: TSQLRest
CRUD Operations
procedure TForm1.AddButtonClick(Sender: TObject);
var Rec: TSQLSampleRecord;
begin
Rec := TSQLSampleRecord.Create;
try
Rec.Name := StringToUTF8(NameEdit.Text);
Rec.Question := StringToUTF8(QuestionMemo.Text);
if Database.Add(Rec,true)=0 then
ShowMessage('Error adding the data') else begin
NameEdit.Text := '';
QuestionMemo.Text := '';
NameEdit.SetFocus;
end;
finally
Rec.Free;
end;
end;
115. TSQLRecord
Mapping by Convention
TSQLRecordPeopleExt = class(TSQLRecord)
..
published
property FirstName: RawUTF8 index 40
property LastName: RawUTF8 index 40
property Data: TSQLRawBlob
property YearOfBirth: integer
property YearOfDeath: word
property LastChange: TModTime
property CreatedAt: TCreateTime
end;
116. TSQLRecord
Mapping by configuration
Model := TSQLModel.Create([TSQLRecordPeopleExt],'root');
VirtualTableExternalRegister(
Model,TSQLRecordPeopleExt,Props,'Test.People');
117. TSQLRecord
Mapping by configuration
Model := TSQLModel.Create([TSQLRecordPeopleExt],'root');
VirtualTableExternalRegister(
Model,TSQLRecordPeopleExt,Props,'Test.People');
Model.Props[TSQLRecordPeopleExt].ExternalDB.
MapField('ID','Key').
MapField('YearOfDeath','YOD');
123. SOA
Define the contract
type
ICalculator = interface(IInvokable)
['{9A60C8ED-CEB2-4E09-87D4-4A16F496E5FE}']
/// add two signed 32 bit integers
function Add(n1,n2: integer): integer;
end;
124. SOA
Implement the contract
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;
125. SOA
Publish the contract on the Server Side
RestServer.ServiceRegister(
TServiceCalculator,[TypeInfo(ICalculator)],sicShared);
Define the contract on the Client Side
RestServer.ServiceRegister(
[TypeInfo(ICalculator)],sicShared);
126. SOA
Use the service
var I: ICalculator;
begin
I := Rest.Services<ICalculator>;
if I<>nil then
result := I.Add(10,20);
end;
var I: ICalculator; // for older versions of Delphi
begin
if Rest.Services['Calculator'].Get(I) then
result := I.Add(10,20);
end;
On both client and server sides
129. Real Time Features
Real Time Notifications
Via WebSockets
Data Replication
Master / Slave
Event-Driven
Asynchronous callbacks
130. Data Replication
On Demand Master / Slave
Master
Slave
MasterServer
(MasterModel)
master.db3
MasterClient
(MasterModel)
HTTP
SlaveServer
(SlaveModel)
On Demand
Replication
slave.db3
131. Data Replication
Real Time Master / Slave
Master
Slave
MasterServer
(MasterModel)
master.db3
MasterClient
(MasterModel)
WebSockets
TCP/IP
SlaveServer
(SlaveModel)
Replication
slave.db3
132. Data Replication
Multi Offices Synch
Main Office
Office A Office B
Main
Server
External DB
Local
Server A
HTTP
Local
Server B
HTTP
Client 1 Client 2 Client 3
local
network
Client 1 Client 2 Client 3 Client 4
local
network
133. Data Replication
Multi Offices Synch
Main Office
Office A Office B
Main
Server
Local Data A
Reference
Read Only
Local Data B
Reference
Read Only
Local Data A
Business
Read/Write
Replication
Local Data B
Business
Read Only
Local Data A
Business
Read Only
Replication
Local Data B
Business
Read/Write
134. Real Time Features
Event-Driven
Asynchronous callbacks
Interface-based services callbacks
Bi-directional connection via WebSockets
using application-level protocols
Security, frame gathering, REST emulation
142. Web Apps
Implement a Controller
method name → page name
var const params → URI params
var out params → Mustache context
143. Web Apps
Implement a Controller
procedure TBlogApplication.AuthorView(var ID: integer;
out Author: TSQLAuthor; out Articles: variant);
begin
RestModel.Retrieve(ID,Author);
Author.HashedPassword := ''; // no need to publish it
if Author.ID<>0 then
Articles := RestModel.RetrieveDocVariantArray(
TSQLArticle,'','Author=? order by RowId desc limit
50',[ID],ARTICLE_FIELDS) else
raise EMVCApplication.CreateGotoError(HTML_NOTFOUND);
End;
→ /blog/AuthorView?....
144. Web Apps
Implement a Controller
procedure TBlogApplication.AuthorView(var ID: integer;
out Author: TSQLAuthor; out Articles: variant);
http://localhost:8092/blog/mvc-info
→ /blog/AuthorView?ID=..[integer]..
{{Main}}: variant
{{ID}}: integer
{{Author}}: TSQLAuthor
{{Articles}}: variant
145. Web Apps
/blog/AuthorView?ID=123
procedure TBlogApplication.AuthorView(var ID: integer;
out Author: TSQLAuthor; out Articles: variant);
begin
→ ID = 123
RestModel.Retrieve(ID,Author);
Author.HashedPassword := ''; // no need to publish it
if Author.ID<>0 then
Articles := RestModel.RetrieveDocVariantArray(
TSQLArticle,'','Author=? order by RowId desc limit
50',[ID],ARTICLE_FIELDS) else
raise EMVCApplication.CreateGotoError(HTML_NOTFOUND);
end;
146. Web Apps
Mustache Data Context
procedure TBlogApplication.AuthorView(var ID: integer;
out Author: TSQLAuthor; out Articles: variant);
begin
RestModel.Retrieve(ID,Author);
Author.HashedPassword := ''; // no need to publish it
if Author.ID<>0 then
Articles := RestModel.RetrieveDocVariantArray(
TSQLArticle,'','Author=? order by RowId desc limit
50',[ID],ARTICLE_FIELDS) else
raise EMVCApplication.CreateGotoError(HTML_NOTFOUND);
end;
{{ID}} {{Author}} {{Articles}}