You are on page 1of 207

mORMot & Friends

Arnaud Bouchez
Opinions
Ahead
Great times for us
Great times for us
Delphi is Hype
Delphi + Pascal > Ruby

If you say Delphi is dead,


YOU are dead!
Two Languages In One
Application Language
like Java C#

System Language
like C C++
Dual Memory Management
Automatic Memory Management
COW and refcount

Manual Memory Management


Uses much less CPU/RAM
Server stability
Dual Memory Management
Automatic Memory Management
COW and refcount

Manual Memory Management


Uses much less CPU/RAM
Server stability

ARC?
New opportunities
New platforms
New compilers
Great communities
Third parties
Open Source
Unleash your power
Decades of experience
Business knowledge
Productive tools
Unleash your power
Decades of experience
Business knowledge
Productive tools
Innovative concepts
mORMot & Friends
Open Source
Architecture & Design
Cross-Cutting features
DB Layer
ORM/ODM/SOA/MVC
Cross platform
Q&A
mORMot & Friends
Open Source
Architecture & Design
Cross-Cutting features
DB Layer
ORM/ODM/SOA/MVC
Cross platform
Q&A
Open Source

Started in 2008
3520 checkins since 2010
56 COCOMO years
Open Source

Started in 2008
3520 checkins since 2010
56 COCOMO years

http://synopse.info/fossil
http://github.com/synopse/mORMot
http://openhub.net/p/mormot
LOC
Code 213,000
Comments 50,000
Blanks 21,000
Total 284,000

http://synopse.info/fossil
http://github.com/synopse/mORMot
http://openhub.net/p/mormot
Doc as Specs
Exhaustive
Maintained
Open Source
http://synopse.info/files/html
1800 pages of pdf
SynProject powered
Test Driven

17,599,266 tests
Write the test
Fail the test
Write the implementation
Pass the test
Test Driven

17,599,266 tests
Regression
Performance
Thread safety
Cross platform – Cross compiler
http://synopse.info/forum
Feedback and support

Topics 2,200
Posts 13,500
Registered users 1,100
Hall of fame
Alexander (sha) Mario Moretti
Alfred Glaenzer (alf) Martin Suer
Arnaud Bouchez MChaos
Aweste Ondrej (reddwarf)
Cheemeng Pavel (mpv)
CoMPi Pierre le Riche
Damien (ddemars) RalfS
David Mead (MDW) Sabbiolina
Delphinium Sanyin
DigDiver Sinisa (sinisav)
EMartin Sllimr7139
Eric Grange Vadim Orel
Esmond Win2014
Joe (jokusoft) Wolfgang Ehrhardt (via MPL)
Jordi Tudela
Hall of fame
Alexander (sha) Mario Moretti
Alfred Glaenzer (alf) Martin Suer
Arnaud Bouchez MChaos
Aweste Ondrej (reddwarf)
Cheemeng Pavel (mpv)
CoMPi Pierre le Riche
Damien (ddemars) RalfS
David Mead (MDW) Sabbiolina
Delphinium Sanyin
DigDiver Sinisa (sinisav)
EMartin Sllimr7139
Eric Grange Vadim Orel
Esmond Win2014
Joe (jokusoft) Wolfgang Ehrhardt (via MPL)
Jordi Tudela … YOU ?
mORMot & Friends
Open Source
Architecture & Design
Cross-Cutting features
DB Layer
ORM/ODM/SOA/MVC
Cross platform
Q&A
Architecture Switch
BBM → Clean
nTier → SOA
SOAP → REST
RAD → MVC/MVVM
SQL → ORM
NoSQL → ODM
OOP → SOLID
BBM → Clean
Architecture?
BBM
Clean & Agile
Architecture
Premature architecture
may be the root of all evil

Not looking at the big picture


is WORSE
Prevalent Architecture
Big Ball Of Mud
Customer Focused
Pragmatic Agile
nTier → SOA
Multi-Tier
SOA
Multi-Tier
Three-tier architecture
Multi-Tier
Four-tier architecture
Multi-Tier
Logical vs Physical
Multi-Tier
Logical vs Physical
Service-Oriented Architecture (SOA)
Service-Oriented Architecture (SOA)

