View
1.666
Download
19
Category
Preview:
DESCRIPTION
Slides published for BeDelphi 2014 Event. Create high performance Client Server ORM SOA REST MVC applications using Open Source Synopse mORMot framework and Delphi. Publish any SQL or NoSQL database content over JSON or XML: SQLite3, PostgreSQL, Oracle, MSSQL, FireBird, MongoDB. Define RESTful services using interfaces. Create MVC web applications, using Mustache templates. Running under Windows or Linux, with VCL/FMX clients on Mac OSX, Android or iOS/iPhone/iPad, or AJAX/PhoneGap.
Citation preview
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)
Alfred Glaenzer (alf)
Arnaud Bouchez
Aweste
Cheemeng
CoMPi
Damien (ddemars)
David Mead (MDW)
Delphinium
DigDiver
EMartin
Eric Grange
Esmond
Joe (jokusoft)
Jordi Tudela
Mario Moretti
Martin Suer
MChaos
Ondrej (reddwarf)
Pavel (mpv)
Pierre le Riche
RalfS
Sabbiolina
Sanyin
Sinisa (sinisav)
Sllimr7139
Vadim Orel
Win2014
Wolfgang Ehrhardt (via MPL)
Hall of fame Alexander (sha)
Alfred Glaenzer (alf)
Arnaud Bouchez
Aweste
Cheemeng
CoMPi
Damien (ddemars)
David Mead (MDW)
Delphinium
DigDiver
EMartin
Eric Grange
Esmond
Joe (jokusoft)
Jordi Tudela
Mario Moretti
Martin Suer
MChaos
Ondrej (reddwarf)
Pavel (mpv)
Pierre le Riche
RalfS
Sabbiolina
Sanyin
Sinisa (sinisav)
Sllimr7139
Vadim Orel
Win2014
Wolfgang Ehrhardt (via MPL)
… 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
GET
POST
PUT
DELETE
CRUD Operations
READ
CREATE
UPDATE
DELETE
REST Interfaces
HTTP Verbs
GET
POST
PUT
DELETE
SQL Statements
SELECT
INSERT
UPDATE
DELETE
REST Interfaces
Verbs + URI vs
GET customer/123
POST customer
PUT order/456
DELETE order/456
Methods
GetCustomer
NewCustomer
ModifyOrder
DeleteOrder
REST Content
Transmitted
by representation
XML
<Customer> <ID>1234</ID> <Name>Dupond</Name> <Address>Tree street
</Address> </Customer>
JSON
{"Customer": {"ID":1234,
"Name":"Dupond", "Address":"Tree street"
} }
REST Content Troll
XML vs
Type safe
SOAP standard
Binary (CDATA)
Validation (XSDL)
JSON
Truly human-readable
Native AJAX / JavaScript
Compact (UTF-8 friendly)
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
Normalization
Consistency
Transactions
Vertical scaling
NoSQL
Denormalization
Duplicated data
Document ACID
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
TDynArray
TDocVariant
Logging
Testing
Compression
Crypto
Mustache
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
Model
View
Controller
ORM
Mustache
IMVCApplication
Classic MVC
Web Apps
Model
View
Controller
MVCModel.pas
*.html
MVCViewModel.pas
Blog MVC Sample
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
Recommended