Flexible set
of design principles

Inter-operable
producer/consumer services
Service-Oriented Architecture (SOA)

Inter-operable
producer/consumer services
Service-Oriented Architecture (SOA)

Service Composition
Service-Oriented Architecture (SOA)

Loosely coupled
systems and domains

Mostly stateless

MicroServices
Service-Oriented Architecture (SOA)

Implementation Independence
Platform
Location
Availability
Versions
SOAP → REST
SOAP
REST
SOAP
Simple Object Access Protocol

XML WSDL
Standard
Proven
SOAP
Simple? Object Access Protocol

XML WSDL
Standard?
Proven
REST
REST
Brother of HTTP

Same Father, Roy Fielding


REST
Brother of HTTP

Resource based
Using identifiers
Uniform interface
Transmission by representation
Stateless
REST
Brother of HTTP

http://www.mysite.com/pictures/logo.png
Image Resource
REST
Brother of HTTP

http://www.mysite.com/index.html
Static Resource
REST
Brother of HTTP

http://www.mysite.com/Customer/1001
Dynamic Resource returning XML or JSON content
REST
Brother of HTTP

http://www.mysite.com/Customer/1001/Picture
Dynamic Resource returning an image
REST
Brother of HTTP

http://www.mysite.com/pictures/logo.png
Image Resource
http://www.mysite.com/index.html
Static Resource
http://www.mysite.com/Customer/1001
Dynamic Resource returning XML or JSON content
http://www.mysite.com/Customer/1001/Picture
Dynamic Resource returning an image
REST
Brother of HTTP

But
REST <> HTTP

REST over any message protocol


even stand-alone REST
REST Interfaces
HTTP Verbs CRUD Operations
GET READ
POST CREATE
PUT UPDATE
DELETE DELETE
REST Interfaces
HTTP Verbs SQL Statements
GET SELECT
POST INSERT
PUT UPDATE
DELETE DELETE
REST Interfaces
Verbs + URI vs Methods
GET customer/123 GetCustomer
POST customer NewCustomer
PUT order/456 ModifyOrder
DELETE order/456 DeleteOrder
REST Content
Transmitted
by representation
XML JSON
<Customer> {"Customer":
<ID>1234</ID> {"ID":1234,
<Name>Dupond</Name> "Name":"Dupond",
<Address>Tree street "Address":"Tree street"
</Address> }
</Customer> }
REST Content Troll
XML vs JSON
Type safe Truly human-readable
SOAP standard Native AJAX / JavaScript
Binary (CDATA) Compact (UTF-8 friendly)
Validation (XSDL) Simple to implement
RAD → MVC / MVVM
RAD
MVC & MVVM
SOA
RAD
Our beloved Delphi
RAD
Mixes UI and logic
→ Maintenance
Evolution
Test
Multi-platform
Nightmare
MVC
Isolate domain logic from UI

Model
View
Controller – View Model
Model
View
Controller
MVC process
MVVM
MVC & SOA

View

Controller

Model
MVC & Web

View

Controllers

Model
SQL/NoSQL→ ORM/ODM
SQL
NoSQL
ORM
ODM
SQL
De facto Standard
ACID by transactions
Relational (RDBMS)
NoSQL
Not Only SQL
NoSQL
Not Only SQL

Graphs
Aggregates
NoSQL
Graph-oriented
NoSQL
Aggregate-oriented
NoSQL
Aggregate = all data in a given context

(boundaries for ACID)


SQL / NoSQL
Data Modeling
SQL / NoSQL
SQL NoSQL

Normalization Denormalization
Consistency Duplicated data
Transactions Document ACID
Vertical scaling Horizontal scaling
SQL
De facto Standard?
ACID by transactions
Relational? (RDBMS)
ORM
Object Relational Mapping

CRUD on objects
vs
SQL on relational tables
ORM
Object Relational Mapping
ORM
Object Relational Mapping

By convention

By configuration
Database-First / Code-First
ORM
In practice
myObject.Value := 10;

myContext.Update(myObject);

UPDATE OBJTABLE SET …

01010101001110011111
ORM
Benefits

Stay at OOP level


Manage SQL flavors
Persistence Ignorance
Optimize SQL
Cache
ORM
No magic bullet

Hard task
Hidden process
Legacy (tuned) SQL
Performance
NoSQL
Aggregate = all data in a given context

These documents map our objects!


ODM
Object Document Mapping

Aggregate = Object
Flexible Schema
Denormalized
OOP → SOLID
Interfaces
SOLID

Just because you can doesn’t mean you should


Interfaces
What, not how

A type that comprises


abstract virtual methods

Rely on abstraction
rather than implementation
Interfaces
Abstraction is your health

Publish classes as services


Test, mock
Write SOLID code
Interfaces
Abstraction is your health

Publish classes as services


Test, mock
Write SOLID code
and manage memory for you
Interfaces
Abstraction is your health

Publish classes as services


Test, mock
Write SOLID code
and manage memory for you
unless zeroing weak pointers
SOLID Principles
Single responsibility
Open/closed
Liskov substitution
Interface segregation
Dependency inversion

.. unleash interfaces!
mORMot & Friends
Open Source
Architecture & Design
Cross-Cutting features
DB Layer
ORM/ODM/SOA/MVC
Cross platform
Q&A
Cross Cutting Features
UTF-8 JSON Compression
TDynArray Crypto
TDocVariant PDF
Logging Mustache
Testing SpiderMonkey

Uncoupled features: could be used


without the ORM/SOA/MVC framework
SynCommons
UTF-8 JSON
From the ground up

With objects, records,


dynamic arrays, variants, any value

Performance and integration


SynCommons
TDynArray

Wrapper to an existing dynamic array


TList<> on steroids
e.g. sorting, search,
binary or JSON serialization
using enhanced RTTI if available
SynCommons
TDynArray

In conjunction with records and variants:


value objects
data transfer objects (DTO)
SynCommons
TDocVariant

Stores documents
objects, arrays, variants
with low overhead
natively JSON
with late-binding support
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}
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
SynCommons
TDocVariant + mORMot.pas
TSQLRecordData = class(TSQLRecord)
private
fName: RawUTF8;
fData: variant;
public
published
property Name: RawUTF8 read fTest write fTest
stored AS_UNIQUE;
property Data: variant read fData write fData;
end;
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
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
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])]);
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;
TDocVariant + mORMot.pas

property Data: variant read fData write fData;

Data will be stored as TEXT


in the underlying RDBMS
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
SynCommons
Logging

Low overhead
Local or remote
Fast viewer tool
Exception catch, stack trace
Used by the whole framework
SynCommons
Testing

Light and cross-platform


Convention over configuration
Stubs and mocks
Compression
SynZip
faster unzip

SynLZO

SynLZ
speed symmetric
SynCrtSock
Cross-platform Network library

Socket WinHTTP WinINet clients


Optimized HTTP server
IOCP driven
http.sys kernel-mode
SynCrypto
SHA 1
SHA 256
AES 128
AES 192
AES 256
MD5
Pascal or optimized asm
SynPDF
From TCanvas to PDF
Unicode
Font embedding
Encryption
SynPDF
From TCanvas to PDF
Unicode
Font embedding
Encryption

Code-based report engine


SynMustache
Mustache template system

Data context as TDocVariant


UTF-8 JSON
With extensions
SynMustache
Data Context
{
"header": "Colors",
"items": [
{"name": "red", "first": true, "url": "#Red"},
{"name": "green", "link": true, "url": "#Green"},
{"name": "blue", "link": true, "url": "#Blue"}
],
"empty": true
}
SynMustache
Template
<h1>{{header}}</h1>
{{#items}}
{{#first}}
<li><strong>{{name}}</strong></li>
{{/first}}
{{#link}}
<li><a href="{{url}}">{{name}}</a></li>
{{/link}}
{{/items}}
{{#empty}}
<p>The list is empty.</p>
{{/empty}}
SynMustache

Result
<h1>Colors</h1>
<li><strong>red</strong></li>
<li><a href="#Green">green</a></li>
<li><a href="#Blue">blue</a></li>
<p>The list is empty.</p>
SynMustache
Data Context
{
"header": "Colors",
"items": [
{"name": "red", "first": true, "url": "#Red"},
{"name": "green", "link": true, "url": "#Green"},
{"name": "blue", "link": true, "url": "#Blue"}
],
"empty": true
}
SynMustache
Template
<h1>{{header}}</h1>
{{#items}}
{{#first}}
<li><strong>{{name}}</strong></li>
{{/first}}
{{#link}}
<li><a href="{{url}}">{{name}}</a></li>
{{/link}}
{{/items}}
{{#empty}}
<p>The list is empty.</p>
{{/empty}}
SynMustache

Result
<h1>Colors</h1>
<li><strong>red</strong></li>
<li><a href="#Green">green</a></li>
<li><a href="#Blue">blue</a></li>
<p>The list is empty.</p>
SynMustache
Data Context
{
"header": "Colors",
"items": [
{"name": "red", "first": true, "url": "#Red"},
{"name": "green", "link": true, "url": "#Green"},
{"name": "blue", "link": true, "url": "#Blue"}
],
"empty": true
}
SynMustache
Template
<h1>{{header}}</h1>
{{#items}}
{{#first}}
<li><strong>{{name}}</strong></li>
{{/first}}
{{#link}}
<li><a href="{{url}}">{{name}}</a></li>
{{/link}}
{{/items}}
{{#empty}}
<p>The list is empty.</p>
{{/empty}}
SynMustache

Result
<h1>Colors</h1>
<li><strong>red</strong></li>
<li><a href="#Green">green</a></li>
<li><a href="#Blue">blue</a></li>
<p>The list is empty.</p>
SynMustache
Data Context
{
"header": "Colors",
"items": [
{"name": "red", "first": true, "url": "#Red"},
{"name": "green", "link": true, "url": "#Green"},
{"name": "blue", "link": true, "url": "#Blue"}
],
"empty": true
}
SynMustache
Template
<h1>{{header}}</h1>
{{#items}}
{{#first}}
<li><strong>{{name}}</strong></li>
{{/first}}
{{#link}}
<li><a href="{{url}}">{{name}}</a></li>
{{/link}}
{{/items}}
{{#empty}}
<p>The list is empty.</p>
{{/empty}}
SynMustache

Result
<h1>Colors</h1>
<li><strong>red</strong></li>
<li><a href="#Green">green</a></li>
<li><a href="#Blue">blue</a></li>
<p>The list is empty.</p>
SynSM
Latest Spidermonkey
Javascript JIT engine

Call JS from Delphi


TSMVariant for late binding
SynSM
Latest Spidermonkey
Javascript JIT engine

Call JS from Delphi


TSMVariant for late binding

SynSM + mORMot = multi-threaded node.js


Sample 23
mORMot & Friends
Open Source
Architecture & Design
Cross-Cutting features
DB Layer
ORM/ODM/SOA/MVC
Cross platform
Q&A
DB Layer
SynMongoDB
NoSQL

SynDB
SQL

Uncoupled features: could be used


without the ORM/SOA/MVC framework
SynMongoDB
MongoDB native access

BSON types - TBSONVariant


TDocVariant
Extended JSON
Sample 24
SynDB
Direct RDBMS access layer

Not linked to DB.pas


Multi providers
UTF-8 JSON
Interface based
Knows SQL dialects
SynDBExplorer
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
SynDB
Providers
SynDB
Connect to a DB
var Props: TSQLDBConnectionProperties;
...
Props := TOleDBMSSQLConnectionProperties.Create(
'.\\SQLEXPRESS','AdventureWorks2008R2','','');
try
UseProps(Props);
finally
Props.Free;
end;
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;
SynDB
Late-binding
procedure UseProps(Props: TSQLDBConnectionProperties);
var Row: Variant;
begin
with Props.Execute(
'select * from Sales.Customer '+
'where AccountNumber like ?‘,['AW000001%'],@Row) do
while Step do
assert(Copy(Row.AccountNumber,1,8)='AW000001');
end;
SynDB
TQuery emulation
Q := TQuery.Create(aSQLDBConnection);
try
Q.SQL.Clear; // optional
Q.SQL.Add('select * from DOMAIN.TABLE');
Q.SQL.Add(' WHERE ID_DETAIL=:detail;');
Q.ParamByName('DETAIL').AsString := '1234';
Q.Open;
Q.First; // optional
while not Q.Eof do begin
assert(Q.FieldByName('id_detail').AsString='1234');
Q.Next;
end;
Q.Close; // optional
finally
Q.Free;
end;
SynDB
Fast read/only TDataSet
ds1.DataSet := ToDataSet(ds1,
aProps.Execute('select * from people',[]));

Read/write TClientDataSet
ds1.DataSet := ToClientDataSet(ds1,
aProps.Execute('select * from people',[]));
SynDB
Remote access via HTTP
SynDB
Remote access via HTTP

http.sys based server


SynLZ compression
Digital signature
Authentication
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
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
SynDBExplorer
Manage and request your DBs

Any supported database


High performance grid
Export to CSV or SQLite3
SQLite3 integrated
Remote server or client
SynDBExplorer
mORMot & Friends
Open Source
Architecture & Design
Cross-Cutting features
DB Layer
ORM/ODM/SOA/MVC
Cross platform
Q&A
ORM/ODM/SOA/MVC
ORM/ODM/SOA/MVC
RESTful
ORM
SOA
MVC
RESTful ORM
Not an ORM
with a transmission layer

But a RESTful ORM


from the ground up
TSQLRest
RESTful access

Convention over configuration


CRUD methods - Cache
Authentication – Authorization
Services

On Client or Server side


TSQLRest
TSQLRest
TSQLRest
TSQLRest
TSQLRestServer
Server Storage

In-memory
SQLite3 local
External SQL
External NoSQL
Redirected
TSQLRestServer
TSQLRestServer
Per table redirection
TSQLRestClient
Client Access

In process
Library
HTTP
Named pipes
Windows messages
TSQLRest Cache
TSQLRecord
Convention over configuration
TSQLSampleRecord = class(TSQLRecord)
private
fQuestion: RawUTF8;
fName: RawUTF8;
fTime: TModTime;
published
property Time: TModTime read fTime write fTime;
property Name: RawUTF8 read fName write fName;
property Question: RawUTF8 read fQuestion write fQuestion;
end;
TSQLRecord
Convention over configuration
TSQLSampleRecord = class(TSQLRecord)
private
fQuestion: string;
fName: string;
fTime: TModTime;
published
property Time: TModTime read fTime write fTime;
property Name: string read fName write fName;
property Question: string read fQuestion write fQuestion;
end;
TSQLModel
Define your data model
function CreateSampleModel: TSQLModel;
begin
result := TSQLModel.Create([TSQLSampleRecord]);
end;

Shared on both Client and Server side


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;
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;
TSQLRestServer
var Model: TSQLModel;
Database: TSQLRestServerDB;
HTTPServer: TSQLHttpServer;

Model := CreateSampleModel;
Database := TSQLRestServerDB.Create(Model,'data.db3');
Database.CreateMissingTables;
HTTPServer := TSQLHttpServer.Create('8080',[Database]);
HTTPServer.AccessControlAllowOrigin := '*';
TSQLRestClient
var Model: TSQLModel;
Database: TSQLRest;

Model := CreateSampleModel;
Database := TSQLHttpClient.Create(ServerIP,'8080',Model);
Sample 04
Sample 04
http://localhost:8080/root
http://localhost:8080/root/samplerecord

disable authentication…
http://localhost:8080/root/samplerecord
http://localhost:8080/root/samplerecord/1
TSQLRestServer
External SQL
var Model: TSQLModel;
Props: TSQLDBConnectionProperties;
Database: TSQLRestServerDB;
HTTPServer: TSQLHttpServer;

Model := CreateSampleModel;
Props := TODBCConnectionProperties.Create('',
'Driver=PostgreSQL Unicode';…','','');
VirtualTableExternalRegisterAll(Model,Props);
Database := TSQLRestServerDB.Create(Model,':memory:');
Database.CreateMissingTables;
HTTPServer := TSQLHttpServer.Create('8080',[Database]);
HTTPServer.AccessControlAllowOrigin := '*';
Sample 28
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;
TSQLRecord
Mapping by configuration
Model := TSQLModel.Create([TSQLRecordPeopleExt],'root');
VirtualTableExternalRegister(
Model,TSQLRecordPeopleExt,Props,'Test.People');
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');
TSQLRecord Change Tracking
Objects Time Machine
Database.TrackChanges([TSQLInvoice]);
TSQLRecord Change Tracking
Objects Time Machine
Database.TrackChanges([TSQLInvoice]);

aInvoice := TSQLInvoice.Create;
aHist := TSQLRecordHistory.CreateHistory(
aClient,TSQLInvoice,400);
try
writeln('History Count: ',aHist.HistoryCount);
for i := 0 to aHist.HistoryCount-1 do begin
aHist.HistoryGet(i,aEvent,aTimeStamp,aInvoice);
writeln;
writeln('Event: ',ord(aEvent))^);
writeln('TimeStamp: ',TTimeLogBits(aTimeStamp).ToText);
writeln('Identifier: ',aInvoice.Number);
end;
BATCH
Send all modifications at once

“Unit of Work” pattern


Array Binding or Multiple INSERT
Huge performance boost
Sample 15
SOA
Interface-based services

Design by contract
Factories
Instances live mode
REST UTF-8 JSON Security
Thread safety
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;
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;
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);
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
Sample 14
MVC/MVVM
Auto Generated UI

Dynamic Web Sites


SynFile
Web Apps
Classic MVC
Web Apps
Classic MVC

Model ORM
View Mustache
Controller IMVCApplication
Web Apps
Blog MVC Sample

Model MVCModel.pas
View *.html
Controller MVCViewModel.pas
Web Apps
Implement a Controller

method name → page name


var const params → URI params
var out params → Mustache context
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?....
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
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;
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}}


Sample 30
Web Apps
Sample 30

http://localhost:8092/blog/default
http://localhost:8092/blog/mvc-info
http://localhost:8092/blog/articleView?id=99
http://localhost:8092/blog/articleView/json?id=99
http://localhost:8092/blog/authorView?id=1
mORMot & Friends
Open Source
Architecture & Design
Cross-Cutting features
DB Layer
ORM/ODM/SOA/MVC
Cross platform
Q&A
Server
Delphi
Win32 Win64
XE7 XE6 XE5 XE4 XE3 XE2
XE1 XE0 XE-1 XE-2 XE-3 XE-4 XE-5

FPC
Win32 Linux-x86 Linux-ARM
2.7.1 svn (2.6.4)
Server
Delphi
Win32 Win64
XE7 XE6 XE5 XE4 XE3 XE2
XE 2010 2009 2007 2005 7 6

FPC
Win32 Linux-x86 Linux-ARM
2.7.1 svn (2.6.4)
Clients
Delphi
Win32 Win64 OSX Android iOS
XE7 XE6 XE5 XE4 XE3 XE2
XE 2010 2009 2007 2005 7 6 5

FPC
All platforms
2.6.x 2.7.x
Clients
Smart Mobile Studio 2.1
HTML5
Mobile / PhoneGap

any REST JSON Client


AJAX C# Java …
Sample 27
Sample 27
Project14ServerHttpWrapper
http://localhost:888/root/wrapper/
+ SMS Project14Client

RegressionTests + LogView server

RegressionTestsServer + SMS Sample 29


RoadMap
Data Replication
Master / Slave
P2P
Offline mode

Event-Driven

http://synopse.info/fossil/wiki?name=RoadMap
mORMot & Friends
Open Source
Architecture & Design
Cross-Cutting features
DB Layer
ORM/ODM/SOA/MVC
Cross platform
Q&A
http://synopse.info/files/pdf/BeDelphi2014.pdf

You might also like