Synopse MORMot Framework SAD 1.18

March 29, 2018 | Author: Dominik Henning | Category: Free Software, Gnu, Representational State Transfer, Source Code, Copyright


Comments



Description

Synopse mORMot FrameworkSoftware Architecture Design 1.18 Date: June 16, 2013 PROJECT DOCUMENTATION Project Name: Synopse mORMot Framework Document Name: Software Architecture Design Document Revision: 1.18 Date: June 16, 2013 Project Manager: Arnaud Bouchez Document License THE ATTACHED DOCUMENTS DESCRIBE INFORMATION RELEASED BY SYNOPSE INFORMATIQUE UNDER A GPL 3.0 LICENSE. Synopse mORMot Framework Documentation. Copyright (C) 2008-2013 Arnaud Bouchez. Synopse Informatique - http://synopse.info.. This document is free document; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. The Synopse mORMot Framework Documentation is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this documentation. If not, see http://www.gnu.org/licenses.. Trademark Notice Rather than indicating every occurrence of a trademarked name as such, this document uses the names only in an editorial fashion and to the benefit of the trademark owner with no intention of infringement of the trademark. Prepared by: Title: Arnaud Bouchez Project Manager Signature: Software Architecture Design - Rev. 1.18 Date Page 1 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 Document Purpose The Software Architecture Design document purpose is to describe the implications of each software requirement specification on all the affected software modules for the Synopse mORMot Framework project. The current revision of this document is 1.18. Related Documents Name Description Rev. Date SWRS Software Requirements Specifications 1.18 June 16, 2013 Software Design Document 1.18 June 16, 2013 Design Input Product Specifications 1.18 June 16, 2013 SDD DI Software Architecture Design - Rev. 1.18 Page 2 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 Software Architecture Design - Rev. 1.18 Page 3 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 Table of Contents Introduction Purpose 35 Responsibilities 36 GNU General Public License 36 1. Synopse mORMot Overview 1.1. Client-Server ORM/SOA framework 50 1.2. Highlights 51 1.3. Benefits 52 1.4. Legacy code and existing projects 53 1.5. mORMot 54 2. Architecture principles 2.1. General design 56 2.2. Architecture Design Process 58 2.3. Model-View-Controller 60 2.4. Multi-tier architecture 61 2.5. Service-oriented architecture 63 2.6. Object-relational mapping 65 2.7. Domain-Driven design 67 3. Enter new territory 3.1. Meet the mORMot Software Architecture Design - Rev. 1.18 70 Page 4 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 3.2. Main units 71 4. SynCommons unit 4.1. Unicode and UTF-8 73 4.2. Currency handling 74 4.3. Dynamic array wrapper 74 4.3.1. TList-like properties 75 4.3.2. Enhanced features 76 4.3.3. Capacity handling via an external Count 76 4.3.4. JSON serialization 77 4.3.5. Daily use 77 4.4. Enhanced logging 78 4.4.1. Setup logging 79 4.4.2. Call trace 80 4.4.3. Including symbol definitions 81 4.4.4. Exception handling 81 4.4.5. Serialization 82 4.4.6. Multi-threaded applications 83 4.4.7. Log to the console 83 4.4.8. Automated log archival 84 4.4.9. Log files rotation 84 4.4.10. Integration within tests 85 4.4.11. Log Viewer 85 4.4.11.1. Open log files 85 4.4.11.2. Log browser 86 4.4.11.3. Customer-side profiler 86 4.4.11.4. Per-thread inspection 87 5. Object-Relational Mapping 5.1. TSQLRecord fields definition 5.1.1. Text fields 89 91 Software Architecture Design - Rev. 1.18 Page 5 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 5.1.2. Date and time fields 92 5.1.3. Enumeration fields 92 5.1.4. Floating point and Currency fields 92 5.1.5. TSQLRecord fields 93 5.1.6. Variant fields 93 5.1.7. Record fields 94 5.2. Working with Objects 94 5.3. Queries 95 5.3.1. Return a list of objects 95 5.3.2. Query parameters 95 5.3.3. Introducing TSQLTableJSON 96 5.3.4. Note about query parameters 97 5.4. Objects relationship: cardinality 99 5.4.1. "One to one" or "One to many" 99 5.4.2. "Has many" and "has many through" 101 5.4.2.1. Shared nothing architecture (or sharding) 102 5.4.2.1.1. Embedding all needed data within the record 102 5.4.2.1.2. Nesting objects and arrays 103 5.4.2.1.2.1. Dynamic arrays fields 104 5.4.2.1.2.1.1. Dynamic arrays from Delphi Code 104 5.4.2.1.2.1.2. Dynamic arrays from SQL code 105 5.4.2.1.2.2. TPersistent/TCollection fields 106 5.4.2.1.2.3. Any TObject, including TObjectList 109 5.4.2.2. ORM implementation via pivot table 109 5.4.2.2.1. Introducing TSQLRecordMany 109 5.4.2.2.2. Automatic JOIN query 113 5.5. ORM Cache 114 5.6. Calculated fields 115 5.6.1. Setter for TSQLRecord 115 5.6.2. TSQLRecord.ComputeFieldsBeforeWrite 116 Software Architecture Design - Rev. 1.18 Page 6 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 6. Daily ORM 6.1. ORM is not Database 119 6.1.1. Objects, not tables 119 6.1.2. Methods, not SQL 120 6.1.3. Think multi-tier 122 6.2. One ORM to rule them all 122 6.2.1. Rude class definition 122 6.2.2. Persist TSQLRecord, not any class 123 6.2.3. Several ORMs at once 124 6.2.4. The best ORM is the one you need 125 7. MVC pattern 7.1. Creating a Model 126 7.2. Filtering and Validating 127 7.3. Views 129 7.3.1. RTTI 129 7.3.2. User Interface 130 8. Database layer 8.1. SQLite3-powered, not SQLite3-limited 132 8.1.1. SQLite3 as core 133 8.1.2. Extended by SQLite3 virtual tables 134 8.1.3. Data access benchmark 135 8.1.3.1. Insertion speed 136 8.1.3.2. Reading speed 137 8.1.3.3. Analysis and use case proposal 139 8.2. SQLite3 implementation 8.2.1. Statically linked or using external dll 140 140 8.2.1.1. Static bcc-compiled .obj 141 8.2.1.2. Official MinGW-compiled sqlite3.dll 142 8.2.1.3. Visual C++ compiled sqlite3.dll 143 Software Architecture Design - Rev. 1.18 Page 7 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 8.2.2. Prepared statement 144 8.2.3. R-Tree inclusion 146 8.2.4. FTS3/FTS4 147 8.2.4.1. Dedicated FTS3/FTS4 record type 147 8.2.4.2. Stemming 148 8.2.4.3. FTS searches 149 8.2.5. Column collations 150 8.2.6. REGEXP operator 152 8.2.7. NULL handling 152 8.2.8. ACID and speed 153 8.2.8.1. Synchronous writing 153 8.2.8.2. File locking 154 8.2.8.3. Performance tuning 154 8.3. Virtual Tables magic 155 8.3.1. Virtual Table module classes 156 8.3.2. Defining a Virtual Table module 156 8.3.3. Using a Virtual Table module 159 8.3.4. Virtual Table, ORM and TSQLRecord 160 8.3.5. In-Memory "static" process 160 8.3.5.1. In-Memory tables 161 8.3.5.2. In-Memory virtual tables 161 8.3.6. Virtual Tables to access external databases 163 8.3.7. Virtual tables from the client side 164 9. External database access 9.1. Database agnosticism 166 9.1.1. Direct access to any Database engine 167 9.1.2. Data types 168 9.1.3. SynDB Units 169 9.1.4. Classes 169 9.1.5. ISQLDBRows interface 171 Software Architecture Design - Rev. 1.18 Page 8 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 9.1.6. Late binding 172 9.2. Database access 173 9.2.1. OleDB or ODBC to rule them all 174 9.2.2. ZEOS via direct ZDBC 175 9.2.3. Oracle via OCI 175 9.2.4. SQLite3 177 9.2.5. DB.pas libraries 177 9.2.5.1. NexusDB access 178 9.2.5.2. FireDAC / AnyDAC library 178 9.2.5.3. UniDAC library 179 9.2.5.4. BDE engine 179 9.3. ORM Integration 180 9.3.1. Transparent use 180 9.3.2. Behind the scene 182 10. JSON RESTful Client-Server 10.1. JSON 184 10.1.1. Why use JSON? 184 10.1.2. Values serialization 185 10.1.3. Record serialization 185 10.1.4. Dynamic array serialization 186 10.1.5. TSQLRecord TPersistent TStrings TRawUTF8List 188 10.1.6. TObject serialization 189 10.1.7. TObjectList serialization 190 10.2. REST 191 10.2.1. RESTful implementation 191 10.2.2. REST and BLOB fields 192 10.2.3. REST and JSON 192 10.2.4. REST is Stateless 193 10.3. REST and JSON 194 10.3.1. JSON format density Software Architecture Design - Rev. 1.18 194 Page 9 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 10.3.2. JSON (not) expanded layouts 194 10.3.3. JSON global cache 195 11. Client-Server process 11.1. TSQLRest classes 197 11.1.1. Server classes 197 11.1.2. Client classes 198 11.2. In-process/stand-alone application 199 11.3. Local access via named pipes or GDI messages 199 11.4. Network and Internet access via HTTP 199 11.4.1. HTTP server(s) 200 11.4.2. High-performance http.sys server 200 11.4.3. URI authorization as Administrator 201 11.4.3.1. Secure specific authorization 202 11.4.3.2. Automatic authorization 202 11.4.4. HTTP client(s) 202 11.5. Thread-safety 204 12. Client-Server ORM 12.1. ORM as local or remote 206 12.2. Stateless design 212 12.2.1. Server side synchronization 212 12.2.2. Client side synchronization 212 12.3. BATCH sequences for adding/updating/deleting records 213 12.3.1. BATCH process 213 12.3.2. Implementation details 215 12.3.3. Array binding 216 12.4. CRUD level cache 217 12.4.1. Where to cache 217 12.4.2. When to cache 218 12.4.3. What to cache 219 Software Architecture Design - Rev. 1.18 Page 10 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 12.4.4. How to cache 219 13. Server side SQL/ORM process 13.1. Custom SQL functions 221 13.2. Implementing a function 222 13.3. Registering a function 223 13.3.1. Direct low-level SQLite3 registration 223 13.3.2. Class-driven registration 223 13.3.3. Custom class definition 224 13.4. Low-level Delphi stored procedure 225 13.5. External stored procedure 226 14. Server side Services 227 15. Client-Server services via methods 15.1. Publishing a service on the server 229 15.2. Defining the client 230 15.3. Direct parameter marshalling on server side 231 15.4. Returns non-JSON content 232 15.5. Advanced process on server side 233 15.6. Browser speed-up for unmodified requests 233 15.7. Handling errors 234 15.8. Benefits and limitations of this implementation 235 16. Interfaces 16.1. Delphi and interfaces 236 16.1.1. Declaring an interface 236 16.1.2. Implementing an interface with a class 237 16.1.3. Using an interface 237 16.1.4. There is more than one way to do it 238 16.1.5. Here comes the magic 239 16.2. SOLID design principles 239 Software Architecture Design - Rev. 1.18 Page 11 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 16.2.1. Single responsibility principle 240 16.2.2. Open/closed principle 240 16.2.3. Liskov substitution principle 241 16.2.4. Interface segregation principle 243 16.2.5. Dependency Inversion Principle 243 16.3. Circular reference and (zeroing) weak pointers 243 16.3.1. Weak pointers 243 16.3.2. Handling weak pointers 245 16.3.3. Zeroing weak pointers 245 16.3.4. Weak pointers functions implementation details 246 16.4. Interfaces in practice: dependency injection, stubs and mocks 247 16.4.1. Dependency injection 247 16.4.2. Why use fake / emulated interfaces? 249 16.4.3. Stubs and mocks 249 16.4.4. Defining stubs 249 16.4.5. Defining a mock 250 16.4.6. Running the test 250 16.5. Stubs and Mocks in mORMot 251 16.5.1. Features and motivations 251 16.5.2. Stubbing complex return values 252 16.5.3. Stubbing via a custom delegate or callback 253 16.5.3.1. Delegate with named variant parameters 253 16.5.3.2. Delegate with indexed variant parameters 254 16.5.3.3. Delegate with JSON parameters 254 16.5.3.4. Accessing the test case when mocking 255 16.5.4. Calls tracing 255 17. Client-Server services via interfaces 17.1. Implemented features 257 17.2. How to make services 259 Software Architecture Design - Rev. 1.18 Page 12 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 17.3. Defining a data contract 259 17.3.1. Define an interface 259 17.3.2. Available types for methods parameters 260 17.3.3. TPersistent / TSQLRecord parameters 261 17.3.4. Record parameters 262 17.3.5. TCollection parameters 262 17.3.5.1. Use of TCollection 263 17.3.5.2. Inherit from TInterfacedCollection 263 17.3.5.3. Register a TCollection type 264 17.4. Server side 264 17.4.1. Implementing the service contract 264 17.4.2. Set up the Server factory 265 17.4.3. Instances life time implementation 265 17.4.4. Accessing low-level execution context 268 17.4.5. Using services on the Server side 269 17.5. Client side 269 17.5.1. Set up the Client factory 270 17.5.2. Using services on the Client side 270 17.6. Sample code 271 17.6.1. The shared contract 271 17.6.2. The server sample application 272 17.6.3. The client sample application 273 17.6.4. Enhanced sample: remote SQL access 273 17.7. Implementation details 277 17.7.1. Security 277 17.7.2. Implementation class types 279 17.7.3. Server-side execution options 279 17.7.4. Transmission content 280 17.7.4.1. Request format 280 17.7.4.2. Response format 281 Software Architecture Design - Rev. 1.18 Page 13 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 17.7.4.2.1. Standard answer as JSON object 281 17.7.4.2.2. Returns direct JSON content 283 17.7.4.2.3. Custom returned content 283 17.8. Comparison with WCF 284 18. Hosting 18.1. Shared server 288 18.2. Two servers 289 18.3. Two instances on the same server 290 19. Security 19.1. Authentication 293 19.1.1. Principles 293 19.1.1.1. HTTP basic auth over HTTPS 293 19.1.1.2. Session via Cookies 294 19.1.1.3. Query Authentication 294 19.1.2. Framework authentication 294 19.1.2.1. Per-User authentication 295 19.1.2.2. Session handling 297 19.1.3. Authentication schemes 297 19.1.3.1. Class-driven authentication 297 19.1.3.2. mORMot secure RESTful authentication 298 19.1.3.3. Authentication using Windows credentials 300 19.1.3.4. Weak authentication 300 19.1.4. Clients authentication 300 19.1.4.1. Client interactivity 301 19.1.4.2. Authentication using AJAX 301 19.2. Authorization 301 19.2.1. Per-table access rights 301 19.2.2. Additional safety 302 19.2.2.1. SQL remote execution Software Architecture Design - Rev. 1.18 302 Page 14 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 19.2.2.2. Service execution 302 20. Domain-Driven-Design 20.1. DDD objects 304 20.2. DDD patterns 305 20.3. mORMot's DDD 306 21. Testing and logging 21.1. Automated testing 307 21.1.1. Involved classes in Unitary testing 307 21.1.2. First steps in testing 308 21.1.3. Implemented tests 310 21.2. Logging 310 22. Source code 22.1. License 312 22.2. Availability 313 22.2.1. Obtaining the Source Code 313 22.2.2. Expected compilation platform 314 22.2.3. Note about sqlite3*.obj files 315 22.2.4. Folder layout 315 22.3. Installation 318 23. mORMot Framework source 23.1. mORMot Framework used Units 319 23.2. SynCommons.pas unit 325 23.3. SynCrtSock.pas unit 479 23.4. SynCrypto.pas unit 497 23.5. SynDB.pas unit 509 23.6. SynDBDataset.pas unit 549 23.7. SynDBODBC.pas unit 553 23.8. SynDBOracle.pas unit 557 Software Architecture Design - Rev. 1.18 Page 15 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 23.9. SynDBSQLite3.pas unit 564 23.10. SynDBVCL.pas unit 570 23.11. SynDBZEOS.pas unit 571 23.12. SynGdiPlus.pas unit 576 23.13. SynLZ.pas unit 584 23.14. SynLZO.pas unit 586 23.15. SynOleDB.pas unit 587 23.16. SynPdf.pas unit 600 23.17. SynSelfTests.pas unit 642 23.18. SynSQLite3.pas unit 647 23.19. SynSQLite3RegEx.pas unit 695 23.20. SynSQLite3Static.pas unit 696 23.21. SynSSPIAuth.pas unit 698 23.22. SynTaskDialog.pas unit 700 23.23. SynWinSock.pas unit 706 23.24. SynZip.pas unit 707 23.25. mORMot.pas unit 715 23.26. mORMotDB.pas unit 908 23.27. mORMotFastCgiServer.pas unit 914 23.28. mORMotHttpClient.pas unit 917 23.29. mORMotHttpServer.pas unit 920 23.30. mORMoti18n.pas unit 924 23.31. mORMotReport.pas unit 934 23.32. mORMotSelfTests.pas unit 951 23.33. mORmotService.pas unit 953 23.34. mORMotSQLite3.pas unit 959 23.35. mORMotToolBar.pas unit 966 23.36. mORMotUI.pas unit 980 Software Architecture Design - Rev. 1.18 Page 16 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 23.37. mORMotUIEdit.pas unit 990 23.38. mORMotUILogin.pas unit 993 23.39. mORMotUIOptions.pas unit 997 23.40. mORMotUIQuery.pas unit 999 23.41. mORmotVCL.pas unit 1001 23.42. SynDBBDE.pas unit 1002 23.43. SynDBFireDAC.pas unit 1005 23.44. SynDBNexusDB.pas unit 1008 23.45. SynDBUniDAC.pas unit 1012 24. SynFile application 24.1. General architecture 1015 24.2. Database design 1016 24.3. User Interface generation 1020 24.3.1. Rendering 1020 24.3.2. Enumeration types 1023 24.3.3. ORM Registration 1023 24.3.4. Report generation 1024 24.3.5. Application i18n and L10n 1027 24.3.5.1. Creating the reference file 1027 24.3.5.2. Adding a new language 1029 24.3.5.3. Language selection 1029 24.3.5.4. Localization 1030 25. Main SynFile Demo source 25.1. Main SynFile Demo used Units 1031 25.2. FileClient.pas unit 1034 25.3. FileEdit.pas unit 1036 25.4. FileMain.pas unit 1038 25.5. FileServer.pas unit 1040 Software Architecture Design - Rev. 1.18 Page 17 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 25.6. FileTables.pas unit 1042 26. SWRS implications Software Architecture Design Reference Table 26.1. Client Server ORM/SOA framework 1046 1047 26.1.1. SWRS # DI-2.1.1 1047 26.1.2. SWRS # DI-2.1.1.1 1047 26.1.3. SWRS # DI-2.1.1.2.1 1048 26.1.4. SWRS # DI-2.1.1.2.2 1048 26.1.5. SWRS # DI-2.1.1.2.3 1049 26.1.6. SWRS # DI-2.1.1.2.4 1049 26.1.7. SWRS # DI-2.1.2 1049 26.1.8. SWRS # DI-2.1.3 1050 26.1.9. SWRS # DI-2.1.4 1051 26.1.10. SWRS # DI-2.1.5 1051 26.2. SQlite3 engine 1052 26.2.1. SWRS # DI-2.2.1 1052 26.2.2. SWRS # DI-2.2.2 1053 26.3. User interface 1053 26.3.1. SWRS # DI-2.3.1.1 1053 26.3.2. SWRS # DI-2.3.1.2 1054 26.3.3. SWRS # DI-2.3.1.3 1054 26.3.4. SWRS # DI-2.3.2 1054 Software Architecture Design - Rev. 1.18 Page 18 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 Pictures Reference Table The following table is a quick-reference guide to all the Pictures referenced in this Software Architecture Design (SAD) document. Pictures Page Adopt a mORMot 72, 206, 307 Adopt a mORMot 88, 221, 312 Adopt a mORMot 118, 227, 1015 Adopt a mORMot 126, 229 Adopt a mORMot 132, 236 Adopt a mORMot 166, 257 Adopt a mORMot 184, 288 Adopt a mORMot 55, 196, 292 Client-Server implementation - Client side 207 Domain Driven Design n-Tier Architecture - Physical View 62 Domain Driven Design n-Tier Architecture - Implementation 304 Domain Driven Design n-Tier Architecture - Logical View 62 Architecture Iterative Process (SCRUM) 58 Multi-Tier Architecture - Logical View 61 Service Oriented Architecture - Logical View 63 Client-Server implementation - Server side 207 Client-Server implementation - Server side 211 Client-Server implementation - Server side with Virtual Tables 209 Client-Server implementation - Stand-Alone application 208 Client-Server implementation - Server side with "static" Virtual Tables 210 BATCH mode Client-Server latency 214 BATCH mode latency issue on external DB 216 HTTP/1.1 Client architecture 203 RESTful Client classes 199 HTTP/1.1 Client RESTful classes 203 Software Architecture Design - Rev. 1.18 Page 19 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 Pictures Page RESTful Client-Server classes 197 AuditTrail Record Layout 1019 AuthGroup Record Layout 295 AuthUser Record Layout 296 Data Record Layout 1018 Memo Record Layout 1018 SafeData Record Layout 1019 SafeMemo Record Layout 1018 Design Inputs, FMEA and Risk Specifications 35 FTS3/FTS4 ORM classes 148 ESQLQueryException classes hierarchy 171 External Databases classes hierarchy 182 SynFile TSQLRecord classes hierarchy 1017 TOleDBStatement classes hierarchy 171 TSQLDataBaseSQLFunction classes hierarchy 224 TSQLDBConnectionPropertiesThreadSafe classes hierarchy 170 TSQLDBSQLite3Connection classes hierarchy 170 TSQLite3Library classes hierarchy 141 Custom Virtual Tables records classes hierarchy 160 TSQLRestClient classes hierarchy 192 TSQLRestServerAuthentication classes hierarchy 298 Virtual Tables classes hierarchy 156 Filtering and Validation classes hierarchy 127 Default filters and Validation classes hierarchy 128 TSynTest classes hierarchy 308 THttpServerGeneric classes hierarchy 200 mORMot class hierarchy 716 mORMotDB class hierarchy 908 Software Architecture Design - Rev. 1.18 Page 20 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 Pictures Page mORMotHttpClient class hierarchy 917 mORMotHttpServer class hierarchy 920 mORMoti18n class hierarchy 924 mORMotReport class hierarchy 934 mORmotService class hierarchy 953 mORMotSQLite3 class hierarchy 959 mORMotToolBar class hierarchy 967 mORMotUI class hierarchy 980 mORMotUIEdit class hierarchy 990 mORMotUILogin class hierarchy 993 mORMotUIOptions class hierarchy 997 mORMotUIQuery class hierarchy 999 FileClient class hierarchy 1034 FileEdit class hierarchy 1036 FileMain class hierarchy 1038 FileServer class hierarchy 1040 FileTables class hierarchy 1042 SynCommons class hierarchy 326 SynCrtSock class hierarchy 479 SynCrypto class hierarchy 497 SynDB class hierarchy 509 SynDBBDE class hierarchy 1002 SynDBFireDAC class hierarchy 1005 SynDBNexusDB class hierarchy 1008 SynDBUniDAC class hierarchy 1012 SynDBDataset class hierarchy 549 SynDBODBC class hierarchy 553 SynDBOracle class hierarchy 557 Software Architecture Design - Rev. 1.18 Page 21 of 1055 one server. 2013 Pictures Page SynDBSQLite3 class hierarchy 564 SynDBZEOS class hierarchy 571 SynGdiPlus class hierarchy 576 SynOleDB class hierarchy 587 SynPdf class hierarchy 601 SynSelfTests class hierarchy 643 SynSQLite3 class hierarchy 647 SynSQLite3Static class hierarchy 696 SynTaskDialog class hierarchy 700 SynZip class hierarchy 707 CRUD caching in mORMot 218 mORMot Persistence Layer Architecture 133 N-Layered Domain-Oriented Architecture of mORMot 68 Alternate Domain-Oriented Architecture of mORMot 68 General mORMot architecture .Stand-alone application 50 General mORMot architecture .Client / Server 50 General mORMot architecture .18 Page 22 of 1055 . 1.shared server 289 Service Hosting on mORMot .two servers 290 Service Hosting on mORMot .18 Date: June 16.Client Server implementation 56 Why a Client-Server ORM 65 Service Hosting on mORMot .Synopse mORMot Framework Software Architecture Design 1.Rev. two instances 291 mORMot Source Code Folders 315 mORMot Source Code Main Units 70 Model View Controller concept 60 Unit dependencies in the "Lib\SQLite3" directory 323 Unit dependencies in the "Lib\SynDBDataset" directory 324 Unit dependencies in the "Lib" directory 321 Unit dependencies in the "Lib\SQLite3\Samples\MainDemo" directory 1033 Software Architecture Design . Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16. 1. mORMot and SQLite3 177 SynDB and UniDAC 179 SynDB and Zeos / ZDBC 175 Meet the mORMot 48 User Interface generated using TMS components 1022 User Interface generated using VCL components 1022 Software Architecture Design .Rev.18 Page 23 of 1055 . 2013 Pictures Page Unit dependencies in the "Lib\SQLite3" directory 1032 Unit dependencies in the "Lib" directory 1031 RESTful Server classes 197 RESTful Server static classes 198 SynDB First Level Providers 173 SynDB and BDE 180 SynDB and FireDAC / AnyDAC 179 SynDB Architecture 167 SynDB and NexusDB 178 Oracle Connectivity with SynDBOracle 176 SynDB and ODBC 174 SynDB and OleDB 174 SynDB. Others .pas 156. 307 Lib\SynCrypto.pas 88. 1.pas 77.pas 88 Lib\mORMotSQLite3.pas 1016 Lib\SQLite3\Samples\MainDemo\FileTables.pas 88 Lib\SQLite3\mORMot.18 Date: June 16. 1026 Lib\SQLite3\mORMotReport. 1028 Lib\SQLite3\Samples\MainDemo\FileServer.Source Reference Table Source code File Names Page Lib\mORMot. 310 Lib\SQLite3\mORMoti18n.pas 1020 Lib\SQLite3\Samples\MainDemo\FileClient.pas 1023.pas 1024 Lib\SQLite3\mORMotUIEdit. 2013 Source code File Names Reference Table The following table is a quick-reference guide to all the Source code File Names referenced in this Software Architecture Design (SAD) document.pas 1015 Lib\SynCommons. 257 Lib\mORMotDB.pas 1016.Rev. 1026 Lib\SynSQLite3.pas 88 Lib\SynGdiPlus.pas 1016 Lib\SQLite3\Samples\MainDemo\FileMain.pas 72. 88 Software Architecture Design .pas 213.pas 1016.Synopse mORMot Framework Software Architecture Design 1.18 Page 24 of 1055 .pas 1016 Lib\SynDB. 1024 Lib\SQLite3\Samples\MainDemo\FileEdit. 277. 168. 139. 135. 176. 314. 178. 185. 51.18 Page 25 of 1055 . 280. 132. 166. 119. 315 A ACID Aggregates AJAX AnyDAC ARC Array bind AsTSQLRecord 124. 179. 282. 299. 216 100 Atomic 163. 132. 1. 153 305 48. 281. 176. 153. 103. 161 Authentication 134. 134.msg 1027 6 64 bit 93. 106. 61. 2013 Keywords Reference Table The following table is a quick-reference guide to all the Keywords referenced in this Software Architecture Design (SAD) document. 137. 153. 217 95 Software Architecture Design . 1020 48. 213 BDE Benchmark BinToBase64WithMagic 51. 161. 185. 192. . 135. 168. 155. 184. 292 ATTACH DATABASE 161. 314. 283. 235. 260. 178 243 53. 258. 144. 139. 60. 306 BATCH 108. 194. 293 B Backup 155 Base64 103. 178. 167.18 Date: June 16. 167.Rev. 51. 179. 258. 200.Synopse mORMot Framework Software Architecture Design 1. 204. . 233. 179 135. 232. 166. 53. 292. 284. 261. 97. 55. 69. 114. 122. 82. 200. 310. 1016. 241. 129. 199. 105. 233. 123. 53. 61. 135. 144. 74. 123. 196. 102. 115. 63. 51. 166. 197. 130.18 Date: June 16. 240. 248.18 Page 26 of 1055 . 1052 CQRS 53. 88. 192. 273. 192. 2013 BLOB Business rules 91. 160. 121 55. 105. 66. 204 Camel 129. 67. 243. 74. 293. 133. 146. 91. 124. 103. 124 CreateAndFillPrepare CRUD Currency 95. 115. 105. 195. 213. 185. 185. 88. 167 DMZ 288 Domain Values 124 Domain-Driven 48. 61. 294 Collation 134. 1. 94. 123. 186. 94. 114. 93. 135. 1023 Cardinality Client-Server 99. 104. 295. 90. 305 72. 269. 125. 105. 217. 102 48. 296. 119. 103. 161. 86. 119. 139. 123. 192. 150. 193. 210. 168. 103. 103. 157 Contract 227. 221. 139. 163. 123. 108. 304 DTO Dynamic array 124.Rev. 51. 1016 51 C Cache 48. 103. 222 Software Architecture Design . 222. 215. 132. 134. 51. 63. 301 72. 92.Synopse mORMot Framework Software Architecture Design 1. 134. 195. 243. 186 D DAO 248 Data Access Objects 248 Data Transfer Object 248 DateTimeToSQL 95 DateToSQL 95 DBExpress 48. 119. 51. 68. 295. 270. 109 101 Hosting 49. 202. 288 Http. 215. 135.sys 51. 147. 318 HTTP 48. 285. 199. 167. 305 Filtering 127 FireDAC 48. 273.Rev. 200. 178. 178 FPC 72. 147.18 Page 27 of 1055 . 196. 1. 130.Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16. 316 HTTPS 293. 243. 212. 61. 314 FTS 133. 235. 132. 312 GUID 237 H Has many through Has many 101. 242 Event Sourcing 124. 155 G Gateway 259. 200. 200. 214. 2013 E E2201 314 Entity objects 305 Enumerated 89. 122. 247. 195. 286 General Public License 36. 299 HTTP_RESP_STATICFILE 201 I Software Architecture Design . 71. 286 F Factory 242. 51. 192. 119. 166. 265. 193. 175. 262. 293. 149. 265. 293. 191. 148. 210 JSON 48. 301. 312 72. 92. 1. 195. 119 MIME 230. 189. 1026. 102. 155.Rev. 115. 102. 274 ISO 8601 90. 260. 185. 1023. 239. 139. 243. 222 Interface 51. 200. 243. 119. 133. 314 JOIN 97. 102. 280. 153. 60. 293. 105. 114. 184. 108. 81. 73. 318. 64. 134. 77. 305 Lazarus 175. 250. 251 Software Architecture Design . 1016 L L10n 1027 Layer Supertype 123. 113. 53. 232 Mock 48. 214. 93. 163. 73. 119. 242. 130. 184. 2013 I18n IntegerDynArrayContains 48. 82. 61. 95. 78. 134 Iso8601ToSQL 95 ISQLDBRows 171 J JavaScript 61. 194. 273. 96. 192. 130. 74. 174. 63. 242.18 Date: June 16. 249. 168. 172. 104. 119. 227. 243. 133. 156. 109 312 241. 90. 194. 1020 M Many to many 93 Map/reduce 217 Master/Detail 99. 118. 91. 236. 194. 1027 103. 177.18 Page 28 of 1055 .Synopse mORMot Framework Software Architecture Design 1. 103. 153. 83. 310. 135. 51. 314 Lazy loading Lesser General Public License License Log 102. 166. 122. 178. 182. 166. 229 75. 114. 109. 182. 135. 167.Synopse mORMot Framework Software Architecture Design 1. 51. 157.Rev. 178 O ODBC 48. 317. 134. 166. 317 OleDB 48. 65. 1015. 99. 183. 130. 161. 103. 139. 289. 75. 126. 123. 98. 53. 99. 180. 61. 180. 169. 118.18 Date: June 16. 132. 61.18 Page 29 of 1055 . 192. 282. 140. 227. 99 OOP 116. 145. 132. 160. 240. 233. 1016. 88. 242. 146. 73. 149. 119. 317. 135. 156. 276 48. 1024. 61. 166. 2013 Mozilla Public License MS SQL MVC 312 48. 1024. 51. 99 One to one 93. 1026 306 77. 166. 149. 220. 166. 276. 174. 315. 301. 139. 174. 61. 51. 120. 317 ORM 48. 1016. 171. 99. 89. 167. 159. 121. 61. 241. 117. 133. 101. 104. 1017 Oracle 48. 121. 1. 239. 170. 133. 146. 162. 103. 134. 180. 163. 235. 126. 114. 177. 65. 314 51. 103. 1016. 276. 169. 134. 98. 316. 1051 P Packages Pdf Persistence Ignorance Prepared Published method Published properties 268. 51. 169. 135. 167. 317 One to many 93. 109. 140. 119. 1020. 185. 174. 226. 144. 60. 113. 89. 129. 140. 120. 175. 186. 1015. 258. 71. 157. 132. 174. 132. 88. 310. 1020 N N-Tier NexusDB 206 48. 132. 1017 Q Software Architecture Design . 242. 162. 114. 53. 94. 51. 305. 119. 168 204. 194. 1020. 306. 294. 91. 55. 1016. 121. 260 RDBMS 99. 77. 276. 97. 146. 305 1026. 130. 135. 310 51. 187 82. 262 Reference-counted 238 REGEXP 152 RegisterClassForJSON RegisterCustomJSONSerializ er RegisterCustomSerializer 90. 74. 103 Record 185. 119. 91. 88. 123. 60. 261. 51. 93. 248. 78. 201. 235. 53. 106. 145. 97. 64. 166. 115. 294. 94. 71. 185. 1. 168. 189. 90. 206. 184. 284 116 Software Architecture Design . 212. 61. 293. 204. 50.Synopse mORMot Framework Software Architecture Design 1. 61. 2013 Query Authentication Quotes 292. 283. 292. 285. 145 R RawByteString 73. 192 RawJSON 260. 1023. 294. 183. 288. 109. 82. 161. 189 Regular expression 134. 1020. 161. 185. 1016. 191. 75. 108.18 Page 30 of 1055 . 133. 74. 106. 114. 193. 213. 129. 192. 299 98. 94. 51. 197. 221. 169. 261. 306 48.18 Date: June 16.Rev. 103 185. 66. 257. 149. 192. 88. 1027 S Seam Security Serialization Server time stamp 53. 1051 RTREE 133. 227. 123. 1016 Repository Resourcestring 242. 112. 152 Report 51. 262. 283 RawUTF8 73. 122. 1023. 103. 310. 217. 155 RTTI 61. 195. 293. 298. 234. 98. 90. 1027 REST 48. 186. 277. 182. 208. 302. 119. 99. 195. 146. 310 84. 260 92. 221. 194. 221. 213. 157. 106. 173. 294. 212.Synopse mORMot Framework Software Architecture Design 1. 95. 90. 168. 61. 124. 163. 106. 205. 221. 53. 132. 155. 119. 299. 200. 242. 119. 140. 284. 166.Rev. 134.18 Date: June 16. 297. 122. 316. 310. 315. 1016. 210 106. 239. 317 Stand-alone Stateless Statement Static Stored procedure 49. 285. 130. 50. 160. 150. 103. 175. 260. 106. 266. 240. 196. 194. 116. 126. 156. 169. 134. 177. 155.inc 72 SynUnicode 73. 133. 82. 292 Stub 48. 168. 103. 204. 251 SynDB SynDBExplorer SynLZ 71. 86. 106. 227. 140. 161. 249. 98. 242. 168. 1. 134. 292. 310 Sharding 102. 147. 177. 1051 Session 48. 161. 105. 293. 60. 199. 89. 115. 292. 66. 91. 146. 293. 61. 160. 51. 122. 149. 94. 133 Software Architecture Design . 195. 118. 191. 228. 63. 60. 91. 88. 260 T TCollection TCreateTime 75. 286 SOLID 68. 291 55. 243. 243. 317 151. 316. 200. 159. 129. 122. 89. 193. 153. 257. 198. 185. 315. 103 Shared nothing architecture 102 SOA 48. 186. 122. 310. 144. 107. 185. 233. 73. 215. 243. 90. 106. 162. 102. 129.18 Page 31 of 1055 . 250. 152. 134. 114. 61. 167. 119. 259. 63. 119. 279. 2013 Service 55. 51. 316 Synopse. 108. 295. 294 114 156. 310 SQLite3 48. 221 SQL 48. 124. 129. 220. 259. 294. 133. 317 SOAP 235. 71. 239. 130. 161. 221 Strong type 118. 98. 310. 185. 65. 118. 259 SQL function 105. 102. 204. 317 TDateTime 90. 95. 119. 260. 232. 302 Tier TInterfacedCollection TModTime TMS TObject 48. 193. 73. 107. 1016. 115. 149. 92. 50. 97. 95 TDynArray 186. 119. 106. 169. 188. 192 TSQLRecord TSQLRecordMany 60. 110. 160.Synopse mORMot Framework Software Architecture Design 1. 180. 103. 241. 116. 1017 Transaction 107. 146. 1051 90. 102. 103. 119. 113. 108. 104. 123. 188. 260. 90. 162. 133 314. 318. 260 TPersistent 82. 124.Rev. 307. 166. 102. 2013 TDataSet 139. 120. 73. 261 TObjectList 90. 109. 120. 163. 85. 174. 53. 160. 55. 286. 297 TRawUTF8List 90. 212. 113. 227. 201. 186 TDynArrayHashed Test 168 48. 157. 106. 111. 1020 90. 104. 1015. 284 TServiceFactory TSQLModel 247. 189. 269 60. 103. 51. 99. 128. 119 TSQLRecordMappedAutoID 124 TSQLRecordMappedForcedI D 124 Software Architecture Design . 214. 102. 126. 161. 182 TSQLRawBlob 91. 1019 TSQLModelRecordPropertie s 127. 295. 1024. 93. 102. 202. 90. 163. 162. 106. 49. 311. 318 Text Search 51 Thread-safe 134. 103.18 Date: June 16. 240. 109. 242.18 Page 32 of 1055 . 93. 316. 103. 109. 282. 89. 124. 261. 106. 192. 1017. 126. 106. 96. 88. 128. 128. 94. 260. 106. 82. 190. 214. 119. 116. 189 TServiceCustomAnswer 260. 260 92. 61 260. 110. 1019. 1. 103. 232. 149. 119. 55. 95. 209 VirtualTableExternalRegiste r 124. 119. 160. 307 V Validation 127 Value Objects 304 Virtual Table 51. 2013 TSQLRecordProperties 127 TSQLRecordVirtual 124 TSQLRecordVirtualTableAut oID 160. 132. 185. 208. 103. 146. 177. 212 TSQLVirtualTableBinary 155. 160. 149. 156. 156. 195. 97. 161.18 Date: June 16. 51. 126. 302 TSQLRestServerDB 146. 229. 197. 189. 133. 306 72. 126. 96. 272 TSQLRestServerRemoteDB 198. 147. 163. 162. 160. 290 TSQLRestServerStaticInMe mory 124. 160 TSQLVirtualTableJSON 155. 1026 U Ubiquitous Language UniDAC Unit Of Work UTF-8 305 48. 161. 156. 272 TSQLRestServerFullMemory 134. 161. 199. 1.Synopse mORMot Framework Software Architecture Design 1. 92. 163.Rev. 179 286. 226. 192. 204 TSQLTableJSON 95. 144. 103. 199. 265. 166. 181 Software Architecture Design . 187. 1019 TSQLRestClientDB 162. 167. 208. 163. 265. 166. 189 92. 178. 156. 135. 73. 164 TSQLRecordVirtualTableFor cedID 160 TSQLRest 90. 97. 184. 156. 192. 119. 125. 229. 134. 155. 77. 182. 198. 133. 223. 204. 89. 119. 161. 157.18 Page 33 of 1055 . 160 TStrings TTimeLog 90. 317 Zeroing Weak pointers 243 Software Architecture Design . 2013 W WCF Weak pointers WideString Windows Authentication 48. 166. 227. 260 298. 51. 135.Synopse mORMot Framework Software Architecture Design 1. 169. 90. 301 Z ZDBC 166. 175 Zeos 48. 300. 284 243 73.18 Page 34 of 1055 . 1.18 Date: June 16. 132.Rev. 175. 18 Date: June 16. Software Architecture Design .Rev. FMEA and Risk Specifications Purpose This Software Architecture Design (SAD) document applies to the 1. and the class hierarchy of the objects implemented within.see below (page 1015).18 Page 35 of 1055 . with clear diagrams and tables showing the dependencies between the units. After a deep presentation of the framework architecture and main features. The SynFile main demo is presented on its own.Synopse mORMot Framework Software Architecture Design 1. and can be used as a general User Guide of its basic ORM features and User Interface generation . 1.18 release of the Synopse mORMot Framework library. each source code unit is detailed. 2013 Introduction The whole Software documentation process follows the typical steps of this diagram: User Requirements Regulatory Requirements System-wide Risk Assessment define defines Design Inputs (DI) SW FMEA (RK) are specified by Specifications (SWRS) is implemented by Architecture + Design (SAD+SDD) refers to is associated to Test + Documentation Design Inputs. use the GNU General Public License for most of our software. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. without any warranty of any kind. . receive or can get the source code.Rev. you have certain responsibilities if you distribute copies of the software. too. whether gratis or for a fee. and that you know you can do these things. Preamble The GNU General Public License is a free. 29 June 2007 Copyright (C) 2007 Free Software Foundation.Synopse work on the framework is distributed without any warranty.info/forum. We.http://synopse. the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. the Free Software Foundation. Software Requirements Specifications (SWRS) document items are linked directly to the class or function involved with the Software Design Document (SDD) document. too. we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore.This documentation is released under the GPL (GNU General Public License) terms. By contrast.info/fossil.Synopse can provide additional support. To protect your rights. You can apply it to your programs. You must make sure that they. When we speak of free software. if you distribute copies of such a program.. we are referring to freedom. you must pass on to the recipients the same freedoms that you received.see below (page 312). <http://fsf. . . GNU General Public License GNU GENERAL PUBLIC LICENSE Version 3. Developers that use the GNU GPL protect your rights with two steps: Software Architecture Design . which publishes also the latest version of the project source code. not price.. expertise or enhancements. from the source code. 2013 At the end of this document.Support is available in the project forum .Synopse mORMot Framework Software Architecture Design 1. or if you modify it: responsibilities to respect the freedom of others. . Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish).org/> Everyone is permitted to copy and distribute verbatim copies of this license document.18 Page 36 of 1055 . Inc. Responsibilities .from the mORMot Open Source community. it applies also to any other work released this way by its authors. For example. that you can change the software or use pieces of it in new free programs. that you receive source code or can get it if you want it. on request. according to the chosen license terms .18 Date: June 16. . copyleft license for software and other kinds of works. And you must show them these terms so they know their rights. . 1.Tickets can be created in a public Tracker web site located at http://synopse. but changing it is not allowed. 18 Date: June 16. States should not allow patents to restrict development and use of software on general-purpose computers. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. other than the making of an exact copy. is not conveying. so that their problems will not be attributed authors of previous versions. To prevent this. such as semiconductor masks. we stand ready to extend this provision to those domains in future versions of the GPL. TERMS AND CONDITIONS 0. Each licensee is addressed as "you". with no transfer of a copy. although the manufacturer can do so. would make you directly or secondarily liable for infringement under applicable copyright law. which is precisely where it is most unacceptable. Definitions. Therefore. "Licensees" and "recipients" may be individuals or organizations. "The Program" refers to any copyrightable work licensed under this License. the GPL that there is no warranty for this free software. "This License" refers to version 3 of the GNU General Public License. Mere interaction with a user through a computer network. To "propagate" a work means to do anything with it that. For authors' sake. as needed to protect the freedom of users. without permission. except executing it on a computer or modifying a private copy. The systematic pattern of such abuse occurs in the area of products for individuals to use. the GPL requires that modified versions changed. 2013 (1) assert copyright on the software. but in those that do. clearly explains both users' and be marked as erroneously to Some devices are designed to deny users access to install or run modified versions of the software inside them. the GPL assures that patents cannot be used to render the program non-free.18 Page 37 of 1055 . Propagation includes copying. 1. A "covered work" means either the unmodified Program or a work based on the Program. distribution (with or without modification). For the developers' and authors' protection. distribute and/or modify it. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work.Rev. every program is threatened constantly by software patents. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. If such problems arise substantially in other domains. The precise terms and conditions for copying. and in some countries other activities as well. Finally. "Copyright" also means copyright-like laws that apply to other kinds of works. we have designed this version of the GPL to prohibit the practice for those products. distribution and modification follow. making available to the public. and (2) offer you this License giving you legal permission to copy.Synopse mORMot Framework Software Architecture Design 1. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission. we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. Software Architecture Design . or a compiler used to produce the work. including scripts to control those activities. Corresponding Source includes interface definition files associated with source files for the work. such as by intimate data communication or control flow between those subprograms and other parts of the work. and (b) serves only to enable use of the work with that Major Component. This License explicitly affirms your unlimited permission to run the unmodified Program. or to implement a Standard Interface for which an implementation is available to the public in source code form. and (for an executable work) run the object code and to modify the work. All rights granted under this License are granted for the term of copyright on the Program. The "Corresponding Source" for a work in object code form means all the source code needed to generate. 1.18 Page 38 of 1055 . A "Major Component". Software Architecture Design . and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided).Synopse mORMot Framework Software Architecture Design 1. 1.Rev. For example. that (a) is included in the normal form of packaging a Major Component. a prominent item in the list meets this criterion. it does not include the work's System Libraries. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. in this context. and how to view a copy of this License. The "System Libraries" of an executable work include anything. as provided by copyright law. other than the work as a whole. install. and are irrevocable provided the stated conditions are met. one that is widely used among developers working in that language. or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. "Object code" means any non-source form of a work.18 Date: June 16. and so on) of the specific operating system (if any) on which the executable work runs. given its content. window system. or an object code interpreter used to run it. constitutes a covered work. Basic Permissions. means a major essential component (kernel. The Corresponding Source for a work in source code form is that same work. However. and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require. The "source code" for a work means the preferred form of the work for making modifications to it. The output from running a covered work is covered by this License only if the output. but which is not part of that Major Component. 2013 An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice. This License acknowledges your rights of fair use or other equivalent. or. that licensees may convey the work under this License. such as a menu. If the interface presents a list of user commands or options. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body. 2. Source Code. in the case of interfaces specified for a particular programming language. c) You must license the entire work.Rev. you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you. Sublicensing is not allowed. You may convey verbatim copies of the Program's source code as you receive it. 5. 3.18 Page 39 of 1055 . and giving a relevant date. under this License to anyone who comes into possession of a copy. without conditions so long as your license otherwise remains in force. keep intact all notices of the absence of any warranty. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. Conveying Verbatim Copies. This License will therefore apply. Protecting Users' Legal Rights From Anti-Circumvention Law. and you may offer support or warranty protection for a fee. You may convey a work based on the Program. on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. and you disclaim any intention to limit operation or modification of the work as a means of enforcing. run and propagate covered works that you do not convey. as a whole. your or third parties' legal rights to forbid circumvention of technological measures. 2013 You may make. Those thus making or running the covered works for you must do so exclusively on your behalf. Software Architecture Design . to the whole of the work. When you convey a covered work. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996. You may charge any price or no price for each copy that you convey. 4. provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice. keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code. along with any applicable section 7 additional terms. section 10 makes it unnecessary. or similar laws prohibiting or restricting circumvention of such measures. provided that you comply with the terms of this License in conveying all material for which you do not control copyright. provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it.Synopse mORMot Framework Software Architecture Design 1. or provide you with facilities for running those works. in any medium. in the form of source code under the terms of section 4. against the work's users. This requirement modifies the requirement in section 4 to "keep intact all notices". and all its parts. under your direction and control. Conveying Modified Source Versions. or the modifications to produce it from the Program.18 Date: June 16. and give all recipients a copy of this License along with the Program. 1. however. A compilation of a covered work with other separate and independent works. a physical product (including a physical distribution medium). accompanied by a written offer. which are not by their nature extensions of the covered work. e) Convey the object code using peer-to-peer transmission. your work need not make them do so. provided you maintain clear directions next to the object code saying where to find the Corresponding Source. on a durable physical medium customarily used for software interchange. a physical product (including a physical distribution medium). This License gives no permission to license the work in any other way. in one of these ways: a) Convey the object code in. and which are not combined with it such as to form a larger program. d) If the work has interactive user interfaces.Rev. but it does not invalidate such permission if you have separately received it. and only if you received the object code with such an offer. or embodied in. d) Convey the object code by offering access from a designated place (gratis or for a charge). and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. valid for at least three years and valid for as long as you offer spare parts or customer support for that product model. is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. or embodied in. This alternative is allowed only occasionally and noncommercially. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. in accord with subsection 6b. 1. You may convey a covered work in object code form under the terms of sections 4 and 5.18 Page 40 of 1055 . 2013 regardless of how they are packaged. 6. you remain obligated to ensure that it is available for as long as needed to satisfy these requirements.18 Date: June 16. each must display Appropriate Legal Notices. Conveying Non-Source Forms. Regardless of what server hosts the Corresponding Source. If the place to copy the object code is a network server. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. or (2) access to copy the Corresponding Source from a network server at no charge. for a price no more than your reasonable cost of physically performing this conveying of source. You need not require recipients to copy the Corresponding Source along with the object code. b) Convey the object code in. the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities.Synopse mORMot Framework Software Architecture Design 1. if the Program has interactive interfaces that do not display Appropriate Legal Notices. provided Software Architecture Design . to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License. in or on a volume of a storage or distribution medium. provided that you also convey the machine-readable Corresponding Source under the terms of this License. 18 Date: June 16. If additional permissions apply only to part of the Program. 2013 you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. 1. A "User Product" is either (1) a "consumer product". a User Product. or expects or is expected to use. If you convey an object code work under this section in. to the extent that they are valid under applicable law. in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form). Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License. The requirement to provide Installation Information does not include a requirement to continue to provide support service. "normally used" refers to a typical or common use of that class of product. the product. procedures. and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized). industrial or non-consumer uses. and must require no special password or key for unpacking. In determining whether a product is a consumer product. Corresponding Source conveyed.18 Page 41 of 1055 . unless such uses represent the only significant mode of use of the product. or household purposes. or specifically for use in. For a particular product received by a particular user. A separable portion of the object code. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. need not be included in conveying the object code work. or updates for a work that has been modified or installed by the recipient. authorization keys. which means any tangible personal property which is normally used for personal. or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. or with. 7. and Installation Information provided. family. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. but the entire Program remains governed by this License without regard to the additional permissions. whose source code is excluded from the Corresponding Source as a System Library. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. the work has been installed in ROM). But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example.Synopse mORMot Framework Software Architecture Design 1. or (2) anything designed or sold for incorporation into a dwelling. Software Architecture Design . doubtful cases shall be resolved in favor of coverage. that part may be used separately under those permissions. regardless of the status of the particular user or of the way in which the particular user actually uses. reading or copying. "Installation Information" for a User Product means any methods.Rev. A product is a consumer product regardless of whether the product has substantial commercial. the Corresponding Source conveyed under this section must be accompanied by the Installation Information. Additional Terms. warranty. or for the User Product in which it has been modified or installed. or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it. or stated as exceptions. the above requirements apply either way. You may not propagate or modify a covered work except as expressly provided under this License. or d) Limiting the use for publicity purposes of names of licensors or authors of the material. or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient. If the Program as you received it. contains a notice stating that it is governed by this License along with a term that is a further restriction.18 Page 42 of 1055 . may be stated in the form of a separately written license. Software Architecture Design . If you add terms to a covered work in accord with this section. or c) Prohibiting misrepresentation of the origin of that material. or service marks. for which you have or can give appropriate copyright permission. you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License. you may add to a covered work material governed by the terms of that license document. in the relevant source files. for material you add to a covered work. a statement of the additional terms that apply to those files. (Additional permissions may be written to require their own removal in certain cases when you modify the work. and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11).Synopse mORMot Framework Software Architecture Design 1. or any part of it. trademarks. you must place. 8. Any attempt otherwise to propagate or modify it is void. or a notice indicating where to find the applicable terms. you may remove that term. added by you to a covered work.18 Date: June 16. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. or from any part of it. permissive or non-permissive.Rev. 1. 2013 When you convey a copy of a covered work. for any liability that these contractual assumptions directly impose on those licensors and authors. or e) Declining to grant rights under trademark law for use of some trade names. Additional terms. Notwithstanding any other provision of this License. Termination. or requiring that modified versions of such material be marked in reasonable ways as different from the original version. you may at your option remove any additional permissions from that copy.) You may place additional permissions on material. provided that the further restriction does not survive such relicensing or conveying. If a license document contains a further restriction but permits relicensing or conveying under this License. or substantially all assets of one. using. you may not impose a license fee.Rev. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. you do not qualify to receive new licenses for the same material under section 10.18 Date: June 16. unless and until the copyright holder explicitly and finally terminates your license. royalty. An "entity transaction" is a transaction transferring control of an organization. and (b) permanently. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. 9. or importing the Program or any portion of it.18 Page 43 of 1055 . subject to this License. modify and propagate that work. Each time you convey a covered work. and you cure the violation prior to 30 days after your receipt of the notice. Software Architecture Design . by modifying or propagating a covered work. If propagation of a covered work results from an entity transaction. or other charge for exercise of rights granted under this License. For example. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. nothing other than this License grants you permission to propagate or modify any covered work. Moreover. if the predecessor has it or can get it with reasonable efforts. The work thus licensed is called the contributor's "contributor version". These actions infringe copyright if you do not accept this License. Patents. offering for sale. to run. Acceptance Not Required for Having Copies. if you cease all violation of this License. you indicate your acceptance of this License to do so. 1. selling. each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph. If your rights have been terminated and not permanently reinstated. 11. You are not responsible for enforcing compliance by third parties with this License. or subdividing an organization. However. 10.Synopse mORMot Framework Software Architecture Design 1. or merging organizations. plus a right to possession of the Corresponding Source of the work from the predecessor in interest. and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making. your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means. this is the first time you have received notice of violation of this License (for any work) from that copyright holder. You are not required to accept this License in order to receive or run a copy of the Program. the recipient automatically receives a license from the original licensors. 2013 However. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. Automatic Licensing of Downstream Recipients. then your license from a particular copyright holder is reinstated (a) provisionally. Therefore. you convey. to any of the parties who would receive the covered work from you. under which you make payment to the third party based on the extent of your activity of conveying the work. Each contributor grants you a non-exclusive. to make. "Knowingly relying" means you have actual knowledge that.18 Page 44 of 1055 . prior to 28 March 2007. Software Architecture Design . permitted by this License.18 Date: June 16. sell. or propagate by procuring conveyance of. would infringe one or more identifiable patents in that country that you have reason to believe are valid. import and otherwise run. in a manner consistent with the requirements of this License. and under which the third party grants. to extend the patent license to downstream recipients. 2013 A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor. free of charge and under the terms of this License. a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies). not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). knowingly relying on a patent license. In the following three paragraphs. or selling its contributor version. then you must either (1) cause the Corresponding Source to be so available. 1. modify and propagate the contents of its contributor version. propagate. through a publicly available network server or other readily accessible means. prohibits the exercise of. "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. of making.Synopse mORMot Framework Software Architecture Design 1. modify or convey a specific copy of the covered work. unless you entered into that arrangement. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software. and grant a patent license to some of the parties receiving the covered work authorizing them to use. pursuant to or in connection with a single transaction or arrangement. then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. For purposes of this definition. using. a covered work. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. use. or that patent license was granted. offer for sale. royalty-free patent license under the contributor's essential patent claims. worldwide. If you convey a covered work. or (2) arrange to deprive yourself of the benefit of the patent license for this particular work.Rev. If. that would be infringed by some manner. A patent license is "discriminatory" if it does not include within the scope of its coverage. or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. your conveying the covered work in a country. whether already acquired or hereafter acquired. however denominated. but for the patent license. and the Corresponding Source of the work is not available for anyone to copy. but do not include claims that would be infringed only as a consequence of further modification of the contributor version. or (b) primarily for and in connection with specific products or compilations that contain the covered work. or (3) arrange. or your recipient's use of the covered work in a country. a "patent license" is any express agreement or commitment. concerning interaction through a network will apply to the combination as such. then as a consequence you may not convey it at all. Such new versions will be similar in spirit to the present version. However. TO THE EXTENT PERMITTED BY APPLICABLE LAW. 15. Notwithstanding any other provision of this License. The terms of this License will continue to apply to the part which is the covered work. EITHER EXPRESSED OR IMPLIED. 14. Software Architecture Design . If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used. 16. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND. agreement or otherwise) that contradict the conditions of this License. THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. they do not excuse you from the conditions of this License. you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work. Disclaimer of Warranty. you may choose any version ever published by the Free Software Foundation. section 13. no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. but may differ in detail to address new problems or concerns. and to convey the resulting work. Use with the GNU Affero General Public License. No Surrender of Others' Freedom. INCLUDING. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it. SHOULD THE PROGRAM PROVE DEFECTIVE. if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program. that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. For example.18 Page 45 of 1055 . BUT NOT LIMITED TO. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. If conditions are imposed on you (whether by court order. but the special requirements of the GNU Affero General Public License. 2013 12.Rev. 1. If the Program does not specify a version number of the GNU General Public License. Limitation of Liability. YOU ASSUME THE COST OF ALL NECESSARY SERVICING. 13. Each version is given a distinguishing version number. Later license versions may give you additional or different permissions. THERE IS NO WARRANTY FOR THE PROGRAM. Revised Versions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations. the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program.Synopse mORMot Framework Software Architecture Design 1. you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. REPAIR OR CORRECTION.18 Date: June 16. unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. This program is distributed in the hope that it will be useful. attach the following notices to the program.org/licenses/>. the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. 17. Also add information on how to contact you by electronic and paper mail. INCLUDING ANY GENERAL. INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS). type `show c' for details. and you want it to be of the greatest possible use to the public. <one line to give the program's name and a brief idea of what it does. see <http://www. your program's commands might be different. 1. or (at your option) any later version. and you are welcome to redistribute it under certain conditions. reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program.gnu. You should have received a copy of the GNU General Public License along with this program.> Copyright (C) <year> <name of author> This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms. To do so. make it output a short notice like this when it starts in an interactive mode: <program> Copyright (C) <year> <name of author> This program comes with ABSOLUTELY NO WARRANTY.Synopse mORMot Framework Software Architecture Design 1. for a GUI interface. without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. If the program does terminal interaction. Software Architecture Design .Rev. This is free software. either version 3 of the License. See the GNU General Public License for more details. If not. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program. you would use an "about box". and each file should have at least the "copyright" line and a pointer to where the full notice is found. BE LIABLE TO YOU FOR DAMAGES. OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE. EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License.18 Date: June 16. 2013 IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty.18 Page 46 of 1055 . for details type `show w'. SPECIAL. but WITHOUT ANY WARRANTY. Of course. 18 Date: June 16. to sign a "copyright disclaimer" for the program. 2013 You should also get your employer (if you work as a programmer) or school.gnu. if any. 1.org/licenses/>. For more information on this. Software Architecture Design .org/philosophy/why-not-lgpl.gnu.Rev. The GNU General Public License does not permit incorporating your program into proprietary programs. and how to apply and follow the GNU GPL. use the GNU Lesser General Public License instead of this License. you may consider it more useful to permit linking proprietary applications with the library.18 Page 47 of 1055 . If this is what you want to do. if necessary. see <http://www.Synopse mORMot Framework Software Architecture Design 1.html>. If your program is a subroutine library. please read <http://www. But first. see below (page 67): . SAD . or dedicated classes for entities or aggregates. cache. MS SQL. .).see below (page 55). It provides an Open Source self-sufficient set of units (even Delphi starter edition is enough) for creating any Multi-tier application. .Client-Server Services: remote call of high-level data process. including high-level managed types like dynamic arrays or records for Value Objects. Meet the mORMot The main two features of mORMot are therefore: .pas provider (e.Synopse mORMot Framework Software Architecture Design 1. AnyDAC.. OleDB. session. 1. security. with a powerful SQLite3 kernel. Synopse mORMot Overview Synopse mORMot is a Client-Server ORM and Service Oriented Architecture framework (SOA) for Delphi 6 up to XE4. UniDAC. 2013 1.18 Date: June 16.Global Architecture . up to the most complex Domain-Driven design . If you do not know some of those concepts. and direct SQL access if needed.18 Page 48 of 1055 .following a RESTful model using JSON over several communication protocols (including HTTP/1. . .g. ODBC.Domain Model layer handling all the needed business logic in plain Delphi objects. Zeos connection or any DB. FireDAC. logging and testing (framework uses test-driven approach and features stubbing and mocking).Client-Server ORM: objects persistence and remote access. NexusDB. targeting Win32 and Win64 platforms. or rich AJAX clients. don't worry: this document will detail them . DBExpress.Cross-Cutting infrastructure layers for handling data filtering and validation. .Data persistence infrastructure layer with ORM persistence over direct Oracle.Application layer implementing Service Oriented Architecture via interface-based services (like WCF) and Client-Server ORM .Presentation layer featuring MVC UI generation with i18n and reporting for rich Delphi clients..Rev.1). SAD . and you can use it from any RAD or AJAX clients. and our rich SOA architecture is able to implement both vertical and horizontal scalable hosting. But you have also some UI units available (including screen auto-creation. your ROI is maximized. In short. with mORMot. 2013 With mORMot. Service Oriented Architecture. This really makes the difference. including AJAX).Synopse mORMot Framework Software Architecture Design 1. No dependency is needed at the client level (no DB driver. even through a corporate proxy or a VPN. and will be accessible from light clients (written in Delphi or any other mean. 1. The business logic of your applications will be easily exposed as Services. with no installation process.18 Page 49 of 1055 .Global Architecture . Endpoints are configured automatically for each published interface on the server side.see below (page 135): a single server is able to handle a lot of clients. reporting and ribbon GUI). ready to implement Domain-Driven solutions. ORM is not used only for data persistence of objects in databases (like in other implementations).18 Date: June 16. nor third-party runtime): it is able to connect via standard HTTP. and creating a load-balancing proxy is a matter of one method call. The framework Core is non-visual: it provides only a set of classes to be used from code. Speed and scalability has been implemented from the ground up . but as part of a global n-Tier. Rich Delphi clients can be deployed just by copying and running a stand-alone small executable.Rev. 1. depending on some run-time parameters! SAD . using diverse communication protocols: PC 2 PC n Client 2 (AJAX) Client n (Delphi) JSON + REST over HTTP/1. ORM.Client / Server Or the application can be stand-alone: Stand-Alone application Client direct access Server General mORMot architecture .1 Local Network PC Server Server JSON + REST named pipe connection Client 4 (Delphi) General mORMot architecture .see below (page 55). Several clients.Rev.Stand-alone application Switch from this embedded architecture to the Client-Server one is just a matter of how mORMot classes are initialized.1.Synopse mORMot Framework Software Architecture Design 1. the very same executable can even be running as a stand-alone application. a server.18 Page 50 of 1055 . SOA best-practice patterns .18 Date: June 16. Client-Server ORM/SOA framework The Synopse mORMot framework implements a Client-Server RESTful architecture.Global Architecture .1 PC 1 PC 3 Client 1 (Delphi) Client 3 (Delphi) Internet (VPN) JSON + REST over HTTP/1. 2013 1. N-Tier. trying to follow some MVC. can access to the same remote or local server. or a client. For instance. .pas unit nor any third-party (so even the Delphi Starter edition is enough) .Ability to use SQL and RESTful requests over multiple databases at once (thanks to SQLite3 unique Virtual Tables mechanism). TPersistent or TObject (via registration of a custom serializer) instance.g. . FireDAC.Very fast JSON producer and parser. .the code just has to define actions.. UniDAC or even the BDE. .18 Page 51 of 1055 . with any version of Delphi (no need to upgrade your IDE).the SynDB classes are self-sufficient.Fastest available HTTP server using http. with integrated Business rules as fast ORM-based classes (not via external scripting or such) and Domain-Driven design.Truly RESTful authentication with a dual security model (session + per-query). some points can be highlighted. buffered reading and writing avoid most memory consumption. and do not depend on the Delphi DB.Client-Server orientation. . . AnyDAC. without any IDE usage. SAD .but may communicate via named pipes.Full Text Search engine included.sys kernel-mode server .pas based solution (e.More than 1000 pages of documentation.Rev. using custom RESTful JSON services . together with a modern Ribbon ('Office 2007'-like) screen layout .Designed to be as fast as possible (asm used when needed.18 Date: June 16. . with caching at SQL level. via an interface-based contract shared on both client and server sides. . which could serve complex PDF reports from your application. .Global Architecture . or any record content. for Oracle) . .but you SynDBDataset unit is also available to access any DB..Integrated Reporting system. just like JSON). which make this framework distinct to other available solutions: .).) so benchmarks sound impressive when compared to other solutions .Direct User Interface generation: grids are created on the fly. truly Unicode (uses UTF-8 encoding in its kernel. . multi-thread ready architecture. DBExpress. 2013 1.Delphi and AJAX clients can share the same server. TCollection.Service-Oriented-Architecture model.Multi-Tier architecture.so you can enhance it to fulfill any need.2. NexusDB. with integrated JSON serialization. . but true ORM and SOA approach. Highlights At first. .. 1.Full source code provided . .g. or even a dynamic array. with enhanced Google-like ranking algorithm. but able to connect to any other database (via OleDB / ODBC / Zeos or direct client library access e.No RAD components.but can be used in stand-alone applications. in order to construct the whole interface from a few lines of code.Works from Delphi 6 up to XE4. with optimized request caching and intelligent update over a RESTful architecture . . GDI messages or in-process as lighter alternatives.Synopse mORMot Framework Software Architecture Design 1.Using SQLite3 as its kernel.you can send as JSON any TStrings. . and assign them to the tables.see below (page 135).. but with only one way of doing it . minimize costs. . and all regression tests are provided.Integrated: all crosscutting scenarios are coupled.Tested: most of the framework is test-driven.Do-not-reinvent-the-wheel. documented and maintained: project is developed since years. with some active members .Synopse mORMot Framework Software Architecture Design 1. and decrease the overall maintenance effort. . you may suffer from the well-known NIH ("Not Invented Here") syndrome.mORMot won't leave you soon! SAD . .18 Page 52 of 1055 . mORMot provides a comprehensive set of features that can help you to manage your crosscutting concerns though a reusable set of components and core functionality.less configuration and less confusion for the developer and its customers. a lot of code-reuse. reduce the use of precious test resources.KISS design: you have all needed features at hand.Rev. it is a commonly accepted fact that the use of standard and proven code libraries and components can save development time. including system-wide integration tests.Global Architecture . JSON/RESTful orientation from the ground up. On the other side. so you benefit of consisting APIs and documentation.Pascal oriented: implementation is not following existing Java or C# patterns (with generics (ab)use. since we did it for you: it is now time to focus on your business. 1. but try to unleash the object pascal genius. Benefits As you can see from the previous section.3.Open Source. variable syntaxes and black-box approach).18 Date: June 16. Of course. . . like many developers. Benefits of mORMot are therefore: . 2013 1. .see below (page 166).com/articles/Utilizing-Logging. .see below (page 74).Make your application ready to offer a RESTful interface. . in his book Working Effectively With Legacy Code. e.You can little by little move your logic out of the client side code into some server services defined via interfaces.HTTP request may be made available using Client-Server services via methods . which is very easy to use even on the server side (serving PDF files). .see below (page 166). is able to offer dedicated audit and support for such a migration.infoq. .pas code-based system. . to replace some BDE queries. shared on the server side. . A seam is an area where you can start to cleave off some legacy code and begin to introduce changes. pictures or PDF reports. not direct DB .see below (page 1024).see http://www.4.Rev. Even mocking abilities of mORMot .18 Date: June 16. SAD . N-Tier and SOA. Do not forget that Synopse. migrating into SOA is IMHO the main benefit of mORMot for existing projects. still hosted in your external SQL server . Legacy code and existing projects Even if mORMot will be more easily used in a project designed from scratch.see below (page 114). a dedicated SQLite3-based consolidation database or even the caching features .g.Use low-level classes like record or dynamic array wrappers . e. mORMot implements the needed techniques for introducing what Michael Feathers calls. 1. . as a company.see below (page 78). including JSON or binary persistence.will help you in this delicate task .g. The sooner. for retrieving HTML pages generated on the fly. starting with a Delphi 6 edition.. and delegate some queries from your main database.see below (page 229). and can't easily move up due to some third party components or existing code base. when your business logic heavily relies on objects.If you are still using an old version of Delphi. in particular.it may help integrating some CQRS pattern (Command Query Responsibility Segregation) into your application via a RESTful interface. 2013 1. or even creating the server side part of an AJAX application. the better. including the TQuery emulation class.You may benefit from our very fast in-memory engine. for consuming JSON content via AJAX or mobile clients.see below (page 247) . it fits very well the purpose of evolving any existing Delphi project.New tables may be defined via the ORM features of mORMot. Due to its modular design. mixed pure-ORM and regular-SQL requests may coexist. when performance is needed .Reports could benefit of the mORMotReport.Synopse mORMot Framework Software Architecture Design 1. . you can integrate some framework bricks to your existing application: . One benefit of such a framework is to facilitate the transition from a Client-Server architecture to a N-Tier layered pattern. mORMot will offer all the needed features to start ORM.18 Page 53 of 1055 .You may add logging to your code . as any previous data. to track issues and customer-side profiling.see below (page 257). or introduce nice unique features like direct database access or array binding for very fast data insertion . without the overhead of SOAP or WCF . a seam.You can use the direct DB layers.Global Architecture . 5.Because marmots do hibernate. just like our precious objects. . they use to fight at Spring for their realm.Global Architecture .. . and those large ground rodents. mORMot Why is this framework named mORMot? . or whatever you may think of.. 1. . SAD .Because even if they eat greens.Because marmots are highly social and use loud whistles to communicate with one another.Rev.Because we like mountains. just like our applications are designed not to be isolated.Because it may be an acronym for "Manage Object Relational Mapping Over Territory". which may induce a SQLite3-only library.Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16.18 Page 54 of 1055 .Because its initial identifier was "Synopse SQLite3 database framework". whereas the framework is now able to connect to any database engine. . . 2013 1. see below (page 191).18 Date: June 16.Synopse mORMot Framework Software Architecture Design 1. up to complex Domain-Driven design see below (page 67). .see below (page 60).18 Page 55 of 1055 .Multi-tier architecture .Stateless CRUD/REST .Service-oriented architecture . .see below (page 307). .Test-Driven Design .Global Architecture . . 2013 2.see below (page 63). 1.see below (page 65). All those points render possible any project implementation. SAD .Rev.Object-relational mapping . .see below (page 61). Architecture principles Adopt a mORMot This framework tries to implement some "best-practice" patterns.Model-View Controller . among them: . 18 Page 56 of 1055 . and sample code is available to help you discovering the amazing mORMot realm. General design A general design of the mORMot architecture is shown in the following diagram: Cross-Cutting features Client (Delphi) Logging Unit Testing Mocking User Interface JSON Unicode UTF-8 Remote access Objects cache Security Cryptography File process Compression runs Reporting asks asks uses ORM methods over TSQLRecord Services requests RESTful Client uses REST JSON Server Business rules RESTful Server uses Business rules runs requires Services implementation Authentication (users. 1.18 Date: June 16.1.Synopse mORMot Framework Software Architecture Design 1. 2013 2. SAD .Global Architecture . Such a drawing may sound huge and confusing.Rev. especially when you have a RAD background. and did not work much with modern design patterns. Following pages will detail and explain how the framework implements this architecture.Client Server implementation Don't be afraid. sessions) REST to SQL makes CRUD makes CRUD ORM SQlite3 engine makes CRUD external tables SQLite3 data file in-memory tables JSON or binary files SQL External Database 1 External Database 2 General mORMot architecture . Optimized low-level process of binary and text content. .Process can be defined via a set of Services.Databases can be one or several standard RDBMS (with auto-generated SQL).Rev.Client-Server architecture. . SAD .Data is mapped by objects (ORM).Security (authentication and authorization) is integrated to all layers. . .Layered (multi-tier) implementation.A consistent testing and debugging API is integrated. .Global Architecture . .Transmitting some JSON content over a RESTful architecture. or fast in-memory objects lists.18 Page 57 of 1055 . . .Business rules and data model are shared on both Client and Server sides. 1. .Synopse mORMot Framework Software Architecture Design 1.User interface and reporting classes are available. 2013 In the previous diagram.18 Date: June 16. . you can already identify some key concepts of mORMot: . Let architecture be decided at so high level that it won't affect the actual coding style of the developers (just don't be caught). how to implement the use cases.Let each team decides. .Rev. Architecture is part of the coding. from his/her own knowledge (and mood?). Even if some people of your company may be in charge of global software architecture. nor just about best practice. Architecture is always driven by the actual needs of the application. with no system-wide collaboration. or even if your project managements follows a classic V-cycle and does not follow the agile manifesto.2. with no review. Team BackLog Use Cases Design Architecture Proposal Risk Assessment Technology & Models Dev Tasks Requirements Definition of Done Customer Software Client Architecture Iterative Process (SCRUM) This diagram presents how Architecture is part of a typical SCRUM iterative agile process. 1. nor peer collaboration. SAD . .18 Date: June 16.18 Page 58 of 1055 . There is no such "one architecture fits all" nor "one framework fits all" solution. architecture should never be seen as a set of rules. Architecture Design Process First point is to state that you can't talk about architecture in isolation. from its own knowledge (and untold internal leadership?). not by whatever the architect read about last night and is dying to see how it works in the real world. 2013 2.Global Architecture . but about a way of implementing a working solution for your customers.Synopse mORMot Framework Software Architecture Design 1. to be applied by every and each developers. In fact. but not all the coding. Architecture is just a thinking of how you are building your own software. how to implement the use cases. implementation documentation. software architecture is not about theory and diagrams.Let each developer decides. Here are some ways of achieving weak design: . Purpose of frameworks like mORMot is to provide your teams with working and integrated set of classes. i.Let architecture be so much detailed that each code line has to follow a typical implementation pattern.Synopse mORMot Framework Software Architecture Design 1.no one is alone.18 Page 59 of 1055 . .Sharing is a need . .Long term is prepared by today's implementation. . 2013 . some advices: . no team is better. .Global Architecture . . .e.between individuals.Collaboration is a need . with managers.They did not know it was impossible. with some middle-term objectives at best. as teams. try to make tomorrow's work easier for you and your team-workers. therefore producing over engineered code.Let architecture map the existing. Therefore. enjoying the collaboration with other Open Source users. SAD . frameworks or just-blogged ideas be used with no discrimination (do not trust the sirens of dev marketing).18 Date: June 16. .Let technology. 1.Stay customer and content focused. in order to use evolving and pertinent software architecture. so they did it. no manager is always right.Be lazy.Rev. so that you can focus on your product. Rev. can be implemented via some custom TSQLRecord classes or via custom RESTful Services .Global Architecture . and responds to instructions to change state (usually from the controller). both database-related and business-logic related.see below (page 227). it does not need to handle those events .see below (page 193).18 Date: June 16.18 Page 60 of 1055 . the model is not necessarily merely a database. The pattern isolates "domain logic" (the application logic for the user) from the user interface (input and presentation). AJAX clients can also be used RESTful and JSON will make it easy. testing and maintenance of each (separation of concerns). responds to requests for information about its state (usually from the view). Model-View-Controller The Model-View-Controller (MVC) is a software architecture. 1. The view is currently only all the User-Interface part of the framework. within the RESTful commands. It will use the model as reference for rendering the data. A controller accepts input from the user and instructs the model and viewport to perform actions based on that input. The view renders the model into a form suitable for interaction. In event-driven systems. Some custom actions. The controller receives user input and initiates a response by making calls on model objects. SAD . The controller is mainly already implemented in our framework. In our ORM.g.Synopse mORMot Framework Software Architecture Design 1. related to the business logic. which is mostly auto-generated from code. the model in MVC is both the data and the business/domain logic needed to manipulate the data in the application. A viewport typically has a one to one correspondence with a display surface and knows how to render to it.3. which centralizes all TSQLRecord inherited classes used by an application. for refreshing the User Interface) and model (for data handling). indirect association indirect association Model View direct association direct association Controller Model View Controller concept In the framework. the model notifies observers (usually views) when the information changes so that they can react . a model is implemented via a TSQLModel class. and will interact with both the associated view (e. currently considered an architectural pattern used in software engineering. The model manages the behavior and data of the application domain. 2013 2. typically a user interface element. permitting independent development. Multiple views can exist for a single model for different purposes.but since our ORM is stateless. 4.Logic Tier is performed by pure ORM aspect and SOA implementation: you write Delphi classes which are mapped by the Data Tier into the database.18 Date: June 16. For example. The most widespread use of multi-tier architecture is the three-tier architecture. by using RTTI and structures.see below (page 166). and you can write your business logic as Services called as Delphi interface. the application processing.and the Ajax applications need to be written by using your own tools and JavaScript framework. Both ORM and SOA aspects of our RESTful framework make it easy to develop using such a three-tier architecture. SAD .g. an application that uses middle-ware to service data requests between a user and a database employs multi-tier architecture. 1. 2013 2. up to a Domain-Driven design .1 (the Delphi Client User Interface is generated from Code.Rev. In fact.Presentation Tier which can be e. .Synopse mORMot Framework Software Architecture Design 1.Application Tier which serves JSON content according to the client application. there is no "official" Ajax framework included yet).Persistence/Data Tier which can be either in-process (like SQLite3 or in-memory) or external (like Oracle / MS SQL Server). shared among all applications.see below (page 67) as such: .18 Page 61 of 1055 .see below (page 67) .Data Tier is either SQLite3 and/or an internal very fast in-memory database.Global Architecture . and database table layout are defined from Delphi classes. a Delphi or AJAX client. . multi-tier architecture (often referred to as n-tier architecture) is a client–server architecture in which the presentation.if your project reaches some level of complexity. .Presentation Tier is either a Delphi Client. or an AJAX application. not as a RAD . . . and the data management are logically separate processes.Logical View The Synopse mORMot Framework follows this development pattern: . mORMot can scales up to a Domain-Driven Design four-tier architecture .Business Logic Tier which centralizes all the Domain processing. Presentation Tier Logic Tier Data Tier Multi-Tier Architecture . because the framework can communicate using RESTful JSON over HTTP/1. most SQL queries are created on the fly. you can also use external databases (as MS SQL Server or Oracle) . Multi-tier architecture In software engineering. Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 Presentation Tier Application Tier Business Logic Tier Data Tier Domain Driven Design n-Tier Architecture - Logical View Note that you have to make a difference between physical and logical n-tier architecture. Most of the time, n-Tier is intended to be a physical (hardware) view, for instance a separation between the database server and the application server, placing the database on a separate machine to facilitate ease of maintenance. In mORMot, and more generally in SOA - see below (page 63), we deal with logical layout, with separation of layers through interfaces - see below (page 236) - and the underlying hardware implementation will usually not match the logical layout. Client 1 (Delphi) Presentation Tier Client 2 (AJAX) Presentation Tier Application Server Application Tier Business Logic Tier DB Server Data Tier Domain Driven Design n-Tier Architecture - Physical View In this document, we will focus on the logical way of thinking / coding, letting the physical deployment be made according to end-user expectations. SAD - Global Architecture - Rev. 1.18 Page 62 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 2.5. Service-oriented architecture Service-oriented architecture (SOA) is a flexible set of design principles used during the phases of systems development and integration in computing. A system based on a SOA will package functionality as a suite of inter-operable services that can be used within multiple, separate systems from several business domains. The SOA implementations rely on a mesh of software services. Services comprise unassociated, loosely coupled units of functionality that have no calls to each other embedded in them. Each service implements one action, such as filling out an online application for an account, or viewing an online bank statement, or placing an online booking or airline ticket order. Rather than services embedding calls to each other in their source code, they use defined protocols that describe how services pass and parse messages using description meta-data. Consumers Service Bus Publishers Client A Publisher 1 Service 1 Client B Publisher 2 Service 2 Client C Publisher 3 Service 3 Service Oriented Architecture - Logical View For more details about SOA, see http://en.wikipedia.org/wiki/Service-oriented_architecture.. SOA is mainly about decoupling. That is, it enables implementation independence in a variety of ways, for instance: Dependency Desired decoupling Decoupling technique Platform Hardware, Framework or Operating System should not constrain choices of the Services consumers Standard protocols, mainly Web services (e.g. SOAP or RESTful/JSON) Location Consumers may not be impacted by service hosting changes Routing and proxies will maintain Services access Availability Maintenance tasks shall be transparent Remote access allows centralized support on Server side Versions New services shall be introduced without requiring upgrades of clients Contract marshaling can be implemented on the Server side SOA and ORM - see below (page 65) - do not exclude themselves. In fact, even if some software architects tend to use only one of the two features, both can coexist and furthermore complete each other, in any Client-Server application: - ORM access could be used to access to the data with objects, that is with the native presentation of the Server or Client side (Delphi, JavaScript...) - so ORM can be used to provide efficient access to the data or the business logic - this is the idea of CQRS pattern; SAD - Global Architecture - Rev. 1.18 Page 63 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 - SOA will provide a more advanced way of handling the business logic: with custom parameters and data types, it is possible to provide some high-level Services to the clients, hiding most of the business logic, and reducing the needed bandwidth. In particular, SOA will help leaving the business logic on the Server side, therefore will help increasing the Multi-tier architecture (page 61). By reducing the back-and-forth between the Client and the Server, it will also reduce the network bandwidth, and the Server resources (it will always cost less to run the service on the Server than run the service on the Client, adding all remote connection and serialization to the needed database access). Our interface-based SOA model allows the same code to run on both the client and the server side, with a much better performance on the server side, but a full interoperability of both sides. SAD - Global Architecture - Rev. 1.18 Page 64 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 2.6. Object-relational mapping Before defining what an ORM is, let's face one drawback of using a database via an object-oriented language like Delphi is that you must have your objects interact with the database. Some implementation schemes are possible, in which are some pros and cons. First, here is a diagram presenting the possible implementation schemes of database access with Delphi. UI Components RAD DataBase UI UI MVC binding code mapping Delphi classes UI 2 (web) MVC binding ORM Handwritten SQL DataBase UI 1 MVC binding Client 1 Generated SQL Database Client 2 Secure protocol (REST) Server Persistence layer ORM Generated SQL Database Why a Client-Server ORM The table below is a very suggestive (but it doesn't mean wrong) Resumé of some common schemes, in the Delphi world. ORM is just one nice possibility among others. Scheme Use DB views and tables, with GUI components Pros Cons - SQL is a powerful language - Can use high-level DB tools (UML) and RAD approach - Business logic can't be elaborated without stored procedures - SQL code and stored procedures will bind you to a DB engine - Poor Client interaction - Reporting must call the DB directly - No Multi-tier architecture SAD - Global Architecture - Rev. 1.18 Page 65 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 Map DB tables or views with Delphi classes - Can use elaborated business logic, in Delphi - Separation from UI and data - SQL code must be coded by hand and synchronized with the classes - Code tends to be duplicated - SQL code could bind you to a DB engine - Reports can be made from code or via DB related tools - Difficult to implement true Multi-tier architecture Use a Database ORM - Can use very elaborated business logic, in Delphi - SQL code is generated (in most cases) by the ORM - ORM will adapt the generated SQL to the DB engine - More abstraction needed at design time (no RAD approach) - In some cases, could lead to retrieve more data from DB than needed - Not yet a true Multi-tier architecture, because ORM is for DB access only and business logic will need to create separated classes Use a Client-Server ORM - Can use very elaborated business logic, in Delphi - SQL code is generated (in most cases) by the ORM - ORM will adapt the generated SQL to the DB engine - Services will allow to retrieve or process only needed data - Server can create objects viewed by the Client as if they were DB objects, even if they are only available in memory or the result of some business logic defined in Delphi - Complete Multi-tier architecture - More abstraction needed at design time (no RAD approach) Of course, you'll find out that our framework implements a Client-Server ORM, which can be down-sized to stand-alone mode if needed, but which is, thanks to its unique implementation, scalable to any complex Domain-Driven Design. As far as we found out, looking at every language and technology around, almost no other ORM supports such a native Client-Server orientation. Usual practice is to use a Service-oriented architecture (page 63) for remote access to the ORM. Some projects allow remote access to an existing ORM, but they are separated projects. Our mORMot is pretty unique, in respect to its RESTful Client-Server orientation, from the ground up. SAD - Global Architecture - Rev. 1.18 Page 66 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 2.7. Domain-Driven design The "official" definition of Domain-Driven design is supplied at http://domaindrivendesign.org.. : Over the last decade or two, a philosophy has developed as an undercurrent in the object community. The premise of domain-driven design is two-fold: - For most software projects, the primary focus should be on the domain and domain logic; - Complex domain designs should be based on a model. Domain-driven design is not a technology or a methodology. It is a way of thinking and a set of priorities, aimed at accelerating software projects that have to deal with complicated domains. It can be implemented in a kind of Multi-tier architecture (page 61). In this case, we are talking about N-Layered Domain-Oriented Architecture. It involves a common representation splitting the Logic Tier into two layers, i.e. Application layer and Domain Model layer. Of course, this particular layered architecture is customizable according to the needs of each project. We simply propose following an architecture that serves as a baseline to be modified or adapted by architects according to their needs and requirements. See http://msdn.microsoft.com/en-us/magazine/dd419654.aspx.. for a general presentation of the corresponding concepts, in the .NET world. It could be presented as in the following n-Tier model: Layer Description Presentation MVC UI generation and reporting Application Services and high-level adapters Domain Model Where business logic remains Data persistence ORM and external services Cross-Cutting Horizontal aspects shared by other layers In fact, this design matches perfectly the RESTful SOA approach of the Synopse mORMot framework. See the following diagram: SAD - Global Architecture - Rev. 1.18 Page 67 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 Presentation Reporting AJAX i18n REST Client UI HTTP 1.1 Application REST Server Domain Model Services Data persistence ORM Cross-Cutting Security Sessions SQLite3 Cache Filtering Validation Logging External DB N-Layered Domain-Oriented Architecture of mORMot In fact, since a Service-oriented architecture (page 63) tends to ensure that services comprise unassociated, loosely coupled units of functionality that have no calls to each other embedded in them, we may define two levels of services, implemented by two interface factories, using their own hosting and communication: - One set of services at Application layer, to define the uncoupled contracts available from Client applications; - One set of services at Domain Model layer, which will allow all involved domains to communicate with each other, without exposing it to the remote clients. Therefore, those layers could be also implemented as such: Application Application REST Client HTTP 1.1 Domain Model Application REST Server Application Services Domain REST Client Fast RPC Domain REST Server Domain Services ORM Alternate Domain-Oriented Architecture of mORMot Due to the SOLID design of mORMot - see below (page 239) - you can use as many Client-Server SAD - Global Architecture - Rev. 1.18 Page 68 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 services layers as needed in the same architecture (i.e. a Server can be a Client of other processes), in order to fit your project needs, and let it evolve from the simplest architecture to a full scalable Domain-Driven design. In order to provide the better scaling of the server side, cache can be easily implemented at every level, and hosting can be tuned in order to provide the best response time possible: one central server, several dedicated servers for application, domain and persistence layers... For a technical introduction about DDD and how mORMot can help you implement this design, see below (page 304). With mORMot, your software solution will never be stuck in a dead-end. You'll be able to always adapt to your customers need, and maximize your ROI. SAD - Global Architecture - Rev. 1.18 Page 69 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 3. Enter new territory 3.1. Meet the mORMot The Synopse mORMot framework consists in a huge number of units, so we will start by introducing them. SynDBSQlite3.pas SynDBOracle.pas SynDBODBC.pas SynOleDB.pas SynDBZEOS.pas SynDBDataset.pas SynDBFireDAC.pas SynDBUniDAC.pas SynDBNexusDB.pas SynDBBDE.pas SynDB.pas SynSQLite3.pas mORMotDB.pas SynCommons.pas mORMotSQlite3.pas mORMot.pas mORMotHttpClient.pas mORMotHttpServer.pas SynCrtSock.pas mORMotUI.pas mORMotToolBar.pas mORMoti18n.pas mORMotUILogin.pas mORMotUIEdit.pas mORMotUIQuery.pas mORMotUIOptions.pas mORMotReport.pas SynPdf.pas mORMot Source Code Main Units When you will finish reading this document, you won't be afraid any more! :) SAD - mORMot Framework - Rev. 1.18 Page 70 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 3.2. Main units The main units you have to be familiar with are the following: Unit name Description SynCommons.pas Common types, classes and functions mORMot.pas Main unit of the ORM / SOA framework SynSQLite3.pas SynSQLite3Static.pas SQLite3 database engine mORMotSQLite3.pas Bridge between mORMot.pas and SynSQLite3.pas SynDB.pas SynDB*.pas Direct RDBMS access classes mORMotDB.pas ORM external SynDB.pas access, via SQlite3 virtual tables SynCrtSock.pas Implements HTTP/1.1 client and server protocol mORMotHttpClient.pas mORMotHttpServer.pas RESTful HTTP/1.1 Client and Server mORMotUI*.pas Grid and Forms User Interface generation mORMotToolBar.pas ORM ToolBar User Interface generation mORMotReport.pas Integrated Reporting engine Other units are available in the framework source code repository, but are either expected by those files above (e.g. like SynDB*.pas database providers), or used only optionally in end-user client applications. In the following pages, the features offered by those units will be presented. Do not forget to take a look at all sample projects available in the SQLite3\Samples sub-folders - nothing is better than some simple code to look at. Then detailed information will be available in the second part of this document - see below (page 312). SAD - mORMot Framework - Rev. 1.18 Page 71 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 4. SynCommons unit Adopt a mORMot First of all, let us introduce some cross-cutting features, used everywhere in the Synopse source code. Even if you do not need to go deeply into the implementation details, it will help you not be disturbed with some classes and types you may encounter in the framework source, and its documentation. It was a design choice to use some custom low-level types, classes and functions instead of calling the official Delphi RTL. Benefits could be: - Cross-platform and cross-compiler support (e.g. leverage specificities, about memory model or RTTI); - Unicode support for all version of Delphi, even before Delphi 2009, or with FPC; - Optimized for process speed, multi-thread friendliness and re-usability; - Sharing of most common features (e.g. for text/data processing); - KISS design. In order to use Synopse mORMot framework, you should better be familiar with some of those definitions. First of all, a Synopse.inc include file is provided, and appears in most of the framework units: {$I Synopse.inc} // define HASINLINE USETYPEINFO CPU32 CPU64 It will define some conditionals, helping write portable and efficient code. In the following next paragraphs, we'll comment some main features of the lowest-level part of the framework, mainly located in SynCommons.pas: - Unicode and UTF-8; - Currency type; - Dynamic array wrappers (TDynArray and TDynArrayHashed); - Logging. SAD - mORMot Framework - Rev. 1.18 Page 72 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 4.1. Unicode and UTF-8 Our mORMot Framework has 100% UNICODE compatibility, that is compilation under Delphi 2009/2010/XE/XE2/XE3/XE4. The code has been deeply rewritten and tested, in order to provide compatibility with the String=UnicodeString paradigm of these compilers. But the code will also handle safely Unicode for older versions, i.e. from Delphi 6 up to Delphi 2007. Since our framework is natively UTF-8 (this is the better character encoding for fast JSON streaming/parsing and it is natively supported by the SQLite3 engine), we had to establish a secure way our framework used strings, in order to handle all versions of Delphi (even pre-Unicode versions, especially the Delphi 7 version we like so much), and provide compatibility with the Free Pascal Compiler. Some string types have been defined, and used in the code for best cross-compiler efficiency (avoiding most conversion between formats): - RawUTF8 is used for every internal data usage, since both SQLite3 and JSON do expect UTF-8 encoding; - WinAnsiString where WinAnsi-encoded AnsiString (code page 1252) are needed; - Generic string for i18n (e.g. in unit mORMoti18n), i.e. text ready to be used within the VCL, as either AnsiString (for Delphi 2 to 2007) or UnicodeString (for Delphi 2009 and later); - RawUnicode in some technical places (e.g. direct Win32 *W() API call in Delphi 7) - note: this type is NOT compatible with Delphi 2009 and later UnicodeString; - RawByteString for byte storage (e.g. for FileFromString() function); - SynUnicode is the fastest available Unicode native string type, depending on the compiler used (i.e. WideString before Delphi 2009, and UnicodeString since); - Some special conversion functions to be used for Delphi 2009+ UnicodeString (defined inside {$ifdef UNICODE}...{$endif} blocks); - Never use AnsiString directly, but one of the types above. Note that RawUTF8 is the preferred string type to be used in our framework when defining textual properties in a TSQLRecord and for all internal data processing. It is only when you're reaching the User Interface layer that you may convert explicitly the RawUTF8 content into the generic VCL string type, using either the Language. UTF8ToString method (from mORMoti18n.pas unit) or the following function from SynCommons.pas: /// convert any UTF-8 encoded String into a generic VCL Text // - it's prefered to use TLanguageFile.UTF8ToString() in mORMoti18n.pas, // which will handle full i18n of your application // - it will work as is with Delphi 2009+ (direct unicode conversion) // - under older version of Delphi (no unicode), it will use the // current RTL codepage, as with WideString conversion (but without slow // WideString usage) function UTF8ToString(const Text: RawUTF8): string; Of course, the StringToUTF8 method or function are available to send back some text to the ORM layer. A lot of dedicated conversion functions (including to/from numerical values) are included in SynCommons.pas. Those were optimized for speed and multi-thread capabilities, and to avoid implicit conversions involving a temporary string variable. Warning during the compilation process are not allowed, especially under Unicode version of Delphi (e.g. Delphi 2010): all string conversion from the types above are made explicitly in the framework's code, to avoid any unattended data loss. SAD - mORMot Framework - Rev. 1.18 Page 73 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 4.2. Currency handling Faster and safer way of comparing two currency values is certainly to map the variables to their internal Int64 binary representation, as such: function var A64: B64: begin result end; CompCurrency(var A,B: currency): Int64; Int64 absolute A; Int64 absolute B; := A64-B64; This will avoid any rounding error during comparison (working with *10000 integer values), and will be faster than the default implementation, which uses the FPU (or SSE2 under x64 architecture) instructions. You some direct currency handling in the SynCommons.pas unit. It will by-pass the FPU use, and is therefore very fast. There are some functions using the Int64 binary representation (accessible either as PInt64(@aCurrencyVar)^ or the absolute syntax): - function Curr64ToString(Value: Int64): string; - function StrToCurr64(P: PUTF8Char): Int64; - function Curr64ToStr(Value: Int64): RawUTF8; - function Curr64ToPChar(Value: Int64; Dest: PUTF8Char): PtrInt; - function StrCurr64(P: PAnsiChar; const Value: Int64): PAnsiChar; Using those functions can be much faster for textual conversion than using the standard FloatToText() implementation. They are validated with provided regression tests. Of course, in normal code, it is certainly not worth using the Int64 binary representation of currency, but rely on the default compiler/RTL implementation. In all cases, having optimized functions was a need for both speed and accuracy of our ORM data processing, and also for below (page 166). 4.3. Dynamic array wrapper The SynCommons unit has been enhanced, since version 1.13: - BinToBase64 and Base64ToBin conversion functions; - Low-level RTTI functions for handling record types: RecordEquals, RecordSave, RecordSaveLength, RecordLoad; - TDynArray and TDynArrayHashed objects, which are wrappers around any dynamic array. With TDynArray, you can access any dynamic array (like TIntegerDynArray = array of integer) using TList-like properties and methods, e.g. Count, Add, Insert, Delete, Clear, IndexOf, Find, Sort and some new methods like LoadFromStream, SaveToStream, LoadFrom, SaveTo, Slice, Reverse, and AddArray. It includes e.g. fast binary serialization of any dynamic array, even containing strings or records - a CreateOrderedIndex method is also available to create individual index according to the dynamic array content. You can also serialize the array content into JSON, if you wish. One benefit of dynamic arrays is that they are reference-counted, so they do not need any Create/try..finally...Free code, and are well handled by the Delphi compiler (access is optimized, and all array content will be allocated at once, therefore reducing the memory fragmentation and CPU cache slow-down). SAD - mORMot Framework - Rev. 1.18 Page 74 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 They are no replacement to a TCollection nor a TList (which are the standard and efficient way of storing class instances, and are also handled as published properties since revision 1.13 of the framework), but they are very handy way of having a list of content or a dictionary at hand, with no previous class nor properties definition. You can look at them like Python's list, tuples (via records handling) and dictionaries (via Find method, especially with the dedicated TDynArrayHashed wrapper), in pure Delphi. Our new methods (about searching and serialization) allow most usage of those script-level structures in your Delphi code. In order to handle dynamic arrays in our ORM, some RTTI-based structure were designed for this task. Since dynamic array of records should be necessary, some low-level fast access to the record content, using the common RTTI, has also been implemented (much faster than the "new" enhanced RTTI available since Delphi 2010). 4.3.1. TList-like properties Here is how you can have method-driven access to the dynamic array: type TGroup: array of integer; var Group: TGroup; GroupA: TDynArray; i, v: integer; begin GroupA.Init(TypeInfo(TGroup),Group); // associate GroupA with Group for i := 0 to 1000 do begin v := i+1000; // need argument passed as a const variable GroupA.Add(v); end; v := 1500; if GroupA.IndexOf(v)<0 then // search by content ShowMessage('Error: 1500 not found!'); for i := GroupA.Count-1 downto 0 do if i and 3=0 then GroupA.Delete(i); // delete integer at index i end; This TDynArray wrapper will work also with array of string or array of records... Records need only to be packed and have only not reference counted fields ( byte, integer, double...) or string reference-counted fields (no Variant nor Interface within). But TDynArray is able to handle records within records, and even dynamic arrays within records. Yes, you read well: it will handle a dynamic array of records, in which you can put some strings or whatever data you need. The IndexOf() method will search by content. That is e.g. for an array of record, all record fields content (including string properties) must match. Note that TDynArray is just a wrapper around an existing dynamic array variable. In the code above, Add and Delete methods are modifying the content of the Group variable. You can therefore initialize a TDynArray wrapper on need, to access more efficiently any native Delphi dynamic array. TDynArray doesn't contain any data: the elements are stored in the dynamic array variable, not in the TDynArray instance. SAD - mORMot Framework - Rev. 1.18 Page 75 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 4.3.2. Enhanced features Some methods were defined in the TDynArray record/object, which are not available in a plain TList - with those methods, we come closer to some native generics implementation: - Now you can save and load a dynamic array content to or from a stream or a string (using LoadFromStream/SaveToStream or LoadFrom/SaveTo methods) - it will use a proprietary but very fast binary stream layout; - And you can sort the dynamic array content by two means: either in-place (i.e. the array elements content is exchanged - use the Sort method in this case) or via an external integer index look-up array (using the CreateOrderedIndex method - in this case, you can have several orders to the same data); - You can specify any custom comparison function, and there is a new Find method will can use fast binary search if available. Here is how those new methods work: var Test: RawByteString; ... Test := GroupA.SaveTo; GroupA.Clear; GroupA.LoadFrom(Test); GroupA.Compare := SortDynArrayInteger; GroupA.Sort; for i := 1 to GroupA.Count-1 do if Group[i]<Group[i-1] then ShowMessage('Error: unsorted!'); v := 1500; if GroupA.Find(v)<0 then // fast binary search ShowMessage('Error: 1500 not found!'); Some unique methods like Slice, Reverse or AddArray are also available, and mimic well-known Python methods. Still closer to the generic paradigm, working for Delphi 6 up to XE4, without the need of the slow enhanced RTTI... 4.3.3. Capacity handling via an external Count One common speed issue with the default usage of TDynArray is that the internal memory buffer is reallocated when you change its length, just like a regular Delphi dynamic array. That is, whenever you call Add or Delete methods, an internal call to SetLength(DynArrayVariable) is performed. This could be slow, because it always executes some extra code, including a call to ReallocMem. In order not to suffer for this, you can define an external Count value, as an Integer variable. In this case, the Length(DynArrayVariable) will be the memory capacity of the dynamic array, and the exact number of stored item will be available from this Count variable. A Count property is exposed by TDynArray, and will always reflect the number of items stored in the dynamic array. It will point either to the external Count variable, if defined; or it will reflect the Length(DynArrayVariable), just as usual. A Capacity property is also exposed by TDynArray, and will reflect the capacity of the dynamic array: in case of an external Count variable, it will reflect Length(DynArrayVariable). As a result, adding or deleting items could be much faster. SAD - mORMot Framework - Rev. 1.18 Page 76 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 var Group: TIntegerDynArray; GroupA: TDynArray; GroupCount, i, v: integer; begin GroupA.Init(TypeInfo(TGroup),Group,@GroupCount); GroupA.Capacity := 1023; // reserver memory for i := 0 to 1000 do begin v := i+1000; // need argument passed as a const variable GroupA.Add(v); // faster than with no external GroupCount variable end; Check(GroupA.Count=1001); Check(GroupA.Capacity=1023); Check(GroupA.Capacity=length(Group)); 4.3.4. JSON serialization The TDynArray wrapper features some native JSON serialization abilities: TTextWriter. AddDynArrayJSON and TDynArray. LoadFromJSON methods are available for UTF-8 JSON serialization of dynamic arrays. See below (page 186) for all details about this unique feature. 4.3.5. Daily use The TTestLowLevelCommon._TDynArray and _TDynArrayHashed methods implement the automated unitary tests associated with these wrappers. You'll find out there samples of dynamic array handling and more advanced features, with various kind of data (from plain TIntegeryDynArray to records within records). The TDynArrayHashed wrapper allow implementation of a dictionary using a dynamic array of record. For instance, the prepared statement cache is handling by the following code in SynSQLite3.pas: TSQLStatementCache = record StatementSQL: RawUTF8; Statement: TSQLRequest; end; TSQLStatementCacheDynArray = array of TSQLStatementCache; TSQLStatementCached = object Cache: TSQLStatementCacheDynArray; Count: integer; Caches: TDynArrayHashed; DB: TSQLite3DB; procedure Init(aDB: TSQLite3DB); function Prepare(const GenericSQL: RaWUTF8): PSQLRequest; procedure ReleaseAllDBStatements; end; Those definitions will prepare a dynamic array storing a TSQLRequest and SQL statement association, with an external Count variable, for better speed. It will be used as such in TSQLRestServerDB: constructor TSQLRestServerDB.Create(aModel: TSQLModel; aDB: TSQLDataBase); begin fStatementCache.Init(aDB); (...) The wrapper will be initialized in the object constructor: SAD - mORMot Framework - Rev. 1.18 Page 77 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 procedure TSQLStatementCached.Init(aDB: TSQLite3DB); begin Caches.Init(TypeInfo(TSQLStatementCacheDynArray),Cache,nil,nil,nil,@Count); DB := aDB; end; The TDynArrayHashed.Init method will recognize that the first TSQLStatementCache field is a RawUTF8, so will set by default an AnsiString hashing of this first field (we could specify a custom hash function or content hashing by overriding the default nil parameters to some custom functions). So we can specify directly a GenericSQL variable as the first parameter of FindHashedForAdding, since this method will only access to the first field RawUTF8 content, and won't handle the whole record content. In fact, the FindHashedForAdding method will be used to make all the hashing, search, and new item adding if necessary - just in one step. Note that this method only prepare for adding, and code needs to explicitly set the StatementSQL content in case of an item creation: function TSQLStatementCached.Prepare(const GenericSQL: RaWUTF8): PSQLRequest; var added: boolean; begin with Cache[Caches.FindHashedForAdding(GenericSQL,added)] do begin if added then begin StatementSQL := GenericSQL; // need explicit set the content Statement.Prepare(DB,GenericSQL); end else begin Statement.Reset; Statement.BindReset; end; result := @Statement; end; end; The latest method of TSQLStatementCached will just loop for each statement, and close them: you can note that this code uses the dynamic array just as usual: procedure TSQLStatementCached.ReleaseAllDBStatements; var i: integer; begin for i := 0 to Count-1 do Cache[i].Statement.Close; // close prepared statement Caches.Clear; // same as SetLength(Cache,0) + Count := 0 end; The resulting code is definitively quick to execute, and easy to read/maintain. 4.4. Enhanced logging A logging mechanism is integrated with cross-cutting features of the framework. It includes stack trace exception and such, just like MadExcept, using .map file content to retrieve debugging information from the source code. Here are some of its features: - Logging with a set of levels, not only a level scale; - Fast, low execution overhead; - Can load .map file symbols to be displayed in logging (i.e. source code file name and line numbers are logged instead of an hexadecimal value); - Compression of .map into binary .mab (900 KB -> 70 KB); - Inclusion of the .map/.mab into the .exe, with very slow size increase; - Exception logging (Delphi or low-level exceptions) with unit names and line numbers; - Optional stack trace with units and line numbers; SAD - mORMot Framework - Rev. 1.18 Page 78 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 - Methods or procedure recursive tracing, with Enter and auto-Leave (using a fake interface instance); - High resolution time stamps, for customer-side profiling of the application execution; - Set / enumerates / TList / TPersistent / TObjectList / dynamic array JSON serialization; - Per-thread or global logging; - Optional multiple log files on the same process; - Optional rotation when main log reaches a specified size, with compression of the rotated logs; - Integrated log archival (in .zip or any other format, including our .synlz); - Optional colored echo to a console window, for interactive debugging; - Fast log viewer tool available, including thread filtering and customer-side execution profiling. 4.4.1. Setup logging Logging is defined mainly by a per-class approach. You usually define your logging expectations by using a TSynLog class, and setting its Family property. Note that it is perfectly feasible to use you own TSynLog class instance, with its own TSynLog family settings, injected at the constructor level; but in mORMot, we usually use the per-class approach, via TSynLog, TSQLLog, SynDBLog and SQLite3Log see below (page 310). For sample code (and the associated log viewer tool), see "11 - Exception logging" folder in "Sqlite3\Samples". In short, you can add logging to your program, just by using the TSynLog class, as such: TSynLog.Add.Log(sllInfo,Stats.DebugMessage); This line will log the Stats.DebugMessage text, with a sllInfo notification level. See the description of all Log() overloaded methods of the ISynLog interface, to find out how your project can easily log events. First of all, you need to define your logging setup via code: with TSynLog.Family do begin Level := LOG_VERBOSE; //Level := [sllException,sllExceptionOS]; //PerThreadLog := true; //HighResolutionTimeStamp := true; //AutoFlushTimeOut := 5; OnArchive := EventArchiveSynLZ; //OnArchive := EventArchiveZip; ArchiveAfterDays := 1; // archive after one day end; The main setting here is TSynLog.Family.Level := ... which defines which levels are to be logged. That is, if sllInfo is part of TSynLog.Family.Level, any TSynLog.Add.Log(sllInfo,...) command will log the corresponding content - otherwise, it will be a no-operation. LOG_VERBOSE is a constant setting all levels at once. You have several debugging levels available, and even 4 custom types: TSynLogInfo = ( sllNone, sllInfo, sllDebug, sllTrace, sllWarning, sllError, sllEnter, sllLeave, sllLastError, sllException, sllExceptionOS, sllMemory, sllStackTrace, sllFail, sllSQL, sllCache, sllResult, sllDB, sllHTTP, sllClient, sllServer, sllServiceCall, sllServiceReturn, sllUserAuth, sllCustom1, sllCustom2, sllCustom3, sllCustom4, sllNewRun); Here are the purpose of each logging level: SAD - mORMot Framework - Rev. 1.18 Page 79 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 - sllInfo will log general information events; sllDebug will log detailed debugging information; sllTrace will log low-level step by step debugging information; sllWarning will log unexpected values (not an error); sllError will log errors; sllEnter will log every method start; sllLeave will log every method quit; sllLastError will log the GetLastError OS message; sllException will log all exception raised - available since Windows XP; sllExceptionOS will log all OS low-level exceptions (EDivByZero, ERangeError, EAccessViolation...); - sllMemory will log memory statistics; - sllStackTrace will log caller's stack trace (it is by default part of TSynLogFamily. LevelStackTrace like sllError, sllException, sllExceptionOS, sllLastError and sllFail); - sllFail was defined for TSynTestsLogged. Failed method, and can be used to log some customer-side assertions (may be notifications, not errors); - sllSQL is dedicated to trace the SQL statements; - sllCache should be used to trace any internal caching mechanism (it is used for instance by our SQL statement caching); - sllResult could trace the SQL results, JSON encoded; - sllDB is dedicated to trace low-level database engine features; - sllHTTP could be used to trace HTTP process; - sllClient/sllServer could be used to trace some Client or Server process; - sllServiceCall/sllServiceReturn to trace some remote service or library; - sllUserAuth to trace user authentication (e.g. for individual requests); - sllCustom1..sllCustom4 items can be used for any purpose by your programs; - sllNewRun will be written when a process re-opens a rotated log. Logging is not using directly a TSynLogInfo level, but the following set: /// used to define a logging level // - i.e. a combination of none or several logging event // - e.g. use LOG_VERBOSE constant to log all events TSynLogInfos = set of TSynLogInfo; Most logging tools in the wild use a level scale, i.e. with a hierarchy, excluding the lower levels when one is selected. Our logging classes use a set, and not directly a particular level, so you are able to select which exact events are worth recording. In practice, we found this pattern to make a lot of sense and to be much more efficient for support. 4.4.2. Call trace The logging mechanism can be used to trace recursive calls. It can use an interface-based mechanism to log when you enter and leave any method: procedure TMyDB.SQLExecute(const SQL: RawUTF8); var ILog: ISynLog; begin ILog := TSynLogDB.Enter(self,'SQLExecute'); // do some stuff ILog.Log(sllInfo,'SQL=%',[SQL]); end; // when you leave the method, it will write the corresponding event to the log SAD - mORMot Framework - Rev. 1.18 Page 80 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 It will be logged as such: 20110325 19325801 + 20110325 19325801 info 20110325 19325801 - MyDBUnit.TMyDB(004E11F4).SQLExecute SQL=SELECT * FROM Table; MyDBUnit.TMyDB(004E11F4).SQLExecute Note that by default you have human-readable time and date written to the log, but it is also possible to replace this timing with high-resolution timestamps. With this, you'll be able to profile your application with data coming from the customer side, on its real computer. Via the Enter method (and its auto-Leave feature), you have all information needed for this. 4.4.3. Including symbol definitions In the above logging content, the method name is set in the code (as 'SQLExecute'). But if the logger class is able to find a .map file associated to the .exe, the logging mechanism is able to read this symbol information, and write the exact line number of the event. By default, the .map file information is not generated by the compiler. To force its creation, you must ensure the {$D+} compiler directive is set in every unit (which is the case by default, unless you set {$D-} in the source), and the "Detailed Map File" option selected in the Project > Options > Linker page of the Delphi IDE. In the following log entries, you'll see both high-resolution time stamp, and the entering and leaving of a TTestCompression.TestLog method traced with no additional code (with accurate line numbers, extracted from the .map content): 0000000000000B56 (376) 0000000000001785 (385) + TTestCompression(00AB3570).000E6C79 SynSelfTests.TTestCompression.TestLog - TTestCompression(00AB3570).000E6D09 SynSelfTests.TTestCompression.TestLog There is already a dedicated TSynLogFile class able to read the .log file, and recognize its content. The first time the .map file is read, a .mab file is created, and will contain all symbol information needed. You can send the .mab file with the .exe to your client, or even embed its content to the .exe (see the Map2Mab.dpr sample file located in the Samples\11 - Exception logging\ folder). This .mab file is very optimized: for instance, a .map of 927,984 bytes compresses into a 71,943 .mab file. 4.4.4. Exception handling Of course, this logging mechanism is able to intercept the raise of exceptions, including the worse (e.g. EAccessViolation), to be logged automatically in the log file, as such: 000000000000090B EXCOS EAccessViolation (C0000005) at 000E9C7A SynSelfTests.Proc1 (785) stack trace 000E9D51 SynSelfTests.Proc2 (801) 000E9CC1 SynSelfTests.Proc1 (790) 000E9D51 SynSelfTests.Proc2 (801) 000E9CC1 SynSelfTests.Proc1 (790) 000E9D51 SynSelfTests.Proc2 (801) 000E9CC1 SynSelfTests.Proc1 (790) 000E9D51 SynSelfTests.Proc2 (801) 000E9CC1 SynSelfTests.Proc1 (790) 000E9D51 SynSelfTests.Proc2 (801) 000E9CC1 SynSelfTests.Proc1 (790) 000E9E2E SynSelfTests.TestsLog (818) 000EA0FB SynSelfTests (853) 00003BF4 System.InitUnits 00003C5B System.@StartExe 000064AB SysInit.@InitExe 000EA3EC TestSQL3 (153) The TSynLogInfo logging level makes a difference between high-level Delphi exceptions (sllException) and lowest-level OS exceptions (sllExceptionOS) like EAccessViolation. For instance, if you add to your program: uses SynCommons; SAD - mORMot Framework - Rev. 1.18 Page 81 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 (...) TSynLog.Family.Level := [sllExceptionOS]; all OS exceptions (excluding pure Delphi exception like EConvertError and such) will be logged to a separated log file. TSynLog.Family.Level := [sllException,sllExceptionOS]; will trace also Delphi exceptions, for instance. You can specify some Exception class to be ignored, by adding them to Family.ExceptionIgnore internal list. It could make sense to add this setting, if your code often triggers some non-breaking exceptions, e.g. with StrToInt(): TSynLog.Family.ExceptionIgnore.Add(EConvertError); If your Delphi code executes some .Net managed code (e.g. exposed via some COM wrapper components), the unit is able to recognize most un-handled .Net exceptions, and log them with their original C# class name (for instance, EOleSysError 80004003 will be recorded as a much more user-friendly "[.NET/CLR unhandled ArgumentNullException]" message. You can set the following global variable to assign a customized callback, and be able to customize the logging content associated to any exception: type /// global hook callback to customize exceptions logged by TSynLog // - should return FALSE if Context.EAddr and Stack trace is to be appended TSynLogExceptionToStr = function(WR: TTextWriter; const Context: TSynLogExceptionContext): boolean; var /// allow to customize the Exception logging message TSynLogExceptionToStrCustom: TSynLogExceptionToStr = nil; The Context: TSynLogExceptionContext content is to be used to append some text to the specified TTextWriter instance. An easier possibility is to inherit your custom exception class from ESynException, and override its unique virtual method: /// generic parent class of all custom Exception types of this unit ESynException = class(Exception) public /// can be used to customize how the exception is logged // - this default implementation will call the DefaultSynLogExceptionToStr() // callback or TSynLogExceptionToStrCustom, if defined // - override this method to provide a custom logging content // - should return TRUE if Context.EAddr and Stack trace is not to be // written (i.e. as for any TSynLogExceptionToStr callback) function CustomLog(WR: TTextWriter; const Context: TSynLogExceptionContext): boolean; virtual; end; See TSynLogExceptionContext to check the execution context, and the implementation of the function DefaultSynLogExceptionToStr() function. 4.4.5. Serialization dynamic arrays can also be serialized as JSON in the log on request, via the default TSynLog class, as defined in SynCommons unit - see Dynamic array wrapper (page 74). The TSQLLog class (using the enhanced RTTI methods defined in mORMot.pas unit) is even able to serialize TSQLRecord, TPersistent, TList and TCollection instances as JSON, or any other class instance, after call to TJSONSerializer. RegisterCustomSerializer. SAD - mORMot Framework - Rev. 1.18 Page 82 of 1055 4. and create a per-thread log file. with the corresponding ThreadID . 1."Yea rOfBirth":1754."LastName":"Croivébaton". try People. without the need to open the log file. will result in the following log content: 0000000000001172 + 000E9F67 SynSelfTests. var People: TSQLRecordPeople. e. Log: ISynLog. for instance on a server running the same logic in parallel in several threads).7.4.YearOfDeath := 1793. if needed (it could be sometimes handy. PerThreadLog := ptOneFilePerThread. it could be very handy to output the logging content to a console window. and inspect which requests are processed.FirstName := 'Louis'.LastName := 'Croivébaton'. SAD . for instance: you can interact with the Client.YearOfBirth := 1754.mORMot Framework .Family do begin Level := LOG_VERBOSE.ID := 16. but in a custom directory: with TSynLogDB. then look in real time at the server console window. This can be very useful for a multi-threaded server process. the following code: procedure TestPeopleProc. Each logging class (inheriting from TSynLog) has its own TSynLogFamily instance."Data":"". The logging settings are made at the logging class level.log content not in the . as implement with mORMot's Client-Server classes below (page 196)."YearOfDeath":1793}} 0000000000001731 000EA005 SynSelfTests.6.18 Page 83 of 1055 . begin Log := TSQLLog. each class sharing the settings of the TSynLogFamily.TestPeopleProc (784) 000000000000171B info {"TSQLRecordPeople(00AB92E0)":{"ID":16. If you specified PerThreadLog := ptIdentifiedInOnFile for the family.Rev. Log to the console For debugging purposes. People. It enables interactive debugging of a Client-Server process.People). Multi-threaded applications You can define several log files per process. Log. and even a per-thread log file. People. 4. end.Enter. and write the .the supplied LogView tool will handle it as expected.Free. end."FirstName":"Louis". People := TSQLRecordPeople. end. People. People. You can therefore initialize the "family" settings before using logging.18 Date: June 16. 2013 For instance.Create.TestPeopleProc (794) 4. DestinationPath := 'C:\Logs'. finally People. which is to be used to customize the logging class level. Then you can have several instances of the individual TSynLog classes.g. like in this code which will force to log all levels (LOG_VERBOSE).exe folder. a new column will be added for each log row.Log(sllInfo.Synopse mORMot Framework Software Architecture Design 1. RotateFileCount := 5. RotateFileSizeKB := 20*1024. so compression will be very fast. // log all events to the console end. Automated log archival Log archives can be created with the following settings: with TSynLogDB. // rotate by 20 MB logs end. colors will be used to write the corresponding information.8. .note that rotated files are compressed using SynLZ..) OnArchive := EventArchiveZip. without any timestamp within. grouping every . . . SAD . since it is currently implemented in a blocking mode. Log files rotation You can set TSynLogFamily. . 4. SynLZ files are less compressed. EchoToConsole := LOG_VERBOSE. 4.nil is the default value. compression speed won't be an issue for the application.4. and not to be enabled on a production server.log file into a proprietary SynLZ format: resulting file name will be located in ArchivePath\log\YYYYMM\*.9. However.log. and the command-line UnSynLz. This feature is therefore disabled by default. and flushes each row to the log file. Depending on the events.RotateFileCount will define how many files are kept on disk . and on a regular application.4.log files in ArchivePath\log\YYYYMM. taking a timeout delay from the ArchiveAfterDays property value: . The ArchivePath property can be set to several functions.18 Date: June 16. for instance. ArchivePath := '\\Remote\WKS2302\Archive\Logs'.log will remain on disk until they will be deleted by hand. // or any path end.18 Page 84 of 1055 .Family do begin (. 2013 The EchoToConsole property enable you to select which events are to be echoed on the console (perhaps you expect only errors to appear..zip files. to enable log file rotation: . but only to make interactive debugging easier.SynZip. for instance). Log file rotation is as easy as: with TSQLLog.RotateFileCount and RotateFileSizeKB properties.EventArchiveDelete in order to delete deprecated . Note that this echoing process slow down the logging process a lot. Errors will be displayed as light red.EventArchiveSynLZ to compress the .EventArchiveZip will archive the .RotateFileSizeKB will define the maximum size of the main uncompressed log file .mORMot Framework .Family do begin Level := LOG_VERBOSE.exe tool (calling FileUnSynLZ function of SynCommons unit) can be used to uncompress it in to plain .log file.synlz.zip files are more standard.Synopse mORMot Framework Software Architecture Design 1.Family do begin Level := LOG_VERBOSE.log files.zip files. the log file will have a fixed name.If both values are > 0.Rev. but created much faster than . with TSQLLog. . 1. and won't do anything: the . dpr regression tests: . // share the same log file with whole mORMot end.11.0. after compression.18 Date: June 16. in the "11 . Our LogViewer tool is able to uncompress those .msg].exe 0.0. for instance.1. [Ident.000 unitary tests create a 390 MB log file).18 Page 85 of 1055 . to share testing events with the main mORMot logs: with TSQLLog.Exception logging" sub-folder. PerThreadLog and HighResolutionTimeStamp properties will be ignored. TSynLogTestLog := TSQLLog. That is.TDynArray. 4. 2013 Such a logging definition will create those files on disk. Log Viewer Since the log files tend to be huge (for instance. uncompressed. and you'll open it just by double-clicking on such files. begin inherited.Synopse mORMot Framework Software Architecture Design 1._TDynArray (18214) 000E9C94 TestSQL3 (163) The difference between a test suit without logging (TSynTests) and a test suit with logging (TSynTestsLogged) is only this overridden method: procedure TSynTestsLogged. end. 4. 4.4.Log(sllFail.3=5.'%: % "%"'. 1.synlz to TestSQL3. for the TestSQL3.500.2600 Wow64=0 Freq=3579545 TSynLogTest 1.1. Note that in this case.Failed(const msg: string.Family do begin Level := LOG_VERBOSE.log files.4. the 10. a log viewer was definitively in need.0 (2011-04-13) Host=Laptop User=MyName CPU=2*0-15-1027 OS=2.TestSQL3.13 2011-04-13 05:40:25 20110413 05402559 fail TTestLowLevelCommon(00B31D70) Low level common: TDynArray "dynamic array failure" stack trace 0002FE0B SynCommons. so that any failure will create an entry in the log with the source line. or use the "Browse" button to browse for a file.Family. if you set the logging for our unitary tests.TTestLowLevelCommon.TestSQL3.aTest). e.11. You'll be able to SAD . aTest: TSynTestCase).g. You can optionally redirect the following global variable at program initialization.4.g.mORMot Framework .Test64K (18206) 0003682F SynCommons. Integration within tests Logging is integrated within the unit testing classes. it will still be opened as plain text. you can associate this tool with your .1. e. In order to enable tests logging.10. with TestCase[fCurrentMethod] do fLogFile.synlz will be the 4 latest log files.Rev.synlz files directly. you have just to enable it. . Open log files You can run it with a specified log file on the command line.4. since both features expect a single process to run.Level := LOG_VERBOSE. Note that if the file is not in our TSynLog format.TestName[fCurrentMethodIndex]. and stack trace: C:\Dev\lib\SQLite3\exe\TestSQL3.Init (15148) 00036736 SynCommons.log which will be the latest log file. The log-viewer application is available as source code in the "Samples" folder. with: TSynLogTestLog. IMHO). Note that only events really encountered in the .11.Synopse mORMot Framework Software Architecture Design 1. a 390 MB log file is opened in less than one second on my laptop.mORMot Framework . 2013 browse its content and search within. you can see all existing events.18 Date: June 16. with a ? button. In fact.which you should have to. and even ask for a source code line number and unit name from an hexadecimal address available in the log. Clicking on the ? button (or pressing the F3 key) allows to repeat the last search.log file.4. Having all SQL and Client-Server events traced in the log is definitively a huge benefit for customer support and bug tracking.Rev. and allows application profiling from the customer side. an optional list of method calls. It uses internally memory mapped files and optimized data structures to access to the data as fast as possible . there is an edit field available.2. so its content will change between log files. general numbers about the log). in a . in a memo. its full line content is displayed at the bottom on the screen.txt file is selected. and trace this into the logs. For instance. When a . 1. starting with the specified folder. By selecting / un-selecting a check-box. . . by browsing for the corresponding . of course.log file appear in this list. but all the nice features of our logging won't be available. and it will be searched within the log events list.3. You can right click on the events check-box list to select a predefined set of events.map file (could be handy if you did not deliver the . and will never reproduce the exact nature of the customer use: for instance.see TSynLogFile class.g. 4. hardware is SAD . Log browser The screen is divided into three main spaces: .11. with its own color and an associated check-box.log / . which will let the viewer be opened in "Browse" mode.On the middle. The corresponding timing is also written within the "Leave" event. by time order. Customer-side profiler One distinctive feature of the TSynLog logging class is that it is able to map methods or functions entering/leaving (using the Enter method). A button gives access to the global Stats about its content (customer-side hardware and software running configuration. profiling an application is done during the testing. When you click on an event. In the very same left panel.map content within your main executable .synlz / . the panel of commands.lnk desktop link).18 Page 86 of 1055 . the log events list. and was designed to be fast.On the left side. Just below the "Browse" button. The command panel allows to Browse your disk for a . You can specify a directory name as a parameter of the tool (e. it takes more time to display the "Open file" dialog window than reading and indexing the 390 MB content.On the right side. Under Windows Seven. Search is case-insensitive. It is worth saying that the viewer was designed to be fast. and another list of threads (not shown by default). 4. Enter any text within this edit field. But this is not. it takes no time to open any log file. The right colored event list follows the events appended to the log. its content is immediately displayed. with a test environment and database. the corresponding events will be instantaneously displayed / or not on the right side list of events.4. This button is a toggle of an optional Drive / Directory / File panel on the leftmost side of the tool. Most of the time. 4. or toggle the optional Thread view list. Per-thread inspection If the TSynLog family has specified PerThreadLog := ptIdentifiedInOnFile property. you are able to inspect the execution log for a given process.Rev. and written as + and in the right-sided event list.. with the corresponding ThreadID of the logged action. I'm quite sure that the first time you'll use this profiling feature on a huge existing application.11. by occurrence (in running order. the log will contain all relevant information. SAD . Several sort order are available: by name (alphabetical sort). And this is the accumulated time spent in the method which is the main argument for code profiling.e.e. you'll find out some bottlenecks you would have never thought about before. In fact. By checking / un-checking any thread of this list. i. according to their name.4. nor the software (Operating System version. 2013 not the same (network. The log-viewer application will identify this column. in the same order than in the event log). allowing to select all threads or no thread in one command. The "Methods profiler" options allow to display the middle optional method calls list. It will allow to go to the next thread.4.e. By enabling customer-side method profiling.mORMot Framework . i. but multiple time. excluding all time spent in the nested methods). most methods are not called once. a new column will be added for each log row. Those events are named "Enter" / "Leave" in the command panel check-box list. memory.. and show a "Thread" group below the left-side commands.18 Page 87 of 1055 . by time (the full time corresponding to this method.Synopse mORMot Framework Software Architecture Design 1. 1. the time written within the "Leave" event). The "Merge method calls" check-box allows to regroup all identical method calls. [anti-]virus installed). A right-click on this thread list will display a pop-up menu. CPU). very easily. and by proper time (i.18 Date: June 16. Rev.To store and retrieve data from any database engine . you can forget about writing SQL queries: CRUD data access statements (SELECT / INSERT / UPDATE /DELETE) are all created on the fly by the Object-relational mapping (ORM) core of mORMot. in a RESTful approach. grid column names are retrieved from property names after translation.Synopse mORMot Framework Software Architecture Design 1.Auto-generate the User Interface (grids.see Object-relational mapping (page 65) . to create menus and reports directly from the field definition. enumerations are displayed as plain text.18 Date: June 16. Generic access to the data is implemented by defining high-level objects as Delphi classes.pas.mORMot Framework .pas. edition screens and menus).To have business logic objects accessible for both the Client and Server side. This allows to truly implement a Multi-tier architecture . those TSQLRecord classes can be used for at least three main purposes: .pas or SynDB. Following the three previous purposes.Define business logic in Delphi code. In our Client-Server ORM.Map the Database tables. .is implemented in mORMot.see Multi-tier architecture (page 61). these properties will be used: .18 Page 88 of 1055 . 2013 5. . . . 1. Object-Relational Mapping Adopt a mORMot The ORM part of the framework . SAD . descendant from a main TSQLRecord class.g.for most common usage. or boolean as a checkbox). Then it will use other units (like mORMotSQLite3.pas unit.To fill a grid content with the proper field type (e. SynSQLite3. to have edition window generated in an automated way. All published properties of the TSQLRecord descendant classes are then accessed via RTTI in a Client-Server RESTful architecture.pas) to access to the various database back-ends. mORMotDB. TEXT is an UTF-8 encoded text): Delphi SQLite3 Remarks byte INTEGER word INTEGER integer INTEGER cardinal N/A Int64 INTEGER boolean INTEGER 0 is false. fSex: TSex. the corresponding Baby table is created by the Framework in the database engine (SQLite3 natively or any external database).. starting at 0 for the first element) set INTEGER each bit corresponding to an enumerated item (therefore a set of up to 64 elements can be stored in such a field) single FLOAT double FLOAT extended FLOAT You should use Int64 instead stored as double (precision lost) SAD .1. i.mORMot Framework . common for both Client and Server. By adding this TSQLBaby class to a TSQLModel instance.e. anything else is true enumeration INTEGER store the ordinal value of the enumerated item(i. in your SQL query any more. ladies come first. here TSex = (sFemale. 0 for sFemale. FLOAT is a double. property Address: RawUTF8 read fAddress write fAddress..e. fBirthDate: TDateTime.Rev. TSQLRecord fields definition For example. 1 for sMale // . 1. fAddress: RawUTF8.will be stored as its ordinal value. All SQL work ('CREATE TABLE . end. a database Baby Table is defined in Delphi code as: /// some enumeration // . property Sex: TSex read fSex write fSex. published property Name: RawUTF8 read fName write fName.Synopse mORMot Framework Software Architecture Design 1.18 Page 89 of 1055 . Just code in Pascal. And you won't miss any ' or . sMale). property BirthDate: TDateTime read fBirthDate write fBirthDate. /// table used for the Babies queries TSQLBaby = class(TSQLRecord) private fName: RawUTF8. and will be converted as specified to database content (in SQLite3. The following published properties types are handled by the ORM.18 Date: June 16. an INTEGER is an Int64.') is done by the framework. Even the needed indexes will be created by the ORM. and all is done for you. 2013 5.as you can see.will be written as 'Female' or 'Male' in our UI Grid // . as AnsiString WideString TEXT UCS2 char-set.Synopse mORMot Framework Software Architecture Design 1. 2013 currency FLOAT safely converted to/from currency type with fixed decimals.the record content must be retrieved via its ID using a PtrInt(Field) typecast or the Field. without rounding error RawUTF8 TEXT this is the preferred field type for storing some textual content in the ORM WinAnsiString TEXT WinAnsi char-set (code page 1252) in Delphi RawUnicode TEXT UCS2 char-set in Delphi. TSQLRest.RawUTF8 is preferred in all cases TDateTime TEXT ISO 8601 encoded date time TTimeLog INTEGER as proprietary fast Int64 date time TModTime INTEGER the server date time will be stored when a record is modified (as proprietary fast Int64) TCreateTime INTEGER the server date time will be stored when a record is created (as proprietary fast Int64) TSQLRecord INTEGER RowID pointing to another record (warning: the field value contains pointer(RowID).see TJSONSerializer.18 Date: June 16.mORMot Framework .18 Page 90 of 1055 .Rev. RegisterCustomSerializer below (page 189) JSON array of objects (ObjectToJSON) . or UnicodeString later string TEXT Not to be used before Delphi 2009 (unless you may loose some data during conversion) . 1.ID method) TSQLRecordMany nothing data is stored in a separate pivot table.g. this is a particular case of TSQLRecord: it won't contain pointer(RowID). not a valid object instance . but an instance) TRecordReference INTEGER store both ID and TSQLRecord type in a RecordRef-like value (use e. as COM BSTR type (Unicode in all version of Delphi) SynUnicode TEXT Will be either WideString before Delphi 2009. Retrieve(Reference) to get a record content) TPersistent TEXT JSON object (ObjectToJSON) TCollection TEXT JSON array of objects (ObjectToJSON) TObjectList TEXT TStrings TEXT JSON array of string (ObjectToJSON) TRawUTF8List TEXT JSON array of string (ObjectToJSON) any TObject TEXT See TJSONSerializer. RegisterClassForJSON below (page 190) SAD . 1. Text fields In practice. the generic string type is handled (as UnicodeString under Delphi 2009 and later). .1. All business process should be made using RawUTF8 variables and methods (you have all necessary functions in SynCommons. On Unicode version of Delphi (starting with Delphi 2009). end. the following class definition will create an index for its SerialNumber property (up to 30 characters long if stored in an external database). a TEXT field stored in a remote SynDB-based database . SAD . For instance. when creating the corresponding column in the database (SQLite3 does not have any such size limit).e.For a WinAnsiString / RawUTF8 field of an "external" class . published property SerialNumber: RawUTF8 index 30 read fSerialNumber write fSerialNumber stored AS_UNIQUE. an index will be created and uniqueness of the value will be checked at insert/update).18 Date: June 16. then you should explicitly convert the RawUTF8 content into a string using U2S / S2U from mORMoti18n.pas or StringToUTF8 / UTF8ToString which will handle proper char-set conversion according to the current i18n settings. you would be able to make a fast lookup for a particular diaper from either its internal mORmot ID.SaveTo binary format variant TEXT numerical or text in JSON Some additional attributes may be added to the published field definitions: .mORMot Framework .If the property is marked as stored AS_UNIQUE (i. property Baby: TSQLBaby read fBaby write fBaby. fModel: TSQLDiaperModel. So we won't recommend its usage. such direct assignation will probably loose data for all non ASCII 7 bit characters. 2013 TSQLRawBlob BLOB This type is an alias to RawByteString dynamic arrays BLOB in the TDynArray. 1. or its official unique serial number: /// table used for the Diaper queries TSQLDiaper = class(TSQLRecord) private fSerialNumber: RawUTF8. it will be created as UNIQUE in the database (i. DynArray(DynArrayFieldIndex) method to create a TDynArray wrapper mapping the dynamic array data. .pas). the index number will be used to define the maximum character size of this field.18 Page 91 of 1055 . but this implicit conversion will be slower than our StringToUTF8 / UTF8ToString functions.For a dynamic array field. you can directly assign a string / UnicodeString value to / from a RawUTF8. so in this case. stored false). the index number can be used for the TSQLRecord.e. but you may loose some content if you're working with pre-Unicode version of Delphi (in which string = AnsiString with the current system code page).see below (page 166). and will expect a link to a model of diaper (TSQLDiaperModel) and the baby which used it (TSQLBaby).Synopse mORMot Framework Software Architecture Design 1. fBaby: TSQLBaby.Rev. property Model: TSQLDiaperModel read fModel write fModel.e. With pre-Unicode version of Delphi (up to Delphi 2007).i. The natural Delphi type to be used for TEXT storage in our framework is RawUTF8. An ID / RowID column will be always available (from TSQLRecord). 5. 5. SAD . 2013 You will find in SynCommons.2. it is safe to directly compare their Int64 underlying value.Rev.6. e.38 bits will map years. . For additional information about UTF-8 handling in the framework.ToDateTime) could create an internal compiler error. In order to circumvent this bug.26.5 bits will map seconds. a proprietary fast Int64 date time format will map the Iso8601 record type. as in PIso8601(@Value)^.18 Page 92 of 1055 . via ord(aEnumValue) or TEnum(aIntegerValue). 1.. This format will be very fast for comparing dates or convert into/from text. But if you simply want to compare TTimeLog kind of date/time. i. according to the number of elements in the set: for instance. and integer(aSetValue) for up to 32 elements in the set.17. 5.22.1.. you can't just use add or subtract two TTimeLog values when doing such date/time computation: use a TDateTime temporary conversion in such case.. word(aSetValue) for up to 16 elements.ToDateTime-Now. .16 bits will map hours. end. .11 bits will map minutes. you would have to use a pointer typecast. procedure TSQLRest.21 bits will map days (minus one).1.ToDateTime above.. with byte/word/integer type. . see Unicode and UTF-8 (page 73).e. unless you access to the VCL / User Interface layer.0. and will be stored more efficiently than plain ISO 8601 TEXT as used for TDateTime fields. as defined in SynCommons.ServerTimeStamp property is computed: function TSQLRest. See for instance how the TSQLRest.pas unit: .12.25 bits will map months (minus one). .18 Date: June 16. Enumeration sets should be mapped as INTEGER.pas unit all low-level RawUTF8 processing functions and classes. to be used instead of any SysUtils. begin PIso8601(@result)^.4. direct typecast of a TTimeLog or Int64 variable into a Iso8601 record (as with Iso8601(aTimeLog). end.pas functions. the framework natively handles the double and currency kind of variables.3. Note that since TTimeLog type is bit-oriented. byte(aSetValue) for up to 8 elements. begin fServerTimeStampOffset := PIso8601(@Value)^. Due to compiler limitation in older versions of Delphi. The mORMot core implementation about RawUTF8 is very optimized for speed and multi-threading.mORMot Framework .. 5.SetServerTimeStamp(const Value: TTimeLog).g.Synopse mORMot Framework Software Architecture Design 1. Enumeration fields Enumerations should be mapped as INTEGER. Date and time fields For TTimeLog / TModTime / TCreateTime.From(Now+fServerTimeStampOffset). Floating point and Currency fields For standard floating-point values.1. so it is recommended not to use string in your code.GetServerTimeStamp: TTimeLog.. we did not use this feature. Should be enough for your pocket change. 5. store a variant as in Delphi code). with a conversion to number before comparison).Net implementation of currency. On the Win32 platform.see Currency handling (page 74) .5808 .6. especially with external engines. The currency type is the standard Delphi type to be used when storing and handling monetary values. but also safer: you will avoid any rounding problem which may be introduced by the conversion to a float type.18 Page 93 of 1055 . It is able to safely store numbers in the range -922337203685477.g. Rounding issues are a nightmare to track in production . double is the native type handled by most database providers . are true instances. especially when converting values to or from JSON text. assuming exact 4 decimals precision. The Int64 binary representation of the currency type (i.when it comes to money.and SQLite3 is quite alone having this feature.e. their definition is used to define a "one to many" or "one to one" relationship between tables. Some dedicated functions have been implemented . In fact. 2013 In fact. which. by design.1. Only exception to this rule is TSQLRecordMany kind of published properties. 922337203685477. since we wanted our framework to work with all databases . It is still implemented the same in the Win64 platform (since XE 2).. it will check their content.Synopse mORMot Framework Software Architecture Design 1. In our framework. 1. native to the x87 FPU . it will create a string. TSQLRecord fields It is worth saying that TSQLRecord published properties are not usually class instances. Even if SQLite3 is able to affect a column type for each row (i. your queries shall ensure that any SQL WHERE statement handles it as expected (e. as with regular Delphi code. As stated by the official Delphi documentation: Currency is a fixed-point data type that minimizes rounding errors in monetary calculations. SAD .5. we tried to avoid any unnecessary conversion to float values when dealing with currency values.it is also native to the SSE set of opcodes of newer CPUs (as handled by Delphi XE 2 in 64 bit mode). For all database process. and will create a numerical value (integer or floating-point) if the stored text has the corresponding layout. Using the Int64 binary representation can be not only faster. otherwise. a dedicated type is worth the cost in a "rich man's world".Rev. See below (page 99) for how you have to work with such TSQLRecord published properties. It will avoid any rounding problems.1. At loading.18 Date: June 16. Lack of extended should not be problematic (if it is mandatory. this type matches the corresponding OLE and .5807.e. and could be implemented with the expected precision via a TEXT field (or a BLOB mapped by a dynamic array). a dedicated set of mathematical classes should be preferred to a database).mORMot Framework . needed to access the pivot table data of "many to many" relationship. Currency values are automatically divided or multiplied by 10000. value*10000 as accessible via a typecast like PInt64(@aCurrencyValue)^) is a safe and fast implementation pattern.for fast and secure access to currency published properties via RTTI. it is stored as a scaled 64-bit integer with the four least significant digits implicitly representing decimal places. In fact. the SynDB units will try to avoid any conversion to/from double for the dedicated ftCurrency columns. When mixed with other real types in assignments and expressions. Variant fields The ORM will store variant fields as TEXT in the database. 5. Since all data is stored as TEXT in the column.it sounds safe to have a framework handling natively a currency type from the ground up. Rev. ID: integer.2.Address := 'New York City'. // retrieve record data Baby := TSQLBaby.Create. Record fields Published properties of records are handled in our code.g. The same TSQLBaby instance can be used to access several record content. assert(Baby.Retrieve(ID. begin // create a new record. depending on the stored value.Create(Client.Free. end.Name := 'Smeeth'. Of course. end.Sex := sMale. Baby. try assert(Baby.Synopse mORMot Framework Software Architecture Design 1.Name := 'Smith'. // update record data Baby := TSQLBaby.see below (page 105). try Client. finally Baby. in order to handle records within your TSQLRecord class definition .Free. Baby. Client. You could use a dynamic array with only one element. for date or numbers processing): just accessing objects via high-level methods.Free.Update(Baby). Baby. No SQL statement to write. try Baby. 2013 At JSON level. but Delphi doesn't create the corresponding RTTI for such properties so it won't work. ID := Client. end.Delete(TSQLBaby. finally Baby.1. finally Baby.18 Page 94 of 1055 . Baby. since Smith. following the RESTful pattern .Name='Smeeth'). Jr was just born Baby := TSQLBaby.Create(Client. // delete the created record Client. Working with Objects To access a particular record. This is the magic of ORM.ID).ID).ID).see below (page 191): var Baby: TSQLBaby.Create.Baby).18 Date: June 16.BirthDate := Now.Add(Baby). variant fields will be transmitted as JSON text or number. // we may have written: Baby := TSQLBaby. SAD . end.7. nothing to care about database engine expectations (e.mORMot Framework . and call Retrieve / Add / Delete / Update methods on purpose.Name='Smith'). 5. 5. 1. the following code can be used to handle CRUD statements (Create Retrieve Update Delete actions are implemented via Add/Update/Delete/Retrieve methods). you can have a TSQLBaby instance alive during a longer time. 3.'Datum=?'. void in case of CreateAndFillPrepare): any later call to Update should lead into a data loss.'Datum>=?'. retrieved as JSON from the Server. Note that there is an optional aCustomFieldsCSV parameter available in all FillPrepare / CreateAndFillPrepare methods. DateTimeToSQL() or Iso8601ToSQL() functions.Free.[Iso8601ToSQL(Client..18 Date: June 16.ServerTimeStamp)]). They are bound in the ? appearance order in the WHERE clause of the [CreateAnd]FillPrepare query method.4)]). double. It may save some remote bandwidth.2.'Datum<=?'.4))]). and only the retrieved filled will be updated on the server side.18 Page 95 of 1055 .[DateToSQL(EncodeDate(2012.Rev. The mORMot engine will create a SQL statement with the appropriate SELECT query.CreateAndFillPrepare(Client.mORMot Framework . end.CreateAndFillPrepare(Client.5. by calling BinToBase64WithMagic() SAD .1.['A%'. and the second as the 1 INTEGER value. Note that you should use this aCustomFieldsCSV parameter only to retrieve some data. if the data is expected to be big (more than a few MB). and that the other fields will remain untouched (i.as in the sample code above for Name or Sex properties. the [CreateAnd]FillPrepare / FillOne methods use a list of records. 'Name LIKE ? AND Sex = ?'.e.5. 5.[DateTimeToSQL(Now)]). finally aMale. This request loops through all matching records. transmit it between the Client and the Server (if any). For TTimeLog / TModTime / TCreateTime kind of properties.CreateAndFillPrepare(Client. try while aMale. retrieve all data as JSON. the WHERE clause of the request expects some parameters to be specified. integer. Any sft@*Blob@ property should better be handled separately.ord(sMale)]). Internally. by which you may specify a CSV list of field names to be retrieved. aRec.CreateAndFillPrepare(Client. and parsed in memory one row a time (using an internal TSQLTableJSON instance).[DateToSQL(2012. Query parameters For safer and faster database process.) can be bound directly .3. aRec. then convert the values into properties of our TSQLBaby object instance. Queries 5. The first parameter will be bound as 'A%' RawUTF8 TEXT. Return a list of objects You can query your table with the FillPrepare or CreateAndFillPrepare methods. But you can specify a small BLOB content using an explicit conversion to the corresponding TEXT format.Synopse mORMot Framework Software Architecture Design 1. accessing each row content via a TSQLBaby instance. 1. Any TDateTime bound parameter shall better be specified using DateToSQL(). via dedicated RetrieveBlob and UpdateBlob method calls (or their global RetrieveBlobFields / UpdateBlobFields twins).CreateAndFillPrepare(Client. aRec. Standard simple kind of parameters (RawUTF8.3. for instance all babies with balls and a name starting with the letter 'A': aMale := TSQLBaby.'Datum<=?'. 2013 5.FillOne do DoSomethingWith(aMale). please use the underlying Int64 value as bound parameter. if not all record fields values are needed in the loop. as such: aRec. since the method will know that is has been called during a FillPrepare / CreateAndFillPrepare process. Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 overloaded functions when preparing such a query. Note that there was a breaking change about the TSQLRecord.Create / FillPrepare / CreateAndFillPrepare and TSQLRest.OneFieldValue / MultiFieldValues methods: for historical reasons, they expected parameters to be marked as % in the SQL WHERE clause, and inlined via :(...): as stated below (page 97) - since revision 1.17 of the framework, those methods expect parameters marked as ? and with no :(...):. Due to this breaking change, user code review is necessary if you want to upgrade the engine from 1.16 or previous. In all cases, using ? is less confusing for new users, and more close to the usual way of preparing database queries - e.g. as stated below (page 166). Both TSQLRestClient.EngineExecuteFmt / ListFmt methods are not affected by this change, since they are just wrappers to the FormatUTF8() function. 5.3.3. Introducing TSQLTableJSON As we stated above, [CreateAnd]FillPrepare / FillOne methods are implemented via an internal TSQLTableJSON instance. In short, TSQLTableJSON will expect some JSON content as input, will parse it in rows and columns, associate it with one or more optional TSQLRecord class types, then will let you access the data via its Get* methods. You can use this TSQLTableJSON class as in the following example: procedure WriteBabiesStartingWith(const Letters: RawUTF8; Sex: TSex); var aList: TSQLTableJSON; Row: integer; begin aList := Client.MultiFieldValues(TSQLBaby,'ID,BirthDate', 'Name LIKE ? AND Sex = ?',[Letters+'%',ord(Sex)]); if aList=nil then raise Exception.Create('Impossible to retrieve data from Server'); try for Row := 1 to aList.RowCount do writeln('ID=',aList.GetAsInteger(Row,0),' BirthDate=',aList.Get(Row,1)); finally aList.Free; end; end; For a record with a huge number of fields, specifying the needed fields could save some bandwidth. In the above sample code, the ID column has a field index of 0 (so is retrieved via aList.GetAsInteger(Row,0)) and the BirthDate column has a field index of 1 (so is retrieved as a PUTF8Char via aList.Get(Row,1)). All data rows are processed via a loop using the RowCount property count - first data row is indexed as 1, since the row 0 will contain the column names. The TSQLTable class has some methods dedicated to direct cursor handling, as such: procedure WriteBabiesStartingWith(const Letters: RawUTF8; Sex: TSex); var aList: TSQLTableJSON; begin aList := Client.MultiFieldValues(TSQLBaby,'ID,BirthDate', 'Name LIKE ? AND Sex = ?',[Letters+'%',ord(Sex)]); try while aList.Step do writeln('ID=',aList.Field(0),' BirthDate=',aList.Field(1)); finally aList.Free; end; end; SAD - mORMot Framework - Rev. 1.18 Page 96 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 By using the TSQLTable.Step method, you do not need to check that aList<>nil, since it will return false if aList is not assigned. And you do not need to access the RowCount property, nor specify the current row number. We may have used not the field index, but the field name, within the loop: writeln('ID=',aList.Field('ID'),' BirthDate=',aList.Field('BirthDate')); You can also access the field values using late-binding and a local variant, which gives some perfectly readable code: procedure WriteBabiesStartingWith(const Letters: RawUTF8; Sex: TSex); var baby: variant; begin with Client.MultiFieldValues(TSQLBaby,'ID,BirthDate', 'Name LIKE ? AND Sex = ?',[Letters+'%',ord(Sex)]) do try while Step(false,@baby) do writeln('ID=',baby.ID,' BirthDate=',baby.BirthDate); finally Free; end; end; In the above code, late-binding will search for the "ID" and "BirthDate" fields at runtime. But the ability to write baby.ID and baby.BirthDate is very readable. Using a with ... do statement makes the code shorter, but should be avoided if it leads into confusion, e.g. in case of more complex process within the loop. See also the following methods of TSQLRest: OneFieldValue, OneFieldValues, MultiFieldValue, MultiFieldValues which are able to retrieve either a TSQLTableJSON, or a dynamic array of integer or RawUTF8. And also List and ListFmt methods of TSQLRestClient, if you want to make a JOIN against multiple tables at once. A TSQLTableJSON content can be associated to a TGrid in order to produce an User Interface taking advantage of the column types, as retrieved from the associated TSQLRecord RTTI. The TSQLTableToGrid class is able to associate any TSQLTable to a standard TDrawGrid, with some enhancements: themed drawing, handle Unicode, column types (e.g. boolean are displayed as check-boxes, dates as text, etc...), column auto size, column sort, incremental key lookup, optional hide IDs, selection... 5.3.4. Note about query parameters (this paragraph is not mandatory to be read at first, so you can skip it if you do not need to know about the mORMot internals - just remember that ? bound parameters are inlined as :(...): in the JSON transmitted content so can be set directly as such in any WHERE clause) If you consider the first sample code: aMale := TSQLBaby.CreateAndFillPrepare(Client, 'Name LIKE ? AND Sex = ?',['A%',ord(sMale)]); This will execute a SQL statement, with an ORM-generated SELECT, and a WHERE clause using two parameters bound at execution, containing 'A%' RawUTF8 text and 1 integer value. In fact, from the SQL point of view, the CreateAndFillPrepare() method as called here is exactly the same as: aMale := TSQLBaby.CreateAndFillPrepare(Client, SAD - mORMot Framework - Rev. 1.18 Page 97 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 'Name LIKE :(''A%''): AND Sex = :(1):'); or aMale := TSQLBaby.CreateAndFillPrepare(Client, 'Name LIKE :(%): AND Sex = :(%):',['''A%''',ord(sMale)],[])); or aMale := TSQLBaby.CreateAndFillPrepare(Client, FormatUTF8('Name LIKE :(%): AND Sex = :(%):',['''A%''',ord(sMale)])); First point is that the 'A' letter has been embraced with quotes, as expected per the SQL syntax. In fact, Name LIKE :(%): AND Sex = :(%):', ['''A%''',ord(sMale)] is expected to be a valid WHERE clause of a SQL statement. Note we used single quotes, but we may have used double quotes (") inside the :( ): statements. In fact, SQLite3 expects single quotes in its raw SQL statements, whereas our prepared statements :( ): will handle both single ' and double " quotes. Just to avoid any confusion, we'll always show single quotes in the documentation. But you can safely use double quotes within :( ): statements, which could be more convenient than single quotes, which should be doubled within a pascal constant string ''. The only not-obvious syntax in the above code is the :(%): used for defining prepared parameters in the format string. In fact, the format string will produce the following WHERE clause parameter as plain text: aMale := TSQLBaby.CreateAndFillPrepare(Client, 'Name LIKE :(''A%''): AND Sex = :(1):'); So that the following SQL query will be executed by the database engine, after translation by the ORM magic: SELECT * FROM Baby WHERE Name LIKE ? AND Sex = ?; With the first ? parameter bound with 'A%' value, and the second with 1. In fact, when the framework finds some :( ): in the SQL statement string, it will prepare a SQL statement, and will bound the parameters before execution (in our case, text A and integer 1), reusing any previous matching prepared SQL statement. See below (page 144) for more details about this mechanism. To be clear, without any prepared statement, you could have used: aMale := TSQLBaby.CreateAndFillPrepare(Client, 'Name LIKE % AND Sex = %',['''A%''',ord(sMale)],[]); or aMale := TSQLBaby.CreateAndFillPrepare(Client, FormatUTF8('Name LIKE % AND Sex = %',['''A%''',ord(sMale)])); which will produce the same as: aMale := TSQLBaby.CreateAndFillPrepare(Client, 'Name LIKE ''A%'' AND Sex = 1'); So that the following SQL statement will be executed: SELECT * FROM Baby WHERE Name LIKE 'A%' AND Sex = 1; Note that we prepared the SQL WHERE clause, so that we could use the same request statement for all females with name starting with the character 'D': SAD - mORMot Framework - Rev. 1.18 Page 98 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 aFemale := TSQLBaby.CreateAndFillPrepare(Client, 'Name LIKE :(%): AND Sex = :(%):', ['''D%''',ord(sFemale)]); Using a prepared statement will speed up the database engine, because the SQL query would have to be parsed and optimized only once. The second query method, i.e. aList := Client.MultiFieldValues(TSQLBaby,'ID,BirthDate', 'Name LIKE ? AND Sex = ?',[Letters+'%',ord(Sex)]); is the same as this code: aList := Client.MultiFieldValues(TSQLBaby,'ID,BirthDate', 'Name LIKE :(%): AND Sex = :(%):',[QuotedStr(Letters+'%'),ord(Sex)],[]); or aList := Client.MultiFieldValues(TSQLBaby,'ID,BirthDate', FormatUTF8('Name LIKE :(%): AND Sex = :(%):',[QuotedStr(Letters+'%'),ord(Sex)])); In both cases, the parameters will be inlined, in order to prepare the statements, and improve execution speed. We used the QuotedStr standard function to embrace the Letters parameter with quotes, as expected per the SQL syntax. Of course, using '?' and bounds parameters is much easier than '%' and manual :(%): in-lining with a QuotedStr() function call. In your client code, you should better use '?' - but if you find some ':(%):' in the framework source code and when a WHERE clause is expected within the transmitted JSON content, you won't be surprised. 5.4. Objects relationship: cardinality All previous code is fine if your application requires "flat" data. But most of the time, you'll need to define master/child relationship, perhaps over several levels. In data modeling, the cardinality of one data table with respect to another data table is a critical aspect of database design. Relationships between data tables define cardinality when explaining how each table links to another. In the relational model, tables can have the following cardinality, i.e. can be related as any of: - "One to one". - "Many to one" (rev. "One to many"); - "Many to many" (or "has many"). Our mORMot framework handles all those kinds of cardinality. 5.4.1. "One to one" or "One to many" In order to handle "One to one" or "One to many" relationship between tables (i.e. normalized Master/Detail in a classical RDBMS approach), you could define TSQLRecord published properties in the object definition. For instance, you could declare classes as such: TSQLMyFileInfo = class(TSQLRecord) private FMyFileDate: TDateTime; FMyFileSize: Int64; published property MyFileDate: TDateTime read FMyFileDate write FMyFileDate; SAD - mORMot Framework - Rev. 1.18 Page 99 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 property MyFileSize: Int64 read FMyFileSize write FMyFileSize; end; TSQLMyFile = class(TSQLRecord) private FSecondOne: TSQLMyFileInfo; FFirstOne: TSQLMyFileInfo; FMyFileName: RawUTF8; published property MyFileName: RawUTF8 read FMyFileName write FMyFileName; property FirstOne: TSQLMyFileInfo read FFirstOne write FFirstOne; property SecondOne: TSQLMyFileInfo read FSecondOne write FSecondOne; end; As stated by TSQLRecord fields definition (page 89), TSQLRecord published properties do not contain an instance of the TSQLRecord class. They will instead contain pointer(RowID), and will be stored as an INTEGER in the database. So do not use directly such published properties, like a regular class instance: you'll have an access violation. When creating such records, use temporary instances for each detail object, as such: var One, Two: TSQLMyFileInfo; MyFile: TSQLMyFile; begin One := TSQLMyFileInfo.Create; Two := TSQLMyFileInfo.Create; MyFile := TSQLMyFile.Create; try One.MyFileDate := .... One.MyFileSize := ... MyFile.FirstOne := TSQLMyFileInfo(MyDataBase.Add(One,True)); // add One and store ID in MyFile.FirstOne Two.MyFileDate := .... Two.MyFileSize := ... MyFile.SecondOne:= TSQLMyFileInfo(MyDataBase.Add(Two,True)); // add Two and store ID in MyFile.SecondOne MyDataBase.Add(MyFile); finally MyFile.Free; Two.Free; One.Free; end; end; Note that you those two assignments are the same: MyFile.FirstOne := TSQLMyFileInfo(MyDataBase.Add(One,True)); MyFile.FirstOne := pointer(MyDataBase.Add(One,True)); Or you may have added the One row first: MyDatabase.Add(One,true); then assigned it to the MyFile record on one of the following expressions: MyFile.FirstOne := TSQLMyFileInfo(One.ID); MyFile.FirstOne := pointer(One.ID); MyFile.FirstOne := One.AsTSQLRecord; The first two statements, using a class/pointer type cast will work only in 32 bit (since ID is an integer). Using TSQLRecord.AsTSQLRecord property will work on all platforms, including 64 bit, and is perhaps easier to deal with in your code. When accessing the detail objects, you should not access directly to FirstOne or SecondOne SAD - mORMot Framework - Rev. 1.18 Page 100 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 properties (there are not class instances, but integer IDs), then use instead the TSQLRecord. Create(aClient: TSQLRest; aPublishedRecord: TSQLRecord: ForUpdate: boolean=false) overloaded constructor, as such: var One: TSQLMyFileInfo; MyFile: TSQLMyFile; begin MyFile := TSQLMyFile.Create(Client,aMyFileID); try // here MyFile.FirstOne.MyFileDate will trigger an access violation One := TSQLMyFileInfo.Create(Client,MyFile.FirstOne); try // here you can access One.MyFileDate or One.MyFileSize finally One.Free; end; finally MyFile.Free; end; end; Or with a with statement: with TSQLMyFileInfo.Create(Client,MyFile.FirstOne) do try // here you can access MyFileDate or MyFileSize finally Free; end; Mapping a TSQLRecord field into an integer ID is a bit difficult to learn at first. It was the only way we found out in order to define a "one to one" or "one to many" relationship within the class definition, without any property attribute features of the Delphi compiler (only introduced in newer versions). The main drawback is that the compiler won't be able to identify at compile time some potential GPF issues at run time. This is up to the developer to write correct code, when dealing with TSQLRecord properties. Using AsTSQLRecord property and overloaded TSQLRecord. Create(aPublishedRecord) constructor will help a lot. 5.4.2. "Has many" and "has many through" As http://en.wikipedia.org/wiki/Many-to-many_(data_model).. wrote: In systems analysis, a many-to-many relationship is a type of cardinality that refers to the relationship between two entities (see also Entity-Relationship Model) A and B in which A may contain a parent row for which there are many children in B and vice versa. For instance, think of A as Authors, and B as Books. An Author can write several Books, and a Book can be written by several Authors. Because most database management systems only support one-to-many relationships, it is necessary to implement such relationships physically via a third and fourth junction table, say, AB with two one-to-many relationships A -> AB and B -> AB. In this case the logical primary key for AB is formed from the two foreign keys (i.e. copies of the primary keys of A and B). From the record point of view, and to follow the ORM vocabulary (in Ruby on Rails, Python, or other ActiveRecord clones), we could speak of "has many" relationship. In the classic RDBMS implementation, a pivot table is created, containing two references to both related records. Additional information can be stored within this pivot table. It could be used, for instance, to store association time or corresponding permissions of the relationship. This is called a "has many through" relationship. SAD - mORMot Framework - Rev. 1.18 Page 101 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 In fact, there are several families of ORM design, when implementing the "many to many" cardinality: - Map collections into JOINed query from the ORM (i.e. pivot tables are abstracted from object lists or collections by the framework, to implement "has many" relationship, but you will have to define lazy loading and won't have "has many through" relationship at hand); - Explicitly handle pivot tables as ORM classes, and provide methods to access to them (it will allow both "has many" and "has many through" relationship). - Store collections within the ORM classes property (data sharding). In the mORMot framework, we did not implement the 1st implementation pattern, but the 2nd and 3rd: - You can map the DB with dedicated TSQLRecordMany classes, which allows some true pivot table to be available (that is the 2nd family), introducing true "has many through" cardinality; - But for most applications, it sounds definitively more easy to use TCollection (of TPersistent classes) or dynamic arrays within one TSQLRecord class, and data sharding (i.e. the 3rd family). Up to now, there is no explicit Lazy Loading feature in our ORM. There is no native handling of TSQLRecord collections or lists (as they do appear in the first family of ORMs). This could sound like a limitation, but it allows to manage exactly the data to be retrieved from the server in your code, and maintain bandwidth and memory use as low as possible. Use of a pivot table (via the TSQLRecordMany kind of records) allows tuned access to the data, and implements optimal lazy loading feature. Note that the only case when some TSQLRecord instances are automatically created by the ORM is for those TSQLRecordMany published properties. 5.4.2.1. Shared nothing architecture (or sharding) 5.4.2.1.1. Embedding all needed data within the record Defining a pivot table is a classic and powerful use of relational database, and unleash its power (especially when linked data is huge). But it is not easy nor natural to properly handle it, since it introduces some dependencies from the DB layer into the business model. For instance, it does introduce some additional requirements, like constraints / integrity checking and tables/classes inter-dependency. Furthermore, in real life, we do not have such a separated storage, but we store all details within the main data. So for a Domain-Driven design (page 67), which tries to map the real objects of its own domain, such a pivot table is breaking the business logic. With today's computer power, we can safely implement a centralized way of storing data into our data repository. Let us quote what wikipedia states at http://en.wikipedia.org/wiki/Shared_nothing_architecture.. A shared nothing architecture (SN) is a distributed computing architecture in which each node is independent and self-sufficient, and there is no single point of contention across the system. People typically contrast SN with systems that keep a large amount of centrally-stored state information, whether in a database, an application server, or any other similar single point of contention. As we stated in TSQLRecord fields definition (page 89), in our ORM, high-level types like dynamic arrays or TPersistent / TCollection properties are stored as BLOB or TEXT inside the main data row. There is no external linked table, no Master/Detail to maintain. In fact, each TSQLRecord instance content could be made self-contained in our ORM. When the server starts to have an increasing number of clients, such a data layout could be a major SAD - mORMot Framework - Rev. 1.18 Page 102 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 benefit. In fact, the so-called sharding, or horizontal partitioning of data, is a proven solution for web-scale databases, such as those in use by social networking sites. How does EBay or Facebook scale with so many users? Just by sharding. A simple but very efficient sharding mechanism could therefore be implemented with our ORM. In-memory databases, or our BigTable component are good candidate for light speed data process. Even SQLite could scale very well in most cases. Storing detailed data in BLOB or in TEXT as JSON could first sounds a wrong idea. It does break one widely accepted principle of the RDBMS architecture. But even Google had to break this dogma. And when MySQL or such tries to implement sharding, it does need a lot of effort. Others, like the NoSQL MongoDB, are better candidates: they are not tight to the SQL flat scheme. Finally, this implementation pattern fits much better with a Domain-Driven design. See below (page 304). Therefore, on second thought, having at hand a shared nothing architecture could be a great advantage. Our ORM is already ready to break the table-oriented of SQL. Let us go one step further. 5.4.2.1.2. Nesting objects and arrays The "has many" and "has many through" relationship we just described does follow the classic process of rows association in a relational database, using a pivot table. This does make sense if you have some DB background, but it is sometimes not worth it. One drawback of this approach is that the data is split into several tables, and you should carefully take care of data integrity to ensure for instance that when you delete a record, all references to it are also deleted in the associated tables. Our ORM engine will take care of it, but could fail sometimes, especially if you play directly with the tables via SQL, instead of using high-level methods like FillMany* or DestGetJoined. Another potential issue is that one business logical unit is split into several tables, therefore into several diverse TSQLRecord and TSQLRecordMany classes. From the ORM point of view, this could be confusing. Starting with the revision 1.13 of the framework, dynamic arrays, TStrings and TCollection can be used as published properties in the TSQLRecord class definition. This won't be strong enough to implement all possible "Has many" architectures, but could be used in most case, when you need to add a list of records within a particular record, and when this list won't have to be referenced as a stand-alone table. Dynamic arrays will be stored as BLOB fields in the database, retrieved with Base64 encoding in the JSON transmitted stream, then serialized using the TDynArray wrapper. Therefore, only Delphi clients would be able to use this field content: you'll loose the AJAX capability of the ORM, at the benefit of better integration with object pascal code. Some dedicated SQL functions have been added to the SQLite engine, like IntegerDynArrayContains, to search inside this BLOB field content from the WHERE clause of any search (see below (page 105)). Those functions are available from AJAX queries. TPersistent / TStrings and TCollection / TObjectList will be stored as TEXT fields in the database, following the ObjectToJSON function format: you can even serialize any TObject class, via a previous call to the TJSONSerializer. RegisterCustomSerializer class method - see below (page 189) - or TObjectList list of instances, if they are previously registered by TJSONSerializer. RegisterClassForJSON - see below (page 190). This format contains only valid JSON arrays or SAD - mORMot Framework - Rev. 1.18 Page 103 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 objects: so it could be un-serialized via an AJAX application, for instance. About this (trolling?) subject, and why/when you should use plain Delphi objects or arrays instead of classic Master/Detail DB relationship, please read "Objects, not tables" and "ORM is not DB" paragraphs below. 5.4.2.1.2.1. Dynamic arrays fields 5.4.2.1.2.1.1. Dynamic arrays from Delphi Code For instance, here is how the regression tests included in the framework define a TSQLRecord class with some additional dynamic arrays fields: TFV = packed record Major, Minor, Release, Build: integer; Main, Detailed: string; end; TFVs = array of TFV; TSQLRecordPeopleArray = class(TSQLRecordPeople) private fInts: TIntegerDynArray; fCurrency: TCurrencyDynArray; fFileVersion: TFVs; fUTF8: RawUTF8; published property UTF8: RawUTF8 read fUTF8 write fUTF8; property Ints: TIntegerDynArray index 1 read fInts write fInts; property Currency: TCurrencyDynArray index 2 read fCurrency write fCurrency; property FileVersion: TFVs index 3 read fFileVersion write fFileVersion; end; This TSQLRecordPeopleArray class inherits from TSQLRecordPeople, so it will add some new UTF8, Ints, Currency and FileVersion fields to this root class fields (FirstName, LastName, Data, YearOfBirth, YearOfDeath). Some content is added to the PeopleArray table, with the following code: var V: TSQLRecordPeople; VA: TSQLRecordPeopleArray; FV: TFV; (...) V2.FillPrepare(Client,'LastName=:(''Dali''):'); n := 0; while V2.FillOne do begin VA.FillFrom(V2); // fast copy some content from TSQLRecordPeople The FillPrepare / FillOne method are used to loop through all People table rows with a LastName column value equal to 'Dali' (with a prepared statement thanks to :( ):), then initialize a TSQLRecordPeopleArray instance with those values, using a FillFrom method call. inc(n); if n and 31=0 then begin VA.UTF8 := ''; VA.DynArray('Ints').Add(n); Curr := n*0.01; VA.DynArray(2).Add(Curr); FV.Major := n; FV.Minor := n+2000; FV.Release := n+3000; FV.Build := n+4000; str(n,FV.Main); SAD - mORMot Framework - Rev. 1.18 Page 104 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 str(n+1000,FV.Detailed); VA.DynArray('FileVersion').Add(FV); end else str(n,VA.fUTF8); The n variable is used to follow the PeopleArray number, and will most of the time set its textual converted value in the UTF8 column, and once per 32 rows, will add one item to both VA and FV dynamic array fields. We could have used normal access to VVA and FV dynamic arrays, as such: SetLength(VA.Ints,length(VA.Ints)+1); VA.Ints[high(VA.Ints)] := n; But the DynArray method is used instead, to allow direct access to the dynamic array via a TDynArray wrapper. Those two lines behave therefore the same as this code: VA.DynArray('Ints').Add(n); Note that the DynArray method can be used via two overloaded set of parameters: either the field name ('Ints'), or an index value, as was defined in the class definition. So we could have written: VA.DynArray(1).Add(n); since the Ints published property has been defined as such: property Ints: TIntegerDynArray index 1 read fInts write fInts; Similarly, the following line will add a currency value to the Currency field: VA.DynArray(2).Add(Curr); And a more complex TFV record is added to the FileVersion field dynamic array with just one line: VA.DynArray('FileVersion').Add(FV); Of course, using the DynArray method is a bit slower than direct SetLength / Ints[] use. Using DynArray with an index should be also a bit faster than using DynArray with a textual field name (like 'Ints'), with the benefit of perhaps less keyboard errors at typing the property name. But if you need to fast add a lot of items to a dynamic array, you could use a custom TDynArray wrapper with an associated external Count value, or direct access to its content (like SetLength + Ints[]) Then the FillPrepare / FillOne loop ends with the following line: Check(Client.Add(VA,true)=n); end; This will add the VA fields content into the database, creating a new row in the PeopleArray table, with an ID following the value of the n variable. All dynamic array fields will be serialized as BLOB into the database table. 5.4.2.1.2.1.2. Dynamic arrays from SQL code In order to access the BLOB content of the dynamic arrays directly from SQL statements, some new SQL functions have been defined in TSQLDataBase, named after their native simple types: - ByteDynArrayContains(BlobField,I64); - WordDynArrayContains(BlobField,I64); - IntegerDynArrayContains(BlobField,I64); - CardinalDynArrayContains(BlobField,I64); - CurrencyDynArrayContains(BlobField,I64) - in this case, I64 is not the currency value directly SAD - mORMot Framework - Rev. 1.18 Page 105 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 converted into an Int64 value (i.e. not Int64(aCurrency)), but the binary mapping of the currency value, i.e. aCurrency*10000 or PInt64(@aCurrency)^; - Int64DynArrayContains(BlobField,I64); - RawUTF8DynArrayContainsCase(BlobField,'Text'); - RawUTF8DynArrayContainsNoCase(BlobField,'Text'). Those functions allow direct access to the BLOB content like this: for i := 1 to n shr 5 do begin k := i shl 5; aClient.OneFieldValues(TSQLRecordPeopleArray,'ID', FormatUTF8('IntegerDynArrayContains(Ints,?)',[],[k]),IDs); Check(length(IDs)=n+1-32*i); for j := 0 to high(IDs) do Check(IDs[j]=k+j); end; In the above code, the WHERE clause of the OneFieldValues method will use the dedicated IntegerDynArrayContains SQL function to retrieve all records containing the specified integer value k in its Ints BLOB column. With such a function, all the process is performed Server-side, with no slow data transmission nor JSON/Base64 serialization. For instance, using such a SQL function, you are able to store multiple TSQLRecord. ID field values into one TIntegerDynArray property column, and have direct search ability inside the SQL statement. This could be a very handy way of implementing "one to many" or "many to many" relationship, without the need of a pivot table. Those functions were implemented to be very efficient for speed. They won't create any temporary dynamic array during the search, but will access directly to the BLOB raw memory content, as returned by the SQlite engine. The RawUTF8DynArrayContainsCase / RawUTF8DynArrayContainsNoCase functions also will search directly inside the BLOB. With huge number of requests, this could be slower than using a TSQLRecordMany pivot table, since the search won't use any index, and will have to read all BLOB field during the request. But, in practice, those functions behave nicely with a relative small amount of data (up to about 50,000 rows). Don't forget that BLOB column access are very optimized in SQlite3. For more complex dynamic array content handling, you'll have either to create your own SQL function using the TSQLDataBase. RegisterSQLFunction method and an associated TSQLDataBaseSQLFunction class, or via a dedicated Service or a stored procedure - see below (page 221) on how to implement it. 5.4.2.1.2.2. TPersistent/TCollection fields For instance, here is the way regression tests included in the framework define a TSQLRecord class with some additional TPersistent, TCollection or TRawUTF8List fields (TRawUTF8List is just a TStringList-like component, dedicated to handle RawUTF8 kind of string): TSQLRecordPeopleObject = class(TSQLRecordPeople) private fPersistent: TCollTst; fUTF8: TRawUTF8List; public constructor Create; override; destructor Destroy; override; published property UTF8: TRawUTF8List read fUTF8; SAD - mORMot Framework - Rev. 1.18 Page 106 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 property Persistent: TCollTst read fPersistent; end; In order to avoid any memory leak or access violation, it is mandatory to initialize then release all internal property instances in the overridden constructor and destructor of the class: constructor TSQLRecordPeopleObject.Create; begin inherited; fPersistent := TCollTst.Create; fUTF8 := TRawUTF8List.Create; end; destructor TSQLRecordPeopleObject.Destroy; begin inherited; FreeAndNil(fPersistent); FreeAndNil(fUTF8); end; Here is how the regression tests are performed: var VO: TSQLRecordPeopleObject; (...) if Client.TransactionBegin(TSQLRecordPeopleObject) then try V2.FillPrepare(Client,'LastName=?',['Morse']); n := 0; while V2.FillOne do begin VO.FillFrom(V2); // fast copy some content from TSQLRecordPeople inc(n); VO.Persistent.One.Color := n+100; VO.Persistent.One.Length := n; VO.Persistent.One.Name := Int32ToUtf8(n); if n and 31=0 then begin VO.UTF8.Add(VO.Persistent.One.Name); with VO.Persistent.Coll.Add do begin Color := n+1000; Length := n*2; Name := Int32ToUtf8(n*3); end; end; Check(Client.Add(VO,true)=n); end; Client.Commit; except Client.RollBack; // in case of error end; This will add 1000 rows to the PeopleObject table. First of all, the adding is nested inside a transaction call, to speed up SQL INSERT statements, via TransactionBegin and Commit methods. Please note that the TransactionBegin method returns a boolean value, and should be checked in a multi-threaded or Client-Server environment (in this part of the test suit, content is accessed in the same thread, so checking the result is not mandatory, but shown here for accuracy). In the current implementation of the framework, transactions should not be nested. The typical transaction usage should be the following: if Client.TransactionBegin(TSQLRecordPeopleObject) then try //.... modify the database content, raise exceptions on error Client.Commit; SAD - mORMot Framework - Rev. 1.18 Page 107 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 except Client.RollBack; // in case of error end; In a Client-Server environment with multiple Clients connected at the same time, you can use the dedicated TSQLRestClientURI.TransactionBeginRetry method: if Client.TransactionBeginRetry(TSQLRecordPeopleObject,20) then ... Note that the transactions are handled according to the corresponding client session: the client should make the transaction block as short as possible (e.g. using a batch command), since any write attempt by other clients will wait for the transaction to be released (with either a commit or rollback). The fields inherited from the TSQLRecord class are retrieved via FillPrepare / FillOne method calls, for columns with the LastName matching 'Morse'. One TPersistent property instance values are set (VO.Persistent.One), then, for every 32 rows, a new item is added to the VO.Persistent.Coll collection. Here is the data sent for instance to the Server, when the item with ID=32 is added: {"FirstName":"Samuel Finley Breese31", "LastName":"Morse", "YearOfBirth":1791, "YearOfDeath":1872, "UTF8":["32"], "Persistent":{"One":{"Color":132,"Length":32,"Name":"32"},"Coll":[{"Color":1032,"Length":64,"Name" :"96"}]} } Up to revision 1.15 of the framework, the transmitted JSON content was not a true JSON object, but sent as RawUTF8 TEXT values (i.e. every double-quote (") character is escaped as - e.g. "UTF8":"[32]"). Starting with revision 1.16 of the framework, the transmitted data is a true JSON object, to allow better integration with an AJAX client. That is, UTF8 field is transmitted as a valid JSON array of string, and Persistent as a valid JSON object with nested objects and arrays. When all 1000 rows were added to the database file, the following loop is called once with direct connection to the DB engine, once with a remote client connection (with all available connection protocols): for i := 1 to n do begin VO.ClearProperties; Client.Retrieve(i,VO); Check(VO.ID=i); Check(VO.LastName='Morse'); Check(VO.UTF8.Count=i shr 5); for j := 0 to VO.UTF8.Count-1 do Check(GetInteger(pointer(VO.UTF8[j]))=(j+1) shl 5); Check(VO.Persistent.One.Length=i); Check(VO.Persistent.One.Color=i+100); Check(GetInteger(pointer(VO.Persistent.One.Name))=i); Check(VO.Persistent.Coll.Count=i shr 5); for j := 0 to VO.Persistent.Coll.Count-1 do with VO.Persistent.Coll[j] do begin k := (j+1) shl 5; Check(Color=k+1000); Check(Length=k*2); Check(GetInteger(pointer(Name))=k*3); end; end; SAD - mORMot Framework - Rev. 1.18 Page 108 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 All the magic is made in the Client.Retrieve(i,VO) method. Data is retrieved from the database as TEXT values, then un-serialized from JSON arrays or objects into the internal TRawUTF8List and TPersistent instances. When the ID=33 row is retrieved, the following JSON content is received from the server: {"ID":33, "FirstName":"Samuel Finley Breese32", "LastName":"Morse", "YearOfBirth":1791, "YearOfDeath":1872, "UTF8":"[\"32\"]", "Persistent":"{\"One\":{\"Color\":133,\"Length\":33,\"Name\":\"33\"},\"Coll\":[{\"Color\":1032,\"L ength\":64,\"Name\":\"96\"}]}"} In contradiction with POST content, this defines no valid nested JSON objects nor arrays, but UTF8 and Persistent fields transmitted as JSON strings. This is a known limitation of the framework, due to the fact that it is much faster to retrieve directly the text from the database than process for this operation. For an AJAX application, this won't be difficult to use a temporary string property, and evaluate the JSON content from it, in order to replace the property with a corresponding object content. Implementation may change in the future. 5.4.2.1.2.3. Any TObject, including TObjectList Not only TPersistent, TCollection and TSQLRecord types can be serialized by writing all published properties. The ORM core of mORMot uses ObjectToJSON() and JSONToObject() (aka TJSONSerializer.WriteObject) functions to process proper JSON serialization. You have two methods to register JSON serialization for any kind of class: - Custom serialization via read and write callbacks - see TJSONSerializer. RegisterCustomSerializer below (page 189); - TObjectList instances, after a proper call to TJSONSerializer. RegisterClassForJSON below (page 190). In the database, such kind of objects will be stored as TEXT (serialized as JSON), and transmitted as regular JSON objects or arrays when working in Client-Server mode. 5.4.2.2. ORM implementation via pivot table Data sharding just feels natural, from the ORM point of view. But defining a pivot table is a classic and powerful use of relational database, and will unleash its power: - When data is huge, you can query only for the needed data, without having to load the whole content (it is something similar to lazy loading in ORM terminology); - In a master/detail data model, sometimes it can be handy to access directly to the detail records, e.g. for data consolidation; - And, last but not least, the pivot table is the natural way of storing data associated with "has many through" relationship (e.g. association time or corresponding permissions). 5.4.2.2.1. Introducing TSQLRecordMany A dedicated class, inheriting from the standard TSQLRecord class (which is the base of all objects stored in our ORM), has been created, named TSQLRecordMany. This table will turn the "many to many" relationship into two "one to many" relationships pointing in opposite directions. It shall SAD - mORMot Framework - Rev. 1.18 Page 109 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 contain at least two TSQLRecord (i.e. INTEGER) published properties, named "Source" and "Dest" (name is mandatory, because the ORM will share for exact matches). The first pointing to the source record (the one with a TSQLRecordMany published property) and the second to the destination record. For instance: TSQLDest = class(TSQLRecord); TSQLSource = class; TSQLDestPivot = class(TSQLRecordMany) private fSource: TSQLSource; fDest: TSQLDest; fTime: TDateTime; published property Source: TSQLSource read fSource; // map Source column property Dest: TSQLDest read fDest; // map Dest column property AssociationTime: TDateTime read fTime write fTime; end; TSQLSource = class(TSQLRecordSigned) private fDestList: TSQLDestPivot; published property SignatureTime; property Signature; property DestList: TSQLDestPivot read fDestList; end; TSQLDest = class(TSQLRecordSigned) published property SignatureTime; property Signature; end; When a TSQLRecordMany published property exists in a TSQLRecord, it is initialized automatically during TSQLRecord.Create constructor execution into a real class instance. Note that the default behavior for a TSQLRecord published property is to contain an INTEGER value which is the ID of the corresponding record - creating a "one to one" or "many to one" relationship. But TSQLRecordMany is a special case. So don't be confused! :) This TSQLRecordMany instance is indeed available to access directly the pivot table records, via FillMany then FillRow, FillOne and FillRewind methods to loop through records, or FillManyFromDest / DestGetJoined for most advanced usage. Here is how the regression tests are written in the SynSelfTests unit: procedure TestMany(aClient: TSQLRestClient); var MS: TSQLSource; MD, MD2: TSQLDest; i: integer; sID, dID: array[1..100] of Integer; res: TIntegerDynArray; begin MS := TSQLSource.Create; MD := TSQLDest.Create; try MD.fSignatureTime := Iso8601Now; MS.fSignatureTime := MD.fSignatureTime; Check(MS.DestList<>nil); Check(MS.DestList.InheritsFrom(TSQLRecordMany)); aClient.TransactionBegin(TSQLSource); // faster process This code will create two TSQLSource / TSQLDest instances, then will begin a transaction (for faster database engine process, since there will be multiple records added at once). Note that during TSQLSource.Create execution, the presence of a TSQLRecordMany field is detected, and the SAD - mORMot Framework - Rev. 1.18 Page 110 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 DestList property is filled with an instance of TSQLDestPivot. This DestList property is therefore able to be directly used via the "has-many" dedicated methods, like ManyAdd. for i := 1 to high(dID) do begin MD.fSignature := FormatUTF8('% %',[aClient.ClassName,i]); dID[i] := aClient.Add(MD,true); Check(dID[i]>0); end; This will just add some rows to the Dest table. for i := 1 to high(sID) do begin MS.fSignature := FormatUTF8('% %',[aClient.ClassName,i]); sID[i] := aClient.Add(MS,True); Check(sID[i]>0); MS.DestList.AssociationTime := i; Check(MS.DestList.ManyAdd(aClient,sID[i],dID[i])); // associate both lists Check(not MS.DestList.ManyAdd(aClient,sID[i],dID[i],true)); // no dup end; aClient.Commit; This will create some Source rows, and will call the ManyAdd method of the auto-created DestList instance to associate a Dest item to the Source item. The AssociationTime field of the DestList instance is set, to implement a "has many through" relationship. Then the transaction is committed to the database. for i := 1 to high(dID) do begin Check(MS.DestList.SourceGet(aClient,dID[i],res)); if not Check(length(res)=1) then Check(res[0]=sID[i]); Check(MS.DestList.ManySelect(aClient,sID[i],dID[i])); Check(MS.DestList.AssociationTime=i); end; This code will validate the association of Source and Dest tables, using the dedicated SourceGet method to retrieve all Source items IDs associated to the specified Dest ID, i.e. one item, matching the sID[] values. It will also check for the AssociationTime as set for the "has many through" relationship. for i := 1 to high(sID) do begin Check(MS.DestList.DestGet(aClient,sID[i],res)); if Check(length(res)=1) then continue; // avoid GPF Check(res[0]=dID[i]); The DestGet method retrieves all Dest items IDs associated to the specified Source ID, i.e. one item, matching the dID[] values. Check(MS.DestList.FillMany(aClient,sID[i])=1); This will fill prepare the DestList instance with all pivot table instances matching the specified Source ID. It should return only one item. Check(MS.DestList.FillOne); Check(Integer(MS.DestList.Source)=sID[i]); Check(Integer(MS.DestList.Dest)=dID[i]); Check(MS.DestList.AssociationTime=i); Check(not MS.DestList.FillOne); Those lines will fill the first (and unique) prepared item, and check that Source, Dest and AssociationTime properties match the expected values. Then the next call to FillOne should fail, SAD - mORMot Framework - Rev. 1.18 Page 111 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 since only one prepared row is expected for this Source ID. Check(MS.DestList.DestGetJoined(aClient,'',sID[i],res)); if not Check(length(res)=1) then Check(res[0]=dID[i]); This will retrieve all Dest items IDs associated to the specified Source ID, with no additional WHERE condition. Check(MS.DestList.DestGetJoined(aClient,'Dest.SignatureTime=:(0):',sID[i],res)); Check(length(res)=0); This will retrieve all Dest items IDs associated to the specified Source ID, with an additional always invalid WHERE condition. It should always return no item in the res array, since SignatureTime is never equal to 0. Check(MS.DestList.DestGetJoined(aClient, FormatUTF8('Dest.SignatureTime=?',[],[MD.SignatureTime]),sID[i],res)); if Check(length(res)=1) then continue; // avoid GPF Check(res[0]=dID[i]); This will retrieve all Dest items IDs associated to the specified Source ID, with an additional WHERE condition, matching the expected value. It should therefore return one item. Note the call of the global FormatUTF8() function to get the WHERE clause. You may have written instead: Check(MS.DestList.DestGetJoined(aClient, 'Dest.SignatureTime=:('+Int64ToUTF8(MD.SignatureTime)+'):',sID[i],res)); But in this case, using manual inlined :(..): values is less convenient than the '?' calling convention, especially for string (RawUTF8) values. MD2 := MS.DestList.DestGetJoined(aClient, FormatUTF8('Dest.SignatureTime=?',[],[MD.SignatureTime]),sID[i]) as TSQLADest; if Check(MD2<>nil) then continue; try Check(MD2.FillOne); Check(MD2.ID=dID[i]); Check(MD2.Signature=FormatUTF8('% %',[aClient.ClassName,i])); finally MD2.Free; end; end; This overloaded DestGetJoined method will return into MD2 a TSQLDest instance, prepared with all the Dest record content associated to the specified Source ID , with an additional WHERE condition, matching the expected value. Then FillOne will retrieve the first (and unique) matching Dest record, and checks for its values. aClient.TransactionBegin(TSQLADests); // faster process for i := 1 to high(sID) shr 2 do Check(MS.DestList.ManyDelete(aClient,sID[i*4],dID[i*4])); aClient.Commit; for i := 1 to high(sID) do if i and 3<>0 then begin Check(MS.DestList.ManySelect(aClient,sID[i],dID[i])); Check(MS.DestList.AssociationTime=i); end else Check(not MS.DestList.ManySelect(aClient,sID[i],dID[i])); This code will delete one association per four, and ensure that ManySelect will retrieve only expected SAD - mORMot Framework - Rev. 1.18 Page 112 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 associations. finally MD.Free; MS.Free; end; This will release associated memory, and also the instance of TSQLDestPivot created in the DestList property. 5.4.2.2.2. Automatic JOIN query All those methods (ManySelect, DestGetJoined...) are used to retrieve the relations between tables from the pivot table point of view. This saves bandwidth, and can be used in most simple cases, but it is not the only way to perform requests on many-to-many relationships. And you may have several TSQLRecordMany instances in the same main record - in this case, those methods won't help you. It is very common, in the SQL world, to create a JOINed request at the main "Source" table level, and combine records from two or more tables in a database. It creates a set that can be saved as a table or used as is. A JOIN is a means for combining fields from two or more tables by using values common to each. Writing such JOINed statements is not so easy by hand, especially because you'll have to work with several tables, and have to specify the exact fields to be retrieved; if you have several pivot tables, it may start to be a nightmare. Let's see how our ORM will handle it. A dedicated FillPrepareMany method has been added to the TSQLRecord class, in conjunction with a new constructor named CreateAndFillPrepareMany. This particular method will: - Instantiate all Dest properties of each TSQLRecordMany instances - so that the JOINed request will be able to populate directly those values; - Create the appropriate SELECT statement, with an optional WHERE clause. Here is the test included in our regression suite, working with the same database: Check(MS.FillPrepareMany(aClient, 'DestList.Dest.SignatureTime<>% and id>=? and DestList.AssociationTime<>0 '+ 'and SignatureTime=DestList.Dest.SignatureTime '+ 'and DestList.Dest.Signature<>"DestList.AssociationTime"',[0],[sID[1]])); Of course, the only useful parameter here is id>=? which is used to retrieve the just added relationships in the pivot table. All other conditions will always be true, but it will help testing the generated SQL. Our mORMot will generate the following SQL statement: select A.ID AID,A.SignatureTime A00,A.Signature A01, B.ID BID,B.AssociationTime B02, C.ID CID,C.SignatureTime C00,C.Signature C01 from ASource A,ADests B,ADest C where B.Source=A.ID and B.Dest=C.ID and (C.SignatureTime<>0 and A.id>=:(1): and B.AssociationTime<>0 and A.SignatureTime=C.SignatureTime and C.Signature<>"DestList.AssociationTime") You can notice the following: - All declared TSQLRecordMany instances (renamed B in our case) are included in the statement, with all corresponding Dest instances (renamed as C); - Fields are aliased with short unique identifiers (AID, A01, BID, B02...), for all simple properties of every classes; - The JOIN clause is created (B.Source=A.ID and B.Dest=C.ID); SAD - mORMot Framework - Rev. 1.18 Page 113 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 - Our manual WHERE clause has been translated into proper SQL, including the table internal aliases (A,B,C) - in fact, DestList.Dest has been replaced by C, the main ID property has been declared properly as A.ID, and the "DestList.AssociationTime" text remained untouched, because it was bounded with quotes. That is, our ORM did make all the dirty work for you! You can use Delphi-level conditions in your query, and the engine will transparently convert them into a valid SQL statement. Benefit of this will become clear in case of multiple pivot tables, which are likely to occur in real-world applications. After the statement has been prepared, you can use the standard FillOne method to loop through all returned rows of data, and access to the JOINed columns within the Delphi objects instances: Check(MS.FillTable.RowCount=length(sID)); for i := 1 to high(sID) do begin MS.FillOne; Check(MS.fID=sID[i]); Check(MS.SignatureTime=MD.fSignatureTime); Check(MS.DestList.AssociationTime=i); Check(MS.DestList.Dest.fID=dID[i]); Check(MS.DestList.Dest.SignatureTime=MD.fSignatureTime); Check(MS.DestList.Dest.Signature=FormatUTF8('% %',[aClient.ClassName,i])); end; MS.FillClose; Note that in our case, an explicit call to FillClose has been added in order to release all Dest instances created in FillPrepareMany. This call is not mandatory if you call MS.Free directly, but it is required if the same MS instance is about to use some regular many-to-many methods, like MS.DestList.ManySelect() - it will prevent any GPF exception to occur with code expecting the Dest property not to be an instance, but a pointer(DestID) value. 5.5. ORM Cache Here is the definition of "cache", as stated by Wikipedia: In computer engineering, a cache is a component that transparently stores data so that future requests for that data can be served faster. The data that is stored within a cache might be values that have been computed earlier or duplicates of original values that are stored elsewhere. If requested data is contained in the cache (cache hit), this request can be served by simply reading the cache, which is comparatively faster. Otherwise (cache miss), the data has to be recomputed or fetched from its original storage location, which is comparatively slower. Hence, the greater the number of requests that can be served from the cache, the faster the overall system performance becomes. To be cost efficient and to enable an efficient use of data, caches are relatively small. Nevertheless, caches have proven themselves in many areas of computing because access patterns in typical computer applications have locality of reference. References exhibit temporal locality if data is requested again that has been recently requested already. References exhibit spatial locality if data is requested that is physically stored close to data that has been requested already. In our ORM framework, since performance was one of our goals since the beginning, cache has been implemented at four levels: - Statement cache for implementing SQL prepared statements, and parameters bound on the fly see Query parameters (page 95) and below (page 144) - note that this cache is available not only for the SQlite3 database engine, but also for any external engine - see below (page 166); - Global JSON result cache at the database level, which is flushed globally on any INSERT / UPDATE see below (page 195); SAD - mORMot Framework - Rev. 1.18 Page 114 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 - Tuned record cache at the CRUD/RESTful level for specified tables or records on the server side see below (page 217); - Tuned record cache at the CRUD/RESTful level for specified tables or records on the client side - see below (page 217). Thanks to those specific caching abilities, our framework is able to minimize the number of client-server requests, therefore spare bandwidth and network access, and scales well in a concurrent rich client access architecture. In such perspective, a Client-Server ORM does make sense, and is of huge benefit in comparison to a basic ORM used only for data persistence and automated SQL generation. 5.6. Calculated fields It is often useful to handle some calculated fields. That is, having some field values computed when you set another field value. For instance, if you set an error code from an enumeration (stored in an INTEGER field), you may want the corresponding text (to be stored on a TEXT field). Or you may want a total amount to be computed automatically from some detailed records. This should not be done on the Server side. In fact, the framework expects the transmitted JSON transmitted from client to be set directly to the database layer, as stated by this code from the mORMotSQLite3 unit: function TSQLRestServerDB.EngineUpdate(Table: TSQLRecordClass; ID: integer; const SentData: RawUTF8): boolean; begin if (self=nil) or (Table=nil) or (ID<=0) then result := false else begin // this SQL statement use :(inlined params): for all values result := EngineExecuteFmt('UPDATE % SET % WHERE RowID=:(%):;', [Table.RecordProps.SQLTableName,GetJSONObjectAsSQL(SentData,true,true),ID]); if Assigned(OnUpdateEvent) then OnUpdateEvent(self,seUpdate,Table,ID); end; end; The direct conversion from the received JSON content into the SQL UPDATE statement values is performed very quickly via the GetJSONObjectAsSQL procedure. It won't use any intermediary TSQLRecord, so there will be no server-side field calculation possible. Record-level calculated fields should be done on the Client side, using some setters. There are at least three ways of updating field values before sending to the server: - Either by using some dedicated setters method for TSQLRecord properties; - Or by overriding the ComputeFieldsBeforeWrite virtual method of TSQLRecord. - If the computed fields need a more complex implementation (e.g. if some properties of another record should be modified), a dedicated RESTful service should be implemented - see below (page 227). 5.6.1. Setter for TSQLRecord For instance, here we define a new table named INVOICE, with only two fields. A dynamic array containing the invoice details, then a field with the total amount. The dynamic array property will be stored as BLOB into the database, and no additional Master/Detail table will be necessary. type TInvoiceRec = record SAD - mORMot Framework - Rev. 1.18 Page 115 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 Ident: RawUTF8; Amount: currency; end; TInvoiceRecs = array of TInvoiceRec; TSQLInvoice = class(TSQLRecord) protected fDetails: TInvoiceRecs; fTotal: Currency; procedure SetDetails(const Value: TInvoiceRecs); published property Details: TInvoiceRecs read fDetails write SetDetails; property Total: Currency read fTotal; end; Note that the Total property does not have any setter (aka write statement). So it will be read-only, from the ORM point of view. In fact, the following protected method will compute the Total property content from the Details property values, when they will be modified: procedure TSQLInvoice.SetDetails(const Value: TInvoiceRecs); var i: integer; begin fDetails := Value; fTotal := 0; for i := 0 to high(Value) do fTotal := fTotal+Value[i].Amount; end; When the object content will be sent to the Server, the Total value of the JSON content sent will contain the expected value. Note that with this implementation, the SetDetails must be called explicitly. That is, you should not only modify directly the Details[] array content, but either use a temporary array during edition then assign its value to Invoice.Details, or force the update with a line of code like: Invoice.Details := Invoice.Details; // force Total calculation 5.6.2. TSQLRecord.ComputeFieldsBeforeWrite Even if a TSQLRecord instance should not normally have access to the TSQLRest level, according to OOP principles, the following virtual method have been defined: TSQLRecord = class(TObject) public procedure ComputeFieldsBeforeWrite(aRest: TSQLRest; aOccasion: TSQLEvent); virtual; (...) It will be called automatically on the Client side, just before a TSQLRecord content will be sent to the remote server, before adding or update. In fact, the TSQLRestClientURI.Add / Update / BatchAdd / BatchUpdate methods will call this method before calling TSQLRecord.GetJSONValues and send the JSON content to the server. On the Server-side, in case of some business logic involving the ORM, the TSQLRestServer.Add / Update methods will also call ComputeFieldsBeforeWrite. By default, this method will compute the TModTime / sftModTime and TCreateTime / sftCreateTime properties value from the current server time stamp, as such: procedure TSQLRecord.ComputeFieldsBeforeWrite(aRest: TSQLRest; aOccasion: TSQLEvent); var F: integer; begin if (self<>nil) and (aRest<>nil) then with RecordProps do begin SAD - mORMot Framework - Rev. 1.18 Page 116 of 1055 18 Date: June 16.ServerTimeStamp).Fields[F].Fields[F]. end. 2013 if HasModTimeFields then for F := 0 to high(FieldType) do if FieldType[f]=sftModTime then SetInt64Prop(Self. You may override this method for you own purpose. saved the fact that you call this inherited implementation to properly handle TModTime and TCreateTime published properties. if HasCreateTimeField and (aOccasion=seAdd) then for F := 0 to high(FieldType) do if FieldType[f]=sftCreateTime then SetInt64Prop(Self. SAD .Rev. 1.aRest.ServerTimeStamp).18 Page 117 of 1055 . end.Synopse mORMot Framework Software Architecture Design 1.aRest.mORMot Framework . included into the Delphi language during compile time.org/index. Do you want to rename or delete a field? Change the class definition. You do not have to switch your mind from one syntax to another. and only during execution time for the SQL. then select the Name property. 2013 6.wiki. forget about field typing mismatch or wrong type assignment in your database tables. Daily ORM Adopt a mORMot When you compare ORM and standard SQL. ). And happy coding. In one word.Synopse mORMot Framework Software Architecture Design 1. First. Another risk-related improvement is about the strong type checking.18 Page 118 of 1055 . Python or SAD .html/doc/tip/www/theory1.fossil-scm. You can even forget about the SQL itself for most projects. and the Delphi compiler will let you know all places where this property was used in your code. but you will avoid it most of the time. Strong typing is great in such cases for code SQA. and can use field completion in the IDE. without any risk of missing a hidden SQL statement anywhere. It is much more convenient to type Baby. For example. in your code. and if you worked with some scripting languages (like JavaScript. Do you want to add a field to an existing database? Just add the property definition. You will avoid most runtime exceptions for your database access: your clients will thank you for that.18 Date: June 16. some aspects must be highlighted. only some performance-related or complex queries should be written in SQL. Because SQL is a true language (see SQL Is A High-Level Scripting Language at http://www..Rev. 1. Think object pascal. and the framework will create the missing field in the database schema for you. Your software architecture will thank you for it. Another good impact is the naming consistency. what about if you want to rename your table? Just change the class definition.mORMot Framework . The ORM code is much more readable than the SQL. and access to its value. you do not have to worry about field orders and names. and your IDE will do all refactoring for you. Another interesting feature is the enhanced Grid component supplied with this framework.1. . Another point is that a table is not to be created for every aspect of your software configuration.g. but logical units. named pipe or HTTP). TPersistent. but "Which data do I need?". You can even work off line. its ORM core is optimized but not tied to SQL. is that you should better not create Master/Detail tables.18 Page 119 of 1055 . In an ORM. The database is just one way of your objects persistence: . you should usually define fewer tables than in a "regular" relational database. All the SQL coding or communication and error handling will be done by the framework.mORMot Framework . because you can use the high-level type of the TSQLRecord properties to handle some per-row data.Don't think about tables with simple types (text/number. just create an instance of a TSQLRestClient object (with the communication layer you want to use: direct access. as JSON. 2013 Ruby). and the AJAX-ready orientation. The first point.1. with a local database replication of the remote data. then use the unique corresponding table to store all configuration encoded as some JSON data. ORM is not Database It is worth emphasizing that you should not think about the ORM like a mapping of an existing DB schema. For Client-Server . and can create key indexing and perform foreign key checking in class definition. and its properties and methods are strong enough to access the data. Objects. For instance. The REST protocol can be used in most application. And do not hesitate to separate SAD .18 Date: June 16.). don't be tempted to always create a pivot table (via a TSQLRecordMany property). TStrings or TCollection properties. Let's confess that some DB architects design one configuration table per module or per data table. This is an usual mistake in ORM design.Don't wonder "How will I store it?". or some DFM-like data. TStrings or TCollection published properties instead. via dynamic array. via TSQLRestServerStaticInMemory. you could design a configuration class. .Synopse mORMot Framework Software Architecture Design 1. and use it as any normal Delphi object..Don't think "SQL". TPersistent. 6. think about classes. by using natively JSON flows for Client-Server data streaming.Don't think about Master/Detail. instead of creating one TSQLRecord property per potential table.see below (page 184) . The same code can be used in the Client or Server side: the parent TSQLRest object is available on both sides. since the framework provides you with an easy to use "Refresh" and caching mechanism. e. but consider using a dynamic array. not tables With an ORM.you do not have to open a connection to the database. but objects with high level types.1. The mORMot framework is even able to persist the object without any SQL database. . 6.. 1. but just one "master" object with the details stored within. which may be shocking for a database architect. GDI messages. Or consider that you can use a TRecordReference property pointing to any registered class of the TSQLModel. you should have wished to have this feature in your project! It is worth noting that our framework allows writing triggers and stored procedures (or like stored procedures) in Delphi code. In fact.Rev. It is up to the ORM to: .. via the CreateMissingTables method .Drive := X.Synopse mORMot Framework Software Architecture Design 1. In the above lines. try for X := 'A' to 'Z' do begin D. TSQLRestClientDB(GlobalClient).FillDrives(aList: TStrings).Create(DrivesModel. .and not compute by hand a "CREATE TABLE IF NOT EXISTS.and not any "INSERT OR IGNORE INTO DRIVES.DB.Rev. not SQL At first. nil. 'root').. Methods. end. With our framework. .. you can serialize directly any TSQLRecord or TPersistent instance into JSON. end.g.').Create.Server.Execute( 'INSERT OR IGNORE INTO drives (drive) VALUES ("' + StringToUTF8(X) + ':")').Create([TDrives]. GlobalClient. for all not data-related configuration . 'drives. end. GlobalClient := TMyClient. in order to retrieve some data.true). X. TSQLRestServerDB)." SQL statement. without the need of adding this TSQLRecord to the TSQLModel list.ExecuteList([TSQLDrives]. don't do that! The correct ORM-oriented implementation should be the following: DrivesModel := TSQLModel.2. finally D. 2013 the configuration from the data.13 of the framework. 6. TSQLRestServerDB). how the mORMotOptions unit works. GlobalClient. you should be tempted to write code as such (this code sample was posted on our forum. via the TableRowCount method .Server. Since revision 1.". begin table := TSQLRestClientDB(GlobalClient).sqlite'. you'll be tempted to code something like that (extracted from the same forum article): procedure TMyClient.Execute( 'CREATE TABLE IF NOT EXISTS drives ' + '(id INTEGER PRIMARY KEY. if GlobalClient. drive TEXT NOT NULL UNIQUE COLLATE NOCASE).see e.Create all missing tables. for X := 'A' to 'Z' do begin TSQLRestClientDB(GlobalClient). and it will be automatically serialized as TEXT in the database. FieldIndex: Integer. 'drives. end. 'SELECT * FROM drives').mORMot Framework .DB.Create(DrivesModel. Please. no SQL was written.18 Date: June 16. Then.sqlite'. var table: TSQLTableJSON.TableRowCount(TDrives)=0 then begin D := TDrives. and is not bad code.1. you can even define TPersistent published properties in your TSQLRecord class. SAD .Append some data using an high-level TDrives Delphi instance and the Add method . 1.Check if there is some rows of data..Add(D. GlobalClient := TSQLRestClientDB.Free. just not using the ORM orientation of the framework): DrivesModel := CreateDrivesModel(). CreateDrivesModel().CreateMissingTables(0).18 Page 120 of 1055 .instead of a "SELECT COUNT(*) FROM DRIVES". it retrieves all columns content from the server. 1.CreateAndFillPrepare(GlobalClient. 2013 if (table <> nil) then try FieldIndex := table.'') do try while FillOne do aList. For instance.''. with a specific WHERE clause using a prepared SAD . This is a common potential issue of an ORM: since the library doesn't know which data is needed. code is somewhat easy to follow.FieldIndex('drive'). We even added the BeginUpdate / EndUpdate VCL methods. even if you need only one. you have an even more high-level method. end. it could make sense to ask only for this very column. and easier to understand. in order to retrieve only the Drive property content. For a particular ID range. FieldIndex))).BeginUpdate. end.CreateAndFillPrepare(GlobalClient. if (FieldIndex >= 0) then for X := 1 to table.Add(UTF8ToString(table. Drive is now a RawUTF8 property). try aList.18 Page 121 of 1055 .FillDrives(aList: TStrings). One drawback of the CreateAndFillPrepare method is that. it will retrieve all object data.g.g. finally table.EndUpdate.OneFieldValues(TSQLDrives. end. begin aList. using the CreateAndFillPrepare then FillOne method in a loop: procedure TMyClient.'Drive') do Note that for this particular case.18 Date: June 16.GetU(X. with no SELECT statement to write. end.'drive'. end.). to have even cleaner and faster code (if you work with a TListBox e.Clear. an hidden TSQLTableJSON class is created in order to retrieve the data from the server. which is some cases is not worth it.aList). The abstraction introduced by the ORM methods makes the code not slowest. begin GlobalClients.RowCount do Items. But ORM is not perfect in all cases. end. handling directly a TStrings property as the recipient: procedure TMyClient.Synopse mORMot Framework Software Architecture Design 1. finally Free. You can specify the optional aCustomFieldsCSV parameter as such. but less error-prone (e. by default. Thanks to the TSQLTableJSON class. you may have written. Note that in the above code. The whole query is made in one line.FillDrives(aList: TStrings). But it could also be coded as such. if the Drive field is the only column content to retrieve. and potentially save some bandwidth: with TSQLDrives. with TSQLDrives.''. finally aList.Free.Add(UTF8ToString(Drive)).mORMot Framework .Rev. Using a temporary FieldIndex variable make also it fast inside the loop execution. In the following pages. There is another "mis-use" for the "stored AS_UNIQUE" property.18 Page 122 of 1055 . It is certainly worth reading all the (verbose) interface part of the mORMot.2. If you need additional high-level features.OneFieldValues(TSQLDrives. Think multi-tier And do not forget the framework is able to have several level of objects. Since this parameter was ignored and not used for most classes. One ORM to rule them all Just before entering deeper into the mORMot material in the following pages (Database layer.2. If you have a very specific database schema.1.[]. you'll find all needed documentation about this particular unit.aLastID]. and it is worth saying that FPC has an alternative syntax. and can't persist any plain class". freely available at http://synopse."One of the things I don't like so much about your approach to the ORM is the mis-use of existing Delphi constructs like "index n" attribute for the maximum length of a string-property.see below (page 221) . Those concerns are pretty understandable.see below (page 184).e. so it was not possible to be compatible with Delphi 6 up to latest versions (as we wished for our units). feel free to ask for them. you may find out that this implementation may sounds restricted.3.which almost all are following the Hibernate way of doing.info. to have faster lookup).pas unit. 1. Such usage is not only possible. Since our framework is used in real applications. Client-Server. if possible with source code sample. business-logic objects can be of very high level."You have to inherit from TSQLRecord. Services). It is perfectly right to speak about 'mis-use of index' . 2013 statement: GlobalClients. to make your own idea about all the high-level methods available. . and accessed via some RESTful service commands for writing . Rude class definition Attributes do appear in Delphi 2010. 6. but strongly encouraged.Synopse mORMot Framework Software Architecture Design 1.aList)."There is no way to easily map an existing complex database". and why it may be quite unique within the family of ORMs . Our mORMot framework is not meant to fit any purpose. it was re-used (also for dynamic array properties.mORMot Framework . 'ID>=? AND ID<=?'.1.both coded in Delphi. most useful methods should already have been made available. is to use either custom SQLite3 SQL functions or stored procedures .Rev.[aFirstID. with official Class-attributes". 6. Older versions of Delphi (still very deployed) do not have attributes available in the language.18 Date: June 16.g. just using RTTI.. 6. but it is worth understanding why it has been implemented as such. Another possibility to access your high-level type. Other ORMs solve this i. in our forum. Then both business-logic and DB objects at the Server side. the TSQLRest class. which is used to identify unique SAD . encapsulating some SQL views for reading.but this was the easiest and only way we found out to have such information. Some common (and founded) criticisms are the following (quoting from our forum): . You should have business-logic level objects at the Client side. thanks to our Client-Server architecture .see below (page 227). e.'drive'. . and you need to link to all the DB plumbing code to your application. indexes. just from the TSQLRecord class definition. some coders have a concern about such class definitions. The framework favors convention over configuration. and can't persist anything. which is a DB feature. 6.see below (page 292). In fact. 1.2. So it may be faster (and safer) to rely on it. it was some kind of strong argument. In short. as safe and efficient as possible. It will make it pretty database-agnostic (you can even not use a SQL database at all).2. Attributes do have a huge downsize. It has been optimized a lot (e. When you take a look at the supplied validators and filters . or to match a pattern. as I do.config syndrome). than defining all your class hierarchy by SAD . 2013 mandatory columns.Rev. Using attributes is one of the most common ways of describing tables in most ORMs. You can move all of this behavior into a common Layer Supertype. Almost everything is created by code. For mORMot. like ours: on the Client side. Persist TSQLRecord. so I do not think reinventing a CRUD / database service is worth the prize. On the other hand. with a cache and other nice features). That is why other kind of ORMs provide a way of mapping classes to tables using external files (some ORMs provide both ways of definition). and main cause of success: CRUD is enough in our KISS-friendly design.18 Page 123 of 1055 . which is known to save a lot of time (if you use WCF on a daily basis. You have secure access to the ORM classes. when you are dealing with a Client-Server ORM. .At ORM level for DB related stuff (like indexes. For the very same reasons. for TSQLRecord / TSQLRest / ORM remote access. not a business feature). validators and filters). The mORMot point of view (which is not the only one).18 Date: June 16. via RTTI.like in-memory or SQLite3 is able to do it). our purpose was in fact very similar to the "Layer Supertype" pattern of Domain-Driven-Design. you have already all Client-Server CRUD operations available. is to let the DB persist the data. those attributes are pointless (client does not need to know anything about the database).At Model level for Business related stuff (like uniqueness. or to ensure that it will be stored in uppercase within the DB? Other question worth asking is about the security. above the DB layer (and has also complete security attributes for services) . It works however the underneath DB grants are defined (even an DB with no user rights . If you access the data remotely.see below (page 127) . even code gurus identified the attributes overuse as a potential weakness of code maintainability.you'll find out that this is much powerful than the attributes available in "classic" ORMs: how could you validate an entry to be an email. with user/group attributes. but rely on higher levels layers to implement the business logic. as explained by Martin Fowler: It is not uncommon for all the objects in a layer to have methods you don't want to have duplicated throughout the system. you and your support team know about the . this is the REST point of view. and will make the framework code easier to debug and maintain. And why those days.g. a global access to the DB is certainly not enough. ready to be used in your projects. They are mixing DB and logic: you are somewhat polluting the business-level class definition with DB-related stuff. required) are managed in mORMot at two levels: . the column definitions (uniqueness.mORMot Framework . Our framework handle per-table CRUD level access for its ORM. Those classes are abstract common Supertypes. not any class About the fact that you need to inherit from TSQLRecord.Synopse mORMot Framework Software Architecture Design 1. since we don't have to deal with all the DB engine particularities. This feature is not yet implemented. Several ORMs at once To be clear. unless you like your software to be a maintenance nightmare! Some Event Sourcing architectures even implement several DB back-end at once: . remote access will be safe: your clients won't be able to change the consolidation DB content! SAD . it is very powerful. . from consolidated data . whatever OleDB or ODBC provider. From the Domain-Driven / SOA point of view. or dedicated classes. but already existing in the DB. with sometimes a very complex layout. The concern of not being able to persist any class (it needs to inherit from TSQLRecord) does perfectly make sense.18 Date: June 16. on file. from the implementation point of view.Rev. MS SQL.3. since you have a lot of methods included within this class definition. On the other hand.And store the modification events in another ACID DB (e.pas unit). mORMot offers three kind of table definitions: . and therefore a cleaner design. external DB tables are created and managed by the ORM. Another benefit of using a parent class is to enforce code safety using Delphi's strong type abilities: you won't be able to pass a non-persistent type to methods which expect one. or with dedicated classes (or interface).And even sometimes fill some dedicated consolidation DBs for further analysis. or virtual). using a SQLite3 engine. we use index for text column length. it is now an established rule to make a distinction between DTO and Domain Values (Entity objects or Aggregates). Jet. or SQLite3 tables (in memory. and clients won't even need to know that they are implemented in-memory.see below (page 166).mORMot Framework .g. mostly in a read-only way. for dedicated reporting.Via TSQLRecordMappedAutoID / TSQLRecordMappedForcedID "external mapped" classes: DB tables are not created by the ORM. These classes will allow creation of tables in any supported external database engine (SQlite3.g.g. but we will rely on definition from code. or any DB.this is one potential CQRS implementation pattern with mORMot. Oracle. In this case. persistence objects (aka ORM objects) should be either the aggregate roots themselves (you do not store Entity objects and even worse DTOs). high-performance in-memory) for most common requests to be immediate.Via TSQLRecord / TSQLRecordVirtual "native ORM" classes: data storage is using either fast in-memory lists via TSQLRestServerStaticInMemory. 6.Synopse mORMot Framework Software Architecture Design 1. It does also make sense to have a common ancestor able to identify all three kind of mORMot's table definitions: the same abstract ancestor is used. but on the road-map. the consolidation DB). In most implementations. we do not use index for strings (column length is not used by any of those engines).18 Page 124 of 1055 .Via TSQLRecord "external ORM-managed" classes: after registration via a call to the VirtualTableExternalRegister() function. See below (page 304) for more details about DDD and how mORMot's TSQLRecord can help you reuse existing code. AFAIK it could be possible to directly access ORM objects remotely (e. Do not mix layers. This is the only needed parameter to be defined for such a basic implementation.2. MS SQL or Oracle). 1. e. SQLite3. . either with a fluent definition. in regard to TSQLRecord kind of classes. nor even external files. . For this kind of classes we won't probably use attributes. write less and safer.It will store the status on one DB (e. .g. Thanks to the framework security. In this case. or any external database. Having a dedicated class help the layer separation. 2013 hand. via SQL . MS SQL or even with no SQL engine. . mORMot is a first class candidate: we identified that some users are using the built-in JSON serialization and HTTP server features to create their application. mORMot will handle it soon (it is planned and prepared within the framework architecture).4. since it expects objects to inherit from TSQLRecord . but probably in the future) to create some kind of scalable Domain-Driven design architecture. .Rev. The best ORM is the one you need Therefore. About how to use mORMot with existing code.If your understanding of ORM is just to persist some existing objects with a lot of existing business code. depending of your intent: . we may sum up some potential use of ORM. mORMot is not just an ORM.If you want a very fast low-level Client-Server layer.Synopse mORMot Framework Software Architecture Design 1. the framework will be a light and fast candidate. even those allowing to persist any class. 2013 As can be easily guessed. would not be so easy to work with.see below (page 160). you'll have all needed features at hand with mORMot. see Legacy code and existing projects (page 53). 6. nor just a "classic" ORM. such design models are far away from a basic ORM built only for class persistence.If your expectation is to map an existing complex DB. . via SQLite3. Therefore. 1.18 Date: June 16.but note that most ORMs.mORMot Framework . . SAD .18 Page 125 of 1055 .2.If you want to persist some data objects (not tied to complex business logic). mORMot won't help you directly. Oracle. using TSQLRestServerStaticInMemory class which is able to persist its content with small files .If you need (perhaps not now. both database-related and business-logic related. Creating a Model According to the Model-View-Controller (MVC) pattern . but pure in-memory tables! Each TSQLModel instance is in fact associated with a TSQLRest instance. 2013 7.Synopse mORMot Framework Software Architecture Design 1. but may have been defined as TSQLRestServerStaticInMemory instance via the TSQLRestServer. In fact.mORMot Framework .1. In order to follow the MVC pattern.18 Date: June 16. An Owner property gives access to the current running client or server TSQLRest instance associated with this model. 1. the TSQLModel instance is to be used when you have to deal at table level. and have a common function to create the related TSQLModel class. The TSQLModel class centralizes all TSQLRecord inherited classes used by an application. It is therefore a good practice to use a common unit to define all TSQLRecord types.GetTableNames or TSQLDataBase.the database schema should be handled separately from the User Interface.GetFieldNames methods in your code. models are used on both Client and Server sides. You could even have a mORMot server running without any SQLite3 engine at all.see below (page 166). MVC pattern Adopt a mORMot 7. For instance. or being external tables . By design.StaticDataCreate method.see Model-View-Controller (page 60) .Rev. here is the corresponding function as defined in the first samples available in the source SAD .18 Page 126 of 1055 . do not try to use low-level TSQLDataBase. For instance. the tables declared in the Model may not be available in the SQLite3 database schema. They all will be children of any of those both classes: TSynValidate TSynFilter TSynFilterOrValidate Filtering and Validation classes hierarchy SAD .. not in the User Interface.2.Props. or if client and server instances are running in the same process.TableProps[]. you may have to change a bit your habits here. If you were used to develop RAD database application using Delphi. like dedicated SQL auto-generation and external DB settings. ModelProps: TSQLModelRecordProperties. for accessing the model properties.Rev. 2013 code repository (unit SampleData. begin result := TSQLModel.ExternalTableName .18 Date: June 16.data filtering and validation should be implemented in the business logic. For a more complex model including link to User Interface. Props := ModelProps.. In order to make this easy. TSQLRecordProperties Low-level table properties.18 Page 127 of 1055 .pas): function CreateSampleModel: TSQLModel. Data filtering and validation should be implemented not in the User Interface. but in pure Delphi code. as retrieved from below (page 129) by the ORM kernel of mORMot. and allow to define both filtering and validation. So you may use code like this: var i: integer.. Access these instances from TSQLModel. begin . a same TSQLRecord can be used in several models: this is typically the case for TSQLAuthUser tables.mORMot Framework .Synopse mORMot Framework Software Architecture Design 1.Fields[] end. a dedicated set of classes are available in the SynCommons.. // now you can use Props. Props: TSQLRecordProperties. you have two structures available: Class Description TSQLModelRecordProperti es Model-specific ORM parameters. Access these instances from TSQLModel. end. for i := 0 to high(Model.see Multi-tier architecture (page 61) .pas unit.TableProps[] array.SQLTableName or Props. // now you can access ModelProps.TableProps[i]. So. Filtering and Validating According to the n-Tier architecture . 1.Props.TableProps) do begin ModelProps := Model. 7. see below (page 130).Create([TSQLSampleRecord]). end. In practice. Some "standard" classes are already defined in the SynCommons. or via some TSQLValidate classes. textual validation..Rev. strong password validation. 1. you can add some filters/validators to your TSQLModel creation function: function CreateFileModel(Owner: TSQLRest): TSQLModel. 2013 TSQLRecord field content validation is handled in the new TSQLRecord. @FileTabs. the mORMotUIEdit unit now handles TSQLRecord automated filtering (using TSQLFilter classes) and validation (using one of the TSQLValidate classes).sizeof(FileTabs[0]). The unique field validation is now in TSQLRecord. like TSynValidateUniqueField which inherits from TSynValidateRest.Synopse mORMot Framework Software Architecture Design 1. Of course.pas units.length(FileTabs). simple regex pattern. TSQLRecord field content filtering is handled in the new TSQLRecord.18 Date: June 16. TypeInfo(TFileAction).mORMot Framework . begin result := TSQLModel. Email (with TLD+domain name). Filter virtual method. Note that some database-related filtering are existing. to be used for most common usage: TSynFilterUpperCaseU TSynFilterUpperCase TSynFilterTrim TSynFilter TSynFilterLowerCaseU TSynFilterLowerCase TSynValidatePassWord TSynValidateText TSynValidateTableUniqueField TSynValidateTable TSynValidateUniqueField TSynValidateRest TSynValidatePatternI TSynValidatePattern TSynFilterOrValidate TSynValidate TSynValidateIPAddress TSynValidateEmail Default filters and Validation classes hierarchy You have powerful validation classes for IP Address.18 Page 128 of 1055 .[]. or via some TSQLFilter classes. Validate virtual method. Validate and not in mORMotUIEdit itself (to have a better multi-tier architecture).'synfile'). To initialize it. SAD .TypeInfo(TFileEvent).Create(Owner..pas and mORMot. the mORMot CRUD operations won't call the registered filters or validators.All database structures are set in the code by normal classes definition.ModifiedFields.mORMot Framework . It is up to your code to filter and validate the record content. end. TSQLUser.TSQLFilterLowerCase). but with the robustness of strong type syntax..['?']).Filter(ModifiedFields). and most of the needed SQL code is created on the fly by the framework. . if ErrMsg<>'' then begin // invalid field content -> show message. RTTI The Delphi language (aka Object Pascal) provided Runtime Type Information (RTTI) more than a decade ago. thanks to the Camel approach (see below).ProcessMessages. it allows the software logic to be extracted from the code itself. and aRecord. 7.pas unit filters and validates the user interface input: procedure TRecordEditForm.Most of the text displayed on the screen does rely on RTTI. ErrMsg := Rec. Reporting and edition windows can be generated in an automated way.All User Interface is generated by the code. In order to perform the filtering of some content. 2013 TSQLFile. Therefore. SAD . 1. by using some simple data structures.true). In short. end else // close window on success ModalResult := mrOk. ShowMessage(ErrMsg. // perform content validation FieldIndex := -1. ready to be translated into local languages. 7. Here are the places where this technology was used: . focus component and abort saving if cardinal(FieldIndex)<cardinal(length(fFieldComponents)) then begin C := fFieldComponents[FieldIndex].format(sInvalidFieldN. Views This framework also handles directly the creation of Ribbon-like interfaces. and the speed of one of the best compiler available.Validate() to test for valid content. (. relying on enumerations (see next paragraph).TSQLValidateEmail). .Rev. end. For instance.18 Date: June 16.true).1.SetFocus.AddFilterOrValidate('Email'. Runtime Type Information is information about an object's data type that is set into memory at run-time. you'll have to call the aRecord.format(sInvalidFieldN. resulting in a true Object-relational mapping (ORM) framework. with full data view and navigation as visual Grids. By default. before calling the SQLite3 database engine.@FieldIndex). Application.Filter() method.3.BtnSaveClick(Sender: TObject). by some constant definitions.Synopse mORMot Framework Software Architecture Design 1.[fFieldCaption[FieldIndex]]). In short. C. The whole User Interface is designed in code. the resulting program has the advantages of very fast development (Rails-like).. The RTTI support in Delphi has been added first and foremost to allow the design-time environment to do its job. this is how mORMotUIEdit. end else ShowMessage(ErrMsg. Our framework makes huge use of RTTI.AddFilterOrValidate('Name'.Validate(Client.18 Page 129 of 1055 . but developers can also take advantage of it to achieve certain code simplifications. from the database level to the User Interface.) // perform all registered filtering Rec.3. org/wiki/CamelCase.User Interface coherency. In Delphi.. Java. and could lead into "write fast. Then this TBabyAction enumerated type is used to create the User Interface ribbon of the main window.18 Date: June 16. which mix the User Interface with data logic. Advantages of the RTTI can therefore by sum up: . begin result := TSQLModel.TypeInfo(TFileEvent)). TypeInfo(TFileAction). For further information about "Camel Case" and its usage in Object Pascal. Python see http://en. even for User Interface generation. 7.Direct database access from the language object model. since most screen are created on the fly.Synopse mORMot Framework Software Architecture Design 1. try to maintain" scenarios. . then used everywhere in the program. defined by the paCreateNew identifier in the source code. It therefore avoid RAD (Rapid Application Development) abuse. The caption of the buttons to be displayed on the screen is then extracted by the framework using "Camel Case": the second button.length(FileTabs). paQuit). User Interface User Interface generation from RTTI and the integrated reporting features will be described below (page 1020). All needed TSQLRecord classes are declared in a FileTabs: array[0.4] of TFileRibbonTabParameters = ( ..All internal Event process (such as Button press) relies on enumerations RTTI. thanks to Object Pascal strong type syntax.Easy i18n of the software.mORMot Framework . just by creating an array of set of this kind: BarEdit: array[0. enumeration types or Enum provides a way of to define a list of values.g. end.Rev. These values are written once in the code. . @FileTabs.pas: function CreateFileModel(Owner: TSQLRest): TSQLModel. is displayed as "Create new" on the screen.[]. during presentation of the Main Demo application design. without additional components or systems.2.. In short. since the whole program logic is code-based. [paQuit] ).18 Page 130 of 1055 .Create(Owner. The values have no inherent meaning.Options and program parameters are using RTTI for data persistence and screen display (e.sizeof(FileTabs[0]). and their ordinality follows the sequence in which the identifiers are listed.. some tool-bar actions can be defined with: type /// item toolbar actions TBabyAction = ( paCreateNew.1] of set of TBabyAction = ( [paCreateNew. paEdit. . paDelete.wikipedia. paEdit]. . 1.Enhanced code security.3. and this "Create new" is used for direct i18n of the software.. such complex model including User Interface auto-creation could be written as such extracted from unit FileTables. Dot Net. paDelete. For example. without the need of writing SQL or use of a MVC framework. and the User Interface is created from it.Software maintainability. the Settings window of your program can be created by pure code): adding an option is a matter of a few code lines. SAD . 2013 . . Rev. and will use TFileAction / TFileEvent enumeration types to handle the User Interface activity and Business Logic.18 Date: June 16. SAD . 2013 constant array.18 Page 131 of 1055 .mORMot Framework .Synopse mORMot Framework Software Architecture Design 1. 1. pas unit.mORMot Framework . e.g. Zeos or Oracle connections to store your precious ORM objects.15 of the framework you may be able to access any remote database. Database layer Adopt a mORMot 8. Since revision 1. Zero-Configuration. and can be used instead or together with the SQLite3 engine.18 Date: June 16.1. if you wish.18 Page 132 of 1055 . 2013 8. SAD . Secure. Server-less. Single Stable Cross-Platform Database File database engine. UniDAC (or the deprecated BDE). 1. A fast in-memory engine is included. MS SQL server can be used via OleDB. FireDAC. Or you can use any DB.Rev. As stated below.Synopse mORMot Framework Software Architecture Design 1. to access NexusDB or any database engines supported by DBExpress. AnyDAC. For instance. you can use any other database access layer. which is a Free. SQLite3-powered. not SQLite3-limited The core database of this framework uses the SQLite3 library. ODBC. and use one or more OleDB. 1.1. . the main enhancement added to the SQLite3 engine is that it can be deployed in a stand-alone or Client-Server architecture. From the technical point of view.dll.Uses ISO 8601:2004 format to properly handle date/time values in TEXT field. hence common field or table names mismatch. thanks to its Virtual Table unique feature. 2013 mORMot ORM direct direct SQLite3 direct virtual TObjectList External DB direct Oracle SQLite3 ODBC OleDB ZDBC DB. with integrated SQL optimized ranking function. . or in faster and smaller Int64 custom types (TTimeLog / TModTime / TCreateTime). SQLite3 as core This framework uses a compiled version of the official SQLite3 library source code.Rev. . 8.1. or load external sqlite3. and includes it natively into Delphi code. .mORMot Framework . . here are the current compilation options used for building the SQLite3 engine: .18 Page 133 of 1055 . This framework therefore adds some very useful capabilities to the Standard SQLite3 database engine.pas TDataSet FireDAC AnyDAC UniDAC BDE DBExpress NexusDB mORMot Persistence Layer Architecture SQlite3 will be used as the main SQL engine.Of course.Use via mORMot's ORM let database layout be declared once in the Delphi source code (as published properties of classes).Locking of the database at the record level (SQLite3 only handles file-level locking). through unified memory model. whereas the default SQLite3 library works only in stand-alone mode. . avoiding most SQL writing. and usage of the FastMM4 memory manager (which is almost 10 times faster than the default Windows memory manager for memory allocation).The framework makes use only of newest API (sqlite3_prepare_v2) and follows latest SQLite3 SAD . that is Top-Secret security).It can include FTS3/FTS4 full text search engine (MATCH operator).18 Date: June 16.Can be either statically linked to the executable.SQLite3 library unit was compiled including RTREE extension for doing very fast range queries.Optional direct encryption of the data on the disk (up to AES-256 level. .Synopse mORMot Framework Software Architecture Design 1. as listed in the previous paragraph of this document: .Faster database access. . able to JOIN all those tables. but keeping all its advantages. MOD or CONCAT. named SynSQLite3. via our provided very fast in memory dataset (which can be made persistent by writing and reading JSON files on disk).Rev. via the powerful SQLite3 Virtual Table mechanisms . and some dedicated functions able to directly search for data within BLOB fields containing an Delphi high-level type (like a serialized dynamic array). For instance. as TSQLTableDB/TSQLRestServerDB/TSQLRestClientDB which call TSQLDataBase. 8.pas. As a result.1.. but with so many nice features. Additional SQL functions like Soundex for English/French/Spanish phonemes.g. Additional REGEXP operator/function using the Open Source PCRE library to perform regular expression queries in SQL statements. . as TSQLRequest and TSQLBlobStream which just wrap them. no concurrent access could happen. for lighter web server or client User Interface e.pas. Extended by SQLite3 virtual tables Since the framework is truly object oriented. The SQLite3 engine is implemented in a separate unit. which will found our ORM framework using SQLite3 as its core.Synopse mORMot Framework Software Architecture Design 1.org. User authentication handling (SQLite3 is user-free designed). The framework ORM is able to access any database class (internal or external). SQLite3 source code was compiled without thread mutex: the caller has to be thread-safe aware. another database engine could be used instead of the framework. in addition to the default SQLite3 file-based engine. SAD . but TSQLDataBase is thread-safe.the resulting C source code delivered as . avoiding most call of the SQLite3 engine in multi-user environment (any AJAX usage should benefit of it). The overhead of including SQlite3 in your server application will be worth it: just some KB to the executable. and an internal efficient caching algorithm is added.pas. since with the new Client-Server approach of this framework. You can even use our framework without any link to the SQLite3 engine itself. ISO 8601 time encoding. A bridge between the two units is made with mORMotSQLite3. in order to speed up most read queries. The embedded SQLite3 database engine can be easily updated from the official SQLite3 source code available at http://sqlite. Compiled with SQLITE_OMIT_SHARED_CACHE define. since mutex has to be acquired once): low level sqlite3_*() functions are not thread-safe. as stated below (page 166).e.see below (page 155). but also e. 2013 - - - - - - official documentation.18 Page 134 of 1055 .mORMot Framework .g.2. Custom SQL functions can be defined in Delphi code. we included a fast in-memory database engine as TSQLRestServerFullMemory) and link to a another engine (like FireBird. Automatic SQL statement parameter preparation.18 Date: June 16. TSQLDatabase can cache the last results for SELECT statements. or use a tuned client-side or server-side per-record caching. or a private one).. any external database (via OleDB / ODBC providers or direct Oracle connection) can be accessed via our SynDB-based dedicated units. and the main unit of the framework is mORMot. Each engine may have its own purpose. this is faster on most configurations. Additional collations (i.pas unit) . You could easily write your own TSQLRestServer descendant (as an example. according to the application expectations.obj is also available in the official Synopse source code repository. fast Win1252 diacritic-agnostic comparison and native slower but accurate Windows UTF-16 functions. for execution speed up. the framework has several potential database back-ends.use the amalgamation C file with a few minor changes (documented in the SynSQLite3Static. sorting functions) were added to handle efficiently not only UTF-8 text. 1. even if only external databases are used. In these tables: .When data is retrieved from server or client ORM Cache (page 114).see below (page 160) either static (with no SQL support) or virtual (i.You can persist up to 570. since TSQLRestClient and TSQLRestServer are run in-process. .With a high-performance database like Oracle and our direct access classes. or DB.'ZEOS *' indicates that the database was accessed directly via the ZDBC layer. so newer compilers may give even better results. In this timing. SQL featured via SQLite3 virtual table mechanism) which may persist the data on disk as JSON or compressed binary. . but publish a snapshot of mORMot persistence layer abilities. CRUD/REST routing. you can read more than 900.3.000 objects per second.000 objects per second. in the same thread .'Jet' stands for a MSAccess database engine.g.'FireDAC *' stands for FireDAC library. available from official site. but reflect the current status of the integration of several DB libraries within the mORMot database access. I suspect. Zeos. The following tables try to sum up all available possibilities. . We just bypass the communication layer.1. mORMot excels in speed: . but still enough for most work.pas based classes). you can write 62. . So you have here some raw SAD .000 objects per second (for our pure Delphi in-memory engine).e.as a TSQLRestServerDB instance. . Data access benchmark On an recent notebook computer (Core i7 and SSD drive)..'ODBC *' for a direct access to ODBC.)' is about access to a SQLite3 engine as external database .'BDE *' when using a BDE connection.'NexusDB' is the free embedded edition. . .'SQLite3 (ext .'TObjectList' indicates a TSQLRestServerStaticInMemory instance . .When using alternate database access libraries (e. depending on the back-end database interfaced. .LockingMode := lmExclusive . This benchmark was compiled with Delphi 7.18 Date: June 16. accessed via OleDB. virtual cross-database layer. with or without Synchronous := smOff and/or DB. This list of database provider is to be extended in the future.'UniDAC *' stands for UniDAC library. either as file or memory. 1.000 (via array binding) and read 92. whatever the database back-end is. Note that these tests are not about the relative speed of each database engine.see below (page 153). over a 100 MB network. and give some benchmark (average objects/second for writing or read). speed is lower. . .see below (page 166). Difficult to find a faster ORM.mORMot Framework . 2013 8. we do not benchmark only the "pure" SQL/DB layer access ( SynDB units).18 Page 135 of 1055 . Any feedback is welcome! Numbers are expressed in rows/second (or objects/second). SQL on-the-fly translation. or retrieve 870.pas). .Rev. ..'Oracle' shows the results of our direct OCI access layer (SynDBOracle. JSON marshaling.'SQLite3 (mem)' stands for the internal SQLite3 engine running in memory.'SQLite3 (file full/off/exc)' indicates use of the internal SQLite3 engine.Synopse mORMot Framework Software Architecture Design 1. but the whole Client-Server ORM of our framework: process below includes read and write RTTI access of a TSQLRecord. with in-lining and advanced optimizations. Purpose here is not to say that one library is better or faster than another.000 objects per second. . mORMot Framework . CPU was noticeable used only for SQLite3 in-memory and TObjectList . As a result. You can compile the "15 . the bottleneck is not the CPU. but the storage or network.which makes a great difference. with a SQlite3 database. Benchmark was run on a Core i7 notebook. So it was a development environment. linked to a shared Oracle 11g database.'Batch' mode will be described below (page 213).'Direct' stands for a individual Client.3. rates and timing may vary depending on network and server load. with an average hardware configuration.most of the time. very similar to low-cost production site.000 rows of data. including anti-virus and background applications. Direct Batch Trans Batch Trans SQLite3 (file full) 503 399 96391 123064 SQLite3 (file off) 923 930 99534 130907 SQLite3 (file off exc) 31829 35798 101874 132752 SQLite3 (mem) 85803 109641 103976 135332 TObjectList (static) 321089 548365 312031 547105 TObjectList (virtual) 314366 513136 316676 571232 SQLite3 (ext full) 451 511 12092 137249 SQLite3 (ext off) 971 909 108133 144475 SQLite3 (ext off exc) 42805 51256 113155 150829 SQLite3 (ext mem) 97344 121400 113229 153256 ZEOS SQlite3 487 455 16826 19680 FireDAC SQlite3 25182 49795 41962 114241 UniDAC SQlite3 473 412 27370 37962 ZEOS Firebird 1835 2142 18734 22540 UniDAC Firebird 7065 7637 9157 10399 Jet 4197 4318 4789 4947 Oracle 511 59455 948 59762 SAD . over a 100 Mb corporate network. e. .g.1. .'Trans' indicates that all insertion is nested within a transaction . 8.Rev.External DB performance" supplied sample code.1. 1. During the process. not dedicated to give best performance.18 Page 136 of 1055 . 2013 performance testimony of our framework's ORM and RESTful core. with standard SSD. and run the very same benchmark on your own configuration.Add() insertion.18 Date: June 16. Insertion speed Here we insert 5. but you get results similar to what could be expected on customer side.Synopse mORMot Framework Software Architecture Design 1. with diverse scenarios: . the FireDAC library set both options. therefore it is the reason why it is slower than other engines at individual row insertion (less than 10 objects per second with a mechanical hardrive instead of a SDD) outside the scope of a transaction.3. in objects/second: By one All Virtual All Direct SQLite3 (file full) 26936 514456 531858 SQLite3 (file off) 27116 538735 428302 SQLite3 (file off exc) 122417 541125 541653 SQLite3 (mem) 119314 539781 545494 TObjectList (static) 303398 529661 799232 TObjectList (virtual) 308109 403323 871080 SQLite3 (ext full) 137525 264690 546806 SQLite3 (ext off) 134807 262123 531011 SAD . .Synopse mORMot Framework Software Architecture Design 1. SQLite3 process on file waits for the hard-disk to have finished flushing its data. Batch process benefit of the array binding feature a lot (known as Array DML in FireDAC/AnyDAC).18 Page 137 of 1055 . Another possibility could be to execute DB. running SELECT * FROM table from a FillPrepare() method call).18 Date: June 16. 2013 ODBC Oracle 550 536 1024 1043 ZEOS Oracle 343 362 1086 1087 FireDAC Oracle 512 32328 980 34668 UniDAC Oracle 465 496 915 879 BDE Oracle 418 410 661 755 NexusDB 6278 6749 7901 8801 Due to its ACID implementation.'By one' states that one object is read per call (ORM generates a SELECT * FROM table WHERE ID=? for Client.Synchronous := smOff and/or DB. Reading speed Now the same data is retrieved via the ORM layer: .'All *' is when all 5000 objects are read in a single call (i. either forced to use the virtual table layer.see below (page 153).e. Here are some reading speed values. For both our direct Oracle access SynDBOracle.Retrieve() method).mORMot Framework . so results above are to be compared with "SQLite3 off exc" rows.pas library and FireDAC.Rev. Note that by default. as stated by the "off" and "off exc" rows of the table . you should better use transactions and regroup all writing into services or a BATCH process.LockingMode := lmExclusive at SQLite3 engine level before process: in case of power loss at wrong time it may corrupt the database file. So if you want to reach the best writing performance in your application with the default engine. or with direct static call. but it will increase the rate by a factor of 50 (with hard drive). 1.2. 8.1. Synopse mORMot Framework Software Architecture Design 1. especially the "By name" row for "TObjectList" columns. Our direct classes.pas are slower than the others for reading speed. but has the weakness of being in-memory. TObjectList / TSQLRestServerStaticInMemory engine gives impressive results. it appears that all libraries based on DB. When running with DB.see the following benchmark. or even ZEOS/ZDBC performs better.18 Date: June 16. In fact.see below (page 153). both insertion and search speed is awesome. External database access is only required when data is expected to be shared with other processes. which correspond to a search of an unique RawUTF8 property value via this hashing method. which is known to be very optimized for speed.) SQLite3 SQLite3 SQLite3 (ext file (ext file (ext Oracle full) off) mem) SAD . SQLite3 SQLite3 TObjec SQLite3 (file (file tList (mem) full) off) (static) TObjec tList (virt. and benefits from exclusive access to the database file .18 Page 138 of 1055 Jet . reading speed is very high. 2013 SQLite3 (ext off exc) 133936 261574 536941 SQLite3 (ext mem) 136915 258732 544069 ZEOS SQlite3 3232 83243 95934 FireDAC SQlite3 7639 80261 108117 UniDAC SQlite3 1586 73142 96989 ZEOS Firebird 3882 69974 85416 UniDAC Firebird 2177 71858 89856 Jet 2619 144801 222736 Oracle 593 74312 66131 ODBC Oracle 1134 33267 33049 ZEOS Oracle 863 44207 53868 FireDAC Oracle 896 33171 37912 UniDAC Oracle 500 21918 23688 BDE Oracle 689 3343 3426 NexusDB 1419 121294 195687 The SQLite3 layer gives amazing reading results.Rev. due to its optimized O(1) hash algorithm . Even FireDAC. so it is not ACID by design. For both writing and reading. search of non-unique values may be slow: the engine has to loop through all rows of data. and the data has to fit in memory.mORMot Framework . is limited by the TDataSet structure. But for unique values (defined as stored AS_UNIQUE). "off exc" rows).e. In the above table. As a consequence. TDataSet sounds to be a real bottleneck. 1. Note that indexes are available for IDs and stored AS_UNIQUE properties.LockingMode := lmExclusive defined (i. which makes it a perfect fit for most typical ORM use. via a TSQLRestClientDB instance. for testing) StaticDataCreate Best possible performance for small amount of data.g.Rev.3. without ACID nor SQL VirtualTableRegister Best possible performance for small amount of data. DBExpress / BDE). For both insertion and reading.1 for mORMot clients) will give even better results for BATCH and retrieve all modes. Note that all those tests were performed locally and in-process.000 requests per second for objects read and write.see below (page 195) and ORM Cache (page 114) . you achieve more than 700.1. for disk spanning ext. SQLite3 file default General safe data handling int. if ACID is not required nor complex SQL ext.g. the typical use may be the following: Database Created by Use int.g. with incredibly fast CRUD operations: 100. a Client-Server architecture (e. using HTTP/1. so you may expect speed enhancements for real applications. Therefore. During the tests.pas provider (e. for testing) TObjectList static TObjectList virtual SAD .g. internal caching . 8.18 Page 139 of 1055 . SQLite3 mem VirtualTableExternalRegister Fast external back-end (e.000 read requests per second. e.Synopse mORMot Framework Software Architecture Design 1. when an object is retrieved from the cache. so numbers are lower than with the previous tables. 167095 162956 168651 253292 118203 97083 90592 94688 56639 52764 All Direct 167123 144250 168577 254284 256383 170794 165601 168856 88342 75999 Above table results were run on a Core 2 duo laptop. whereas array binding boosts Oracle writing BATCH process performance by 100 times). including serialization and Client-Server communication! In the above list.g.mORMot Framework . whatever database is used.3. SQLite3 file VirtualTableExternalRegister External back-end. 1. you have the full power of SQL (including JOINs) at hand. 2013 By one 10461 10549 44737 103577 103553 43367 44099 45220 901 1074 By name 9694 9651 32350 70534 60153 22785 22240 23055 889 1071 All Virt. Or any DB. Analysis and use case proposal When declared as virtual table (via a VirtualTableRegister call). the MS SQL Server is not integrated. with direct access. but with the additional layer introduced by using a TDataSet instance. but may be used instead of Oracle (minus the fact that BULK insert is not implemented yet for it.was disabled.18 Date: June 16. when data is more read than written: for instance. SQLite3 mem :memory: Fast data handling with no persistence (e. Any other OleDB or ODBC providers may also be used. pas.pas unit and its TDataSet bottleneck .1.pas unit.2. just by changing a TSQLDBConnectionProperties class type. Zeos/FireDAC/Uni DAC Whatever database back-end is used. Oracle / MS SQL / Firebird VirtualTableExternalRegister Fast.Or stand-alone with high-level SQL access. The SQLite3 APIs and constants are defined in SynSQlite3.2.g. using our SynDB generic access classes. for general information about its common features.1.dll library file. Statically linked or using external dll Since revision 1. See SDD # DI-2. It can be used therefore: .18 Page 140 of 1055 .Or from an external sqlite3. 8. We'll define here some highlights specific to our own implementation of the SQLite3 engine.Synopse mORMot Framework Software Architecture Design 1. and accessible via a SAD .and we will also prefer an active Open Source project! ext. . SQLite3 implementation Beginning with the revision 1. ..but you won't be able to switch to another database engine easily. via SynDBSQLite3. via SynSQLite3. with some advantages for Zeos. don't forget that mORMot design will allow you to switch from one library to another.15 of the framework.Rev. 8.pas unit is able to access the SQLite3 engine in two ways: .pas. Jet VirtualTableExternalRegister Could be used as a data exchange format (e. 2013 ext. according to your project needs. since direct ZDBC access will by-pass the DB. but the database access can be tuned for each ORM table. and defined as a stand-alone unit named SynSQLite3. And note that you can mix external engines.pas . secure and industry standard.see mORMotSQLite3.Or Client-Server based access with all our ORM features .18 Date: June 16. 1.g.2. our SynSQlite3. .org. can be shared outside mORMot ext.pas .so you will be able to change to any other database engine (e. and let you consult the official documentation of this great Open Source project at http://sqlite.Either statically linked within the project executable. and insertion speed is higher than SQLite3. NexusDB VirtualTableExternalRegister The free embedded version let the whole engine be included within your executable.mORMot Framework . the SQLite3 engine itself has been separated from our mORMotSQLite3. so it may be a good alternative if your project mostly insert individual objects using a batch within a transaction let SQlite3 be the faster engine ext. on purpose: you are not tied to one single engine.18 of the framework. MS SQL or Oracle) when needed.pas.Either stand-alone with direct access of all its features. with Office applications) VirtualTableExternalRegister Allow access to several external engines. even using its lowest-level C API. 1. or an external sqlite3.g. run in a 32 bit project.Synopse mORMot Framework Software Architecture Design 1. // release any previous instance (e.dll instance Referring to SynSQLite3Static. you have to set the global sqlite3 variable as such: FreeAndNil(sqlite3). Writing speed SQLite3 (file full) Direct Batch Trans Batch Trans 477 389 97633 122865 SAD . 1.obj was forced .open() instead of sqlite3_open().breaking change: before version 1. 8. To use the SQLite3 engine. calling e.pas Instantiate an external sqlite3.mORMot Framework .1.obj within the .Rev. Here are some benchmarks. FreeAndNil(sqlite3) is not mandatory.dll. Then all mORMot's calls will be made through it.so you must add a reference to SynSQLite3Static in your project uses clause to work as expected.obj First of all.18 Date: June 16. using either the static bcc-compiled engine. Warning .Create. sqlite3. compiled with Delphi XE3.pas in the uses clause of your project is enough to link the . our version included with SynSQLite3Static.pas unit. link of static . an instance of TSQLite3Library class shall be assigned to this global variable. is to be benchmarked.2.18 of the framework. There are two implementation classes: TSQLite3LibraryStatic TSQLite3LibraryDynamic TSQLite3Library TSQLite3Library classes hierarchy Class Unit Purpose TSQLite3LibraryStatic SynSQLite3Static. static) sqlite3 := TSQLite3LibraryDynamic. Static bcc-compiled . and should be necessary only to avoid any memory leak if another SQLite3 engine instance was allocated (may be the case if SynSQLite3Static is referred somewhere in your project's units). Of course.dll library.pas Statically linked engine (. compiled via MinGW or Visual C++.exe) TSQLite3LibraryDynamic SynSQLite3.18 Page 141 of 1055 . 2013 TSQLite3Library class definition.obj engine into your executable. In order to use an external sqlite3.g. It defines a global sqlite3 variable as such: var sqlite3: TSQLite3Library. web site. Writing speed Direct Batch Trans Batch Trans SQLite3 (file full) 418 503 86322 119420 SQLite3 (file off) 918 873 93196 127317 SQLite3 (mem) 83108 106951 99892 138003 TObjectList (static) 320204 573723 324696 547465 SAD .dll library. 8..2.1.2. 2013 SQLite3 (file off) 868 869 96827 125862 SQLite3 (mem) 84642 108624 104947 135105 TObjectList (static) 338478 575373 337336 572147 TObjectList (virtual) 338180 554446 331873 575837 SQLite3 (ext full) 486 496 101419 7011 SQLite3 (ext off) 799 303 105402 135109 SQLite3 (ext mem) 93893 129550 109027 152811 By one All Virtual All Direct SQLite3 (file full) 26924 494559 500200 SQLite3 (file off) 27750 496919 502714 SQLite3 (mem) 124402 444404 495392 TObjectList (static) 332778 907605 910249 TObjectList (virtual) 331038 404891 905961 SQLite3 (ext full) 102707 261547 521322 SQLite3 (ext off) 131130 255806 513505 SQLite3 (ext mem) 135784 248780 502664 Reading speed Good old Borland C++ builder produces some efficient code here. Those numbers are very good.org.Synopse mORMot Framework Software Architecture Design 1. Probably. 1.mORMot Framework . when compared to the other two options.Rev. using FastMM4 as memory manager and tuned compilation options does make sense.dll Here we used the official sqlite3.18 Page 142 of 1055 . Official MinGW-compiled sqlite3.18 Date: June 16. and compiled with the MinGW/GCC compiler. as published in the http://sqlite. corresponding source code..dll library. compiled with Visual C++.2.pas) .Rev.net/projects/wxcode/files/Components/wxSQLite3.not available in the official library. to download the Writing speed Direct Batch Trans Batch Trans SQLite3 (file full) 470 498 93801 112170 SQLite3 (file off) 886 819 90298 132883 SQLite3 (mem) 86897 110287 105207 140896 TObjectList (static) 332005 596445 321357 570776 TObjectList (virtual) 327225 585000 329272 579240 SQLite3 (ext full) 459 503 91086 140599 SQLite3 (ext off) 501 519 110338 150394 SAD .18 Page 143 of 1055 .18 Date: June 16. and compiled .mORMot Framework .dll The Open Source wxsqlite project provides a sqlite3. 2013 TObjectList (virtual) 323247 563697 324443 564716 SQLite3 (ext full) 501 410 100152 133679 SQLite3 (ext off) 913 438 102806 135545 SQLite3 (ext mem) 96028 122798 108363 150920 By one All Virtual All Direct SQLite3 (file full) 26883 473529 438904 SQLite3 (file off) 27729 472188 451304 SQLite3 (mem) 116550 459432 457959 TObjectList (static) 318248 891265 905469 TObjectList (virtual) 327739 359040 892697 SQLite3 (ext full) 127346 180812 370288 SQLite3 (ext off) 127749 227759 438096 SQLite3 (ext mem) 129792 224386 436338 Reading speed 8.3. 1. and including RC4 and AES 128/256 encryption (better than the basic encryption implemented in SynSQLite3Static. See http://sourceforge.dll.1. Visual C++ compiled sqlite3.Synopse mORMot Framework Software Architecture Design 1. a prepared version. 8. That is.. and when targeting 64 bit Windows applications. only the one-record SQL SELECT * FROM . No library to deploy and copy. From our profiling. available for all SQL request.Synopse mORMot Framework Software Architecture Design 1.mORMot Framework . In order to use this statement caching.pas statically linked implementation sounds like the best overall approach for Windows 32 bit: best speed for virtual tables (which is the core of our ORM). despite a somewhat less efficient virtual table process. if a previous SQL statement is run with some given parameters. Previously.. prepared statements make common requests (i.. select / insert / update on one row) at least two times faster. for the TSQLRest. it can speed the SQLite3 process a lot. everything is embedded in the project executable.12 of the framework. and no dll hell. there are now two ways of writing the same SQL request: Write the SQL statement as usual: SAD . In some cases. As a conclusion. Prepared statement In order to speed up the time spent in the SQLite3 engine (it may be useful for high-end servers). Retrieve method). our SynSQLite3Static. any SQL statements must have the parameters to be surrounded with ':(' and '):'. It is a bit faster than the other two. on an in-memory database (':memory:' specified as file name).18 Date: June 16. the framework is able to natively handle prepared SQL statements. Therefore.e.18 Page 144 of 1055 .g. WHERE RowID=.2. we added an internal SQL statement cache in the database access. was prepared (used e.dll will be used for cross-platform support. External sqlite3. The SQL format was indeed enhanced by adding an optional way of marking parameters inside the SQL request.Rev. available in cache. Starting with version 1. 2013 SQLite3 (ext mem) 98112 133276 117346 By one All Virtual All Direct SQLite3 (file full) 28527 516689 521159 SQLite3 (file off) 28927 513769 519156 SQLite3 (mem) 127740 529100 523176 TObjectList (static) 335053 869262 879352 TObjectList (virtual) 334739 410374 885269 SQLite3 (ext full) 132594 258371 506277 SQLite3 (ext off) 138159 260892 507717 SQLite3 (ext mem) 139567 254919 516208 158634 Reading speed Under Windows.. to enforce statement preparing and caching. and new parameters are bounded to it before the execution by SQLite3. the Visual C++ compiler gives very good results. is used. ready to run as expected. 1.2. then run.[].15 of the framework.SQLTableName. whereas SQL statement should only use single ' quotes): :(1234): :(12.OneFieldValue.Text := 'SELECT Name FROM Table WHERE ID=:Index'. TSQLRecord.[Table.[aID])..18 Page 145 of 1055 .Synopse mORMot Framework Software Architecture Design 1.Create.'Name'. the SQL will be parsed by the SQLite3 engine.seDelete. 1.[aID]). For instance.Table. for instance: aName := OneFieldValue(TSQLMyRecord. In your code.'Name'. you should better use. in this case.AsInteger := aID. which will accept both '%' and '?' characters in the SQL WHERE format text. TSQLRecord.EngineExecuteFmt and TSQLRestClient. in-lining '?' parameters with proper :(. available since revision 1. I found out that this SQL format enhancement is much easier to use (and faster) in the Delphi code than using parameters by name or by index. here is how an object deletion is implemented: function TSQLRestServerDB.): expression in your request. instead of aName := OneFieldValue(TSQLMyRecord.MultiFieldValues. TQLRestClient.ParamByName('Index').34): :(12E-34): :("text"): :('It''s great'): All internal SQL statement generated by the ORM are now using this new parameter syntax... 2013 SELECT * FROM TABLE WHERE ID=10.ID).'ID='+Int32ToUtf8(aID)). TSQLRest.'ID=?'.'Name'.'Name'. Example of possible inlined values are (note double " quotes are allowed for the text parameters. Use the new optional markers to identify the changing parameter: SELECT * FROM TABLE WHERE ID=:(10):.): encoding and quoting the RawUTF8 / strings parameters on purpose.mORMot Framework .'ID=:(%):'. begin if Assigned(OnUpdateEvent) then OnUpdateEvent(self.EngineDelete(Table: TSQLRecordClass. // notify BEFORE deletion result := EngineExecuteFmt('DELETE FROM % WHERE RowID=:(%):. The generic SQL code used for the matching will be this one: SELECT * FROM TABLE WHERE ID=?. from your client code. or instead of a plain aName := OneFieldValue(TSQLMyRecord.FillPrepare. any matching already prepared statement will be re-used for direct run. In fact.Rev. Using :(%): will let the DELETE FROM table_name WHERE RowID=? statement be prepared and reused between calls. but would rather use the overloaded TSQLRecord.'. in this case.ListFmt methods.ID]). ID: integer): boolean. SAD .[aID]). TSQLRest. a statement will be compiled.'ID=%'. SQL.CreateAndFillPrepare. end.. an internal pool of prepared TSQLRequest statements is maintained. like in this classic VCL code: SQL. you may not use directly the :(.18 Date: June 16. or even easier aName := OneFieldValue(TSQLMyRecord. and the integer value 10 will be bounded to the prepared statement before execution. In the later case. .0): AND :(maxY<=36.36. Queries against the ID or the coordinate ranges are almost immediate: so you can e.html. MapBox WHERE MapData.Rev.g. RTreeMatch method offers: for instance. an R-Tree is able to quickly find all entries that are contained within the query rectangle or which overlap the query rectangle. The MapBox_in SQL function is registered in TSQLRestServerDB. including the ID property).e. As such. R-Trees are most commonly used in geospatial systems where each entry is a rectangle with minimum and maximum X and Y coordinates. extract some coordinates box from the main regular TSQLRecord table. For example. An R-Tree is a special index that is designed for doing range queries. to achieve the best speed possible.35. and made caching easier on the Server side: the whole SQL query contains all parameters within one unique RawUTF8 value. And so forth. it will process a raw array of double.mORMot Framework .:('\uFFF0base64encoded-81.2): AND MapBox_in(MapData. Delphi double) published properties grouped by pairs.6. 2013 At a lowest-level.2] the following lines: aClient.BlobField.g. like the other virtual tables types (e.BlobField. our framework is able to handle prepared statements without keeping bound parameters separated from the main SQL text. A R-Tree is able to quickly find all events. Both BlobToCoord and ContainedIn class methods are used to handle the box storage in the BLOB.and maximum-value. then use a TSQLRecordRTree-joined query to make the process faster. It inherits from TSQLRecordVirtual. This idea is easily extended to three dimensions for use in CAD systems.. e. TSQLRecordFTS3). BlobField filled with [-81.'BlobField'. to link an R-Tree representation to a regular TSQLRecord table containing the main data.maxY<=.ID=MapBox.35.. Given a query rectangle.-79.Synopse mORMot Framework Software Architecture Design 1.0): AND maxX<=:(-79. Its ID: integer property must be set before adding a TSQLRecordRTree to the database.3.ResultID). Inlined values will be bound separately to the external SQL statement. is available to create such tables. or all events that both started and ended within a given time interval. each as minimum. suppose a database records the starting and ending times for a large number of events.g.org/rtree. R-Trees also find use in time-domain range look-ups.18 Page 146 of 1055 .ID From MapData. By default. will execute the following SQL statement: SELECT MapData. 1. up to 5 dimensions (i. aMapData. SAD . this is exactly what the TSQLRestClient. named TSQLRecordRTree..ID AND minX>=:(-81. and can be therefore directly compared to the cached entries. See http://www.. R-Tree inclusion Since the 2010-06-25 source code repository update.36. It is also worth noting that external databases (see next paragraph) will also benefit from this statement preparation. Create constructor for all TSQLRecordRTree classes of the current database model. or all events that started during a particular time interval.6): AND minY>=:(35.sqlite.2'):). 11 columns. the RTREE extension is now compiled by default within all supplied . that were active at any time during a given time interval.18 Date: June 16.RTreeMatch(TSQLRecordMapData. where clause). in-lining the bounds values inside the statement enabled better serialization in a Client-Server architecture.-79.e. 8.2.6. running with aMapData. with a default box match (that is ContainedIn method will match the simple minX>=.obj files. for example. Any record which inherits from this TSQLRecordRTree class must have only sftFloat (i.TSQLRecordMapBox. A dedicated ORM class. and included in the release v.html.1.Synopse mORMot Framework Software Architecture Design 1. FTS4 tables may consume more disk space than the equivalent table created using FTS3. The overhead may be reduced by using a TSQLRecordFTS3 table type instead of TSQLRecordFTS4 declaration.pas) to enable FTS3 in your application. 1.FTS4 supports some additional options that may used with the matchinfo() function. They share most of their code in common.7.TSQLRecordFTS4 to create a FTS4 table with default "simple" stemming. in mORMotSQLite3.pas and SynSQLite3. as reference material about FTS3 usage in SQLite3. and the full-text query system finds the set of documents that best matches those terms considering the operators and groupings the user has specified.TSQLRecordFTS3Porter to create a FTS3 table using the Porter Stemming algorithm (see below). FTS3/FTS4 FTS3/FTS4 are SQLite3 virtual table modules that allow users to perform full-text searches on a set of documents.4. or series of terms. .TSQLRecordFTS3 to create a FTS3 table with default "simple" stemming. Usually the overhead is 1-2% or less.1. some types have been defined: .FTS4 contains query performance optimizations that may significantly improve the performance of full-text queries that contain terms that are very common (present in a large percentage of table rows). Yahoo and Altavista do with documents placed on the World Wide Web".g. and will therefore spare some KB of code. The most common (and effective) way to describe full-text searches is "what Google.TSQLRecordFTS4Porter to create a FTS4 table using the Porter Stemming algorithm. . The differences are: .5 of the framework.mORMot Framework . FTS3 and FTS4 are nearly identical.11 of the framework. Users input a term. .2.org/fts3.. Leave it undefined if you do not need this feature.18 Page 147 of 1055 . 2013 8.obj file is always available in the distribution file: just define the INCLUDE_FTS3 conditional globally for your application (it is expected e.Rev.2. Dedicated FTS3/FTS4 record type In order to allow easy use of the FTS feature.4. . but this comes at the expense of sacrificing some of the extra supported matchinfo() options. Since version 1. the sqlite3fts3. but may be as high as 10% if the documents stored in the FTS table are very small.sqlite. and their interfaces are the same. added with SQLite version 3.4. See http://www. perhaps connected by a binary operator or grouped together into a phrase. FTS4 is indeed an enhancement to FTS3.18 Date: June 16. The following graph will detail this class hierarchy: SAD . 8. Because it stores extra information on disk in two new shadow tables in order to support the performance optimizations and extra matchinfo() options. are transformed to their lowercase equivalents as part of the tokenization process. as the simple tokenizer transforms the term in the query to lowercase before searching the full-text index.just as "Frustrated" is.All uppercase characters within the ASCII range (UTF code-points less than 128). Their only contribution is to separate adjacent terms. So. Thus. For example.org/fts3.org/~martin/PorterStemmer. the terms extracted from the document and added to the full-text index are. All other characters are discarded when splitting a document into terms. but matches against similar English language terms. The simple (default) tokenizer extracts tokens from a document or basic FTS full-text query according to the following rules: . .. as the term "Frustration" is reduced by the Porter stemmer algorithm to "frustrat" .Rev. For example. FTS is able to find not just exact matches for queried terms. 2013 TSQLRecord TSQLRecordVirtual TSQLRecordFTS3 TSQLRecordFTS3Porter TSQLRecordFTS4 TSQLRecordFTS4Porter FTS3/FTS4 ORM classes 8. where eligible characters are all alphanumeric characters.html#tokenizer. Such a document would match a full-text query such as "MATCH 'Frustrated'". 1. the porter tokenizer extracts the following tokens: "right now thei veri frustrat". but also queries such as "MATCH 'Frustration'". they're very frustrated.18 Page 148 of 1055 . . The Porter Stemming algorithm tokenizer uses the same rules to separate the input document into terms. Even though some of these terms are not even English words.2. and all characters with UTF code-points greater than or equal to 128. in some cases using them to build the full-text index is more useful than the more intelligible output produced by the simple tokenizer.2. Using the porter tokenizer. full-text queries are case-insensitive when using the simple tokenizer. For more information on the Porter Stemmer algorithm. the document not only matches full-text queries such as "MATCH 'Frustrated'".". page. SAD .mORMot Framework .see http://sqlite.Synopse mORMot Framework Software Architecture Design 1. using the same input document as in the paragraph above. please refer to the http://tartarus. Stemming The "stemming" algorithm .is the way the english text is parsed for creating the word index from raw text.4. when a document containing the text "Right now.. but as well as folding all terms to lower case it uses the Porter Stemming algorithm to reduce related English language words to a common root. the "_" character. when using the porter tokenizer. in order.18 Date: June 16. "right now they re very frustrated".A term is a contiguous sequence of eligible characters. // MUCH faster with this for i := StartID to StartID+COUNT-1 do begin FTS.DocID := IntArray[i].WhereClause. Use of the FTSMatch method is not mandatory: in fact. begin // FTS3 tables do not have any ID.'Subject MATCH ''salVador1'''.Subject := aClient.'FirstName'.FTS.OneFieldValue(TSQLRecordPeople. but may speed up future queries: you should not call this method after every modification of the FTS tables. FTS searches A good approach is to store your data in a regular TSQLRecord table. it is just a wrapper around the OneFieldValues method.OptimizeFTS3Index(Client.IntResult)).Add(FTS. but after some text has been added. Then you can add some Body/Subject content to this FTS3 table.mORMot Framework .3. but RowID or DocID result := OneFieldValues(Table. The matching IDs are stored in the IntResult integer dynamic array.'RowID'. then store your text content in a separated FTS3 table. The only difference with a "standard" ORM approach is that the DocID property must be set before adding the TSQLRecordFTS3 instance: there is no ID automatically created by SQLite.Create. you could also use the Unicode string type. aClient. which is mapped as a UTF-8 text field for the SQLite3 engine). To support full-text queries. via the ORM feature of the framework: FTS := TSQLFTSTest. FTS maintains an inverted index that maps from each unique term or word that appears in the dataset to the locations in which it appears within the table contents.2. end. from its ID.DocID). 2013 8.Body := FTS.true).DocID). var DocID: TIntegerDynArray): boolean. fBody: RawUTF8. end. Then the FTS search query will use the custom FTSMatch method: Check(aClient.Subject+' bodY'+IntToStr(FTS.TransactionBegin(TSQLFTSTest)). that is RawUTF8 (under Delphi 2009 and up. you can define this new class: TSQLFTSTest = class(TSQLRecordFTS3) private fSubject: RawUTF8. 1. The dedicated OptimizeFTS3Index method is called to merge all existing index b-trees into a single large b-tree containing the entire index. Note that you can use a regular SQL query instead. Note that FTS tables must only content UTF-8 text field. For example (extracted from the regression test code). The steps above are just typical. // Commit must be BEFORE OptimizeFTS3. aClient. SAD .Rev. the ID property was renamed as DocID. property Body: RawUTF8 read fBody write fBody. published property Subject: RawUTF8 read fSubject write fSubject. which is the internal name for the FTS virtual table definition of its unique integer key ID property.4. try Check(aClient. This can be an expensive operation.18 Page 149 of 1055 . associated to this TSQLRecordFTS3 table via its ID / DocID property.FTSMatch(TSQLFTSTest. memory leak otherwize Check(FTS. just like any regular TSQLRecord content. Note that for TSQLRecordFTS* types.FTSMatch(Table: TSQLRecordFTS3Class. just using the "neutral" RowID column name for the results: function TSQLRest. FTS.18 Date: June 16.DocID). but an ID must be specified in order to link the FTS record to the original TSQLRecordPeople row.fServer)). FTS.Synopse mORMot Framework Software Architecture Design 1.Commit. const WhereClause: RawUTF8. 0. the results will be sorted by relevance: Check(aClient. we defined some additional kind of collations. 8.IntResult. This method expects some additional constant parameters for weighting each FTS table column (there must be the same number of PerFieldWeight parameters as there are columns in the TSQLRecordFTS3 table). With this method. An overloaded FTSMatch method has been defined.e.[1. .BINARY .html#appendix_a.18 Date: June 16. i. It will return the RowID of documents that match the full-text query sorted from most to least relevant. When calculating relevance. there is a need to define how column data is to be compared.0.org/fts3. 2013 end.5.5])). SQLite has three built-in collating functions: BINARY. using UTF8ILComp(). In the mORMot ORM. NOCASE. In the above sample code. i.sqlite. 1. Note that only ASCII characters are case folded.NOCASE .Compares string data using memcmp(). able to use a ranking algorithm. and will handle detailed matching information. except that trailing space characters are ignored. It is needed for proper search and ordering of the data. and he Body will be weighted as 0. which will ignore Win-1252 Latin accents SAD . when SQLite compares two strings. except the 26 upper case characters of ASCII are folded to their lower case equivalents before the comparison is performed.5) DESC The rank internal SQL function has been implemented in Delphi.mORMot Framework . By default. query term instances in the 'subject' column are given twice the weighting of those in the 'body' column.The same as binary.5. This is the purpose of so-called collations.'body1*'.0.The same as binary. .0.e. the Subject field will have a weight of 1. regardless of text encoding. it uses a collating sequence or collating function (two words for the same thing) to determine which string is greater or if the two strings are equal. any match in the 'body' column content will be ranked twice less than any match in the 'subject'. which is probably of higher density. Column collations In any database.. . The above query will call the following SQL statement: SELECT RowID FROM FTSTest WHERE FTSTest MATCH 'body1*' ORDER BY rank(matchinfo(FTSTest).to implement the most efficient way of implementing ranking.Rev.Synopse mORMot Framework Software Architecture Design 1. following the guidelines of the official SQLite3 documentation as available from their Internet web site at http://www.RTRIM . SQLite does not attempt to do full UTF case folding due to the size of the tables required.FTSMatch(TSQLFTSTest. and RTRIM: . via some internal calls to the sqlite3_create_collation() API: TSQLFieldType Default collation sftAnsiText NOCASE sftUTF8Text SYSTEMNOCASE.1.18 Page 150 of 1055 .2. But you can use our SynDBExplorer safely.SetCustomCollationForAllRawUTF8('WIN32CASE'). SetCustomCollationForAllRawUTF8() or SetCustomCollation() methods in an overridden class procedure InternalRegisterCustomProperties(). Or you can call TSQLModel.mORMot Framework . so that it will be common to all database models.SetCustomCollationForAllRawUTF8() method. 1. SAD . SYSTEMNOCASE/ISO8601/WIN32CASE/WIN32NOCASE). The following collations are therefore available when using SQLite3 within the mORMot ORM: Collation Description BINARY Default memcmp() comparison NOCASE Default ASCII 7 bit comparison RTRIM Default memcmp() comparison with right trim SYSTEMNOCASE mORMot's Win-1252 8 bit comparison ISO8601 mORMot's date/time comparison WIN32CASE mORMot's comparison using case-insensitive Windows API WIN32NOCASE mORMot's comparison using not case-insensitive Windows API Note that WIN32CASE/WIN32NOCASE will be slower than the others. you can set for each database model: aModel.Synopse mORMot Framework Software Architecture Design 1.18 Page 151 of 1055 . but will handle properly any kind of complex scripting. if you want to use the Unicode-ready Windows API at database level. for both client and server.Rev. which will do it for a given model. every time the corresponding TSQLRecord is used.e.18 Date: June 16. since it is stored as plain JSON content sftBlob sftBlobDynArray sftBlobCustom BINARY You can override those default collation schemes by calling TSQLRecordProperties. i. If you use non-default collations (i. That is. since it will declare all the above collations. 2013 sftEnumerate sftSet sftInteger sftID sftRecord sftBoolean sftFloat sftCurrency ftTimeLog sftModTime sftCreateTime BINARY is used for those numerical values sftDateTime ISO8601. you may have trouble running requests with "plain default" SQLite3 tools. decoding the text into a date/time value before comparison sftObject sftVariant NOCASE.e. SynSQLite3RegEx. mORmot. end. At the SQL and SAD . if the content is retrieved directly from the database driver and by-passes the virtual table mechanism . with the proper SQL statement of each external DB engine. . you should include unit SynSQLite3RegEx.FirstName will contain the 'Finley' word in a regular expression. try CreateRegExpFunction(Server. which will be called in order to implement the REGEXP operator. 1.Rev. The above code will execute the following SQL statement (with a prepared parameter for the regular expression itself): SELECT * from People WHERE Firstname REGEXP '\bFinley\b'. In fact. nil for a field referring to another record.see below (page 166). and register the RegExp() SQL function to a given SQLite3 database instance. and '' for a string field.Free. In order to enable the operator.6. by enabling the REGEXP operator in addition to standard SQL operators (= == != <> IS IN LIKE GLOB MATCH).Synopse mORMot Framework Software Architecture Design 1.18 Page 152 of 1055 . as such: uses SynCommons.Create(Model. 'FirstName REGEXP ?'. Server := TSQLRestServerDB. NULL doesn't exist as such (it is a SQL concept). 8.7.. REGEXP operator Our SQLite3 engine can use regular expression within its SQL queries.. the REGEXP operator is a special syntax for the regexp() user function. This unit will call directly the UTF-8 API of the PCRE library.. NULL handling Since you access Delphi properties.DB).CreateAndFillPrepare(Client. No regexp() user function is defined by default and so use of the REGEXP operator will normally result in an error message.regular-expressions. it will find all objects where TSQLRecordPeople. \b defines a word boundary search.zip. with TSQLRecordPeople.db3'). finally Server. 2013 When using external databases .pas to your uses clause. It will use the Open Source PCRE library to perform the queries.DB. So you will have 0 for an integer field.pas wrapper unit as published at http://www.'test. returned data may not match your expectations according to the custom collations: you will need to customize the external tables definition by hand. That is.'SAMUEL FINLEY ')). Check(IdemPChar(pointer(FirstName).['\bFinley\b']) do try while FillOne do begin Check(LastName='Morse'). end. It will use the statically linked PCRE library as available since Delphi XE. for older versions of Delphi.2.info/download/TPerlRegEx. and maintain a per-connection cache of compiled regular expressions to ensure the best performance possible.see below (page 155).18 Date: June 16. or will rely on the PCRE. Calling CreateRegExFunction() for a given connection will add a SQL function named "regexp()" at run-time. finally Free. mORMotSQLite3. 8.mORMot Framework .2. end. "Write one" speed is enhanced from 8-9 rows per second into about 400 rows per second..sqlite. 2013 JSON levels. allowing several processes to access the same database file concurrently. In the mORMot ORM/SQL code. NULL will appear only in case of a BLOB storage with a size of 0 bytes.g. and features the ACID properties of the database engine. as a method common to all your application classes. which guarantee that database transactions are processed reliably: for instance.mORMot Framework . So depending on your application requirements. when running on a normal hard drive. When the tests performed during Data access benchmark (page 135) use Synchronous := smOff. which can be added to your database class.8. It is worth noting that NULL handling is not consistent among all existing database engines.18 Page 153 of 1055 . In SQLite3 itself. If the application running SQLite crashes. you should not see it as a value. SQLite continues without syncing as soon as it has handed data off to the operating system. for example.8.Rev. since the object pascal language does not allow defining a nullable type (yet).. When Synchronous is set to smOff. On the other hand.18 Date: June 16. It can be performed by using a simple SQL statement.2. 8. .org/lang_expr.File locking: it means that the database file is locked for exclusive use during writing. the default SQlite3 write speed is quite slow.Synopse mORMot Framework Software Architecture Design 1. At higher level (Delphi code or JavaScript/AJAX code) the NULL value is to be handled explicitly. IS and IS NOT operators). the data will be safe. on a physical hard drive (SSD or NAS drives may not suffer from this delay). but the database might become corrupted if the operating system crashes or the computer loses power before that data has been written to the disk surface. 1. ACID is implemented by two means at file level: . NULL is handled as stated in http://www. By default. no null-oriented ORM methods are implemented in our framework. some operations are as much as 50 or more times faster with this setting. in case of a power loss or hardware failure. This guarantees that the data is written to the disk. 8. the engine will pause after issuing a OS-level write command. ACID is an acronym for "Atomicity Consistency Isolation Durability" properties.html.2. (see e. In SQLite3. Otherwise.Synchronous writing: it means that the engine will wait for any written content to be flushed to disk before processing the next request. the data will be saved on disk in a consistent way. In fact. SAD .Synchronous property to smOff instead of the default smFull setting. Synchronous writing You can overwrite the first default ACID behavior by setting the TSQLDataBase. or only with proper (unit) testing.1. so we recommend not using it in any database statements. the NULL value does exist and are converted as expected. There is no direct way of making a difference between NULL and '' for a string field. ACID and speed As stated above in Data access benchmark (page 135). Changing these default settings can ensure much better writing performance. you may switch Synchronous setting to off. Staying at ORM level may help. with no potential loss of data.. MainDBFileName.Create(Model. so will affect all tables handled by the TSQLRestServerDB instance.''''.but individual insertions will have a major speed up . File locking You can overwrite the first default ACID behavior by setting the TSQLDataBase.false.nil.Synopse mORMot Framework Software Architecture Design 1.Create(Model. just as with SQlite3.Create(Model.MainDBFileName.nil.Props.TSQLRecordSample.DB.'').Props.see below (page 166).'').Server. Performance tuning By default.Create(DBFileName. As such.Server.false.TSQLRecordSample.LockingMode := lmExclusive. Client := TSQLRestClientDB.DB. TSQLDBSQLite3Connection(Props. VirtualTableExternalRegister(Model.TSQLRecordSample. in the expense of slow writing outside a transaction.see Data access benchmark (page 135). for instance: Props := TSQLDBSQLite3ConnectionProperties. Client. 2013 To change the main SQLite3 engine synchronous parameter. But if you defined some SQLite3 external tables .Create(Model. you can define the setting for a particular external connection.Server.DB.Props.nil.TSQLRestServerDB.TSQLRestServerDB.MainConnection).Synchronous := smOff. for external tables: Props := TSQLDBSQLite3ConnectionProperties.18 Date: June 16.TSQLRestServerDB. you may code for instance: Client := TSQLRestClientDB.Create(Model.''''.'').MainConnection). but small write transactions will be much faster. VirtualTableExternalRegister(Model.''). To change the main SQLite3 engine locking mode parameter.TSQLRestServerDB. database viewer tools) to access the file at the same time. We do not change this policy.2. Client. defining LockingMode := lmExclusive without Synchronous := smOff could be of great benefit for a server which purpose is mainly to serve ORM content to clients.Synchronous := smOff.TSQLRestServerDB. Note that this setting is common to a whole TSQLDatabase instance. But if you defined some SQLite3 external tables .2. for instance: Props := TSQLDBSQLite3ConnectionProperties.Create(Model. you may code for instance: Client := TSQLRestClientDB.Server. VirtualTableExternalRegister(Model. Client := TSQLRestClientDB.MainDBFileName.Create(DBFileName.Create(DBFileName. Or. Client. so will affect all tables handled by the TSQLRestServerDB instance.mORMot Framework .'').false. SQLite will lock the database file for exclusive use during the whole session. Note that this setting is common to a whole TSQLDatabase instance. by a factor usually greater than 40.3.LockingMode property to LockingMode instead of the default lmNormal setting. 8.Synchronous := smOff.18 Page 154 of 1055 .nil. as such: Client := TSQLRestClientDB.false. Client.''). exclusive file locking improves the reading speed by a factor of 4 (in case of individual row retrieval).LockingMode := lmExclusive. Bigger transactions involving several hundredths/thousands of INSERT won't be accelerated .''). you can define the setting for a particular external connection. 8.'SampleRecord').nil.MainDBFileName. In fact.Rev.LockingMode := lmExclusive. The best performance will be achieved by combining the two previous options.''''.see below (page 166).TSQLRestServerDB.8.8.false.'').MainDBFileName. 1. SAD . since it will ensure best safety.MainDBFileName. Client := TSQLRestClientDB. the slow but truly ACID setting will be used with mORMot.nil. It will prevent other processes (e. TSQLDBSQLite3Connection(Props.'SampleRecord').'').2.'SampleRecord').DB.false.g. When LockingMode is set to lmExclusive. 18 Page 155 of 1055 . some virtual implementations might provide read-only tables.Server. do not forget to perform backups as often as possible (at least several times a day). TSQLDBSQLite3Connection(Props. If you can afford loosing some data in very rare border case.Particular virtual table implementations might impose additional constraints.see below (page 166). or if you are sure your hardware configuration is safe (e.BackupGZ methods for a fast backup of a running database. and if the default safe but slow setting is not enough for you. if you need 100% of service availability. setting Synchronous := smOff would help your application scale for writing. since it is not able to release all internal instance statements before backup. But behind the scenes. you can use such tables in your SQL statement. Or the application might compute the content of the virtual table on demand.g. (Virtual tables can have indices but that must be built into the virtual table implementation. 1. Setting LockingMode := lmExclusive will benefit of both writing and reading speed.) . Or it might represent a view of data on disk that is not in the SQLite3 format (e. Virtual Tables magic The SQlite3 engine has the unique ability to create Virtual Tables from code. Adding a backup feature on the server side is as simple as running: Client.. 8.LockingMode := lmExclusive. You may use TSQLRestServerDB. SQL statements can in general do anything to a virtual table that they can do to a real table. if the server is connected to a power inverter and has RAID disks) and that you have backups at hand.Backup or TSQLRestServerDB. Server will stop working during this phase.One cannot create a trigger on a virtual table. Or some virtual table implementations might limit the kinds of UPDATEs that can be made. already included in the SQLite3 engine. Consider using an external and dedicated database (like Oracle or MS SQL) if your security expectations are very high. ADD COLUMN commands against a virtual table..18 Date: June 16.gz').One cannot create additional indices on a virtual table. We were not able to fix this issue yet. . so a lower-level backup mechanism could be used instead.g. In all cases.Rev. mixing normal SAD .3. TSQLVirtualTableLog). Note that with the current implementation. just as if they were native SQLite3 tables . . low-level backup is not working as expected on the Win64 platform. and even safely execute a SELECT statement with JOIN or custom functions.MainConnection). so that its backup time will remain unnoticeable on the client side. For example. The error seems to be at the SQlite3 64 bit library level. with the following exceptions: . the virtual table object looks like any other table or view.BackupGZ(MainDBFileName+'. It can be used to access any external database. queries from and updates to a virtual table invoke callback methods on the virtual table object instead of reading and writing to the database file. Example of virtual tables. Thanks to the generic implementation of Virtual Table in SQLite3.Synchronous := smOff. Indices cannot be added separately using CREATE INDEX statements. are FTS or RTREE tables. From the perspective of an SQL statement.mORMot Framework .Synopse mORMot Framework Software Architecture Design 1. 2013 TSQLDBSQLite3Connection(Props. The virtual table mechanism allows an application to publish interfaces that are accessible from SQL statements as if they were tables. Or some virtual table implementations might allow INSERT or DELETE but not UPDATE.MainConnection).One cannot run ALTER TABLE . Using an external database would perhaps keep you main mORMot database small in size. You'll find classes like TSQLVirtualTableJSON or TSQLVirtualTableBinary which handle in-memory data structures. Our framework introduces new types of custom virtual table. Therefore. all those Virtual Table mechanism is implemented in mORMot.Synopse mORMot Framework Software Architecture Design 1.1. in order to easily add such virtual tables with pure Delphi code.see External Databases classes hierarchy below (page 182). 8. File extension on disk will be simply .data file. As you probably have already stated. virtual tables are just tables. which inherits from the common base TSQLRecord class. For instance. named TSQLVirtualTableExternal and TSQLVirtualTableCursorExternal will be defined in a similar manner . TSQLVirtualTableBinary and TSQLVirtualTableCursorJSON classes will implement a Virtual Table using a TSQLRestServerStaticInMemory instance to handle fast in-memory static databases. beginning with revision 1. i. Note that the virtual table module name is retrieved from the class name. there is no other SQL database engine around able to implement this pretty nice feature. To handle external databases. In order to implement a new Virtual Table type. or in a proprietary SynLZ compressed format (for the TSQLVirtualTableBinary class. public class procedure GetTableModuleProperties( SAD . Disk storage will be encoded either as UTF-8 JSON (for the TSQLVirtualTableJSON class. 8.json for the 'JSON' module.Rev. i. Virtual Table module classes A dedicated mechanism has been added to the framework. the TSQLVirtualTableJSON class will have its module named as 'JSON' in the SQL code. two dedicated classes. you'll have to define a so called Module to handle the fields and data access and an associated Cursor for the SELECT statements.3. This is implemented by the two TSQLVirtualTable and TSQLVirtualTableCursor classes as defined in the mORMot. and . the 'Binary' module). the 502 KB People.e. here are the default Virtual Table classes deriving from those classes: TSQLVirtualTableBinary TSQLVirtualTableLog TSQLVirtualTableCursorJSON TSQLVirtualTableJSON TSQLVirtualTable TSQLVirtualTableCursorLog TSQLVirtualTableCursorIndex TSQLVirtualTableCursor Virtual Tables classes hierarchy TSQLVirtualTableJSON. even if.e. in our proprietary optimized format.data for the 'Binary' module. 2013 SQLite3 tables and any other Virtual Table. From the ORM point of view. which will implement a Virtual Table module named "Log". they inherit from TSQLRecordVirtual.json content (as created by included regression tests) is stored into a 92 KB People.18 Page 156 of 1055 . Adding a new module is just made by overriding some Delphi methods: TSQLVirtualTableLog = class(TSQLVirtualTable) protected fLogFile: TSynLogFile.13. 1.3.pas. i. it is independent from the SQLite3 engine. For instance. Just to mention the size on disk difference.e.2. Defining a Virtual Table module Here is how the TSQLVirtualTableLog class type is defined. to my knowledge. the 'JSON' module).mORMot Framework .18 Date: June 16.pas unit. end else SAD . i. and will handle the vtWhereIDPrepared feature: function TSQLVirtualTable. end.its published properties definition will be used by the inherited Structure method to specify to the SQLite3 engine which kind of fields are expected in the SQL statements: TSQLRecordLogFile = class(TSQLRecordVirtualTableAutoID) protected fContent: RawUTF8. // mark TSQLVirtualTableCursorJSON expects it OmitCheck := true. override. Here is how the Prepare method is implemented. since it will depend on the table it is implementing.Where[0] do begin // check ID=? Value. This module will allow direct Read-Only access to a .log file content. The following method will define the properties of this Virtual Table Module: class procedure TSQLVirtualTableLog. aProperties. published /// the log event time stamp property DateTime: TDateTime read fDateTime.18 Page 157 of 1055 . the running TSQLRestServerStaticInMemory instance. But using Delphi class RTTI allows the construction of this SQL statement with the appropriate column type and collation. You could have overridden the Structure method in order to provide the CREATE TABLE SQL statement expected. Fields: PPUTF8CharArray).EstimatedCost := 1.GetTableModuleProperties method won't return any associated TSQLRecordClass. if result then if (vtWhereIDPrepared in fModule. const aTableName: RawUTF8. 2013 var aProperties: TVirtualTableModuleProperties). /// the textual message associated to the log event property Content: RawUTF8 read fContent. Instead.Features) and Prepared.IsWhereIDEquals(true) then with Prepared. 1. start counting at 1. destructor Destroy.mORMot Framework . common to what the rest of the ORM will expect.Synopse mORMot Framework Software Architecture Design 1.GetTableModuleProperties( var aProperties: TVirtualTableModuleProperties). this RecordClass property is not mandatory. The associated cursor class is returned.Features := [vtWhereIDPrepared]. begin aProperties.Prepare(var Prepared: TSQLVirtualTablePrepared): boolean.Rev. end. to define the handled fields . Prepared.VType := varAny. and will return the corresponding field layout of each associated table.18 Date: June 16. which file name will be specified by the corresponding SQL table name. FieldCount: integer. begin result := Self<>nil. the TSQLVirtualTableJSON. override. /// the log event level property Level: TSynLogInfo read fLevel. For instance. override. constructor Create(aModule: TSQLVirtualTableModule. aProperties. so we can speed up RowID=? WHERE clause easily).CursorClass := TSQLVirtualTableCursorLog. fDateTime: TDateTime. end.e. And a TSQLRecord class is specified. Of course. the Structure method is overridden. and vtWhereIDPrepared indicates that any RowID=? SQL statement will be handled as such in the cursor class (we will use the log row as ID number.RecordClass := TSQLRecordLogFile. The supplied feature set defines a read-only module (since vtWrite is not selected). fLevel: TSynLogInfo. end. // out of range ID end. Fields: PPUTF8CharArray). inherited. // generic high cost end. If the WHERE clause is not RowID=? (i.Create(aFileName). end.Count-1.Destroy.IsWhereIDEquals returns false). or fMax<fCurrent.e.FileName(aTableName). Then the corresponding cursor is defined as such: TSQLVirtualTableCursorLog = class(TSQLVirtualTableCursorIndex) public function Search(const Prepared: TSQLVirtualTablePrepared): boolean.mORMot Framework .e.IsWhereIDEquals(false) then begin fCurrent := Prepared. returning fCurrent=fMax=ID-1 for any valid ID.VInt64-1.fLogFile. since we have set the vtWhereIDPrepared feature and the Prepare method identified it in the request and set the OmitCheck flag. end.Create(aModule: TSQLVirtualTableModule.log file name on disk .EstimatedCost := 1E10. override. if (FieldCount=1) then aFileName := UTF8ToString(Fields[0]) else aFileName := aModule. It only associates a TSynLogFile instance according to the supplied file name (our SQL CREATE VIRTUAL TABLE statement only expects one parameter. In fact. The overridden Search method consists only in: function TSQLVirtualTableCursorLog. The only purpose of this method is to handle RowID=? statement SELECT WHERE clause.Where[0]. if Prepared. end. begin FreeAndNil(fLogFile). var aResult: TVarData): boolean. FieldCount: integer. Next and Search methods using those properties to handle navigation throughout the cursor. it will have the generic fCurrent / fMax protected fields.Value. end. // mark EOF by default if result then begin fMax := TSQLVirtualTableLog(Table). 1.Synopse mORMot Framework Software Architecture Design 1. In our case. Then here is how each 'log' virtual table module instance is created: constructor TSQLVirtualTableLog. which is the .Search( const Prepared: TSQLVirtualTablePrepared): boolean. no result if the ID is out of range. the Search method of the cursor class must handle all cases which has been notified as handled during the call to the Prepare method. override.Destroy destructor will free this fLogFile instance: destructor TSQLVirtualTableLog. fLogFile := TSynLogFile.18 Date: June 16. 2013 Prepared. const aTableName: RawUTF8.18 Page 158 of 1055 . begin result := inherited Search(Prepared). if Prepared. and will have the HasData. var aFileName: TFileName. our Search method MUST handle the RowID=? case. // ID=? -> index := ID-1 if cardinal(fCurrent)<=cardinal(fMax) then fMax := fCurrent else // found one fMax := fCurrent-1. i. function Column(aColumn: integer. The TSQLVirtualTableLog. it will use the SQL table name instead). it will return SAD .Rev. begin inherited. Since this class inherits from TSQLVirtualTableCursorIndex.if this file name is not specified. i.Rev.18 Date: June 16. Since all fields are already known by the TSQLVirtualTableLog class. Demo. var aResult: TVarData): boolean.ExecuteJSON('select * from test where rowid=1'). Content fields of TSQLRecordLogFile). var LogFile: TSynLogFile. 8. can be used with any kind of data. next paragraph): RegisterVirtualTableModule(TSQLVirtualTableLog. First we will register this module to a DB connection (this method is to be used only in case of such low-level access . Each column value is retrieved by this method: function TSQLVirtualTableCursorLog. end.fLogFile.Res). s3 := Demo. to ensure that the text memory will be still available at least until the next Column method call. The SetColumn overloaded methods can be used to set the appropriate result to the aResult variable.html.Execute('CREATE VIRTUAL TABLE test USING log(temptest.EventDateTime(fCurrent)).. // ID = index + 1 0: SetColumn(aResult. Then we can execute the following SQL statement to create the virtual table for the Demo database connection: Demo.ExecuteJSON('select * from test').LineSize(fCurrent)). cf.LogFile.ord(LogFile.fCurrent+1).e. We only specify the log file name. but TSQLModel.Demo).LogFile. This will create the virtual table. VirtualTableRegister instead. LogFile := TSQLVirtualTableLog(Table).18 Page 159 of 1055 . In fact.3.LogFile.Count-1. it is not necessary to specify the fields at this level.Column(aColumn: integer. if (self=nil) or (fCurrent>fMax) then exit.org/lang. 2: SetColumn(aResult.'). For UTF-8 text.mORMot Framework . if you define the appropriate methods of a corresponding Virtual SAD .Execute('select count(*) from test'. s2 := Demo.LinePointers[fCurrent]. and then will follow the columns as defined in the text returned by the Structure method (in our case.3.in our ORM you should never call this method. if LogFile=nil then exit.log). You can note that there is no difference with a normal SQLite3 table. directly from the SQLite3 engine. end.Synopse mORMot Framework Software Architecture Design 1. else exit. s := Demo. 2013 fCurrent=0 and fMax=fLogFile. 1. result := true. which will be retrieved by TSQLVirtualTableLog. Level. case aColumn of -1: SetColumn(aResult. Check(Res=1). As stated by the documentation of the TSQLVirtualTableCursor class. here is how this "Log" virtual table module can be used. from the SQL point of view. begin result := false. Using a Virtual Table module From the low-level SQLite3 point of view.ExecuteJSON('select * from test where level=3'). 1: SetColumn(aResult. the DateTime. the full power of the SQL language as implemented by SQLite3 . Create constructor. -1 is the column index for the RowID.EventLevel[fCurrent])).see http://sqlite. it will use a temporary in-memory space. it will let the SQLite3 engine loop through all rows searching for the data. SAD . its ORM representation).18 and using a TSQLVirtualTableBinary Page 160 of 1055 .5. VirtualTableRegister method must be called to associate a TSQLVirtualTableClass (i. TSQLRecordLogFile was defined to map the column name as retrieved by the TSQLVirtualTableLog ('log') module. TSQLRecordVirtualTableForcedID children can be defined for Virtual Table implemented in Delphi.e.Rev. with a new ID generated automatically at INSERT. Model. just by defining some TSQLRecord. since it may increase code size) on the Client side. for a stand-alone application).e.TSQLVirtualTableJSON). In-Memory "static" process We have seen that the TSQLVirtualTableJSON.mORMot Framework . 8. the TSQLModel.Create (or TSQLRestClientDB. For instance. But on the server side. inheriting from some TSQLRecordVirtual dedicated classes: TSQLRecordLogFile TSQLRecordVirtualTableForcedID TSQLRecordVirtualTableAutoID TSQLRecordVirtual TSQLRecord Custom Virtual Tables records classes hierarchy TSQLRecordVirtualTableAutoID children can be defined for Virtual Table implemented in Delphi. TSQLVirtualTableCursorJSON classes implement a Virtual Table module TSQLRestServerStaticInMemory instance to handle fast static in-memory database.3.Create.18 Date: June 16. an exception is raised at virtual table creation. with an ID value forced at INSERT (in a similar manner than for TSQLRecordRTree or TSQLRecordFTS3/4). the association is not needed (nor to be used.VirtualTableRegister(TSQLRecordDali1. the first using the 'JSON' virtual table module. The Virtual Table module associated from such classes is retrieved from an association made to the server TSQLModel.3. Otherwise. the second using the 'Binary' module: Model. 1.TSQLVirtualTableBinary). This registration should be done on the Server side only. ORM and TSQLRecord The framework ORM is able to use Virtual Table modules. the following code will register two TSQLRecord classes. a Virtual Table module implementation) to a TSQLRecordVirtualClass (i. before calling TSQLRestServer.4. 2013 Table module. Virtual Table.VirtualTableRegister(TSQLRecordDali2.Synopse mORMot Framework Software Architecture Design 1. and should not to be used for any other purpose. 8. In a Client-Server application. 2013 Why use such a database type.5.2. 8. This method is only to be called server-side.18 Page 161 of 1055 .3. .SQlite3 in-memory tables are only accessed via SQL statements.SQLite3 tables are stored in the main database file .. i.3. 8.1.. is to call the TSQLRestServer. some content to be shared among users. The in-memory TSQLRestServerStaticInMemory instance handling the storage can be accessed later via the StaticDataServer[] property array of TSQLRestServer. . without the SQLite3 engine so it could be used to produce small efficient server software . . you could create calculated fields easily with TSQLRestServerStaticInMemory dedicated "getter" methods written in Delphi.18 Date: June 16.): this is made possible using our JSON or Binary virtual table modules (but.in some cases..On the server side. and definitively makes sense for an ORM framework. In-Memory virtual tables A more advanced and powerful way of using static tables is to define some classes inheriting from TSQLRecordVirtualTableAutoID. For instance. this primitive but efficient database engine can be used without need of the SQLite3 database engine to be linked to the executable.In Memory ORM" folder.SQlite3 in-memory tables are not persistent. whereas TSQLRestServerStaticInMemory tables can have faster direct access for most common RESTful commands (GET / POST / PUT / DELETE individual rows) . to be honest. if the aServer. when you can create a SQLite3 in-memory table. independently from the SQLite3 engine. there is no difference between a regular and a static table. and associate them with some TSQLVirtualTable classes.StaticVirtualTable[aClass].CommitShouldNotUpdateFile property is set to true in this case. .e. whereas our JSON or Binary virtual table modules can be written on disk on purpose.both of them are not handled natively by our Client-Server framework. file writing should be made by calling explicitly the aServer.mORMot Framework . it could be very convenient to have a direct list of in-memory TSQLRecord instances to work with in pure Delphi code.On the client or server side.see the "SQLite3\Samples\01 . whereas SQlite3 in-memory tables would need additional SQL coding.Rev. so will have their RowID property computed at INSERT).SQlite3 in-memory tables will need two database connections.UpdateToFile method.StaticVirtualTable[aClass]. the ATTACH DATABASE statement could provide a similar feature). . this is exactly what TSQLRestServerStaticInMemory allows. it could be much convenient to provide some additional table content in some separated database file (for a round robin table. The TSQLRecordVirtualTableAutoID parent class will specify that associated virtual table modules will behave like normal SQLite3 tables. a configuration table written in JSON. As we just stated. StaticDataCreate method.this could make a difference in server CPU load. . For the Client. or call to the ATTACH DATABASE SQL statement .The TSQLRestServerStaticInMemory class can be used stand-alone. 1. . saving some KB of code if necessary. the supplied regression tests define such two tables with three columns.. It will be enough to handle most basic RESTful requests.5. In-Memory tables A first way of using static tables. especially with the Batch feature of the framework. of course. named SAD . using the :memory: file name? That is the question.Synopse mORMot Framework Software Architecture Design 1. which will be used for all Database access. TSQLRecordDali2 = class(TSQLRecordDali1).Create(ModelC. From the code point of view.FirstName := V2.YearOfBirth := V2.Create( [TSQLRecordPeople. Check(aClient.Update(VD).FillOne do begin VD.data'.Add(VD.VD).VirtualTableRegister(TSQLRecordDali2.TSQLRecordDali2].YearOfDeath=1989).'root'). inc(n). VD.. 1. VD.YearOfBirth := VD. end.json' and 'Dali2. SAD . Check(VD.YearOfBirth=1904).TSQLVirtualTableJSON).true)=n. while V2.YearOfDeath.YearOfBirth. 2013 FirstName.Synopse mORMot Framework Software Architecture Design 1. end. there is no difference in our ORM with handling those virtual tables.YearOfDeath := VD. published property FirstName: RawUTF8 read fFirstName write fFirstName.nil. Both class types are then added to the TSQLModel instance of the application.ID=i). VD. the JSON version will be much bigger.Rev. Check(VD. n := 0. the corresponding Virtual Table modules are associated with those both classes: ModelC. but also more easy to handle from outside the application. VD.YearOfBirth+i. (..'SALVADOR')). Check(VD.Msg). here is some code extracted from the supplied regression tests: if aClient.TSQLRestServerTest).FirstName. Two files will be created on disk.FillPrepare(aClient.Msg). Check(IdemPChar(pointer(VD.Retrieve(i.Msg). As stated above.mORMot Framework .TSQLVirtualTableBinary). ModelC. This TSQLRestClientDB has in fact a TSQLRestServerDB instance running. fFirstName: RawUTF8. property YearOfBirth: integer read fYearOfBirth write fYearOfBirth. Then. on the server side. compared to regular TSQLRecord tables. end.FirstName). including Virtual Table process. the 'JSON' and 'Binary' Virtual Table modules will be launched automatically when the SQLite3 DB connection will be initialized: Client := TSQLRestClientDB. // update some items in the file for i := 1 to n do begin Check(aClient. fYearOfDeath: word.VirtualTableRegister(TSQLRecordDali1. on the Server side. YearOfBirth and YearOfDeath. Thanks to the VirtualTableRegister calls.TransactionBegin(TSQLRecordDali1) then try // add some items to the file V2. after the published properties definition: TSQLRecordDali1 = class(TSQLRecordVirtualTableAutoID) private fYearOfBirth: integer.Demo.YearOfDeath := V2.) TSQLRecordDali1. Check(aClient. For instance. property YearOfDeath: word read fYearOfDeath write fYearOfDeath.18 Date: June 16.YearOfDeath+i.'LastName=:("Dali"):'). common to both Client and Server side: ModelC := TSQLModel.18 Page 162 of 1055 . named 'Dali1. using the following property: Server. all CRUD operations.in fact. and the COMMIT statement to write nothing on disk. If for some reason.RollBack.mORMot Framework . aClient.UpdateFile. data will be written by default on disk with our TSQLRestServerStaticInMemory-based virtual tables. as INSERT / UPDATE / DELETE). you later change your mind and e. Check(VD. 2013 // check SQL requests for i := 1 to n do begin Check(aClient. you'll have to explicitly call such code on purpose: As we already noticed.Commit. In order to define such external tables. end.StaticVirtualTable[TSQLRecordDali1].YearOfBirth=1904+i).g. even with multiple connections and several remote servers. end. MySQL and Oracle databases. That is.Msg). UpdateToFile method is not immediate. SAD . to nest multiple modification to a Virtual Table with such a transaction. if no explicit transaction is defined (via TransactionBegin / Commit methods). A Commit is needed from the Client side to write anything on disk.Synopse mORMot Framework Software Architecture Design 1.3. 1. Check(VD.e.YearOfDeath=1989+i). The Virtual Table feature of SQLite3 will allow those remote tables to be accessed just like "native" SQLite3 tables . the Commit method in the above code will call TSQLRestServerStaticInMemory.18 Page 163 of 1055 .6. it could be a very powerful way of consolidating any kind of data. then a call to the VirtualTableExternalRegister() function will define this class to be managed as a virtual table. to write a valid SQL query with a JOIN between SQlite3 tables. The TSQLRestServerStaticInMemory.VD). such a transaction will be performed for every database modification (i. for better performance. It is possible to force the In-Memory virtual table data to stay in memory. From the Server side.18 Date: June 16. Microsoft SQL Server. you are the one to blame if your client updates the table data and this update never reaches the disk! 8.CommitShouldNotUpdateFile := true.TableRowCount(TSQLRecordDali1)=1001).UpdateToFile. in order to create disk content. In order to create disk content. some external databases may be accessed by our ORM. Using a dedicated external database server may allow better response time or additional features (like data sharing with other applications or languages). Please note that the SQlite3 engine will handle any Virtual Table just like regular SQLite3 tables.StaticVirtualTable[TSQLRecordDali1]. Added to our code-based reporting engine (able to generate pdf). Think as an ORM-based Business Intelligence from any database source. Virtual Tables to access external databases As will be stated below (page 166). because it will write all table data each time on disk. concerning the atomicity of the data. you may be able e.g. move your table from the TSQLVirtualTableJSON / TSQLVirtualTableBinary engine to the default SQlite3 engine. And in all cases. you'll then have to explicitly call the corresponding method on purpose: Server. It is therefore mandatory. it is the standard way of using the ORM. you define your regular TSQLRecord classes as usual. for performance reasons.Rev. Since StaticVirtualTable property is only available on the Server side. except aClient.Retrieve(i. your code could remain untouched. Check(aClient. In fact. from an external database engine. var aModel: TSQLModel. FHttpServer:= TSQLHttpServer.Create('8080'.Synopse mORMot Framework Software Architecture Design 1.CreateMissingTables(0).see below (page 166) . end. imagine you defined two in-memory JSON virtual tables on Server side: type TSQLServer = class(TSQLRestServerDB) private FHttpServer: TSQLHttpServer. 1. You have several possibilities: .VirtualTableRegister(TSQLValue2. ensure that the Client side set the table property of its own model to rCustomAutoID. but from TSQLRecordVirtualTableAutoID. you need to notify the Client-side model that a table is implemented as virtual. True). 8.Destroy. TSQLVirtualTableJSON). ChangeFileExt(ParamStr(0).Rev. aModel. override.3. ensure that both Client and Server set the table property of its own model to rCustomAutoID. like "no such column: ID".mORMot Framework . . TSQLVirtualTableJSON). Virtual tables from the client side For external databases . Self. end.18 Page 164 of 1055 . 2013 Server-side may omit a call to VirtualTableExternalRegister() if the need of an internal database is expected: it will allow custom database configuration at runtime. Otherwise you may encounter some SQL errors when executing requests. you can safely define your tables as TSQLValue1 = class(TSQLRecord).If your tables are defined as TSQLRecord. begin aModel := CreateModel. // model will be released with TSQLServer instance inherited Create(aModel. destructor TSQLServer.Free. In this case.18 Date: June 16. inherited.see In-Memory virtual tables (page 161).the SQL conversion will be done on the fly in a more advanced way. public constructor Create.Inherit each table not from TSQLRecord. '. as was stated above as standard procedure for virtual tables . aModel. For instance. end. aModel.db'). with no further code on client side. First option could be done as such: type TSQLValue1 = class(TSQLRecordVirtualTableAutoID) SAD . if you expect all ORM features to work remotely. so you should be able to work with such virtual tables from the client side without any specific model notification.If your tables are defined as TSQLRecord. You will need to specify also no the client side that those TSQLValue1 and TSQLValue2 tables are virtual.7.VirtualTableRegister(TSQLValue1.Owner := self. destructor Destroy. Self). When working with static (in-memory / TObjectList) storage. depending on the customer's expectations (or license). begin FHttpServer.Create. . constructor TSQLServer. The easiest is definitively to let your static in-memory tables inherit from TSQLRecordVirtualTableAutoID. aModel.. constructor TSQLClient.18 Page 165 of 1055 . // model will be released within TSQLServer instance inherited Create('127.Create([TSQLAuthGroup.Create.Props[TSQLValue2]. end. Or.) TSQLValue2 = class(TSQLRecordVirtualTableAutoID) (.Kind := rCustomAutoID. Just use the framework by the book . aModel). aModel.18 Date: June 16.see In-Memory virtual tables (page 161). TSQLValue2]). 2013 (. var aModel: TSQLModel.0. result. the client model could be updated as such: type TSQLClient = class(TSQLHttpClient) public constructor Create.Kind := rCustomAutoID. Once again..Props[TSQLValue2].. in case the table is defined as TSQLValue1 = class(TSQLRecord).mORMot Framework .Synopse mORMot Framework Software Architecture Design 1.0.Props[TSQLValue1].) Or.Kind := rCustomAutoID.1'. SAD .Kind := rCustomAutoID. TSQLValue1. end. '8080'. is to set the property when creating the shared model: function CreateModel: TSQLModel. 'synopse').Rev. perhaps the easiest way of doing it. TSQLAuthUser.Props[TSQLValue1].. begin aModel:= CreateModel. end.Owner := self. SetUser('Admin'. aModel. in case the table is defined as TSQLValue1 = class(TSQLRecord). 1. begin result:= TSQLModel. this restriction does not apply to below (page 166). result. Thanks to the unique Virtual Tables mechanism of SQLite3. we are already able to access to almost any existing SAD ..Synopse mORMot Framework Software Architecture Design 1.). following the patterns already existing. Any help is welcome here: it is not difficult to implement a new unit.1. Database agnosticism Since revision 1.mORMot Framework . .18 Page 166 of 1055 . . .15. Zeos or Alcinoe libraries). Open Source contribution are always welcome! In fact. This list is not closed.SQLite3 database file. See General mORMot architecture . those external tables may be accessed as native SQLite3 tables in our SQL statements. Unicode native. DBExpress.g. BDE. but a dedicated mechanism allows access to any remote database.Any ZeosLib provider (direct ZDBC access). AnyDac.Client Server implementation (page 56). The framework still relies on SQLite3 as its SQL core on the server.pas / TDataset based provider (including NexusDB.Rev.Any OleDB provider (including MS SQL Server. and may be completed in the near future. FireDAC. External database access Adopt a mORMot 9. You may start from an existing driver (e. via a set of generic units and classes. and mix those tables content with the native ORM tables of the framework. The current list of available external database classes is: . . or others). with a lot of available providers. MySQL. 2013 9. Jet or others).Any DB.. OleDB is a good candidate for database access with good performance. our ORM RESTful framework is able to access any available database engine.Any ODBC provider (including FireBird. 1.18 Date: June 16. Thanks to OleDB. UniDAC. .Oracle direct access (via OCI). Oracle 11g.Generic abstract OOP layout. and we wanted our Clients to have a light-weight and as fast as possible access to this great database. But it will allow you to re-use any existing (third-party) database connection driver.Rev.1.Thin wrapper around any DB. Of course.Ability to be truly Unicode. . . ODBC. able to work with any SQL-based database engine. .e. It is even used for our regression tests. 2013 database.g.). Since revision 1.18. And we will let Microsoft or the OleDB provider perform all the testing and debugging for each driver.use internally UTF-8 encoding. in order to implement stand-alone unitary testing. Since revision 1.pas can be used with our SynDB classes. UniDAC. because all available OleDB providers for Oracle (i. An Oracle dedicated direct access was added. 9. the Turbo Explorer or Starter edition).Synopse mORMot Framework Software Architecture Design 1.pas / TDataset based components (e.pas standard unit and all its dependencies).18 Date: June 16. or to use an unsupported database engine.Handle NULL or BLOB content for parameters and results.g.but you got the general layered design. .pas TDataset FireDAC AnyDAC UniDAC ZDBC (Zeos) NexusDB SQLite3 PostgreSQL MySQL Firebird DBExpress OleDB Sybase MS SQL BDE ODBC Jet/Access Advantage Interbase Oracle DB2 Paradox Informix SynDB Architecture This diagram is a bit difficult to follow at the latest level . MySQL or FireBird). BDE. using TDataset as intermediate layer will be slower than the SynDB direct access pattern. . just for free (in fact. and is the official replacement for OleDB (next version of MS SQL Server will provide only ODBC providers. any ZeosLib / ZDBC driver can be used and DB.1. which could make sense in case of evolution of an existing application. 1..Could access any local or remote Database. from any edition of Delphi (even Delphi 7 personal. DBExpress. It has a wider range of free providers (including e. SynDB DB. it was very easy (and convenient) to implement SQLite3 direct access. it does not use the DB. I guess. and the latest SQLite3 engine. Direct access to any Database engine The SynDB units have the following features: . NexusDB.Tested with MS SQL Server 2008. even with pre-Unicode version of Delphi (like Delphi 7 or 2007) . . ZDBC.17.. It will be split into smaller peaces later. direct access to the ODBC layer has been included to the framework database units.mORMot Framework . both Microsoft's and Oracle's) do have problems with handling BLOB.18 Page 167 of 1055 . Thanks to the design of our classes. FireDAC. SAD . including stored procedures. AnyDAC. as far as Microsoft warned its customers). Oracle (via OCI) or SQLite3 (statically linked or via external dll) databases. The code overhead in the server executable will also be much less than with adding any other third-party Delphi library.Direct fast access to OleDB. . i. SQLite3) .Designed to be used with our ORM.18 Page 168 of 1055 . provide also SQL statements to create a table or an index in a database-abstract manner. just as given from OleDB / ODBC or the low-level database client (e.Rev.html. which is a small but efficient way of running queries in a simple User Interface. INTEGER. or the SQLite3 engine). ftDate. our ORM does not need a whole feature set (do not expect to use this database classes with your VCL DB RAD components). or the generic huge TFieldType as defined in the standard VCL DB.to avoid typing try. . and allow one-line SQL statement. about all available engines.18 Date: June 16. . for database reverse-engineering. . BLOB (with the addition of a ftCurrency and ftDate type.Synopse mORMot Framework Software Architecture Design 1. OCI.org/datatype3. 1. not high-level Delphi types as TSQLFieldType defined in mORMot.see Unicode and UTF-8 (page 73). 9. as needed by our ORM (derived from SQLite's internal column types): NULL.sqlite. ftUTF8. but could be used stand-alone (a full Delphi 7 client executable is just about 200 KB). OCI for Oracle. Int64. ftInt64. . REAL. They are defined as such in SynDB: TSQLDBFieldType = (ftUnknown. for cross-Delphi true Unicode process. .pas. thanks to a TQuery-like wrapper..Available ISQLDBRows interface . . Data types Of course. string or widestring variables and parameters. SAD . which uses the same encoding. those features will be used directly by our ORM.pas unit. It will therefore interface directly with our ORM. for direct re-use with existing code. or even in any existing Delphi application. 2013 .Designed to achieve the best possible performance on 32 bit or 64 bit Windows: most time is spent in the database provider (OleDB. for better support of most DB engines) see http://www.e.finally Query. ftCurrency. . You can note that the only string type handled here uses UTF-8 encoding (implemented using our RawUTF8 type).mORMot Framework . ODBC. but our units will use UTF-8 encoding internally . . . . but handles directly the basic SQL column types. Double.Free SynDBExplorer tool provided.g. ftNull.the code layer added to the database client is very thin and optimized. ftBlob).Direct JSON content creation.Column values accessible with most Delphi types.1.Late-binding column access. . in replacement to the deprecated BDE technology.High-level catalog / database layout abstract methods. with no temporary data copy nor allocation (this feature will be the most used in our JSON-based ORM server).Could be safely used in a multi-threaded application/server (with dedicated thread-safe methods. TEXT. NULL. ftDouble. including Variant or generic string / WideString. it is more tied to the standard SQLite3 generic types. Code can access to the textual data via variant. with fast access to any parameter or column name (thanks to TDynArrayHashed). RawUTF8 and BLOB. it is also a good sample program of a stand-alone usage of those libraries. via a custom variant type. usable even if the database client is not officially multi-thread). DateTime. Those types will map low-level database-level access types. In fact..TQuery emulation class.2.Allow parameter bindings of prepared requests. Currency.Avoid most memory copy or unnecessary allocation: we tried to access the data directly from the retrieved data buffer.Free end. able to retrieve the table and column properties (including indexes). Classes The data is accessed via three families of classes: . server and database name. switching from one database engine to another is just a matter of changing a class type. then you derivate TSQLDBConnection and TSQLDBStatement instances using dedicated NewConnection / ThreadSafeConnection / NewStatement methods.1.Statements.Rev.Synopse mORMot Framework Software Architecture Design 1.Connections. accessing all those external databases with regular SQL code.pas Oracle DB direct access classes (via OCI) SynDBSQLite3.pas TDataset (DB. which may be multiple for one existing connection. there can be multiple connections for the same connection properties instance.pas SynDBNexusDB. 9.pas ZDBC direct access classes SynDBOracle.1.18 Date: June 16. Since all their classes inherit from abstract classes defined in SynDB. which store the database high-level properties (like database implementation classes. user name and password). you define a TSQLDBConnectionProperties instance. 2013 BLOB columns or parameters are accessed as RawByteString variables.pas SynDBFireDAC. Here is the general class hierarchy.of course. which implements an actual connection to a remote database. .18 Page 169 of 1055 .3.pas abstract database direct access classes SynOleDB. for all available remote connection properties: SAD .4.pas SynDBBDE. according to the specified Connection properties . 9. which may be mapped to a standard TStream via our TRawByteStringStream. In practice. . They may be used separately.pas) access classes It is worth noting that those units only depend on SynCommons.mORMot Framework . SynDB Units Here are the units implementing the external database-agnostic features: File Description SynDB. which are individual SQL queries or requests. therefore are independent of the ORM part of our framework.pas ODBC direct access classes SynDBZeos.Connection properties.pas SQLite3 direct access classes SynDBDataset.pas SynDBUniDAC.pas OleDB direct access classes SynDBODBC. 1. Synopse mORMot Framework Software Architecture Design 1. by which most of your database process will be implemented. 2013 TSQLDBFireDACConnectionProperties TSQLDBZEOSConnectionProperties TSQLDBUniDACConnectionProperties TSQLDBOracleConnectionProperties TSQLDBBDEConnectionProperties TSQLDBSQLite3ConnectionProperties TSQLDBDatasetConnectionProperties TOleDBMSOracleConnectionProperties TOleDBOracleConnectionProperties TOleDBODBCSQLConnectionProperties TSQLDBConnectionProperties TSQLDBConnectionPropertiesThreadSafe TOleDBConnectionProperties TOleDBMySQLConnectionProperties TODBCConnectionProperties TOleDBMSSQLConnectionProperties TSQLDBNexusDBConnectionProperties TOleDBMSSQL2012ConnectionProperties TOleDBMSSQL2005ConnectionProperties TOleDBJetConnectionProperties TOleDBAS400ConnectionProperties TSQLDBConnectionPropertiesThreadSafe classes hierarchy Those classes are the root classes of the SynDB units. Then the following connection classes are defined: TODBCConnection TOleDBConnection TSQLDBBDEConnection TSQLDBSQLite3Connection TSQLDBOracleConnection TSQLDBConnection TSQLDBConnectionThreadSafe TSQLDBFireDACConnection TSQLDBUniDACConnection TSQLDBZEOSConnection TSQLDBNexusDBConnection TSQLDBSQLite3Connection classes hierarchy Each connection may create a corresponding statement instance: SAD . the mORMot framework ORM only needs a given TSQLDBConnectionProperties instance to access any external database.Rev. For instance.18 Date: June 16.18 Page 170 of 1055 . 1.mORMot Framework . try UseProps(Props).18 Page 171 of 1055 .5.dpr sample program. Props := TOleDBMSSQLConnectionProperties.''.mORMot Framework . ISQLDBRows interface The easiest is to stay at the TSQLDBConnectionProperties level. Typical use of SynDB classes could be: .\\SQLEXPRESS'. which will write a file with the JSON representation of the Person.Initialize a shared TSQLDBConnectionProperties instance. e. in an abstracted way. .Execute statements directly from this instance's Execute*() methods.. using our SynOleDB unit to connect to a local MS SQL Server 2008 R2 Express edition. 1.'AdventureWorks2008R2'. located in SQlite3 folder. using the Execute() methods of this instance. TADParams for FireDAC (which features Array DML). TSQLDBDatasetStatementAbstract is used to allow the use of custom classes for parameter process. Some dedicated Exception classes are also defined: EODBCException EOleDBException ESQLDBZEOS ESQLDBException ESQLDBOracle ESQLDBBDE ESQLQueryException ESQLDBFireDAC ESQLDBUniDAC ESQLDBDataset Exception ESQLQueryException classes hierarchy Check the TestOleDB.Address table of the sample database AdventureWorks2008R2.Rev.1. . 2013 TSQLDBFireDACStatement TSQLDBDatasetStatementAbstract TSQLDBZEOSStatement TSQLDBUniDACStatement TSQLDBOracleStatement TSQLDBBDEStatement TSQLDBDatasetStatement TSQLDBNexusDBStatement TODBCStatement TSQLDBStatementWithParamsAndColumns TSQLDBStatementWithParams TSQLDBSQLite3Statement TOleDBStatement TSQLDBStatement TOleDBStatement classes hierarchy In the above hierarchy.Create('. Defining a database connection is as easy as: var Props: TSQLDBConnectionProperties.. finally SAD . and access any returned data via an ISQLDBRows interface.g. 9.Synopse mORMot Framework Software Architecture Design 1.''). It will automatically use a thread-safe connection to the database.18 Date: June 16. which will return the column value as a variant. finally Query. The resulting Delphi code to write is just clear and obvious: procedure UseProps(Props: TSQLDBConnectionProperties).1.18 Date: June 16. In fact. 1. You have other dedicated methods.Execute('select * from Sales. Please refer to the documentation of each Create() constructor to set all parameters as expected. as such: procedure UseProps(Props: TSQLDBConnectionProperties). This is the magic of late-binding in Delphi. end. this code is slower than using a standard property based access. access the rows via the Step method and the Row variant. input parameters do vary.finally Free.Synopse mORMot Framework Software Architecture Design 1. Note that a similar feature is available for our SynBigTable unit. begin I := Props. execute it. like this: while Step do SAD .AccountNumber statement.Customer where AccountNumber like ?'. no TSQLDBStatement is defined.mORMot Framework . 2013 Props..['AW000001%']). end. able to retrieve directly the expected data. 9.Free. initialize a statement.Rev.@Row) do while Step do assert(Copy(Row. here to access column content as if column names where native object properties..8)='AW000001'). the MyConnProps. with optional bound parameters. You are not required to add any try. which methods can be used to loop for each result row.see Enhanced logging (page 78). and retrieve individual column values. In practice. via a custom variant time. Note that all bound parameters will appear within the SQL statement.1.Step do assert(Copy(I['AccountNumber']. In this procedure.. when logged using our TSynLog classes . block.AccountNumber. like ColumnUTF8 or ColumnInt. It uses the internal mechanism used for Ole Automation.Free. var I: ISQLDBRows. The above code is perfectly safe. end. end. retrieving the column value via a direct Row. begin with Props. and there is no need to add a try .Execute('select * from Sales.18 Page 172 of 1055 . Note that Props.6. ['AW000001%']. so the code above will initialize (or reuse an existing) thread-safe connection (OleDB uses a per-thread model). In the code above.8)='AW000001'). while I. I['FirstName'] will in fact call the I. var Row: Variant.Execute returns an ISQLDBRows interface. Late binding We implemented late binding access of column values.Column[] default property. Depending on the TSQLDBConnectionProperties sub-class.Execute method returns a TSQLDBStatement instance as a ISQLDBRows. Then any sub-code is able to execute any SQL request. end statements in your code.Customer where AccountNumber like ?'.1. and all memory will be released with the reference count garbage-collector feature of the ISQLDBRows interface. 1. after profiling. Resulting speed is very close to direct Column['AccountNumber'] call.2. ['AW000001%']. after profiling.Rev. the following code will always be faster: var Customer: Integer. we are not able to let the compiler check at compile time for the column name. I was not able to notice any speed increase worth mentioning.2.Execute( 'select * from Sales.AccountNumber expression calls an hidden DispInvoke function. the physical implementation is more complicated.@Customer) do begin Customer := ColumnIndex('AccountNumber'). begin with Props.18 Date: June 16. most of the time is spend in the Step method. let's see the fastest way of accessing the row content. Of course. end. On the contrary the Ole-Automation based late binding was found out to be much slower. But the first version. If the column name in the source code is wrong. Database access From the SynDB logical point of view. especially in fRowSet. will call an optimized version of this function. 2013 assert(Copy(ColumnUTF8('AccountNumber'). In practice. In all cases. just sounds more natural.1. See SDD # DI-2. In fact. Our name lookup via a hashing function (i. end.Synopse mORMot Framework Software Architecture Design 1. 1. an error will be triggered at runtime only.pas TDataset DBExpress FireDAC AnyDAC UniDAC SynDB First Level Providers Of course. and by patching the VCL code in-memory.3. Even if our SynDB library uses a fast lookup using hashing.Customer where AccountNumber like ?'. Our SynCommons unit is able to hack the VCL.mORMot Framework . But to be honest. the Row. since it is late-binding. 9.e. using the textual version of the column name ('AccountNumber') is slower than using directly the column index. which is slow when called multiple times.GetData. while Step do assert(Copy(ColumnString(Customer). SAD .8)='AW000001').8)='AW000001'). as was stated in SynDB Architecture (page 167).18 Page 173 of 1055 . using late-binding of column name. TDynArrayHashed) just does its purpose very well. here is how databases can be accessed: SynDB ZDBC ODBC OleDB Oracle NexusDB SQLite3 BDE DB. First of all. with the code above. 2. OleDB or ODBC to rule them all OleDB (Object Linking and Embedding. sometimes written as OLE DB or OLE-DB) is an API designed by Microsoft for accessing data from a variety of sources in a uniform manner.Synopse mORMot Framework Software Architecture Design 1.com/b/sqlnativeclient/archive/2011/08/29/microsoft-is-aligning-with-odbc-for-nati ve-relational-data-access. 1.Rev. More recently.1. Back & worse strategy from Micro$oft.18 Date: June 16. ODBC (Open DataBase Connectivity) is a standard C programming language middle-ware API for accessing database management systems (DBMS). then was deprecated in favor to OleDB.mORMot Framework . Do not forget about the Advantage Sybase OleDB driver and such. It is worth saying that. when used in a mORMot Client-Server architecture.. but Oracle provides a native OleDB provider (even if we found out that this Oracle provider. 2013 We will now detail how these available database connections are interfaced as SynDB classes.msdn. we will for instance be able to convert directly the OleDB or ODBC binary rows to JSON. ODBC was originally developed by Microsoft during the early 1990s. SynDB OleDB Oracle MS SQL Jet/Access MySQL PostgreSQL Interbase Firebird Sybase SynDB and OleDB Of course. The resulting performance is much higher than using standard TDataSet or other components..18 Page 174 of 1055 . with no temporary conversion into the Delphi high-level types (like temporary string or variant allocations).aspx.. object persistence using an OleDB or ODBC remote access expects only the database instance to be reachable on the Server side. Database. others would need a paid license.. 9. since we will bypass most of the layers introduced by BDE/dbExpress/AnyDAC component sets. one more time! http://blogs. Microsoft is officially deprecating OleDB. including the Microsoft's version. SynDB ODBC Oracle MS SQL MySQL DB2 PostgreSQL Interbase Firebird Sybase Jet/Access Advantage SynDB and ODBC By using our own OleDB and ODBC implementations. have problems with BLOBs). you have got the Microsoft SQL Native Client to access the MS SQL Server 2005/2008.. SAD . Most OleDB / ODBC providers are free (even maintained by the database owner). and urge all developers to switch to the open and cross-platform ODBC API for native connection. native unmanaged interface to the Oracle Database that exposes the full power of the Oracle Database. we included direct integration of ZeosLib into mORMot persistence layer. It is fully object-oriented and with a totally modular design. Kylix and Lazarus + FPC.Synopse mORMot Framework Software Architecture Design 1.3. and it SAD . it does not references DB. high performance. named ZDBC. and makes them accessible via its abstract layer.18 Page 175 of 1055 . 2013 Clients could communicate via standard HTTP. and in completion to our SynOleDB / SynDBODBC units. via a SynDBODBC-based connection.2. Oracle Call Interface (OCI) is the most comprehensive. 9. so official JDBC 2. It allows direct access to any remote Oracle server. . aka Zeos. A similar (even worse) speed penalty has been observer in comparison with the official ODBC driver from Oracle. developed for Delphi. is very close to our SynDB design.oracle.Rev. with direct acces to the ZDBC layer. 9. is a Open Source library which provides native access to many database systems. by-passing the VCL DB additional layer.pas unit.0 specification is the main entry point to the ZDBC API. We noted also that our implementation is 10 times faster than the one provided with ZEOS/ZDBC. using the Oracle Call Interface. SynDB ZDBC Oracle MS SQL MySQL PostgreSQL Interbase Firebird Sybase SQLite3 SynDB and Zeos / ZDBC Such direct access. Originally. using our DB abstraction classes introduced in SynDB. Oracle via OCI For our framework..2.dll library was written. the SynDBOracle unit has been implemented. ZeosLib is a first class citizen library for mORMot. ZDBC was a port of JDBC 2. It connects to the databases by wrapping their native client libraries. We tried to implement all best-practice patterns detailed in the official Building High Performance Drivers for Oracle reference document. 1.0 (Java Database Connectivity API) to Object Pascal. Since revision 1. You can use the latest version of the Oracle Instant Client (OIC) provided by Oracle .mORMot Framework . ZEOS via direct ZDBC ZeosLib.com/technetwork/database/features/instant-client. which is far from optimized (it retrieves the rows one by one from OCI).2.see http://www. SynDBOracle is 3 to 5 times faster than a SynOleDB connection using the native OleDB Provider supplied by Oracle. A direct interface to the oci.18 Date: June 16.which allows to run client applications without installing the standard (huge) Oracle client or having an ORACLE_HOME. Resulting speed is quite impressive: for all requests. That is. so won't need any specific port forwarding or other IT configuration to work as expected. and does not need to marshall all incoming data into a TDataSet compatible layout.18 of the framework. Since that time the API was slightly extended but the main ideas remain unchanged. Just deliver the few dll files in the same directory than the application (probably a mORMot server). As such. Optimized for the latest features of Oracle 11g (e.Implements Array Binding for very fast bulk modifications .Tried to achieve best performance available from every version of the Oracle client. with no BDE.18 Date: June 16. nor OleDB / ODBC provider necessary. for best performance (ZEOS/ZDBC did not handle this. only 32 bit for this current version).Synopse mORMot Framework Software Architecture Design 1. object persistence using an Oracle database expects only the Oracle instance to be reachable on the Server side. . .18 Page 176 of 1055 . .see Data access benchmark (page 135).Able to work with the Oracle Instant Client for No Setup applications (installation via file/folder copy). using native Int64 for retrieving NUMBER fields with no decimal). RAD Application mORMot Application mORMot Application with OIC dlls TCP/IP DBExpress or BDE installed Oracle Client Oracle Server TCP/IP installed Oracle Client Oracle Server TCP/IP Oracle Server Oracle Connectivity with SynDBOracle It is worth saying that.Late-binding access to column names. for instance). .Designed to work under any version of Windows.Natively Unicode (uses internal UTF-8 encoding). . 2013 will work at amazing speed.g. update or deletion of a lot of rows at once . starting from revision 8. 1. DBExpress. either in 32 or 64 bit architecture (but the OCI library must be installed in the same version than the compiled Delphi application. SAD .insert. Here are the main features of this unit: . for all version of Delphi. Midas. with special handling of each database char-set. .Dedicated to work with any version of the Oracle OCI interface.Rev. . i.ORA file. .Use Rows Array and BLOB fetching. .mORMot Framework . when used in a mORMot Client-Server architecture. .Direct access to the Oracle Call Interface (OCI) client.Can use connection strings like '//host[:port]/[service_name]'. .e. with all features of Oracle (other stand-alone direct Oracle access library rely on deprecated Oracle 8 protocol). just like with OleDB or ODBC. avoiding use of the TNSNAME. using a new dedicated Variant type (similar to Ole Automation runtime properties).Connections are multi-thread ready with low memory and CPU resource overhead. When used within the mORMot ORM. with the actual SQLite3 database file as ServerName parameter.18 of the framework. Create constructor.Synopse mORMot Framework Software Architecture Design 1. using those external SQLite3 tables do make sense.Native export to JSON methods. SQLite3 For our ORM framework. or to split your data in several database files.dll library: FreeAndNil(sqlite3). and (optionally the proprietary encryption password in Password . a new SynDBDataset. which will be the main entry point for our ORM framework. // release any previous instance (e. Otherwise. Adding such another Database is just a very thin layer. 9.2. as external tables. we rely on OCI-side statement cache.4. within the main exe) or from external sqlite3. we implemented an efficient SQLite3 wrapper. define a TSQLite3LibraryDynamic instance to load an external sqlite3. static) sqlite3 := TSQLite3LibraryDynamic.Rev. .but by default.Either virtually.18 Page 177 of 1055 .Either directly from the ORM core. if available. to be able to connect to any external database. you have therefore two ways of accessing the SQLite3 engine: .available since rev.pas unit.pas unit in your uses clause. DB. 9.g. To create a connection property to an existing SQLite3 database file. It was an easy task to let the SynSQLite3.dll. it does not make sense to use SynDBSQLite3 external tables. the SQlite3 engine library itself will be shared with both internal and external process. implemented in the SynDBSQLite3. in the future.5. If you want to link the SQLite3 engine to your project executable. mORMot and SQLite3 If your mORMot-based application purpose is to only use one centralized SQLite3 database. In practice. able to SAD .18 Date: June 16. call the TSQLDBSQLite3ConnectionProperties.pas unit has been introduced.Handle Prepared Statements . just as the one used for TSQLRestServerDB. ensure you defined the SynSQLite3Static. mORMot ORM SynDB SQLite3 SynDB. But if you want. These classes will implement an internal statement cache.e.Create. using the cache can make process up to two times faster (when processing small requests). 2013 .mORMot Framework .16). 1. Of course.pas libraries Since revision 1.2. 1. .pas unit be called from our SynDB database abstract classes. UserID) are just ignored. others (DataBaseName. joining the SQLite3 engine either statically (i. 1. 9. with features that rival other heavily licensed products" (vendor's terms). FireDAC / AnyDAC library FireDAC is an unique set of Universal Data Access Components for developing cross platform database applications on Delphi. we will first stick to the providers we need and use. bought by Embarcadero to DA-SOFT Technologies (formerly known as AnyDAC). UniDAC and BDE libraries are interfaced. performance is somewhat degraded in respect to direct SynDB connection (e. in favor to the now deprecated DBExpress.feedback is welcome.pas based library to our SynDB classes. Of course. and included with several editions of Delphi XE3 and up.nexusdb. Due to our Agile process.g.see SynDB Architecture (page 167) . DBExpress would benefit to be integrated. 9. results for SQLite3 or Oracle).18 Page 178 of 1055 .Synopse mORMot Framework Software Architecture Design 1. This is the new official platform for high-speed database development in Delphi. using TDataset to retrieve the results.2. Up to now. which is a perfect match for a Client-Server ORM framework like mORMot . even if Embarcadero just acquired AnyDAC and revamped/renamed it as FireDAC .. FireDAC (formerly AnyDAC). 2013 interface any DB.5. or at least testing abilities. Some dedicated providers have been published in the SynDBDataset sub-folder of the mORMot source code repository.2.see http://www. Client/Server and Embedded database system. SQL:2003 core compliant. This was in fact a third-party component set. and provide wrappers. and a direct connection to the NexusDB engine is available. NexusDB access NexusDB is a "royalty-free.to make it the new official platform.5. Due to the TDataset design. if possible. SynDB DB.18 Date: June 16.php?q=FreeEmbedded.1.pas TDataset NexusDB SynDB and NexusDB We used and tested the free embedded edition.mORMot Framework . Since there are a lot of potential combinations here . but it also opens the potential database access.com/support/index. SAD . It is up to mORMot users to ask for additional features.2.Rev. 2.pas units and the mORMot persistence layer has been tuned.pas TDataset UniDAC OleDB Oracle MS SQL ODBC MySQL DB2 PostgreSQL Sybase Jet/Access Advantage Interbase Firebird NexusDB SQLite3 SynDB and UniDAC 9.5. and replaced by DBExpress since 2000.18 Page 179 of 1055 . See http://www.18 Date: June 16. 2013 SynDB DB.com/unidac. it is a working solution. you can have direct access to high-speed FireDAC Array DML feature.devart. SynDB DB. SAD . BDE engine Borland Database Engine (BDE) is the Windows-based core database engine and connectivity software shipped with earlier versions of Delphi.5.see below (page 216)..Synopse mORMot Framework Software Architecture Design 1.pas TDataset FireDAC AnyDAC ODBC Oracle MS SQL MySQL DB2 PostgreSQL SQLite3 Jet/Access Advantage Interbase Firebird Sybase SynDB and FireDAC / AnyDAC Our integration within SynDB. via the ORM batch process. For instance.4.2. 9.Rev. easy to interface as a SynDB provider. Even if it is deprecated.mORMot Framework . via so-called array binding . 1. UniDAC library Universal Data Access Components (UniDAC) is a cross-platform library of components that provides direct access to multiple databases from Delphi.3. but almost all other database engines expect a maximum length to be specified when defining a VARCHAR column in a table.mORMot Framework . In fact.''.3. fYearOfDeath: word.g. published property FirstName: RawUTF8 index 40 read fFirstName write fFirstName. As you can see.Create(':memory:'. If you do not specify any length in your field definition (i. the ORM will create a column with an unlimited length (e.18 Date: June 16. Transparent use An external record can be defined as such.''). property Data: TSQLRawBlob read fData write fData. SAD .Rev. but you may want it to inherit from TSQLRecordMany to use ORM implementation via pivot table (page 109) for instance. property YearOfBirth: integer read fYearOfBirth write fYearOfBirth. The only difference is this index 40 attribute in the definition of FirstName and LastName published properties: this will define the length (in WideChar) to be used when creating the external field for TEXT column. Here is an extract of the regression test corresponding to external databases: var RInt: TSQLRecordPeople. SQLite3 does not care about textual field length. property CreatedAt: TCreateTime read fCreatedAt write fCreatedAt. property LastChange: TModTime read fLastChange write fLastChange.18 Page 180 of 1055 . 1.pas TDataset BDE ODBC Oracle DB2 MySQL PostgreSQL Firebird Sybase Jet/Access Advantage MS SQL Interbase Paradox Informix SynDB and BDE 9. as expected by mORMot's ORM: type TSQLRecordPeopleExt = class(TSQLRecord) private fData: TSQLRawBlob. if there is no index ??? attribute). 2013 SynDB DB. fLastName: RawUTF8. ORM Integration 9. property YearOfDeath: word read fYearOfDeath write fYearOfDeath.3. (.. fFirstName: RawUTF8. code will work. there is no difference with an internal ORM class: it inherits from TSQLRecord. fCreatedAt: TCreateTime.) fConnection := TSQLDBSQLite3ConnectionProperties.Synopse mORMot Framework Software Architecture Design 1.e.1. RExt: TSQLRecordPeopleExt. fYearOfBirth: integer. end.''. varchar(max) for MS SQL Server in this case. property LastName: RawUTF8 index 40 read fLastName write fLastName. fLastChange: TModTime. but performance and disk usage may be degraded.. in short.Server. for i := 1 to aID do begin ok := fClient. there is no difference with using the local SQLite3 engine or a remote database engine.FillPrepare(fClient. you just call the usual RESTful methods. for i := 1 to aID do if i mod 100=0 then begin Check(fClient. end.RInt.TSQLRestServerDB).Retrieve(aID. i. The only specific instruction is the global VirtualTableExternalRegister function.) end.'deletion'). the ORM server must know SAD .'LastName']..RExt.. end. Check(fClient.RExt.FillOne do begin Check(RExt.Synopse mORMot Framework Software Architecture Design 1.'FirstName=? and LastName=?'. VirtualTableExternalRegister() shall be called before TSQLRestServer. fClient := TSQLRestClientDB..'Update 1/100 rows').) end. end. // query will use index -> fast :) while RExt. Check(RExt.Data. fClient.Data := RInt. 1.LastChange>=Now). Check(fClient. Check(ok=(i and 127<>0). end else begin Check(RExt.g.18 Date: June 16.) aID := fClient.mORMot Framework . a TEXT for SQLite3 will be a NVARCHAR2 field for Oracle).FillOne do begin RExt.false))..TSQLRecordPeopleExt. since for the client there is no difference between any tables . Even the creation of the table in the remote database (the 'CREATE TABLE. RExt.'Not Updated')...FirstName=RInt.e.i).fConnection.Retrieve(i. and you can even handle advanced methods like a FillPrepare with a complex WHERE clause.FillOne do begin RExt.) while RInt.Server. with the appropriate column properties according to the database expectations (e. Add / Retrieve / Update / UnLock / Delete. 2013 VirtualTableExternalRegister(fModel. if i mod 100=0 then begin Check(RExt.UnLock(RExt)). Check(RExt.YearOfDeath.YearOfBirth=RExt.YearOfBirth := RExt.Rev. (.['FirstName'.CreateMissingTables.Delete(TSQLRecordPeopleExt.true).CreateSQLMultiIndex( TSQLRecordPeopleExt.Create(fModel.. fClient. (. (. Check(fClient.db3'. From the Client point of view.nil.'test..' SQL statement) is performed by the framework. while RInt.Update(RExt). Now := fClient. Check(RInt. As you can see.FirstName). the server does).Server.true). [RInt.CreatedAt<=Now).LastName]).false).) Check(fClient. which has to be run on the server side (it does not make any sense to run it on the client side.'PeopleExternal').'Delete 1/128 rows').YearOfDeath.RExt)).YearOfDeath.Add(RExt.'Updated').'for update').FirstName..StaticVirtualTableDirect := StaticVirtualTableDirect. if ok then begin Check(RExt. end.Create constructor: when the server initializes..18 Page 181 of 1055 . the client do not care about storage. or CreateSQLMultiIndex / CreateMissingTables on the server side.FillRewind).YearOfBirth<>RExt. end.Retrieve(i.ServerTimeStamp.. for i := 1 to aID do if i and 127=0 then Check(fClient. (..LastChange<=Now). In order to work as expected. (. LastChange>=Now and RExt. the LastChange field was defined as a TModTime: in fact.g. const aExternalTableName: RawUTF8). aClass: TSQLRecordClass. it will behave as such: i.Update calls. a select getdate() under MS SQL to synchronize the date to be inserted for LastChange). Even if this class does not inherit from TSQLRecordVirtualTableAutoID. 1.It will associate the supplied class with a TSQLVirtualTableExternal module. we use Now := fClient. and released globally when the ORM is no longer needed. Oracle).e. In fact.ServerTimeStamp instead of the local Iso8601Now function. introduced in revision 1. in the case of external databases.3. the time of the remote server (it will execute e.15.LastChange<=Now checks in the latest loop.CreatedAt<=Now check in the above code. aExternalDB: TSQLDBConnectionProperties. its TSQLModelRecordProperties.The full table name.e. the new TSQLRestServerStaticExternal.Rev. A similar feature is tested for the CreatedAt published field.2. This procedure will register on the Server-side an external database for an ORM class: .18 Date: June 16. Behind the scene The mORMotDB.Kind property will be ovewritten to rCustomAutoID in this ORM model).e. which was defined as TCreateTime: it will be set automatically to the current server time at record creation (and not changed on modifications). implements Virtual Tables access for any SynDB-based external database for the framework. as expected by the external database. . This is tested by both RExt.18 Page 182 of 1055 .pas unit. This is the purpose of the RExt. the ORM records can inherit from any TSQLRecord class. The time used is the "server-time".g.The TSQLDBConnectionProperties instance should be shared by all classes. it will therefore have an Integer RowID published property. the current time and date on the server (not on the client). i.mORMot Framework . for each fClient.e. i. 9. .It will define the supplied class to behave like a TSQLRecordVirtualTableAutoID class (i. TSQLVirtualTableCursorExternal and TSQLVirtualTableExternal classes will implement this feature: TSQLRecordVirtualTableAutoID TSQLVirtualTableCursorExternal TSQLVirtualTableExternal TSQLRecordVirtual TSQLVirtualTableCursor TSQLVirtualTable TSQLRecord External Databases classes hierarchy In order to be stored in an external database. Note that in the above code. should be provided here (SQLTableName SAD . and. In order to retrieve this server-side time stamp. since not all databases handle such fields .Add or fClient. the current date and time will be stored each time the record is updated. The registration of the class is done by a call to the following new global procedure: procedure VirtualTableExternalRegister(aModel: TSQLModel.Synopse mORMot Framework Software Architecture Design 1. 2013 whenever an internal or external database shall be managed. .e. auto-incremented at every record insertion (auto-increment will be handled via a select max(rowid) from tablename. TSQLVirtualTableCursorExternal will convert any query on the external table into a proper optimized SQL query.g. aModel := TSQLModel. as stated by Object-Relational Mapping (page 88). or via external databases. As stated by Data access benchmark (page 135). The framework will do all the low-level DB work for you.e.External via virtual table: 198.mORMot Framework . Most of the time.767 assertions passed 1. Depending on the implementation needs.'application. using a virtual or direct call won't affect the CRUD operation speed: it will by-pass the virtual engine whenever possible. 1. internal and external tables can be mixed within SQL statements.aProps.Internal adjustments will be made to convert SQL on the fly from internal ORM representation into the expected external SQL format (e.i. AdaptSQLForEngineList method. the overhead of remote connection won't make noticeable the use of Virtual Tables. but the virtual table will always be ready to interpret any cross-database complex request or statement. SAD .Create('.Rev.see TSQLRestServerStatic. StaticVirtualTableDirect set to TRUE (which is the default) .'root'). which shows the difference between RESTful call and virtual table call. table name or ID property) .\SQLEXPRESS'.41s The first run is made with TSQLRestServer. in previous paragraph).true) All the rest of the code will use the "regular" ORM classes.'AdventureWorks2008R2'. and the second will set this property to FALSE . classes could be persistent either via the internal SQLite3 engine. it will call the SQLite3 engine and let its virtual table mechanism convert it into another SQL calls. methods and functions. And thanks to the Virtual Table feature of SQlite3.g.Customer'). 2013 will be used internally as table name when called via the associated SQLite3 Virtual Table) .TSQLCustomer. In practice.External via REST: 198. Typical usage may be for instance: aProps := TOleDBMSSQLConnectionProperties. and won't use the virtual table mechanism.if no table name is specified ('').767 assertions passed 3.i. In all cases. most access to the external database will be as fast as direct access.db'). not the external database speed.18 Page 183 of 1055 .39s . Here is an extract of the test regression log file (see code above. With real file-based or remote databases (like MS SQL).Synopse mORMot Framework Software Architecture Design 1. You do not have to know where and how the data persistence is stored. according to the indexes existing on the external database. VirtualTableExternalRegister(aModel.18 Date: June 16.'Sales. will use SQLTableName (e. 'Customer' for a class named TSQLCustomer). letting the default StaticVirtualTableDirect=true will ensure the best possible performance. TSQLVirtualTableExternal will also convert individual SQL modification statements (like insert / update / delete) at the SQLite3 level into remote SQL statements to the external database. so what we test here is mostly the communication overhead. It is worth saying that this test is using an in-memory SQLite3 database as its external DB. aServer := TSQLRestServerDB.''.'').Create(aModel. . working with more than 11. In fact. just via a call to VirtualTableExternalRegister() before server initialization. it will call directly TSQLRestServerStaticExternal for RESTful commands.Create([TSQLCustomer].000 rows of data: .e. all RESTful methods (GET/POST/PUT/DELETE) will be handled directly by the TSQLRestServerStaticExternal class. 1. By definition. . JSON RESTful Client-Server Adopt a mORMot Before describing the Client-Server design of this framework.Synopse mORMot Framework Software Architecture Design 1. Web 2. Why use JSON? As we just stated.Like XML.0) application.18 Date: June 16. quicker to implement. .It's natively supported by the JavaScript language. . . and much smaller in size than XML for most use. with no memory allocation nor data copy. SAD . instead of other like XML or any proprietary format. the JSON format is used internally in this framework. we may have to detail some standards it is based on: .It's easier to read (for both human beings and machines). human-readable format for representing simple data structures and associative arrays (called objects). . results in several particularities: .18 Page 184 of 1055 . 2013 10. with almost no wasted space: this feature is used for very fast JSON to text conversion of the tables results. the JavaScript Object Notation (JSON) is a standard. it is a text-based.mORMot Framework .Its layout allows to be rewritten in place into individual zero-terminated UTF-8 strings.1.JSON as its internal data storage and transmission format. 10. JSON 10. 1.Rev. Usage of this layout.1.e. making it a perfect serialization format in any AJAX (i.It's a very efficient format for data caching.REST as its Client-Server architecture. open and lightweight computer data interchange format. the associated record will also use the same Reader and Writer callbacks.1. In practice.Synopse mORMot Framework Software Architecture Design 1.see below (page 189).For binary BLOB transmission.NET framework 3. For instance. and double values are stored as their corresponding floating-point representation. JSON: RawUTF8. 10.By setting explicitly serialization callbacks for the TypeInfo() of the record. via RecordLoad and RecordSave functions .Rev. JSON has been found out to be very easy to work with and stable. BLOB fields are not transmitted with other fields in JSON objects. nested with double quotes ( "). . there are two ways of specifying a custom JSON serialization for record: . by default.NET AJAX services created in Windows Communication Foundation (WCF) since .e.see below (page 186) . which are transmittest within the other fields). You will find in SynCommons unit both BinToBase64 and Base64ToBin functions.When setting a custom dynamic array JSON serializer . With the following code: TTextWriter. and specified in a short and clean RFC document. Since JSON uses UTF-8 encoding. we simply encode the binary data as Base64.e. . it is one of the reasons why we introduced the RawUTF8 type. . end.then encoded as Base64. A binary format is not used for transmission yet. very optimized for speed.18 Page 185 of 1055 .i.18 Date: June 16.The default text encoding for both JSON and SQLite3 is UTF-8. . SAD . much more efficient than hexadecimal. and still JSON compatible without the need to escape its content. so it's Microsoft officially "ready".1. TimeStamp: cardinal. In fact. in their textual representation. 10.3. and in the interface-based SOA architecture of the framework. but is available at other level of the framework. integer or Int64 are stored as numbers.The JSON format is simple. see below (page 192) (only exception are dynamic array fields. any record value will be serialized with a proprietary binary (and optimized) layout . 2013 . Record serialization By default.g. All string content is serialized as standard JSON text field.CustomReader. for content transmission. But custom record JSON can be defined. as an possible file format for in-memory TObjectList database engine (with our SynLZ compression .It is the default data format used by ASP. 1. For instance. which allows the full Unicode char-set to be stored and communicated. and use it everywhere in our framework.2.5. JSON serialization will indeed be used in our main ORM to process of any TSQLRecord published properties. to be stored as plain text within the JSON stream.mORMot Framework . you can serialize the following record definition: TSQLRestCacheEntryValue = record ID: integer.RegisterCustomJSONSerializer(TypeInfo(TSQLRestCacheEntryValue). as with any class . Values serialization Standard Delphi value types are serialized directly within the JSON content. TTestServiceOrientedArchitecture. i. with the very same TTextWriter. Base64 encoding was chosen since it is standard. please note that. e. RegisterCustomJSONSerializer method used for dynamic arrays.see Virtual Tables magic (page 155)). But applications can also supply a custom JSON serialization for any other dynamic array.TimeStamp). if result=nil then aValid := false else begin V.['ID'.see Dynamic array wrapper (page 74) . SynUnicode. This method will always work.JSON]). out aValid: Boolean): PUTF8Char. WinAnsiString. as stated by the documentation of the AddJSONEscape method. this TDynArray wrapper . integer. begin result := JSONDecode(P.TimeStamp := GetCardinal(Values[1]).CustomReader(P: PUTF8Char. In fact. or. and not a wrongly negative versions for numbers > $7fffffff.mORMot Framework .Within the scope of interface-based services. V. The expected format will be as such: {"ID":1786554763. i. string. end. 10. they are stored as BLOB and always transmitted after Base64 encoding . floating-point value or string).4. dynamic arrays values and parameters are using the advanced JSON serialization made available in the TDynArray wrapper. word.exe"} Therefore. an array of const will handle by default any cardinal as an integer value (this is a limitation of the Delphi compiler). the cardinal field named TimeStamp is type-casted to a Int64: in fact. in default. begin aWriter.JSON := Values[2]. end. like array of byte. but won't be easy to deal with from an AJAX client.ID. could be either a true JSON array. via the SAD .1."TimeStamp":323618765. var aValue. end.'TimeStamp'. cardinal.Int64(V.18 Date: June 16. V. feel free to post your proposal in the forum! Other not-known dynamic arrays (like any array of packed record) will be serialized by default as binary. use generic binary and Base64 encoding.'JSON'.see TSQLRecord fields definition (page 89). then Base64 encoded. 1. By forcing the type to be an Int64. In the above code.Within the ORM part of the framework.Rev.18 Page 186 of 1055 . currency. Dynamic array serialization Note that dynamic arrays are handled in two separated contexts: ."JSON":"D:\TestSQL3. aValid := true. They will be serialized as a valid JSON array. . var V: TSQLRestCacheEntryValue absolute aValue. Int64. const aValue).recognizes most common kind of dynamic arrays.ID := GetInteger(Values[0]).Synopse mORMot Framework Software Architecture Design 1. double.V.e. If you have any ideas of standard dynamic arrays which should be handled.CustomWriter( const aWriter: TTextWriter.e.'TimeStamp'.Values). the corresponding reader callback would be like: class function TTestServiceOrientedArchitecture. RawUTF8.'JSON']. var V: TSQLRestCacheEntryValue absolute aValue. On the other side. i.CustomWriter). Values: TPUtf8CharDynArray.AddJSONEscape(['ID'.V. the expected cardinal value will be transmitted. a list of valid JSON elements of the matching type (number. the writer callback could be: class procedure TTestServiceOrientedArchitecture. 2013 TTestServiceOrientedArchitecture. V. aValid := true. Detailed: string.4001.Main := UTF8ToString(GetJSONField(P.%. Of course. [V.18 Date: June 16."2".Major.V.4002..18 Page 187 of 1055 . Main.Add('[%. 2013 TTextWriter.4001. just like Record serialization (page 185).Synopse mORMot Framework Software Architecture Design 1. if P=nil then exit.Rev. var aValue.3002.2002.. V. SAD ."1002"]. Minor.V. using JSONEncode() function and a JSON object layout.' or ']' for last item of array end.Minor := GetNextItemCardinal(P). end. result := P. In order to add a custom serialization for this kind of record.Main. or any other valid JSON content. V. For instance. const aValue).%. V.FVWriter(const aWriter: TTextWriter. e.g. Release. var V: TFV absolute aValue."1001"] We may have used another layout.Release := GetNextItemCardinal(P). Build: integer. twJSONEscape is used to escape the supplied string content as a valid JSON string (with double quotes and proper UTF-8 encoding).Release. if (P=nil) or (P^<>'[') then exit.twJSONEscape).V. if you register a dynamic array custom serializer. result := nil. end.2001.Detailed := UTF8ToString(GetJSONField(P."1".' (which will be appended by TTextWriter. Two callbacks are to be defined in association with dynamic array type information."%". in order to handle proper serialization and un-serialization of the JSON array. The reader method shall return a pointer to the next separator of the JSON input buffer just after this item (either '. without the last '. In fact.Build.Build := GetNextItemCardinal(P).e. we need to implement the two needed callbacks. such a dynamic array will be serialized as a Base64 encoded binary buffer.' aValid := false.V. we would like to serialize a dynamic array of the following record: TFV = packed record Major.2001.' or ']'). for instance.mORMot Framework . // '. RegisterCustomJSONSerializer() class method.%.3001."%"]'. Our expected format will be a JSON array of all fields.3001. begin aWriter. This event will write one entry of the dynamic array.Major := GetNextItemCardinal(P)..FVReader(P: PUTF8Char. This won't be easy to understand from an AJAX client. TFVs = array of TFV. With the default serialization."1001"]. out aValid: Boolean): PUTF8Char. Here comes the writer: class procedure TCollTstDynArray. inc(P).V. 1. i.Detailed]. In this method.P))."1". var V: TFV absolute aValue.Minor.[2.: [1. V. it will also be used for the associated internal record. the Writer is easier to code than the Reader itself: class function TCollTstDynArray. begin // '[1. AddDynArrayJSON).P)). V. nil). V.Release := GetInteger(Values[2]).'Release'. V.Build := GetInteger(Values[3]).'Minor'.' or ']' for last item of array V. V. the JSON serializers are used everywhere in the framework. if it contains some reference-counted types.'Minor'. If you want to go back to the default binary + Base64 encoding serialization. 'Build'. containing all their published properties values.V.Major.StrLen(Values[5])). You can define now your custom JSON serializers. end. out aValid: Boolean): PUTF8Char.5. Values: TPUtf8CharDynArray.1. var aValue. var V: TFV absolute aValue."Main":"1". 1. begin aWriter. TSQLRecord TPersistent TStrings TRawUTF8List Classes with published properties. 2013 The registration process itself is as simple as: TTextWriter. See TSQLRecord fields definition (page 89) for a corresponding table with the ORM database types and the JSON content.nil.Main := UTF8DecodeToString(Values[4]. var V: TFV absolute aValue. aValid := true."Release":3001. as soon as this type is globally registered. i. just as stated with Record serialization (page 185). SAD . it will be serialized as JSON during the mORMot Service process.V. 10.'Main'. V."Detailed":"1001"} Then the corresponding Reader callback could be written as: class function TCollTstDynArray.V.Rev.'Build'.Synopse mORMot Framework Software Architecture Design 1.V.'Detailed'].Release.18 Page 188 of 1055 .['Major'. such process will do only one memory allocation (for Values[]).V.Build. begin aValid := false.Detailed := UTF8DecodeToString(Values[5].FVWriter).StrLen(Values[4])). // result^ = '. Note that if the record corresponding to its item dynamic array has some associated RTTI (i."Minor":2001. In fact.Major := GetInteger(Values[0]). starting for the above code as reference.FVReader2(P: PUTF8Char.V. this dynamic array handling won't change: once registered. TCollTstDynArray. which will let Values[] point to null-terminated un-escaped content within the P^ buffer. end.TCollTstDynArray.FVWriter2(const aWriter: TTextWriter. you may run the registering method as such: TTextWriter. V. Most of the JSON decoding process is performed within the JSONDecode() function.AddJSONEscape(['Major'.mORMot Framework .'Main'.'Detailed'.'Release'. and will therefore be very fast.FVReader.Main."Build":4001. from the user code point of view.RegisterCustomJSONSerializer(TypeInfo(TFVs). every class inheriting from TPersistent or our ORM-dedicated TSQLRecord class will be serialized as a true JSON object. like any string).RegisterCustomJSONSerializer(TypeInfo(TFVs).Minor := GetInteger(Values[1]).e. result := JSONDecode(P. Then.Detailed]).Minor. Here is a Writer method using a JSON object layout: class procedure TCollTstDynArray.Values).e. This will create some JSON content as such: {"Major":1.18 Date: June 16. const aValue). if result=nil then exit. . JSON array or JSON number. In the current implementation of this feature.2. In some cases. aSerializer.e. By default. any TObject can be serialized as JSON in the whole framework: not only for the ORM part (for published properties). All JSON serialization is centralized in ObjectToJSON() and JSONToObject() (aka TJSONSerializer.."BuildDateTime":"1911-03-14T00:00:00"} This is what is expected when serialized within a TSynLog content . i. {$M-} conditionals. RegisterCustomSerializer class method..Rev.e.6. since it has been defined within {$M+} ..mORMot Framework . reducing the need of encoding conversion. it may be handy to have a custom serialization. SAD . the default JSON serialization will be for instance: {"Detailed":"1. or to adapt the serialization scheme to a particular purpose. property BuildDateTime: TDateTime read fBuildDateTime write fBuildDateTime.18 Page 189 of 1055 . by calling the TJSONSerializer. calling low-level GetJSONField() function to decode the JSON content.e. fBuildDateTime: TDateTime. allowing any serialization scheme: even a class content can be serialized as a JSON string. end.WriteObject) functions.3. BuildYear: integer. The callbacks are class methods (procedure() of object). That is. via our dedicated RawUTF8 type. Note that the process is called outside the "{. callbacks expect low-level implementation. and follow function TJSONSerializer. and will be used to serialize or un-serialize the object instance. This is the reason why we also introduced a dedicated TRawUTF8List class. TStrings kind of classes will be serialized as a JSON array of strings. 1. their implementation code shall follow function JSONToObject() patterns. 10. Minor: Integer. You can add a customized serialization of any class.Add/AddInstanceName/AddJSONEscapeString to encode the class instance as JSON. i. RTTI is available for the published properties (just as if it were inheriting from TPersistent). Release: Integer. it may have sense to use a context during serialization). therefore increasing process speed. For instance. for instance if you want to manage some third-party classes. but also for SOA (as parameters of interface-based service methods). we'd like to customize the serialization of this class (defined in SynCommons. 2013 List of delphi strings. Main: string. TObject serialization In fact.pas): TFileVersion = class protected fDetailed: string.1. at runtime. Two callbacks are to be defined for a specific class type. and not plain functions (for some evolved objects. Build: Integer. for direct UTF-8 content storage.4".WriteObject() patterns.18 Date: June 16. published property Detailed: string read fDetailed write fDetailed. That is.Synopse mORMot Framework Software Architecture Design 1. public Major: Integer.}" JSON object layout.see Enhanced logging (page 78) or for current AJAX use. on request. i. Minor := GetInteger(Values[1]).V.FVClassWriter(const aSerializer: TJSONSerializer. TObjectList serialization You can even serialize TObjectList instances.Release.18 after a proper call to Page 190 of 1055 .['Major'.FVClassWriter).Values). result := aFrom.e. 2013 We would like to serialize this class as such: {"Major":1. It will depend of the implementation of the Reader and Writer registered callbacks. aValid := true. Most of the JSON serialization work will be made within the AddJSONEscape method. begin aSerializer. end. So decoding is very fast. That is.StrLen(Values[4]))."Release":3001. V. V. var V: TFileVersion absolute aValue.7. Then. TCollTstDynArray. writing of published properties).'Release'.FVClassReader.V.BuildDateTime := Iso8601ToDateTimePUTF8Char(Values[5]). V. as such: class procedure TCollTstDynArray. aFrom := JSONDecode(aFrom."Build":4001. AddJSONEscape and JSONDecode) to implement serialization as a JSON object.BuildDateTime)]).'Main'. 'Build'.nil.'BuildDateTime'. var V: TFileVersion absolute aValue. V.V.'Release'. The above code uses some low-level functions of the framework (i.Rev. on need. aFrom: PUTF8Char.Main := UTF8DecodeToString(Values[4].Build.'Build'. Here. the JSONDecode function will un-serialize the JSON object into an array of PUTF8Char values. you may serialize the whole class instance just as one JSON string or numerical value.TCollTstDynArray. if aFrom=nil then exit. V. but you may use any other serialization scheme. or even a JSON array.RegisterCustomSerializer(TFileVersion. If you want to disable the custom serialization.e.'Minor'. Then the associated Reader callback could be.Major.Main."BuildDateTime":"1911-03-14"} We will therefore define the Writer callback. expecting the JSON object description as an array of name/value pairs. This will reset the JSON serialization of the specified class to the default serializer (i. 10.'BuildDateTime']. you may call the same method as such: TJSONSerializer. begin aValid := false. without any memory allocation (in fact.mORMot Framework .'Main'. aValue: TObject.Release := GetInteger(Values[2]).Major := GetInteger(Values[0]).RegisterCustomSerializer(TFileVersion. var aValid: Boolean): PUTF8Char.V.Build := GetInteger(Values[3]). for instance: class function TCollTstDynArray. SAD . Values[] will point to un-escaped and #0 terminated content within the aFrom memory buffer.DateTimeToIso8601Text(V.V. V."Main":"1".'Minor'. the registration step will be defined as such: TJSONSerializer. aOptions: TTextWriterWriteObjectOptions). end. Values: TPUtf8CharDynArray.AddJSONEscape(['Major'.FVClassReader(const aValue: TObject.18 Date: June 16.Minor. 1.Synopse mORMot Framework Software Architecture Design 1.nil).1."Minor":2001. // do not forget to free the memory (Comp can be nill if JSON was not valid) Comp. The Synopse mORMot Framework was designed in accordance with Fielding's REST architectural style without using HTTP and without interacting with the World Wide Web.18 Page 191 of 1055 .RegisterClass list is also checked) TJSONSerializer. REST 10.Real. P := @J[1].ClassType=TComplexNumber).92 }'. RESTful implementation Representational state transfer (REST) is a style of software architecture for distributed hypermedia systems such as the World Wide Web.GET to list the members of the collection.18 Date: June 16.2.RegisterClassForJSON([TComplexNumber]). . // create an instance by reading the textual class name field J := '{"ClassName":"TComplexNumber". on which the whole Internet rely. 2013 TJSONSerializer. .2.by JSONToObject() for TObjectList members. Internal TObjectList process will therefore rely on a similar process.1 pages over the Internet (by using the mORMotHttpClient / mORMotHttpServer units and the TSQLHttpServer and TSQLHttpClient classes).3). This new "ClassName" field will be recognized: .RegisterClassForJSON() method. this kind of code can now work: // register the type (but Classes.WriteObject() have their woStoreClassName option defined. // make local copy of constant Comp := TComplexNumber(JSONToNewObject(P. // here Comp is a valid unserialized object :) Check(Valid).RegisterClassForJSON(): you do not have to register them.Rev.and by the new JSONToNewObject() method.Free. creating the proper class instances on the fly. You can even have several classes appearing in one TObjectList: the only prerequisite is that all class types shall have been previously registered on both sides. SAD . 1. and can directly serialize TObjectList of TSQLRecords. In fact.10. . Optionally.Synopse mORMot Framework Software Architecture Design 1.Valid)). As such. RegisterClassForJSON(). CheckSame(Comp.POST to create a new entry in the collection. 10.3. Check(Comp. As a consequence. Such Systems which follow REST principles are often referred to as "RESTful". The standard RESTful methods are implemented: .PUT to update a member of the collection. CheckSame(Comp. The terms "representational state transfer" and "REST" were introduced in 2000 in the doctoral dissertation of Roy Fielding.1. "Imaginary": 7. it is not just a method for building "web services". "Real": 10.92). one of the principal authors of the Hypertext Transfer Protocol (HTTP) specification. the Framework is able to serve standard HTTP/1. a new "ClassName": field will be written as first field of the serialized JSON object.mORMot Framework . Note that all TSQLRecord classes of a model are automatically registered via a call to TJSONSerializer. if ObjectToJSON() or TJSONWriter. by a call to TJSONSerializer.7. in an embedded low resource and fast HTTP server.Imaginary. Rev. .pas for Delphi up to 2007. The GET method has an optional pagination feature. .URI method and http://developer. therefore need twice the normal size of it. From the Delphi code point of view.2.. Some dedicated methods of the generic TSQLRest class handle BLOB fields: RetrieveBlob and UpdateBlob. . REST and JSON The "04 . for locking individual records and for handling database transactions (which speed up database process): . to spare network bandwidth.END to commit a transaction.3.2.18 Page 192 of 1055 . 2013 .BEGIN to initiate a transaction.Synopse mORMot Framework Software Architecture Design 1. 10.com/yui/datatable/#data. which works well but convert BLOB to/from hexadecimal values. 1. compatible with the YUI DataSource Request Syntax for data pagination see TSQLRestServer. The RESTful protocol allows BLOB to be retrieved (GET) or saved (PUT) via a specific URL. data can be transfered as full binary. But their content is not included in standard RESTful methods of the framework. . REST and BLOB fields BLOB fields are defined as TSQLRawBlob published properties in the classes definition . SAD . TSQLRestClientURI TSQLRestServer TSQLRestClient TSQLRest TSQLRestClient classes hierarchy This diagram states how the TSQLRest class implements a common ancestor for both Client and Server classes.UNLOCK to unlock a member of the collection.18 Date: June 16.2. By using such dedicated URL. . like "ModelRoot/TableName/ID/BlobFieldName". and can be proudly compared to any other REST server (like CouchDB) also based on JSON.mORMot Framework .HTTP Client-Server" sample application available in the framework source code tree can be used to show how the framework is AJAX-ready.yahoo. 10.which is an alias to the RawByteString type (defined in SynCommons.LOCK to lock a member of the collection. a RESTful Client-Server architecture is implemented by inheriting some common methods and properties from a main class.DELETE to delete a member of the collection. This is even better than the standard JSON encoding.ABORT to rollback a transaction. since it appeared only with Delphi 2009). The following methods were added to the standard REST definition. and the database will reply to your request. e. if you want.Form1. {"ID":1.Rev. and add/find any entry. This is not necessary in a stateless architecture any more.Close the Project04Client.dpr: Form1."Question":"To be or not to be"} .Type into the address bar any other REST command. Note that Internet Explorer or old versions of FireFox do not recognize the application/json.{"ID":4}] .4. this may concern you: you should have the habit of writing some synchronization code from the server to replicate all changes to all its clients.18 Page 193 of 1055 .Run. You have got a full HTTP/SQLite3 RESTful JSON server in less than 400 KB. 10. . . to populate the database a little. A stateless server is a server that treats each request as an independent transaction that is unrelated to any previous request.You'll see the result of all SampleRecord IDs.18 Date: June 16.'8080'.1 protocol it could use as its communication layer.{"ID":2}. you are never sure that your Client data is up-to-date.db3').Start any Project04Client. you could find it a bit disappointing from a classic Client-Server approach. In the web world.Model).pas: DB := TSQLRestServerDB.Database := TSQLHttpClient. 1. [{"ID":1}.Synopse mORMot Framework Software Architecture Design 1. // TSQLHttpClient(Form1.You'll see the content of the SampleRecord of ID=1.mORMot Framework .You'll see an error message: TSQLHttpServer Server Error 400 .{"ID":3}. 2013 First desactivate the authentication . In a stateless world. Then you can use your browser to test the JSON content: . REST is Stateless Our framework is implementing REST as a stateless protocol. just as the HTTP/1.'.Open your browser.json files. and by commenting the following line in Project04Client. false).SetUser('User'.see below (page 293) . But if you are coming from a rich Client background.. encoded as a JSON list.exe program: the background HTTP server. but won't prevent AJAX requests to work as expected. encoded as JSON.. This is a limitation of those softwares.Start the Project04Server. it's not confusing.2.Create(Model.Database).by changing the parameter from true to false in Unit2. together with its SQLite3 database engine. charset=UTF-8 content type to be viewed internally. The only place where the data is safe is the server."Name":"AB".Create(Server. Application. SAD .Type into the address bar: http://localhost:8080/root/SampleRecord/1 ."Time":"2010-02-08T11:07:09".exe programs. so above requests will download the content as . At first.g.'synopse').g. .exe instances.ChangeFileExt(paramstr(0).Type into the address bar: http://localhost:8080/root/SampleRecord . and type into the address bar: http://localhost:8080/root . e. which proposed to put whole URI in the JSON content. which reflects exactly the layout of the SQL request: first line/row are the field names.18 Date: June 16."ValFloat ":3.1. which can be produced according to the TSQLRestServer."values":["ID".org/coll you will be able to append this URI at the beginning of every future request."Unicode":"abcde+¬ef+á+¬".6."Ansi":"abcde+¬ef+á+¬"."Test":"abcde+¬ef+á+¬". "http://example. the Synopse mORMot Framework always returns the JSON content just as a pure response of a SQL query. since it does not replicate field names: {"fieldCount":1. "http://example.{"ID":3}.{."Int":0. then all next lines. with an array and field names.5."Ansi". and that the Client is able to retrieve any pending update from the Server side..3.2. but always pass through the Server.18 Page 194 of 1055 .3.NoAJAXJSON property: 1."Test".1. but must be made in a separated autonomous table/database."Int". always modify a record content on a server side.org/news/restful_json. Client-side modification could be performed.3."ValFloat". Do not modify the client side directly. 2013 The main rule of this architecture is to ensure that the Server is the only reference. This will avoid any synchronization problem in case of concurrent client modification.Rev.{"ID":4}] Depending on a setting."Unicode"."ValDate".org/coll/1". ] The REST implementation of the framework will return most concise JSON content. 10.{"ID":2}. .3."values":["ID"."abcde+¬ef+á+¬"."2009-03-10T21:19 :36". REST and JSON 10.3. then refresh the client to retrieve the modified value. which can be shorter.."abcde+¬ef+á+¬".2."ValWord".mORMot Framework .org/coll/N".4. "http://example.org/coll/2". mORMot servers may in fact returns this alternative (see below non expanded format)."abcde+¬ef+á+¬". 1."ValDate":"2009-03-10T21:19:36". the "expanded" or standard/AJAX layout. the "not expanded" layout.}] 2. JSON (not) expanded layouts Note that our JSON content has two layouts. because the field name / JavaScript object property name is supplied for every value: [{"ID":0."Next":0}."Next" .]} SAD . The UI components of the framework follow these principles. doesn't it make sense? In all cases.Synopse mORMot Framework Software Architecture Design 1...14159265300000E+0000. 10. which allows you to create pure JavaScript objects from the JSON content.14159265300000E+0000.org/coll/3". [ "http://example.0.row are the field content: {"fieldCount":9."ValWord":1203. JSON format density Most common RESTful JSON used a verbose format for the JSON content: see for example http://bitworking.1203.7]} which preserves bandwidth and human readability: if you were able to send a GET request to the URI http://example.. containing an array of objects: [{"ID":1}.0..0. That is. which pollutes the URI. 1. even if its implementation is some kind of "naive". whatever the corresponding table is.18 Date: June 16."values":["ID". aHandleUserAuthentication: boolean)..since our caching is at the SQL level.6. the NoAJAXJSON property is set to true when the TSQLRestServer.g.1.Rev. In fact. In order to speed-up the server response time. 2013 By default.LockJSON() calls in most TSQLRestServerDB methods. the internal database engine is not to be called on every request.4. aDB: TSQLDataBase. This cache will be reset on every INSERT. and is also indenpendent from the authentication scheme. the following JSON content: [{"ID":1}. Associated with the other levels of cache . and will use JSON for its result encoding.3.Create(aModel: TSQLModel.{"ID":7}] will be transfered as shorter: {"fieldCount":1.{"ID":6}.{"ID":5}.5. a Squid proxy) .see ORM Cache (page 114) . directly in JSON. In practice. this global cache was found to be efficient. it is shared among all CRUD / Restful queries. UPDATE or DELETE SQL statement. you probably won't use JavaScript because all browser communicate via HTTP! But otherwise.3. A TSynCache instance is instantiated within the TSQLDataBase internal global instance. JSON global cache A global cache is used to enhance the framework scaling. via DB. a global cache has been introduced to store in memory the latest SQL SELECT statements results.. // we better use caching in this JSON oriented use (. In this "not expanded" layout.2.Init(aDB. It is in fact much more tuned than other HTTP-level caching mechanisms used in most client-server solutions (using e.UseCache := true.mORMot Framework . begin fStatementCache. aDB.) This will enable a global JSON cache at the SQL level. with the following line: constructor TSQLRestServerDB. SAD . NoAJAXJSON property is set to false.Synopse mORMot Framework Software Architecture Design 1.{"ID":3}.DB).{"ID":4}. especially in a concurrent client access.18 Page 195 of 1055 . ExportServerNamedPipe is called: if you use named pipes for communication.{"ID":2}. The SQLite3 engine access is protected at SQL/JSON cache level. You could force its value to true and you will save some bandwidth if JavaScript is never executed: even the parsing of the JSON Content will be faster with Delphi if JSON content is not expanded.the framework scaling was found to be very good.3.7]} 10. In-process GDI messages Named pipes HTTP Unit mORMot.Rev. .mORMot Framework .pas mORMot.1 over TCP/IP. The framework allow you to create either a TSQLHttpClient. via several communication layers: . which can be used locally between a Server running as a Windows service and some Client instances. TSQLRestClientURIDll. Client-Server process Adopt a mORMot The mORMot framework can be used either stand-alone. for instance).GDI messages. 2013 11.\pipe\mORMot_ Standard Data JSON JSON JSON JSON SAD . or in a Client-Server model. See General mORMot architecture .18 Date: June 16. which is very fast.pas mORMotHttp Server/Client Speed **** *** ** * Hosting In-process Local Local Remote Protocol Method call WM_COPYDATA \\.Synopse mORMot Framework Software Architecture Design 1.Named pipes.HTTP/1. 1.pas mORMot.Client / Server (page 50) about this Client-Server architecture. . only locally on the same computer. for remote access. .Fast in-process access (an executable file using a common library.18 Page 196 of 1055 . TSQLRestClientURINamedPipe or TSQLRestClientURIMessage instance to access to your data according to the communication protocol used for the server. for either stand-alone.e. implementing the RESTful pattern . 1. You should instantiate the classes corresponding to the needed transmission protocol. You may expose the same server over HTTP and over named pipes. 11.1. depending on your customer's expectations. you should better create a new class.18 Page 197 of 1055 . It will then help changing from one protocol or configuration at runtime. but should better rely on abstraction. It will host a SQLite3 SAD . depending on your speed requirements. or a Client (via TSQLRestClientURI classes) access to the data. at the same time. implement your whole code logic relying on abstract TSQLRestClient / TSQLRestServer classes.Rev. i.see below (page 229).see REST (page 191) . 2013 Run as service Stand alone No Yes Yes Note that you can have several protocols exposing the same TSQLRestServer instance. The TSQLRestServerDB class is the main kingn of Server of the framework. Having your own inherited class does make sense. TSQLRest classes This architecture is implemented by a hierarchy of classes. 11. as two main branches: TSQLRestServer TSQLRestClient TSQLRest RESTful Client-Server classes All ORM operations (aka CRUD process) are available from the abstract TSQLRest class definition. in order to implement the business logic.mORMot Framework . all inheriting from a TSQLRest common ancestor.1.18 Date: June 16. which is overridden to implement either a Server (via TSQLRestServer classes). inheriting from one of the above TSQLRestServer classes.1.Synopse mORMot Framework Software Architecture Design 1. Server classes The following classes are available to implement a Server instance: TSQLRestServerDB TSQLRestServerRemoteDB TSQLRestServerFullMemory TSQLRestServer TSQLRest RESTful Server classes In practice. client or server side. especially for implementing your own method-based services . or override internal methods. 1. and persistence on disk as JSON or optimized binary files . as its core Database layer (page 132). but letting ORM process stay out of scope).g. you may also find those classes also inheriting from TSQLRestServer: TSQLRestServerStaticInMemoryExternal TSQLRestServerStaticInMemory TSQLRestServerStaticExternal TSQLRestServerStaticRecordBased TSQLRestServerStatic TSQLRestServer RESTful Server static classes In the above class hierarchy.this kind of server is enough to handle authentication. They do not enter in account in our Client-Server presentation. on the server side. with basic CRUD features (for ORM). or on external databases. the TSQLRestServerStatic[InMemory][External] classes are in fact "fake servers". 11. it may use a TSQLRestServerRemoteDB class instead: this server will use an internal TSQLRestClient instance to handle all ORM operations it can be used e. with associated services and business logic: SAD . and host services in a stand-alone way.Synopse mORMot Framework Software Architecture Design 1.mORMot Framework .2.18 Page 198 of 1055 . as a DMZ for publishing services. If your purpose is not to have a full SQLite3 engine available. but are implementation details.18 Date: June 16. They are used within a main TSQLRestServer to host some given TSQLRecord classes. 1. If your services need to have access to a remote ORM server. Client classes A full set of client classes will implement a RESTful access to a remote database. See below (page 288) for some hosting scenarios. either in-memory. with all ORM and data access retrieved from another server: it will allow to easily implement a proxy architecture (for instance. In the mORMot units. you may create your server from a TSQLRestServerFullMemory class instead of TSQLRestServerDB: this will implement a fast in-memory engine (using TSQLRestServerStaticInMemory instances). to host some services on a stand-alone server.Rev. 2013 engine. 18 Date: June 16.Synopse mORMot Framework Software Architecture Design 1. named pipes are not available by default over a network.mORMot Framework .1 over TCP/IP. but there will be no delay due to the transmission of the data. that is some executable running on the same physical machine. so you a GDI message server won't be accessible when run as a background service.see below (page 217) .18 Page 199 of 1055 . and associate your running TSQLRestServerDB to it. This particular class will initialize an internal TSQLRestServerDB instance.and allow to combine this in-process direct process with other transmission protocols (like named pipes or HTTP). you shall always acquire IT approval and advices before any deployment over a corporate network. This is the reason why this protocol is listed as local access mean only. Local access via named pipes or GDI messages For a Client-Server local application. starting with Vista). ExportServerNamedPipe. So it is the preferred mean of communication for a local application sharing data between clients. at least to negotiate firewall settings.4.3. 11. But it has the problem of being reserved to desktop applications (since Windows Vista). creates a TSQLHttpServer instance. and you'll have full access to the SQLite3 database in the same process. A named pipe communication is able to be served from a Windows service. 2013 TSQLRestClientURINamedPipe TSQLRestClientURIMessage TSQLRestClientURIDll TSQLHttpClientWinINet TSQLRestClientURI TSQLRestClient TSQLRest TSQLRestClientDB TSQLHttpClientWinGeneric TSQLHttpClientWinHTTP TSQLHttpClientGeneric TSQLHttpClientWinSock RESTful Client classes Of course. Network and Internet access via HTTP For publishing a server via HTTP/1. Due to security restriction of newer versions of Windows (i. create a TSQLRestServerDB instance. all those TSQLRestClient* classes expect a TSQLRestServer to be available. Content will still be converted to and from JSON. via the corresponding transmission protocol.Rev.e. In-process/stand-alone application For a stand-alone application. create a TSQLRestClientDB. ExportServerMessage method to instantiate either a in-process. Named-Pipe or GDI messages server. In all cases. even if HTTP protocol is very network friendly (especially over the 80 port). 11. The GDI messages layer has the lowest overhead and is the fastest transport layer available between several applications on the same computer. and is known to be more efficient when transmitting big messages.2. Having JSON at hand will enable internal cache . then use the corresponding ExportServer. 1. SAD . with no speed penalty. 11. High-performance http.sys kernel-mode server. .. the Operating System provides a kernel stack to handle HTTP requests.1 server.4. as a core component.THttpApiServer which is based on http. then will compute the output content to be sent as response: TOnHttpServerRequest = function(Ctxt: THttpServerRequest): cardinal of object. via the OnRequest event handler. in which all high level process is to take place .Synopse mORMot Framework Software Architecture Design 1.sys driver is in fact a full featured HTTP server. It is part of the networking subsystem of the Windows operating system.THttpServer which is a light and tuned server featuring a thread pool and IOCP implementation pattern.mORMot Framework .18 Date: June 16.18 Page 200 of 1055 .4. This event handler prototype is shared by both TThread classes instances able to implement a HTTP/1. SAD .. and has a proven and secure implementation.the request will be computed on the server side. On production.Rev.1.2. The THttpServerGeneric abstract class provides one OnRequest property event.which may slow down the server). The resulting JSON content will be compressed using our very optimized SynLZ algorithm (20 times faster than Zip/Deflate for compression). You can also force to use the second server if DontUseHttpApiServer: Boolean is set to true at constructor level. THttpApiServer seems to give the best results.it expects some input parameters. it won't be compressed by default (even if you can enable the deflate algorithm . In case of a remote service access see below (page 227) . This http. HTTP server(s) THttpApiServer THttpServer THttpServerGeneric TThread THttpServerGeneric classes hierarchy The TSQLHttpServer class is able to use any of two HTTP server classes. running in kernel mode. If the request is a remote ORM operation.sys API. Then the response will be marked as to be sent back to the Client. also marshalling the data as JSON.for an AJAX client. 1. 2013 11.sys server Since Windows XP SP2 and Windows Server 2003. pass it to the TSQLRestServer instance matching the incoming URI request. That's why TSQLHttpServer will first try to use fastest http. Both THttpApiServer and THttpServer classes will receive any incoming request. or computed using the SQLite3 database engine. as defined in SynCrtSock unit: . if the client is a Delphi application knowing about SynLZ . 11. a JSON response will be retrieved from the internal cache of the framework. then fall-back to the generic WinSock-based THttpServer class in case of failure. if you specify HTTP_RESP_STATICFILE as Ctxt. Root. the Synopse mORMot framework will use it.18 Date: June 16. if http. .REST (page 191) .OutContentType.Faster process: Requests are processed faster because they are routed directly from the kernel to the appropriate user-mode worker process instead of being routed between two user-mode processes.OutContent is the UTF-8 file name of a file which must be sent to the client. SAD . the good old WinSock library and the worker process. at the kernel level. the kernel-mode request queue holds the request until a worker process picks it up. Root property is used to compute the RESTful URI needed. the failure is undetectable by the user because the kernel queues the requests while the WWW service starts a new worker process for that application pool. But whole file access and sending will occur in background. As we already stated. using high performance http. Security settings have changed since XP. here comes the UAC nightmare again.Kernel-mode request queuing: Requests cause less overhead in context switching. then handle the headers. If no worker process is available to accept a request.Create constructor call.sys all the magic is made..g.sys to serve a file content as fast as possible. If it's not available. .HttpApi web server" and HttpApiServer.dpr file. Note that it will work only with THttpApiServer kind of server (i. using I/O completion ports and a Thread Pool.e.sys? .dll library (which is the wrapper around http. you could still be able to use the server.18 Page 201 of 1055 .sys. So the URI registration step will always fail with the default settings. it will launch our pure Delphi optimized HTTP server. service is not interrupted.Rev. each with its own TSQLModel. URI authorization as Administrator This works fine under XP. 1. if any of those two steps fails (e.Synopse mORMot Framework Software Architecture Design 1. two steps are performed by the TSQLHttpServer constructor: . and stability is there.. Now only applications running with Administrator rights can register URLs to http. if you need it. just by the book.. In fact.mORMot Framework . . then check against any matching URL. leaving the server threads free to process the next request.4. See sample "09 . Performances are very good.sys is not available.3.. it will listen to any incoming connection request. You can even use a special feature of http.sys API).via the THttpApiServer. Of course. That is. or if it was not possible to register the URLs).The HTTP Server API is first initialized (if needed) during THttpApiServer.AddUrl method. It won't be said that we will let you down! Inside http. You can register several TSQLRestServer instances. But. then Ctxt.sys will handle all the communication by itself. the TSQLHttpServer class will fall back into using the other THttpServer class. The HttpApi. which is a plain Delphi multi-threaded server. under Vista and Seven.e. In short. What’s good about https. In fact. 11.It then tries to register the URI matching the RESTful model . http. i. the TSQLModel. because the kernel forwards requests directly to the correct worker process.Enhanced stability: When a worker process fails.sys) is loaded dynamically: so if you are running an old system (Windows XP SP1 for instance). 2013 The SynCrtSock unit can implement a HTTP server based on this component. so with best performance. no real application. But it will make your application development easier.it will allow any connection via the 888 port. it will be able to register all needed URL. there are several implementation of a HTTP/1.[aServer]. using TSQLModel. as such: aHTTPServer := TSQLHttpServer. as an application in tray icon with normal user rights. 1. 11. 2013 The only case when authorization will be possible is when the application launched as a Windows Service. HTTP client(s) In fact.18 Date: June 16.e. end. 11.dpr to work as expected . The TSQLHttpServer.4. Then when your server application will be launched (for instance.1 clients. 11.Synopse mORMot Framework Software Architecture Design 1. an URI prefix of http://+:888/root/ as expected by the kernel server: program TestSQL3Register. All mORMot samples are compiled with this flag. Root set as 'root'.3.'+'.Create(PORT_NAME. it will be set to useHttpApi. Automatic authorization An easier possibility could be to run the server application at least once as system Administrator. IIS and WCF services) is to explicitly register the URI.AddUrlAuthorize('root'. By default. with default services execution user. Depending on the system it runs on (i.mORMot Framework .2. If you specify useHttpApiRegisteringURI. Secure specific authorization Standard security policy.3. Therefore. Note this does not follow default security policy of Windows. Can be confusing. // force elevation to Administrator under Vista/Seven {$R VistaAdm.1.useHttpApiRegisteringURI). a program can be easily created and called once with administrator rights to make http. Windows services are launched with a User which has the Administrator rights.that is. To keep it simple. By default. SysUtils. as requested by Windows for all its http. as part of your Setup program.'+')). This could be done. uses SynCrtSock.18 Page 202 of 1055 .4.Create() constructor has a aHttpServerKind: TSQLHttpServerOptions parameter. according to this class hierarchy: SAD . or a background Windows service with tuned user rights).Rev.res} begin THttpApiServer.false. Windows XP or Vista and up).'888'. for instance.4.e. a diverse command line tool is to be used. our SynCrtSock unit provides a dedicated method to authorize a particular URI prefix to be registered by any user. Here is a sample program which can be launched to allow our TestSQL3.4.sys based systems (i. the class will register the URI before launching the server process.sys work with our framework. mORMot Framework .Rev. and any protocol over it (including HTTP). 1.18 Page 203 of 1055 . all based on WinSock API.WinHTTP's API set is geared towards a non-interactive environment allowing for use in service-based applications where no user interaction is required or needed.Synopse mORMot Framework Software Architecture Design 1. i. .WinSock is the common user-space API to access the sockets stack of Windows. As stated by their name.1 client. AutoProxy APIs UrlMon WinHTTP RASAPI WinINet WinSock HTTP/1.1 Client RESTful classes So you can select either TSQLHttpClientWinSock. . UDP/IP.WinINet was designed as an HTTP API client platform that allowed the use of interactive message dialogs such as entering user credentials .18 Date: June 16. IP connection it's able to handle any IP protocol.it only handles HTTP protocol. 2013 TSQLHttpClientWinINet TSQLHttpClientWinHTTP TSQLHttpClientWinGeneric TSQLHttpClientWinSock TSQLHttpClientGeneric HTTP/1. and attaches itself to a Windows communication library.e. TSQLHttpClientWinHTTP for a HTTP/1.1 Client architecture Here are some PROs and CONs of those solutions: Criteria WinSock WinINet WinHTTP API Level Low High Medium Local speed Fastest Slow Fast Network speed Slow Medium Fast Minimum OS Win95/98 Win95/98 Win2000 SAD . TSQLHttpClientWinSock will call directly the WinSock API.it's able to handle HTTP and FTP protocols. TSQLHttpClientWinINet or Each class has its own architecture. TSQLHttpClientWinINet will call WinINet API (as used by IE 6) and TSQLHttpClientWinHTTP will cal the latest WinHTTP API: . and is also much faster than WinINet . including TCP/IP. g. . Model and RecordProps access do not change during process). or relative to a table only (e. This was not found to be a major issue. via DB. to configure applications using the 32 bit WinHttp settings.The SQLite3 engine access is protected at SQL/JSON cache level. EngineRetrieve. 11. from the TSQLHttpServer.URI method is expected to be thread-safe. . our Framework was designed to be thread-safe. EngineAdd.A protected fSessionCriticalSection is used to protect shared fSession[] access between clients.Rev. EngineDelete. . Note that even if WinHTTP does not share by default any proxy settings with Internet Explorer.g. there is still a potential performance issue to use the direct TSQLHttpClientWinSock class over a network. or netsh. you can run "proxycfg -u" or "netsh winhttp import proxy source=ie" to use the current user's proxy settings for Internet Explorer.see External database access (page 166) . for TSQLRestServerStaticInMemory). for instance. In fact.Remote external tables . Request method.exe on Windows Vista and Windows Server 2008 or later. the following rules were applied in TSQLRestServer. 2013 HTTPS Not available Available Available Integration with IE None Excellent (proxy) Available (see below) User interactivity None Excellent (authentication. Therefore. Under 64 bit Vista/Seven. since this data is indicative only: a mutex was not used to protect this resource.g.mORMot Framework .18 Page 204 of 1055 . it can import the current IE settings. call netsh or proxycfg bits from %SystemRoot%\SysWOW64 folder explicitly. so all requests process will be queued.e. Thread-safety On the Server side.TSQLRestServerCallBack methods (i. In order to achieve this thread-safety without sacrificing performance. published methods of the inherited TSQLRestServer class) must be implemented to be thread-safe.TSQLRestServerStatic main methods (EngineList.5. EngineUpdateBlob) are thread-safe: e.g. There is some kind of "giant lock" at the SQLite3 engine level.LockJSON() calls in TSQLRestServerDB methods.Most of this methods's logic is to process the incoming parameters.Access to fStats was not made thread-safe. and root cause was not identified yet. so is thread-safe by design (e. . this method is the only one which is expected to be thread-safe. . EngineUpdate. the TSQLHttpClient class maps by default to the TSQLHttpClientWinHTTP class.exe on Windows XP and Windows Server 2003 or earlier. EngineRetrieveBlob.18 Date: June 16. This is the recommended usage from a Delphi client application. The WinHTTP proxy configuration is set by either proxycfg. TSQLRestServerStaticInMemory uses a per-Table Critical Section. the TSQLRestServer. Thanks to the RESTful approach of our framework.URI: . 1. We tried to make the internal Critical Sections as short as possible. since the internal SQL/JSON cache implementation need such SAD . e. dial-up) None As stated above.use thread-safe connections and statements when accessing the databases via SQL.Synopse mORMot Framework Software Architecture Design 1. . It has been reported on our forum. therefore perfectly thread-safe: it's the benefit of the stateless architecture. 1. and since most of the SQLite3 resource use will consist in hard disk access.18 Date: June 16.mORMot Framework . the REST core of the framework is expected to be Client-safe by design.Rev. From the Client-side. which gain to be queued.Synopse mORMot Framework Software Architecture Design 1. 2013 a global lock.18 Page 205 of 1055 . SAD . or remotely. . without any guess on how persistence is handled: some classes may be stored in one SQlite3 database.Rev. on both Client and Server side: SAD . .1. from the same methods defined in TSQLRest abstract class. or remotely via some dedicated Client-Server process (page 196).no installation step is necessary. i. all ORM features can be accessible either stand-alone. others may exist only in server's memory. 1.You can switch from local to remote access just by changing the class type.1 will be implemented as such. among them: . even at runtime. and stand-alone . and you still have the full power of a native rich client.a standard IP network connection is enough. 12. CRUD operations can be executed either at the database level. others may be stored in an external Oracle or MS SQL database. 2013 12. e. That is. cache or security. This feature has several benefits.mORMot Framework . .Clients access their objects in an abstract way. .18 Date: June 16.18 Page 206 of 1055 .Synopse mORMot Framework Software Architecture Design 1. Client-Server ORM Adopt a mORMot As stated above.Therefore the client application can safely remain small.g.No need to deploy the database client library for your application clients .Optimization is implemented at every level of the n-Tier architecture.e. ORM as local or remote Typical Client-Server RESTful POST / Add request over HTTP/1. SAD . 1. several clients can access to the same server.18 Page 207 of 1055 .Server side Of course. 2013 Client Client.Add ORM to JSON over REST return new ID TSQLHttpClient.18 Date: June 16.URI HTTP protocol POST Http Server Client-Server implementation .EngineAdd SQL insert return new ID SQLite3 SQL prepare + execute SQLite3 BTREE atomic write Database file Client-Server implementation .Rev.URI decode POST JSON TSQLRestServerDB.Client side HTTP Client HTTP protocol POST Server Http Server dispatch return 200 OK + ID TSQLRestServer.Synopse mORMot Framework Software Architecture Design 1.mORMot Framework . 18 Date: June 16. 1. The above diagram describes a direct INSERT into the Server's main SQLite3 engine.see Client-Server process (page 196).URI return new ID direct call TSQLRestServerDB.Synopse mORMot Framework Software Architecture Design 1. by defining a TSQLRestClientDB class. named pipes or GDI messages for fast local access.Add ORM to JSON over REST TSQLRestClientDB. the same executable could be launched as server.EngineAdd SQL insert return new ID SQLite3 SQL prepare + execute SQLite3 BTREE atomic write Database file Client-Server implementation . since you may run the server and client side of your project at once within the same application.Rev. or even client application! It is just a matter of how you initialize your TSQLRest classes instances . HTTP/1. as stand-alone application. SAD .mORMot Framework .g.1 for remote access over a network (either corporate or the Internet). It can be also extremely useful at debugging time. Some mORMot users use this feature to ease deployment.see Database layer (page 132). e. It is possible to by-pass the whole Client-Server architecture. from the IDE. but other database back-ends are available . 2013 The same server is also able to publish its RESTful services over several communication protocol at once. which will embed a TSQLRestServerDB instance in the same executable: Stand-Alone application Client. support and configuration. and let the application be stand-alone.Stand-Alone application In fact.18 Page 208 of 1055 .URI decode POST JSON TSQLRestServerDB. the above function correspond to a database model with only external virtual tables. calling the Virtual Table mechanism of SQlite3 for each SAD .URI decode POST JSON TSQLRestServerDB. the client side remains identical.e.Synopse mORMot Framework Software Architecture Design 1.EngineAdd SQL insert return new ID SQLite3 SQL return new ID prepare + execute SQLite3 engine Is a SQLite3 table? SQLite3 BTREE Is a Virtual table? TSQLVirtualTableExternal atomic write Database file external database TSQLDBConnectionProperties compute SQL insert TSQLDBStatement execute SQL OleDB/ODBC or other store data Database Client Client-Server implementation .Rev.18 Page 209 of 1055 . i. Only the server side is modified as such: Server Http Server dispatch return 200 OK + ID TSQLRestServer.Server side with Virtual Tables In fact. 1. and with StaticVirtualTableDirect=false.mORMot Framework .18 Date: June 16. 2013 In case of a Virtual Table use (either in-memory or for accessing an external database). for RESTful / CRUD commands.URI Is a SQLite3 table? TSQLRestServerDB. SAD . showing how native SQLite3. this design will induce no speed penalty. You'll find out how CRUD statements are handled directly for better speed. In practice. if the server is located on the same computer than the database: in this case.Server side with "static" Virtual Tables As stated in External database access (page 166).18 Date: June 16.e. when compared to a direct database access.18 Page 210 of 1055 .even faster when using below (page 213). the execution is more direct: Server Http Server dispatch return 200 OK + ID TSQLRestServer. It could be even faster. use of JSON and REST could be faster .Rev.EngineAdd SQL insert external database SQLite3 SQL return new ID TSQLDBConnectionProperties Is a SQLite3 table? compute SQL SQLite3 engine TSQLDBStatement prepare + execute execute SQL SQLite3 BTREE atomic write Database file OleDB/ODBC or other store data Database Client Client-Server implementation . in-memory or external tables are handled on the server side. 2013 request. 1. i. the static TSQLRestServerStaticExternal instance is called for most RESTful access. whereas any SQL JOIN query can also be processed among all kind of tables. In order to be exhaustive.Synopse mORMot Framework Software Architecture Design 1. here is a more complete diagram.mORMot Framework .EngineAdd Is a static table? return new ID TSQLRestServerStaticExternal. But most of the time. 18 Page 211 of 1055 .Synopse mORMot Framework Software Architecture Design 1. 2013 Server Http Server return 200 OK + result (JSON) dispatch TSQLRestServer. Engine* SQLite3 SQL prepare + execute Is an in-memory table? (Virtual or static) TSQLRestServerStaticInMemory. 1. Engine* compute SQL TSQLDBConnectionProperties TSQLDBStatement SQLite3 engine For any external Virtual table TSQLVirtualTableExternal external database TSQLDBConnectionProperties For any SQLite3 table For any in-memory Virtual Table SQLite3 BTREE TSQLVirtualTableJSON TSQLVirtualTableBinary atomic read/write Database file CRUD in-memory TSQLRecord execute SQL OleDB/ODBC or other handle data Process in-memory TSQLRecord Database Client compute SQL TSQLDBStatement execute SQL OleDB/ODBC or other handle data Database Client SAD .Engine* Is an external Virtual Table? decode into SQL TSQLRestServerStaticExternal.URI Refers to a SQLite3 table or a JOINed query? CRUD over a static table? TSQLRestServerStatic.18 Date: June 16.mORMot Framework .Rev. Engine* TSQLRestServerDB. it's always necessary to have some event triggered on the server side when a record is edited. 12. Event: TSQLEvent. Client side synchronization But if you want all clients to be notified from any update..return true if Data is updated successfully.Synopse mORMot Framework Software Architecture Design 1.if Data contains only one TSQLTableJSON. you can use this method prototype: type /// used to define how to trigger Events on record update // . This is handled natively by our Client User Interface classes.mORMot Framework .) /// a method can be specified here to trigger events after any table update OnUpdateEvent: TNotifySQLEvent.18 Page 212 of 1055 .returns true on success.make use of the InternalState function to check the data content revision // . with the following parameter defining the User interface: /// defines the settings for a Tab TSQLRibbonTabParameters = object (.OnUpdateEvent property // . TSQLRestServer = class(TSQLRest) (. 1. 12. even over a remote network. 2013 Client-Server implementation .18 Date: June 16. What you can do easily.g. or false on any error // during data retrieval from server (e. and // update it if possible // . On the server side. false if an error occured (but action must continue) TNotifySQLEvent = function(Sender: TSQLRestServer.Server side You will find out some speed numbers resulting from this unique architecture in the supplied Data access benchmark (page 135)..2. by design. is to have a timer in your client applications which will call TSQLRestClientURI.Rev. It's not even technically possible with pipe-oriented transport layer. the screens are not refreshed automaticaly SAD . if the TSQLRecord has been deleted) // . Stateless design 12. in order to refresh its value function UpdateFromServer(const Data: array of TObject. The stateless aspect of REST allows this approach to be safe. and is what should be used in such case. out Refreshed: boolean. Server side synchronization Even if REST is Stateless (page 193).see TSQLRestServer. aID: integer): boolean of object.only working types are TSQLTableJSON and TSQLRecord descendants // .1. PCurrentRow can point to the // current selected row of this table. there is no direct way of broadcasting some event from the server to all clients..2.2.) /// by default. it's quick and reactive. aTable: TSQLRecordClass. like named pipes or the TCP/IP HTTP protocol.2. UpdateFromServer() method to refresh the content of any TSQLRecord or TSQLTableJSON instance: /// check if the data may have changed of the server for this objects.. With a per-second timer. PCurrentRow: PInteger = nil): boolean. then back to you.pas unit): procedure TMainForm. the a response is sent back to the client. It's up to the screens to get refreshed. If you are making a number of such calls (e.but you can enable the auto-refresh feature by setting this // property to TRUE. begin Ribbon.mORMot Framework .3. especially with the common understanding (and most implementations) of a RESTful service.3. and even on the server side.18 Page 213 of 1055 . Synchronize method. and creating a WM_TIMER timer to the form AutoRefresh: boolean. BATCH sequences for adding/updating/deleting records 12. any Add / Update / Delete method call requires a back and forth flow to then from the remote server.e. a stateless approach makes writing software easier. See for example this method in the main demo (FileMain.18 Date: June 16. end.WMRefreshTimer.Synopse mORMot Framework Software Architecture Design 1.WMRefreshTimer(Msg). 2013 // . You do not have to care about forcing data refresh in your client screens. i. add 1000 records). In practice. A so-called round-trip occurs: a message is sent to the client. This parameter will work only if you handle the WM_TIMER message in your main application form. you'll have 100*1000 ms = 100 s = 1:40 min just because of this network latency! ORM CRUD operation In-process no latency ORM HTTP Client Internet 100 ms latency ORM HTTP Server In-process no latency ORM database core SAD . In case of a remote connection via the Internet (or a slow network). you could have up to 100 ms of latency: it's just the "ping" timing. BATCH process When use the so-called BATCH sequences? In a standard Client-Server architecture.WMRefreshTimer(var Msg: TWMTimer). the time spent for your IP packet to go to the server.Rev. I found it very convenient to rely on a timer instead of calling the somewhat "delicate" TThread. 1.1. 12. and call Ribbon.g. In a multi-threaded client application. 18 Page 214 of 1055 . It's up to the caller to use a TransactionBegin . Some new TSQLRestClientURI methods have been added to implement BATCH sequences to speed up database modifications: after a call to BatchStart. // send the BATCH sequences to the server Check(ClientDist. V.ID[i]. then post this stream at once to the server. 1.true)=n+nupd+i). 2013 BATCH mode Client-Server latency The BATCH sequence allows you to regroup those statements into just ONE remote call. // update some elements nupd := 0.BatchSend(Results)=200). for i := 0 to aStatic. Check(ClientDist. V.pas: // start the transaction if ClientDist. the ID of the added row) on the same time as you append the request to the BATCH sequence. at once.TransactionBegin(TSQLRecordPeople) then try // start the BATCH sequence Check(ClientDist. Check(ClientDist. for i := 0 to high(Results) do if i<nupd+n then Check(Results[i]=200) else begin SAD .LastName := 'New'.V)). after having performed all the modifications.. it's also a good idea to use a transaction for the whole process. end.BatchDelete(IntArray[i])=i).Synopse mORMot Framework Software Architecture Design 1. then all statements are sent as one to the remote server via BatchSend . Commit except RollBack block.Retrieve(IntArray[i].this is MUCH faster than individual calls to Add / Update / Delete in case of a slow remote connection (typically HTTP over Internet). So you'll have to wait for the BatchSend method to retrieve all results. // now Results[] contains the results of every BATCH statement. // add some elements V..YearOfBirth := i+1000. try. // delete some elements for i := 0 to n-1 do Check(ClientDist. end.. for i := 0 to 1000 do begin V. // Results[0] to Results[n-1] should be 200 = deletion OK // Results[n] to Results[n+nupd-1] should be 200 = update OK // Results[n+nupd] to Results[high(Results)] are the IDs of each added record for i := 0 to n-1 do Check(not ClientDist.BatchAdd(V.Count-1 do if i and 7<>0 then begin // not yet deleted in BATCH mode Check(ClientDist.'BatchDelete'). Then the server answers at once.Rev.BatchUpdate(V)=nupd+n).18 Date: June 16. you can't receive the result (e..mORMot Framework .FirstName := RandomUTF8(10). in a dynamic array of integer. Here is typical use (extracted from the regression tests in SynSelfTests. As you may guess. By default.g..YearOfBirth := 1800+nupd. database modification statements are added to the sequence via BatchAdd / BatchUpdate / BatchDelete. it builds a JSON stream. Internally. Check(Length(Results)=n+nupd+1001). inc(nupd).Retrieve(aStatic.BatchStart(TSQLRecordPeople)).. the BATCH sequence is not embedded into a transaction.V). Since the statements are performed at once. "PUT":{"RowID":3. "YearOfDeath":1519}."LastName":"New". // in case of success.'ID."FirstName":"Alexandre1". (.. "POST":{"FirstName":"‚@•Å"H†m£ g". apply the Transaction ClientDist. For instance. "YearOfDeath":1519}..) all PUT = update actions "PUT":{"RowID":11012."LastName":"Rachmaninoff". rollback the Transaction ClientDist. "PUT":{"RowID":4. (. Thanks to these methods."DELETE":24.'BatchAdd')."YearOfBirth":9025. "YearOfDeath":1870}."YearOfBirth":1001. 2013 Check(Results[i]>0). most time is now spent into the database engine itself. if ClientDist..Items[ndx]) do begin Check(LastName='New'. using Batch*() methods instead of plain Add / Delete / Update.200.. the BatchUpdate method will only update the mapped fields if called on a record in which a FillPrepare was performed. in the following code. with no call to FillClose). 1.TransactionBegin(TSQLRecordPeople) then SAD . all Batch*() methods are serialized as JSON on the client side."YearOfBirth":2000. "POST":{"FirstName":"@….. Beginning with revision 1.'LastName=:("New"):'. so subsequent BatchUpdate(V) calls will only update the YearOfBirth field: // test BATCH update from partial FillPrepare V. Here is typical JSON stream sent to the server: {"People":["DELETE":2. except // In case of error. used bandwidth is minimal.. Check(ndx>=0)."YearOfBirth":1000. and not in the communication layer.16 of the framework."DELETE":11010.) all POST = add actions "POST":{"FirstName":"+tqCXW3Â\""."YearOfBirth":1801."DELETE":13.3. "YearOfDeath":1943}. on success: [200. V. where it will be processed without any client-server round-trip and slow latency. end. ndx := aStatic. then sent as once to the server.KA½à #¶f"..18 Page 215 of 1055 .] All the JSON generation (client-side) and parsing (server-side) is very optimized and fast.e.YearOfBirth')..FillPrepare will retrieve only ID and YearOfBirth fields of the TSQLRecordPeople table."LastName":"Dumas"."FirstName":"Leonard". including serialization."LastName":"New"."LastName":"da Vinçi".Commit. end. "YearOfDeath":1519}. "YearOfDeath":1519} ]} Here is typical JSON stream receiver from the server. 12. with TSQLRecordPeople(aStatic. Check(YearOfBirth=1000+i-nupd-n). all CRUD operations are performed as usual."YearOfBirth":1800..18 Date: June 16.) all DELETE actions .Synopse mORMot Framework Software Architecture Design 1.RollBack. and not unmapped (i."LastName":"New". Implementation details As described above.FillPrepare(ClientDist.IDToIndex(Results[i]).mORMot Framework . end. With the new internal SynLZ compression (available by default in our HTTP Client-Server classes). In the above code. The ORM will take care of all internal process. (.2."FirstName":"Sergei1".Rev. but in Service-oriented architecture (page 63) when most process is done on the server side. when using a remote database on a physical network. In fact.3. ClientDist. this time between the ORM server side and the external Database engine.YearOfBirth inc(n)..Rev.YearOfBirth := n.BatchUpdate(V).18 Date: June 16. n := 0.BindArray() methods. this 1 ms latency due to the external datatabase additional round-trip may sounds negligeable. 2013 try Check(ClientDist.18 Page 216 of 1055 . V.mORMot Framework . while V. (. Check(V. V..BatchStart(TSQLRecordPeople)). introducing array binding for faster database batch modifications. DELETE or UPDATE statements: the same round-trip occurs. // will update only V.3. Our SynDB unit has been enhanced to introduce new TSQLDBStatement.YearOfBirth=n+1000). 1. Your customers would not understand why using a SQLite3 engine would be much faster than a dedicated Oracle instance they do pay for. Array binding When used in conjunction with External database access (page 166). end. BATCH methods can be implemented as array binding if the corresponding TSQLDBConnection implementation implements the feature (only SynDBOracle unit has it by now).LastName='NotTransmitted'). ORM CRUD operation In-process no latency ORM HTTP Client Internet 100 ms latency ORM HTTP Server In-process no latency ORM database core Local Network 1 ms latency External DB BATCH mode latency issue on external DB Of course.LastName := 'NotTransmitted'.Synopse mORMot Framework Software Architecture Design 1.) 12. it may introduce a huge performance difference. It is working in conjuction with our SAD . you won't be able to achieve more than 500-600 requests per second when performing INSERT.FillOne do begin Check(V. all those enhancements may speed up a lot your process. CRUD level cache 12. SAD . See Data access benchmark (page 135) and for details and performance charts the article at http://blog. If you want to use a map/reduce algorithm in your application. it will make using this feature even faster than a "naive" stored procedure with statements within a loop. Where to cache Starting with revision 1.4. but to the fact that in such operations. so CRUD modification actions are grouped within one round-trip over the network.1. at least.Synopse mORMot Framework Software Architecture Design 1. in our benchmarks.g. In fact.16 of the framework.4.g.Rev. in addition to ORM data access. for specific tables or records. Thanks to this enhancement.mORMot Framework . 12. Therefore. and the Server can also have its own cache.18 Page 217 of 1055 . N-tier separation would benefit from it. See ORM Cache (page 114) for the other cache patterns available in the framework. 2013 BATCH methods. Delphi clients can have their own cache. In fact. Oracle or MS SQL) are even faster when using array binding. Reading and writing huge amount of data has never been so fast and easy: you may even be tempted to replace stored-procedure process by high-level code implemented in your Domain service. inserting records within Oracle comes from 400-500 rows per second to more than 50000 rows per second. not only due to the network latency reduce. for both TSQLRestClient and TSQLRestServer kind of classes. tuned record cache has been implemented at the CRUD/RESTful level. If your table has several indexes and constraints.synopse. some modern database engine (e. A client without any cache (e.18 Date: June 16. a unique caching mechanism is shared at the TSQLRest level. a rough AJAX client) will take advantage of the server cache. integrity checking and indexes update is performed at the end of the bulk process.. on both the server and client sides.info/post/2012/07/19/Oracle-Array-Binding-and-BATCH-performance. 1. When to cache The main problem with cache is about data that both changes and is accessed simultaneously by multiple clients. this would increase global server responsiveness and allow more clients to be served with the same hardware.each side will probably require its own set of SAD . You must tune caching at both Client and Server level .1 client cache Local Network PC Server Server DB server cache external DB CRUD caching in mORMot When caching is set on the server for a particular record or table. adding caching on the client side does make sense. It is up to the coder to ensure that no major confusion could arise from concurrency issues. if available. In the current implementation. For applications that frequently access the same data . then either client or server cache will be used.18 Page 218 of 1055 . Due to the high latency of a remote client-server request. just as usual. If the item is found. On the client side.Rev. When properly used. in-memory values could be retrieved from this cache instead of calling the database engine each time.a large category record-level caching improves both performance and scalability. The very same usual ORM methods are to be called to access a record (Retrieve / Update / Add). 12. a "pessimistic" concurrency control is used by our framework. 1. If the data item is not in the local cache. the client uses this cached value.2.18 Date: June 16.mORMot Framework . 2013 PC 2 PC n Client 2 (AJAX) Client n (Delphi) JSON + REST over HTTP/1. Our caching implementation is transparent to the CRUD code. which may be much slower than a local Network.4. and (ab)use of its REST is Stateless (page 193) general design.Synopse mORMot Framework Software Architecture Design 1.1 PC 1 Client 1 (Delphi) Internet (VPN) client cache JSON + REST over HTTP/1. relying on explicit locks. Client caching properties can be tuned in order to handle properly remote HTTP access via the Internet. a local in-memory cache could be first checked when a record is to be retrieved. the query is then sent to the server. Cache.) Client.Cache. it could be even slower to cache it).Cache's SetCache() and SetTimeOut() methods is enough to specify which table(s) or record(s) are to be cached.integrated to mORMot can be very handy to tune the caching settings. 12. or any other kind of unchanging data which is not likely to vary often. either at the client or the server level.SetCache() or SAD . and ensure content coherency. For instance. but delete all settings previously made with Cache. A call to TSQLRest. and will maintain such a tuned caching mechanism. here is how the Client-side caching is tested about one individual record: (. (. either at the client and/or the server side. Another good use of caching is to store data that changes but is accessed by only one client at a time. . TestOne.mORMot Framework ..SetCache(Rec).Clear is used to reset all cache settings (i..3. By setting a cache at the client level for such content.4.) Note that in the above code.Ensure that caching is worth it (if a value is likely to be overridden often. Client.. but added on need.SetCache(TSQLRecordPeople).Not to cache if it may break something relevant (like a global monetary balance value).Cache. In your project project implementation. // cache one record // same as Client. not only flush the cache content.Rec. Profiling can be necessary to identify which data is to be registered within those caches. the server won't be called often to retrieve the client-specific data. How to cache A dedicated TSQLRestCache instance can be created. The main rules may be simply: . The logging feature . for both TSQLRestClient and TSQLRestServer classes.e. the problem of handling concurrent access to the cached data doesn't arise. 12. // reset cache settings Client.see Enhanced logging (page 78) .Cache.Not to cache unless you need to (see Knuth's wisdom).4. Adding a cache shall imply having automated regression tests available.18 Page 219 of 1055 . due to its unique customer-side profiling ability. since in a Client-Server multi-threaded architecture.) Database. caching should better not to be used at first. But most of the time. What to cache Typical content of these two tuned caches can be any global configuration settings. 2013 cache options.ID).. .18 Date: June 16.SetCache(TSQLRecordPeople)..Cache.4. // cache whole table TestOne.Synopse mORMot Framework Software Architecture Design 1. // server-side (.SetCache(TSQLRecordPeople.Cache. test twice.Clear.Test once.Rev. 1. In such case. when performance and efficiency was found to be required. Client. such as catalog information for an online retailer.. "premature optimization is the root of all evil" (Donald Knuth). and is accessed simultaneously by multiple clients. always test and do not forget to test even more. an human guess at the business logic level is enough to set which data is to be cached on each side. . Flush() methods are to be called. only local CRUD operations are tracked.Rev.18 Date: June 16. in the services which executed the corresponding SQL. If such non-CRUD statements did occur on the client side. SAD . 1. a global cache is first enabled for the whole TSQLRecordPeople table. On the Server side. and cache will be notified of any data change. e. which will call a dedicated standard service on the server to flush its cache content on purpose. If such statements did occur on the server side. all CRUD operations of the ORM (like Add / Update / Delete) will be tracked. to enforce data coherency. adding a time out value does definitively make sense. TSQLRestServer. 2013 Cache. If no time out period is set. But direct SQL statements changing table contents (like a UPDATE or a DELETE over one or multiple rows with a WHERE clause) are not tracked by the current implementation: in such case. it's up to the client to flush its own cache on purpose.mORMot Framework . it is possible to ensure that the server content is coherent with the client side. then cache is enabled for only the particular Rec record.SetTimeOut() calls. According to the stateless design. you'll have to manually flush the server cache content.Flush() methods. by using TSQLRestClient.ServerCacheFlush() method. So in the above code. unless the corresponding data is known to be dedicated to this particular client (like a session data). It's worth warning once again that it's up to the code responsibility to ensure that these caches are consistent over the network.g.Cache.18 Page 220 of 1055 .Cache. via a dedicated TSQLRestClientURI.Synopse mORMot Framework Software Architecture Design 1. Server side and client side have their own coherency profile to be ensured. On the Client side. then the cache settings are reset. 13.18 Page 221 of 1055 . According to the current state of our framework. there are several ways of handling such a server-side SQL/ORM process: .Low-level dedicated Delphi stored procedures. . The Server-Side services . . Custom SQL functions The SQLite3 engine defines some standard SQL functions. like any powerful Client-Server RDBMS solution. But custom SQL WHERE statements may improve the client code. Server side SQL/ORM process Adopt a mORMot The framework is able to handle a custom type of "stored procedure" at SQL level in pure Delphi code. 2013 13. a stored procedure is a way of moving some data-intensive SQL process on the server side.html. 1.18 Date: June 16.appear to be the more RESTful compatible way of implementing a stored procedure mechanism in our framework.org/lang_corefunc.sqlite.Write your own SQL function to be used in SQLite3 WHERE statements.. like abs() min() max() or upper().Synopse mORMot Framework Software Architecture Design 1. A complete list is available at http://www.1.see below (page 229) and below (page 257) . and all actions will be taken on the server: since no data has to be exchanged between the client and the server. One of the greatest SQLite3 feature is the ability to define custom SQL functions in high-level SAD . A client will ask for some data to be retrieved or processed on the server. In short. and therefore ORM CRUD requests could be optimized via some server-side process.Rev.External databases stored procedures. such a feature will be much faster than a pure client-sided solution.mORMot Framework . for direct search inside a BLOB column containing some dynamic array binary content (expecting either an INTEGER or a TEXT search value as 2nd parameter). just like in PosEx() Delphi function. The SQL function implementation pattern itself is explained in the sqlite3. Function shall return the position where the match occurred. You may have to use.Rev. . Text [ . . you may have an easy way of implementing server-side process of complex data. 1. else begin ErrorWrongNumberOfArgs(Context). 0 when no match occurs.Soundex SoundexFR SoundexES for computing the English / French / Spanish soundex value of any text. 3: begin StartPos := sqlite3.Then set the result value using sqlite3. . cdecl. begin case argc of 2: StartPos := 1.:(10):) 13. Characters are counted from 1. Int64DynArrayContains. Implementing a function Let us implement a CharIndex() SQL function. Those functions are no part of the SQlite3 engine.mORMot Framework . calling the expected low-level SQLite3 API (note the cdecl calling convention. StartPos ] ) In here.Synopse mORMot Framework Software Architecture Design 1. . end. var argv: TSQLite3ValueArray).Concat to process fast string concatenation.18 Date: June 16.argc is the number of supplied parameters. which are available in argv[] array (you can call ErrorWrongNumberOfArgs(Context) in case of unexpected incoming number of parameters). Here is typical implementation code of the CharIndex() SQL function.18 Page 222 of 1055 .value_*(argv[*]) functions to retrieve a parameter value.result_*(Context. as stated in Dynamic arrays from SQL code (page 105). defined as such: CharIndex ( SubText.*) functions. In fact. if StartPos<=0 then StartPos := 1. SubText is the string of characters to look for in Text. StartPos indicates the starting index where charindex() should start looking for SubText in Text. on the Server-side: . ByteDynArrayContains. RawUTF8DynArrayContainsCase.Use sqlite3.value_int64(argv[2]). Some custom already defined SQL functions are defined by the framework.2. but are available inside our ORM to handle BLOB containing dynamic array properties. as such: UPDATE MyTable SET SomeField=0 WHERE IntegerDynArrayContains(IntArrayField. CurrencyDynArrayContains. .IntegerDynArrayContains.Rank used for page ranking in FTS searches (page 149).create_function_v2() and TSQLFunctionFunc: . In other database engine. its C API allows implementing new functions which may be called within a SQL query. such functions are usually named UDF (for User Defined Functions). since it is a SQLite3 / C callback function): procedure InternalSQLFunctionCharIndex(Context: TSQLite3FunctionContext. var StartPos: integer. SAD . 2013 language. Since you may use such SQL functions in an UPDATE or INSERT SQL statement. argc: integer. CardinalDynArrayContains. WordDynArrayContains. RawDynArrayContainsNoCase. InternalSQLFunctionCharIndex.18 Page 223 of 1055 . 1. then call the PosEx() function to return the position of the supplied text.RegisterSQLFunction(TSQLDataBaseSQLFunction.value_type(argv[0])=SQLITE_NULL) or (sqlite3. This code just get the parameters values using sqlite3. as an INTEGER. sqlite3. using sqlite3.'CharIndex').nil. by creating a TSQLDataBaseSQLFunction custom class and calling the TSQLDataBase. 'CharIndex'. one time with 2 parameters.value_*() functions.Create(InternalSQLFunctionCharIndex. 'CharIndex'.2.3. you can declare the CharIndex SQL function as such: Demo. as such: sqlite3.RegisterSQLFunction() with an defined TSQLDataBaseSQLFunction custom class.create_function_v2(Demo. The RegisterSQLFunction() method is called twice.nil.result_int64(Context.mORMot Framework .'CharIndex' )). The function is registered twice.InternalSQLFunctionCharIndex.1. end.create_function_v2(Demo. to specify the character index to start searching from.value_text(argv[0]). if (sqlite3.SQLITE_ANY. calling sqlite3.3. Registering a function 13.nil).2. one time with 2 parameters. 13.0) else sqlite3. The special case of a NULL parameter is handled by checking the incoming argument type.3. then with 3 SAD .3.Rev. then with 3 parameters.InitializeEngine virtual method.value_type(argv[]).nil.create_function_v2() API.Synopse mORMot Framework Software Architecture Design 1.SynCommons.3.RegisterSQLFunction method.RegisterSQLFunction(InternalSQLFunctionCharIndex. to add an overloaded version with the optional StartPos parameter. calling DB.DB.PosEx( sqlite3.2.Create(InternalSQLFunctionCharIndex. end.2. Demo. The standard way of using this is to override the TSQLRestServerDB. 2013 exit.sqlite3.nil).StartPos)).RegisterSQLFunction(InternalSQLFunctionCharIndex.18 Date: June 16.'CharIndex'). Demo.RegisterSQLFunction(TSQLDataBaseSQLFunction. 13. The two lines above will indeed wrap the following code: Demo. end. we may register it with direct SQLite3 API calls. The local StartPos variable is used to check for an optional third parameter to the SQL function.result_int64(Context. Class-driven registration It is possible to add some custom SQL functions to the SQlite3 engine itself.nil. Direct low-level SQLite3 registration Since we have a InternalSQLFunctionCharIndex() function defined.3.nil.'CharIndex' )).result_int64().value_text(argv[1]).nil.value_type(argv[1])=SQLITE_NULL) then sqlite3. So instead of calling low-level sqlite3.SQLITE_ANY.DB. Rev. const aFunctionName: RawUTF8=''). 1.RegisterSQLFunction(aDynArrayTypeInfo: pointer. with a custom class definition.18 Page 224 of 1055 .A fDummyDynArrayValue pointer. const aFunctionName: RawUTF8).aCompare.you should better use the already existing faster SQL functions // Byte/Word/Integer/Cardinal/Int64/CurrencyDynArrayContains() if possible // (this implementation will allocate each dynamic array into memory before // comparison. the following method will register a SQL function able to search into a BLOB-stored custom dynamic array type: procedure TSQLDataBase. 2013 parameters. And the constructor implementation: SAD . and will be therefore slower than those optimized versions) constructor Create(aTypeInfo: pointer. public /// initialize the corresponding SQL function // .Synopse mORMot Framework Software Architecture Design 1. aCompare: TDynArraySortCompare. Custom class definition The generic function definition may be completed. Here is the corresponding class definition: /// to be used to define custom SQL functions for dynamic arrays BLOB search TSQLDataBaseSQLFunctionDynArray = class(TSQLDataBaseSQLFunction) protected fDummyDynArray: TDynArray. in our framework. 13.if the function name is not specified. end. to be used to store the dynamic array reference values to be used during the dynamic array process. to add an overloaded version with the optional StartPos parameter. TReferenceDynArray will declare 'ReferenceDynArray') // . it will be retrieved from the type // information (e.ElemSave() or with BinToBase64WithMagic(aDynArray. which adds two needed protected fields to the TSQLDataBaseSQLFunction root class: .ElemSave()) // if called via a Client and a JSON prepared parameter) // .3.3. begin RegisterSQLFunction( TSQLDataBaseSQLFunctionDynArray. override. but global and static to the whole application process.Create(aDynArrayTypeInfo. as expected. fDummyDynArrayValue: pointer. We specify directly the TSQLDataBaseSQLFunctionDynArray class instance to work with.the SQL function will expect two parameters: the first is the BLOB // field content. aCompare: TDynArraySortCompare.aFunctionName)). not only relative to the current SQL function context. TSQLDataBaseSQLFunctionDynArray TSQLDataBaseSQLFunction TObject TSQLDataBaseSQLFunction classes hierarchy For instance. and the 2nd is the array element to search (set with // TDynArray. which is handy to have some specific context. .18 Date: June 16.g.mORMot Framework .A fDummyDynArray TDynArray instance which will handle the dynamic array RTTI handling. end. 'MyIntegerDynArrayContains'). as expected by the ORM. the first being a reference to the BLOB column. the dedicated IntegerDynArrayContains SQL function is faster.mORMot Framework .Create(aTypeInfo: pointer. 2013 constructor TSQLDataBaseSQLFunctionDynArray. FormatUTF8('MyIntegerDynArrayContains(Ints.ElemSave()) expression instead..) You can define a similar class in order to implement your own custom SQL function.18 Page 225 of 1055 .'ID'. LoadFrom method). the BinToBase64WithMagic function is used to create a BLOB parameter.sizeof(k))]). which is a pure binary variable (containing no reference-counted internal fields): so we use direct mapping from its binary in-memory representation. Note that since the 2nd parameter is expected to be a BLOB representation of the searched value. Low-level Delphi stored procedure To implement a more complete request.aFunctionName). FormatUTF8('MyIntegerDynArrayContains(Ints. and handle any kind of stored data in a column (for instance.IDs). 1. for more complex element type. ElemSave method. The function can be called as such (lines extracted from the framework regression tests): aClient. calling TDynArray. // temporary allocate all dynamic array content try if ElemLoadFind(Elem)<0 then DynArray := nil.?)'.Init(aTypeInfo..2. the element type is an integer. SAD .18 Date: June 16..sizeof(k))]). const aFunctionName: RawUTF8).fDummyDynArray do try LoadFrom(DynArray). [BinToBase64WithMagic(@k. [BinToBase64WithMagic(@k. (. inherited Create(InternalSQLFunctionDynArrayBlob. end.) with Func.SortDynArrayInteger. Since the MyIntegerDynArrayContains function will create a temporary dynamic array in memory from each row (stored in fDummyDynArrayValue). Here is how a custom SQL function using this TSQLDataBaseSQLFunctionDynArray class is registered in the supplied unitary tests to an existing database connection: Demo.IDs). and the 2nd the searched value. you should use the generic BinToBase64WithMagic(aDynArray.RegisterSQLFunction(TypeInfo(TIntegerDynArray).OneFieldValues(TSQLRecordPeopleArray. 13. begin fDummyDynArray. aCompare: TDynArraySortCompare.[].OneFieldValues(TSQLRecordPeopleArray. finally Clear. Here. Note that we did not use here the overloaded OneFieldValues method expecting '?' bound parameters here. but we may have use it as such: aClient. // release temporary array content in fDummyDynArrayValue end. This new SQL function expects two BLOBs arguments.Compare := aCompare.'ID'.fDummyDynArrayValue). then un-serialize it into a dynamic array (using the fDummyDynArrayValue. fDummyDynArray.Synopse mORMot Framework Software Architecture Design 1. then call the standard ElemLoadFind method to search the supplied element. which will retrieve a BLOB content.4.Rev.:("%"):)'. as such: (.. The InternalSQLFunctionDynArrayBlob function is a low-level SQlite3 engine SQL function prototype. This will allow direct content modification during the SELECT statement. 1.mORMot Framework .Net. EngineExecute method. then define some below (page 227) to launch those functions. See the description of the TOnSQLStoredProc event handler and associated method in the next pages. In fact. Virtual Tables magic (page 155) TSQLVirtualTableCursorJSON cursors are not safe to be used if the Virtual Table data is modified. 13. External stored procedure If the application relies on external databases . custom SQL functions or stored procedures both use the SQLite3 engine as root component. and switching to another database engine may cost. In order to speed up the process.Synopse mORMot Framework Software Architecture Design 1. you'll loose the database-independence of the framework. 2013 some TEXT format to be parsed). Code inside this event handler should not use the ORM methods of the framework. In such situation. P/SQL or whatever). but direct low-level SQLite access. a TOnSQLStoredProc event handler can be called for every row of a prepared statement. and is able to access directly to the database request.18 Page 226 of 1055 .5. This event handler should be specified to the corresponding overloaded TSQLRestServerDB.see External database access (page 166) .the external database may be located on a remote computer. up to now. Be aware that. SAD .Rev.18 Date: June 16. Java. you may define some RDMS stored procedures in the external database format (. Note that in this case. all RESTful Server-sided solutions could produce a lot of network traffic. whereas mORMot uses a code approach.see below (page 239) .Via some TSQLRecord inherited classes. but also a whole diverse use case (RAD/components and wizards versus ORM/MVC) and implementation (mORMot takes advantages of the SQLite3 SQL core and is much more optimized for speed and scaling). We included most of the nice features made available in WCF in mORMot. over several protocols. 2013 14.see below (page 284).as implemented by Microsoft's WCF technology . inserted into the database model.Defining some RESTful service contracts as standard Delphi interface.see Client-Server process (page 196). It is also RAD/Wizard based. The first is similar to RemObject's DataAbstract product. your application's business logic can be implemented in several ways using mORMot: . and accessible via some RESTful URI . so matches the "designed by contract" principle . The last item is purely interface-based. 1.18 Date: June 16. the first two items can be compared to the DataSnap Client-Server features. but it has some known stability and performance issues. and then run it seamlesly on both client and client sides. implemented in the Server as published methods. in a KISS manner. SAD . and consumed in the Client via native Delphi methods. If you paid for a Delphi Architect edition. which allows remote access to database. you can in fact define JSON-based RESTful services.18 Page 227 of 1055 .this is implemented by our ORM architecture . .Rev. There are some similarities with mORMot (like on-the-fly SQL translation for external databases). It makes uses of the new RTTI available since Delphi 2010. Server side Services Adopt a mORMot In order to follow a Service-oriented architecture (page 63) design.By some RESTful services. Since Delphi 2010. and lack of strong security. . in addition to the original DCOM/DBExpress remote data broker.mORMot Framework .Synopse mORMot Framework Software Architecture Design 1. SAD . all three ways of implementing a SOA application.Rev.18 Date: June 16. 2013 So mORMot is quite unique.you won't be stucked with proprietary code nor licenses. in the fact that it features. 1. existing since years .18 Page 228 of 1055 . without the need of upgrading to the latest version of the IDE.mORMot Framework . You can move your existing code base into a Domain-Driven Design. on your management pace (and money). And it is an Open Source project.Synopse mORMot Framework Software Architecture Design 1. in an unique code base. Publishing a service on the server On the server side. isn't it? 15.18 Date: June 16. 2013 15. like all Server-side methods. or a lighter TSQLRestServerFullMemory kind of server. end.18 Page 229 of 1055 . We'll implement the same example as in the official Embarcadero docwiki page above. we need to customize the standard TSQLRestServer class definition (more precisely a TSQLRestServerDB class which includes a SQlite3 engine. the first method is to define published method Server-side. by adding a new published method: type TSQLRestServerTest = class(TSQLRestServerFullMemory) (.1. Very useful service. and will be called remotely from ModelRoot/Sum URL.Synopse mORMot Framework Software Architecture Design 1.mORMot Framework . Add two numbers.) published procedure Sum(var Ctxt: TSQLRestServerCallBackParams). 1. The method name ("Sum") will be used for the URI encoding..Rev. The ModelRoot is the one defined in the Root parameter of the model used by the application. then use easy functions about JSON or URL-parameters to get the request encoded and decoded as expected. which is enough for our purpose). This method.. Client-Server services via methods Adopt a mORMot To implement a service in the Synopse mORMot framework. MUST have the same exact parameter definition as in the SAD . on Client-side. mORMot Framework . SAD . a perfectly AJAX-friendly request.URI method expects such callbacks to handle the thread-safety on their side. 15.err).Results([]) method is used to return the service value as one JSON object with one "Result" member. the following request URI: GET /root/Sum?a=3. Note that all parameters are expected to be plain case-insensitive 'A'.CallBackGetResult('sum'.32} That is. i.Sum(var Ctxt: TSQLRestServerCallBackParams).['a'.'9' characters.'0'. which may be a bit slower. For our floating-point computation method.2 will let our server method return the following JSON object: {"Result":7. the TSQLRestServer. begin with Ctxt do Results([InputDouble['a']+InputDouble['b']]). b: double): double.'Z'. which refers to the whole execution context: type TSQLRestServerCallBack = procedure(var Ctxt: TSQLRestServerCallBackParams) of object. 1.'b'. Defining the client The client-side is implemented by calling some dedicated methods. In fact. may loose some content for older non Unicode versions of Delphi.b]). and in case of string content. only one Ctxt parameter.. Then we implement this method: procedure TSQLRestServerTest. begin val(aClient. An important point is to remember that the implementation of the callback method must be thread-safe . end.a.. It does make sense even more when handling text. but. i. The Ctxt. InputUTF8[] is to be used in such case. begin with Ctxt do Results([Input['a']+Input['b']]).as stated by Thread-safety (page 204).e.2. the code above using Input[] will introduce a conversion via a variant. 2013 TSQLRestServerCallBack prototype.e. RawUTF8 or variant. end. and providing the service name ('sum') and its associated parameters: function Sum(aClient: TSQLRestClientURI.Rev. The Ctxt variable publish some properties named InputInt[] InputDouble[] InputUTF8[] and Input[] able to retrieve directly a parameter value from its name. It's perhaps some more work to handle a critical section in the implementation.18 Page 230 of 1055 . a. end. we may have coded it as such: procedure TSQLRestServerTest.Result. respectively as Integer/Int64. Therefore.Synopse mORMot Framework Software Architecture Design 1. it's the best way to achieve performance and scalability: the resource locking can be made at the tiniest code level.12&b=4.Sum(var Ctxt: TSQLRestServerCallBackParams). So it is a good idea to use the exact expected Input*[] property corresponding to your value type. double.18 Date: June 16. in practice. For instance. var err: integer. with default MIME-type JSON_CONTENT_TYPE. @Ctxt. end.err). var a. Ctxt.Results([a+b]).Synopse mORMot Framework Software Architecture Design 1.Results() method. then converted into native local variables. Here is how we may implement the fastest possible parameters parsing: procedure TSQLRestServerTest. and the corresponding TSQLRestClientURI (or TMyClient). you can use the CallBackGetResult method to call the service from its name and its expected parameters.. whatever.. . Direct parameter marshalling on server side We have used above the Ctxt.Rev.b]).Input*[] properties to retrieve the input parameters. b: double): double. end. i.) function Sum(a. var err: integer.Use the UrlDecodeNeedParameters function to check that all expected parameters were supplied by the caller in Ctxt.Parameters<>nil do begin UrlDecodeExtended(Ctxt.'A='.) function TMyClient. begin val(CallBackGetResult('sum'.['a'.Call UrlDecodeInteger / UrlDecodeInt64 / UrlDecodeExtended / UrlDecodeValue / UrlDecodeObject functions (all defined in SynCommons. (.Returns().a. just as usual.Parameters). The only not obvious part of this code is the parameters marshaling.mORMot Framework .. as encoded server-side via Ctxt. but you can serve any kind of data.'B='..b. This Client-Server protocol uses JSON here.Parameters. b: TMyObject): double. how the values are retrieved from the incoming Ctxt.Result. just by overriding the content type on the server with Ctxt.'b'. begin val(CallBackGetResult('summyobject'.Sum(var Ctxt: TSQLRestServerCallBackParams).18 Page 231 of 1055 . This later implementation is to be preferred on real applications.Parameters text buffer.Error('Missing Parameter').['a'. var err: integer.. On the Server side.3.Parameters. b: double): double. UrlDecodeExtended(Ctxt. end else Ctxt.Parameters.Result.b: Extended. HTML. with the same database model.Parameters. On the Client side.'A. end. This is pretty easy to use and powerful. typical implementation steps are therefore: .a).. binary.'b'. Note that you can specify most class instance into its JSON representation by using some TObject into the method arguments: function TMyClient.e.SumMyObject(a. 1. but the supplied Ctxt gives full access to the input and output context. 2013 You could even implement this method in a dedicated client method .18 Date: June 16.a.b]). end.B') then begin while Ctxt.. or create your own caller using the UrlEncode() function.. 15.Sum(a.err).which make sense: type TMyClient = class(TSQLHttpClient) // could be TSQLRestClientURINamedPipe (. You have to create the server instance. if UrlDecodeNeedParameters(Ctxt.pas) to retrieve each individual parameter SAD . ).. as a JSON object (via the overloaded Ctxt.g. The powerful UrlDecodeObject function (defined in mORMot. content: RawByteString.Implement the service (here it is just the a+b expression). picture. TSQLRecord. SAD . .4.Length(content).18 Date: June 16.Error(''. Or you can return some binary file.Input['filename']).Returns([]) method expecting field name/value pairs).pas) can be used to un-serialize most class instance from its textual JSON representation (TPersistent.Then return the result calling Ctxt. pdf file. end. i..['filename'. content := StringFromFile(fileName). 1.HTML_NOTFOUND) else Ctxt.aFileName]. since the returned MIME-type can be defined as a parameter to Ctxt.RawUTF8(result))<>HTML_SUCCESS then raise Exception.Returns(Int64ToUtf8(ServerTimeStamp). HTML or binary.18 Page 232 of 1055 . e.e.Rev.) will be interpreted as expected by any standard Internet browser: it could be used to serve some good old HTML content within a page.GetFile(var Ctxt: TSQLRestServerCallBackParams).Synopse mORMot Framework Software Architecture Design 1. binary. with any AJAX application on the client side. 'application/json. end. TStringList. not necessary consume the service via JavaScript . .Returns() .Error() in case of any error. you can return directly a value as plain text: procedure TSQLRestServer. end.HEADER_CONTENT_TYPE+ GetMimeContentType(pointer(content). Returns non-JSON content Using Ctxt. var fileName: TFileName.Returns(content. begin fileName := 'c:\data\'+ExtractFileName(Ctxt. and returns plain text. implemented Server-Side in fast Delphi code. begin Ctxt.g.[result]).Returns() will let the method return the content in any format. If you use HTTP as communication protocol. if content='' then Ctxt.TimeStamp(var Ctxt: TSQLRestServerCallBackParams). you can consume these services. begin if CallBackGet('GetFile'.Results() method or Ctxt. or any content. charset=UTF-8'.HTML_SUCCESS. Using Ctxt.it may be useful to specify another mime-type than the default constant JSON_CONTENT_TYPE. For instance. with default mime-type JSON_CONTENT_TYPE: {"Result":"OneValue"} or a JSON object containing an array: {"Result":["One".mORMot Framework . contentType: RawUTF8.Results() will encode the specified values as a JSON object with one "Result" member.TEXT_CONTENT_TYPE_HEADER).HTML_SUCCESS. 2013 from standard JSON content.fileName)).CreateFmt('Impossible to get file: %s'. Using GetMimeContentType() when sending non JSON content (e."two"]} 15. retrieving the corresponding MIME type from its binary content: procedure TSQLRestServer. The corresponding client method may be defined as such: function TMyClient..GetFile(const aFileName: RawUTF8): RawByteString.. DataAsHex(var Ctxt: TSQLRestServerCallBackParams). those fields are meaningless: in fact.Error('Need a valid record and its ID') else if RetrieveBlob(TSQLRecordPeople. especially in SAD . session handling or low-level HTTP headers (if any).InHead). Server-side implementation can use the TSQLRestServer. Advanced process on server side On server side.Context.RecordClass.'REMOTEIP: '). i.BinToHex(aData)]) else Ctxt. which has several members at calling time.Table or Ctxt. If authentication .CallBackGetResult('DataAsHex'. 1.g. Therefore. the returned TSQLAuthUser instance is a local thread-safe copy which shall be freed when done). It means that a service can be related to any table/class of our ORM framework.e. 15.g. end. you can retrieve e.mORMot Framework . If authentication is not available.5.Call.ID<0) then Ctxt. over the Internet). In practice. the current session. end. user and group IDs are available in Session / SessionUser / SessionGroup fields.Ctxt. all incoming and outgoing values. A corresponding client method may be: function TSQLRecordPeople. aUserAgent := FindIniNameValue(pointer(Ctxt.6. and the table is available in Ctxt. result content will be hashed (using crc32 algorithm) and in case of no modification will return "304 Not Modified" status to the browser.Synopse mORMot Framework Software Architecture Design 1.'USER-AGENT: '). according to its TableName/Id: procedure TSQLRestServerTest. as decoded from RESTful URI. For example.[].DataAsHex(aClient: TSQLRestClientURI): RawUTF8. For instance.Rev.18 Date: June 16.Table<>TSQLRecordPeople) or (Ctxt. Ctxt may indicate the expected TSQLRecord ID and TSQLRecord class. method definition has only one Ctxt parameter. you can set the optional Handle304NotModified parameter of both Ctxt.18 Page 233 of 1055 . and will save a lot of bandwidth. begin Result := aClient. including headers and message body. Depending on the transmission protocol used.Session will contain either 0 (CONST_AUTHENTICATION_SESSION_NOT_STARTED) if any session is not yet started. you can access low-level communication content.Results([SynCommons.SessionGetUser method to retrieve the corresponding user details (note that when using this method. In Ctxt. HTTP header information. begin if (self=nil) or (Ctxt.fID).see below (page 293) . At first. including RESTful URI routing.is used. Browser speed-up for unmodified requests When used over a slow network (e. so you would be able to create easily any RESTful compatible requests on URI like ModelRoot/TableName/ID/MethodName. or 1 (CONST_AUTHENTICATION_NOT_USED) if authentication mode is not active.'Data'. the response will be transmitted and received much faster.TableIndex (if you need its index in the associated server Model). var aData: TSQLRawBlob.Call.Returns() and Ctxt. and publish all service calling features and context. Ctxt.ID.Results() methods to return the response body only if it has changed since last time. 2013 15.Error('Impossible to retrieve the Data BLOB field'). here we return a BLOB field content as hexadecimal.ID. The ID of the corresponding record is decoded from its RESTful scheme into Ctxt.aData) then Ctxt.Call^ member. here is how you can access the caller remote IP address and client application user agent: aRemoteIP := FindIniNameValue(pointer(Ctxt. without the actual result content.InHead). Therefore. and returned to the client with an error message containing the Exception class name and its associated message. or a browser.Ctxt) then Ctxt. this content should be easy to interpret.18 Page 234 of 1055 . this option is therefore unset by default. our RESTful authentication .ServiceMethodByPassAuthentication() call. HTML content. Handling errors When using Ctxt.HTML_NOTFOUND): { "ErrorCode":404. this browser-side caching can be very useful. Note that the framework core will catch any exception during the method execution.18 Date: June 16. But when serving some static content (e. Be aware that you should disable authentication for the methods using this Handle304NotModified parameter. Note that in case of hash collision of the crc32 algorithm (we never did see it happen. the client will receive a corresponding serialized JSON error object. end.mORMot Framework .g.g.Batch(var Ctxt: TSQLRestServerCallBackParams).nil. you may call Ctxt. 200 / "OK" for Results() and Success() methods by default.7. if needed. 15. It will therefore be intercepted by the server process (as any other exception).g. here is how a service not returning any content can handle those status/error codes: procedure TSQLRestServer. and should be enabled only if your client does not handle any sensitive accounting process. any browser-side caching benefit will be voided if authentication is used: browser internal cache will tend to grow for nothing since the previous URIs are deprecated. the framework will return the corresponding generic HTTP status text (e.Error. 2013 case of periodic server pooling (e. e. Ctxt. In fact. or 400 / "Bad Request" for Error()) as an integer value. a false positive "not modified" status may be returned.uses a per-URI signature. but such a mathematical possibility exists).g.Method=mPUT) and RunBatch(nil. for Ctxt. SAD . for instance. via a TSQLRestServer. If no custom text is specified. "ErrorText":"Missing Parameter" } If called from an AJAX client. fixed JSON values or even UI binaries).Error('Missing Parameter'.g.see below (page 293) . 1. and will return a "Internal Server Error" / HTML_SERVERERROR = 500 error code with the associated textual exception details.Error() will specify the HTTP status code (e.Results(). The Ctxt.Returns(). In fact.Input*[] properties. "Bad Request" for default status code HTML_BADREQUEST = 400). Ctxt. and it will be a cache-miss most of the time. But you can have full access to the error workflow. any missing parameter will raise an EParsingException.Success() or Ctxt.Error() method (only the two valid status codes are 200 and 201).Error() method has an optional parameter to specify a custom error message in plain English. calling either Ctxt. begin if (Ctxt. which change very often (to avoid men-in-the-middle attacks). For instance.Success else Ctxt.Rev. In case of an error on the server side. for client screen refresh). In this case.Synopse mORMot Framework Software Architecture Design 1. which will be returned to the client in case of an invalid status code. 18 Date: June 16. or modifying the HTTP headers on the fly). parameter marshalling) is to be done by hand on both client and server side code.18 Page 235 of 1055 . Note that due to this implementation pattern. . so it has some advantages: . the mORMot service implementation is very fast.Synopse mORMot Framework Software Architecture Design 1. so it can be related to any table/class of our ORM framework (like DataAsHex service above). . 2013 15. Windows GDI messages.1. a lot of process (e.g. or it can handle any remote query (e.synopse.g. Named Pipe. and not sensitive to the "Hash collision attack" security issue.It can be tuned to fit any purpose (such as retrieving or returning some HTML or binary data.It has a very low performance overhead. for details. so can be used to reduce server workload for some common tasks. since it publishes one big "flat" set of services. But with this implementation. any AJAX or SOAP requests).info/post/2011/12/30/Hash-collision-attack.Rev. 1.mORMot Framework . over all usual protocols of our framework: HTTP/1. In addition. This is were interfaces enter the scene.8.It is integrated into the RESTful URI model. SAD . Benefits and limitations of this implementation Method-based services allow fast and direct access to all mORMot Client-Server RESTful features. direct in-memory/in-process access..see http://blog. as reported with Apache . The mORMot implementation of method-based services gives full access to the lowest-level of the framework core. building and maintaining a huge SOA system with a "method by method" approach could be difficult. as you can see: . but we'll see it later). to make a difference with a T for a class or other implementation-level type definition. not "how" it is made available. an interface defines a type that comprises abstract virtual methods. This is the so called "abstraction" benefit of interfaces (there are another benefits. The short.18 Page 236 of 1055 .It is named ICalculator.mORMot Framework . just methods (fields are part of the implementation. but. like orthogonality of interfaces to classes. Declaring an interface No.There is no visibility attribute (no private / protected / public / published keywords): in fact.18 Date: June 16. easy definition is that an interface is a declaration of functionality without an implementation of that functionality.There is no fields.Rev.1. sorry. Interfaces Adopt a mORMot 16. not of the interface): in fact. It just sounds like a class definition. . SAD . In Delphi OOP model. and not TCalculator: it is a common convention to start an interface name with a I. interface(-book) is not another social network.n2: integer): integer.1. end. 2013 16. Delphi and interfaces 16.1. In Delphi. . 1. it is just as if all methods were published. we can declare an interface like so: type ICalculator = interface(IInvokable) ['{9A60C8ED-CEB2-4E09-87D4-4A16F496E5FE}'] /// add two signed 32 bit integers function Add(n1.Synopse mORMot Framework Software Architecture Design 1. It defines "what" is available. so we may implement it like this: type TServiceCalculator = class(TInterfacedObject. . but those properties shall redirect to existing getter and setter methods.18 Date: June 16. 16.The classic way. . which is not used either. from the interface point of view: it will be used as implementation of an interface.The abstract way (using an interface). 2013 you can have properties in your interface definition. and we can even implement several interfaces within the same method (just add other interface names after like class(TInterfacedObject. function TServiceCalculator. via read and write keywords.There is a strange number below the interface name. but could be used for the class implementation. called a GUID: this is an unique identifier of the interface . procedure SetBulk(const aValue: string).There is a SetBulk method which is not part of the ICalculator definition .Here we have protected and public keywords .1.you can create such a genuine constant on the editor cursor position by pressing Ctrl + Shift + G in the Delphi IDE. . The "classic" way. .There a fBulk protected field member within this class definition.18 Page 237 of 1055 .Add() method (otherwise the compiler will complain for a missing method). . end.mORMot Framework .2. using an explicit class instance: SAD . Our interface is very basic. begin result := n1+n2. ICalculator. 16. . begin fBulk := aValue.SetBulk(const aValue: string). end.We added ICalculator name to the class() definition: this class inherits from TInterfacedObject. Implementing an interface with a class Now that we have an interface.But the methods are just defined as usual. and implements the ICalculator interface.Add method . Using an interface Now we have two ways of using our TServiceCalculator class: . even if the method is declared as private in the implementation class. procedure TServiceCalculator. You can note the following: . end.Synopse mORMot Framework Software Architecture Design 1.Here we have to code an implementation for the TServiceCalculator. 1.Add(n1.n2: integer): integer.Rev. n2: integer): integer.1. whereas there is no implementation expected for the ICalculator.it is perfectly "abstract".but the Add method can have any visibility. we need to create an implementation. ICalculator) protected fBulk: string. IAnotherInterface). public function Add(n1.so we can add other methods to the implementation class. .3. end. result := Calculator.Create.. 16. try Calculator.b: integer): integer.b: integer): integer. begin Calculator := TServiceCalculator. .FRefCount). begin ICalculator := TServiceCalculator. The generated code could look like this: function MyAdd(a. ..Add(a. There is more than one way to do it One benefit of interfaces we have already told about. var Calculator: ICalculator. if Calculator.b: integer): integer.Free.in fact. but you have got the idea.4. var Calculator: TServiceCalculator.. and use the same interface: SAD .FRefCount=0 then Calculator. is automatically freed when the compiler realizes that the number of references to a given interface variable is zero.FRefCount := 1. this is a bit more optimized than this (and thread-safe).And the performance cost is negligible: this is more or less the same as calling a virtual method (just one more redirection level). the computation is performed with the same exact expression: result := Calculator. finally Calculator.18 Date: June 16. Note that we used a try. we can create another implementation class.Create.We do not need any try. ..1.Free.b).mORMot Framework . Then we can use an interface: function MyAdd(a. not a regular class instance. 1. In fact. begin Calculator := TServiceCalculator. interface variables are reference-counted: that is.We defined the local variable as ICalculator: so it will be an interface.Synopse mORMot Framework Software Architecture Design 1. var Calculator: TServiceCalculator. What's up over there? .b).. result := Calculator.Create.finally block to protect the instance memory resource. finally dec(Calculator. is that it is "orthogonal" to the implementation. the use of the interface is tracked by the compiler and the implementing instance. end.We assigned a TServiceCalculator instance to this interface variable: the variable will now handle the instance life time. In fact.Add(a.finally block in the MyAdd function. Of course.b). the compiler creates an hidden try. end.18 Page 238 of 1055 . end. and the instance will be released as soon as the Calculator variable is out of scope.finally block here: in Delphi. try result := Calculator. 2013 function MyAdd(a. .We called the method just as usual .b).Rev. once created. end.Add(a.Add(a. execution will be in-place.1. result := Calculator.. those principles are general statements you may already found out by yourself.18 Date: June 16. Here comes the magic Now you may begin to see the point of using interfaces in a client-server framework like ours.Liskov substitution principle: the notion that “objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program” . Here the computation is not the same: we use n2+n1 instead of n1+n2.”.”. you will benefit of an open and powerful implementation pattern.b: integer): integer.n2: integer): integer.Add(n1. The client application will transmit method calls (using JSON instead of much more complicated XML/SOAP) to the server (using a "fake" implementation class created on the fly by the framework).Add(a. first we'll take a look at good principles of playing with interfaces. begin result := n2+n1. 16.. and in this case. .Single responsibility principle: the notion that an object should have only a single responsibility.18 Page 239 of 1055 . Dependency injection is one method of following this principle. 2013 type TOtherServiceCalculator = class(TInterfacedObject. of course. so very fast. by using its TOtherServiceCalculator class name: function MyOtherAdd(a. . If you start doing serious object-oriented coding. should be open for extension.b). 16. calling all expected methods on both sides. but having all the implementation logic on the server side. By creating a whole bunch of interfaces for implementing the business logic of your project. those principles are best-practice SAD . function TOtherServiceCalculator. as JSON. Our mORMot is able to use the same interface definition on both client and server side. end.Open/closed principle: the notion that “software entities . ..Synopse mORMot Framework Software Architecture Design 1.also named as "design by contract". More on this later on. end..Rev. and the result will be sent back to the client.5. but we can use this another method for our very same interface.2. 1.mORMot Framework . The same interface can be used on the server side. Do not depend upon concretions. If you have some programming skills. this will result into the same value. end. then the execution will take place on the server (with obvious benefits).Interface segregation principle: the notion that “many client specific interfaces are better than one general purpose interface. begin ICalculator := TOtherServiceCalculator.Dependency inversion principle: the notion that one should “Depend upon Abstractions. var Calculator: ICalculator. .. but closed for modification”. ICalculator) protected function Add(n1. SOLID design principles The acronym SOLID is derived from the following OOP principles (quoted from the corresponding Wikipedia article): . n2: integer): integer.Create.. They shall be open for extension. 1. 16. Following this Single responsibility principle may sound simple and easy.2. In fact. at the same time: .One class shall have only one reason that justifies changing its implementation.And database requests feature is handled by TSQLDBStatement instances using dedicated NewConnection / ThreadSafeConnection / NewStatement methods. . You won't have any GUI related method on the Server side. .2. you may change how a database connection is defined (e. When you define an ORM object. if you want to change the GUI. do not put GUI methods within.see External database access (page 166): .g. . Our ORM architecture will enforce you. AJAX Client.Rigidity – Hard to change something because every change affects too many other parts of the system.see Multi-tier architecture (page 61). Therefore: . and the Client side could use the objects instances with several GUI implementations (Delphi Client. Naturally.mORMot Framework .). we tend to join responsibilities in our class definitions. and you won't have to change the statement implementation itself. a TRectangle object should not have both ComputeArea and Draw methods defined at once . and the second is to render it on GUI.Synopse mORMot Framework Software Architecture Design 1. Another example is how our database classes are defined in SynDB. but it is always up to the end coder to design properly his/her interfaces. the fact that our TSQLRecord class definitions are common to both Client and Server sides makes this principle mandatory. . . unexpected parts of the system break.The connection properties feature is handled by TSQLDBConnectionProperties classes.1. to follow this principle.18 Date: June 16. They certainly help to fight the three main code weaknesses: .Classes shall be abstract from the particular layer they are running .pas . add a property to a TSQLDBConnectionProperties child).Immobility – Hard to reuse in another application because it cannot be disentangled from the current application.18 Page 240 of 1055 . Open/closed principle When you define a class or a unit. SAD .Rev..The actual living connection feature is handled by TSQLDBConnection classes. by its Client-Server nature.. it is one of the hardest principles to get right.they would define two responsibilities or axis of change: the first responsibility is to provide a mathematical model of a rectangle. but in fact.2. Single responsibility principle When you define a class. Therefore. Therefore. 16. you won't have to recompile the TSQLRecord class and the associated database model. it shall be designed to implement only one feature. 2013 guidelines you would gain following. The so-called feature can be seen as an "axis of change" or a "a reason for change". .Classes shall have few dependencies on other classes. For instance.Fragility – When you make a change. you should not have to modify its implementation.Code extendibility.Code re-usability.18 Page 241 of 1055 .2. SAD . . abstraction is the key. and/or make the TSQLRecord published properties read-only and using some client-side constructor with parameters. Even if Open Source paradigm allows you to modify the supplied code.No singleton nor global variable .may encourage user contributions in order to fulfill the Open/closed design principle: . When a new version is available. Furthermore.. Even the source code repository is available .RTTI is dangerous . then use specific overridden classes for each and every implementation: this is for instance how Client-Server classes were implemented . but you got the main idea. and most of the framework enhancements have come from user requests. In fact.Rev. All your code shall not depend on a particular implementation. .at http://synopse. you would be able to retrieve it for free from our web site. But benefits will be huge. . Following this principle will make your code far away from a regular RAD style.The main framework units shall remain inviolate.3. this shall not be done unless you are either fixing a bug or adding a new common feature.e.All object members shall be declared private or protected . In short.Your application code extends the Synopse mORMot Framework by defining your own classes or event handlers . 2013 .: . .mORMot Framework . i. then build a new enhanced version of your application. 16. we should better learn from.see below (page 312) .But closed for modification. Barbara Liskov is a great computer scientist. In order to implement this principle. let our framework use RTTI functions for its own cooking..this illustrates the closed for modification design. . this principle will ensure your code to be ready to follow the main framework updates (which are quite regular). This is in fact the purpose of our http://synopse. and common to all users .that is. . Liskov substitution principle Even if her name is barely unmemorable.18 Date: June 16. 1.Code maintainability.this is how it is open for extension. web site. When designing our ORM. without the need to hack the framework source code. we tried to follow this principle.see Client-Server process (page 196). but do not use it in your code. replace your files locally. The framework Open Source license . several conventions could be envisaged: .Synopse mORMot Framework Software Architecture Design 1.You shall better define some abstract classes. Conformance to this open/closed principle is what yields the greatest benefit of OOP. You should define your own units and classes.info.ever.this is a good idea to use Service-oriented architecture (page 63) for defining server-side process.info/fossil. Some other guidelines may be added.and allows you to follow the current step of evolvment of the framework. . then to change a method behavior (this will also probably break the single responsibility principle: each enumeration shall be defined as a class).Use the "behavior" design pattern. .Need to explicitly add all child classes units to the parent class unit uses clause.. task performed. since the behavior of a TSquare object is not consistent with the behavior of a TRectangle object (square width always equals its height.e.Statements like if aObject is TAClass then begin . Most ORM methods expect a TSQLRest parameter to be supplied. .mORMot Framework . The main advantages of this coding pattern are the following: .this principle is therefore mandatory for implementing unitary testing to your project. and its postcondition by a stronger one" . Some patterns which shall not appear in your code: . you may only replace its precondition by a weaker one.18 Page 242 of 1055 .e. i.Rev.see below (page 247) . .. Your code shall refer to abstractions. then objects of type TParent may be replaced with objects of type TChild (i. of or nested if . the Meyer's rule defined as "when redefining a routine [in a derivative].Follow the concept of Design by Contract. . . if a square may be a rectangle. . you should: . . but which failed when tested at higher level if the Liskov principle was broken. whereas it is not the case for most rectangles).you can have implementation which behave correctly when tested individually. .use of preconditions and postconditions also enforce testing model. . not to implementations. By using only methods and properties available at classes parent level. it would signify that TSQLRestServer or TSQLRestClient instances can be substituted to a TSQLRest object. testing would be available not only at isolation level (testing each child class). a TSquare object is definitively not a TRectangle object...).. objects of type TChild may be substitutes for objects of type TParent) without altering any of the desirable properties of that program (correctness. from the client point of view . you may consider using separated object types for implementing persistence and object creation (this is the common separation between Factory and Repository).. but also at abstracted level.the parent class would need to be modified whenever a new derivative of the base class is defined. your code won't need to change because of a specific implementation..Write your tests using abstract local variables (and this will allow test code reuse for all children classes).Code re-usability is enhanced by method re-usability: a method defined at a parent level does not require to be implemented for each child. the open/close principle will be ..for instance.Use an enumerated item and a case .If this principle is violated.Define a method which will stay abstract for some children. 2013 Her "substitution principle" states that.. if TChild is a subtype of TParent. when defining your objects hierarchy . SAD .e.18 Date: June 16.. you will be for instance able to stub or mock an interface or a class .Thanks to this principle. in a parent method.Furthermore. In order to fulfill this principle.Separate your classes hierarchy: typically. i. The SOA and ORM concepts as used by our framework are compatible with the Liskov substitution principle. 1. etc.Synopse mORMot Framework Software Architecture Design 1. end else if aObject is TAnotherClass then . For our framework. and certainly breaks the Liskov's substitution principle.Synopse mORMot Framework Software Architecture Design 1. In conventional application architecture. lower-level components are designed to be consumed by higher-level components which enable increasingly complex systems to be built.18 Date: June 16. with the same exact code. or Dependency Injection are then employed to facilitate the run-time provisioning of the chosen low-level component implementation to the high-level component.4. This great Client-Server SOA implementation pattern . and existing only with the high-level component package. Details should depend upon abstractions. In other languages (like Java or .16.5. Weak pointers The memory allocation model of the Delphi interface type uses some kind of Automatic Reference Counting (ARC). no client should be forced to depend on methods it does not use. Circular reference and (zeroing) weak pointers 16. 16. it helps creating small and business-specific contracts. A simple implementation pattern could be to use only interfaces owned by. and allows the use of native Delphi interface to call services from an abstract factory. 1.3. This design limits the reuse opportunities of the higher-level components.2. 16. which can be executed on both client and server side.3.18 Page 243 of 1055 . As a result.mORMot Framework . the stateless used design will also reduce the use of 'fat' session-related processes: an object life time can be safely driven by the interface scope.Rev. a SOA framework like mORMot has to offer so-called Weak pointers and Zeroing Weak SAD . The goal of the dependency inversion principle is to decouple high-level components from low-level components such that reuse with different low-level component implementations becomes possible.Net).2. various patterns such as Plug-in. Service Locator. change. a more direct Design by Contract implementation pattern is also available (involving a more wide usage of interfaces). . Both should depend on abstractions. it will help a system stay decoupled and thus easier to re-factor. and redeploy. 16. By defining Delphi interface instead of plain class.helps decoupling all services to individual small methods.Abstractions should not depend upon details. In a nutshell.High-level modules should not depend on low-level modules. Interface segregation principle This principle states that once an interface has become too 'fat' it shall be split into smaller and more specific interfaces so that any clients of the interface will only know about the methods that pertain to them. Our Client-Server architecture facilitated this decoupling pattern. 2013 Furthermore. In this case also. Beginning with revision 1. In order to avoid memory and resource leaks and potential random errors in the applications (aka the terrible EAccessViolation exception on customer side) when using Interfaces (page 236). our framework allows direct use of interfaces to implement services.see Server side Services (page 227) . Dependency Inversion Principle Another form of decoupling is to invert the dependency between high and low level of a software design: .1. Of course.18 Date: June 16. Unfortunately. Even when all other references are removed. all references are defined: . function GetParent: IParent. One common solution is to use Weak pointers. end. it will increase memory use. property Parent: IParent read GetParent write SetParent. property Child: IChild read GetChild write SetChild. string.Synopse mORMot Framework Software Architecture Design 1. . end. they still will hold on to one another and will not be released.SetChild(const Value: IChild). The following implementation will definitively leak memory: procedure TParent. by a chain of objects that might have the last one in the chain referring back to an earlier object. tied to an implementation class. but reference objects. variant or a dynamic array). In order to avoid such issues when performance matters. procedure TChild. end.as weak references for pointer and class instances.mORMot Framework . currency. since the circular references are handled by their memory model: objects lifetime are maintained globally by the memory manager. begin FParent := Value. In Delphi.Rev.with explicit copy for low-level value types like integer. and may slow down the application when garbage collector enters in action. function GetChild: IChild.as strong reference with reference counting for interface instances. most common kind of reference-copy variables (i. which are not value objects. this pattern is not applicable to interface. but the target interface has a strong pointer back to the original. experts tend to pre-allocate and re-use objects: this is one common limitation of this memory model. . begin FChild := Value. Note that garbage collector based languages (like Java or C#) do not suffer from this problem. See the following interface definition for instance: IParent = interface procedure SetChild(const Value: IChild). By default in Delphi. variant.SetParent(const Value: IParent).18 Page 244 of 1055 . widestring.g. double or record (and old deprecated object or shortstring). .via copy-on-write with reference counting for high-level value types (e. and why Delphi is still a good SAD . dynamic array or string) solve this issue by implementing copy-on-write. end. which can't be copied. IChild = interface procedure SetParent(const Value: IParent). 2013 pointers features. by which the interface is assigned to a property without incrementing the reference count. This can also happen indirectly. Int64. 1. The main issue with strong reference counting is the potential circular reference problem. slowdown the process due to additional actions during allocation and assignments (all objects and their references have to be maintained in internal lists).e. This occurs when an interface has a strong pointer to another. function HasChild: boolean. Synopse mORMot Framework Software Architecture Design 1. ARC is told to be much more efficient.7 Lion. Therefore.Value). thanks to ARC. end. But since weak references don't contribute to an interface reference count. begin SetWeak(@FParent. a class instance should not be deallocated if there are still outstanding references to it. the following function was defined in mORMot..and also Objective C) when it deals with performance and stability.SetChild(const Value: IChild). Zeroing weak pointers But there are still some cases where it is not enough.. It will by-pass the reference counting.3.pas: SAD .Rev. procedure TChild. 2013 candidate (like unmanaged C or C++ . 16. It will assign the `interface` to a field by assigning the `pointer` of this instance to the internal field.which both are very sensitive on "modest" mobile devices.whereas the Delphi compiler just relies on a out-of-scope pattern.g. 16. to allow some referenced objects to be reclaimed by garbage collection: but it is a diverse mechanism.2. And voilà! No access violation any more! Such a Zeroing ARC model has been implemented in Objective C by Apple. but for objects. When this happens.18 Date: June 16. end. 1. ARC is available not only for interfaces. due to its deterministic nature: Apple's experts ensure that it does make a difference. ARC's Zeroing Weak pointers come to mind.pas: procedure SetWeak(aInterfaceField: PIInterface. A debugging nightmare. a class instance can be released when there are outstanding weak references to it. const aValue: IInterface). under the same naming. In short. so memory won't be leaked any more.SetParent(const Value: IParent). Handling weak pointers In order to easily create a weak pointer. and is certainly more sophisticated than the basic implementation available in the Delphi compiler: it is told (at least from the marketing paper point of view) to use some deep knowledge of the software architecture to provide an accurate access to all instances . in replacement (and/or addition) to the previous manual memory handling implementation pattern: in its Apple's flavor. the automatic zeroing of the outstanding weak references prevents them from becoming dangling pointers. end.Value). So mORMot will try to offer a similar feature. it could be used as such: procedure TParent. Some memory leak or even random access violations could occur. even if the Delphi compiler does not implement it (yet). In regard to classic garbage collector memory model.18 Page 245 of 1055 . starting with Mac OS X 10. In order to easily create a so-called zeroing weak pointer. such languages have to introduce some kind of "weak pointers". In some cases (e. when using an object cache). your phone UI won't glitch during background garbage recycling.mORMot Framework .3. Under normal circumstances. in term of memory use and program latency . the following function was added to mORMot. begin SetWeak(@FChild. In order to solve this issue.3. begin PPointer(aInterfaceField)^ := Pointer(aValue). It means that weak references will be set to nil when the object they reference is released. mORMot Framework . and will ensure that weak pointers are effectively zeroed when SetWeakZero() is used: function TParent. begin SetWeakZero(self.Value). is thread-safe and is compatible with most Delphi versions . to avoid the need of supplying the self parameter.@FChild. begin SetWeakZero(self.No performance penalty for other classes not involved within weak references.Rev. // here Child is destroyed Check(Parent. end. but unfortunately.3. But it will allow to write code as such: procedure TParent.SetChild(const Value: IChild).Value). the following code is supplied in the regression tests. due to the fact that a list of all weak references has to be maintained per class instance. 16.18 Page 246 of 1055 . Here. and equals false when SetWeakZero() has been used to assign the Child element to its Parent interface. begin result := FChild<>nil.SetParent(const Value: IParent).HasChild: boolean. The Delphi RTL/VCL itself use similar code when necessary.Synopse mORMot Framework Software Architecture Design 1. 1.Low memory [email protected]. Child := nil. using some nice tricks (like per-instance optional speed up using a void IWeakInterface interface whose VMT slot will refer to the references list). But the SetWeakZero() function has a much more complex implementation. .Compatible with Delphi 6 and later (avoid syntax tricks like generic).4. end. end. Weak pointers functions implementation details The SetWeak() function itself is very simple. begin SetWeak0(@FChild. the class helper implementation is so buggy it won't be even able to compile before Delphi XE version of the compiler. and good scalability when references begin to define huge graphs.. A potential use case could be: procedure TParent. . Some good existing implementations can be found on the Internet: .which is mandatory at least on the server side of our framework. .18 Date: June 16. For instance.Andreas Hausladen provided a classical and complete implementation at http://andy.HasChild=(aWeakRef=weakref). and set to nil when this referring instance is released.SetChild(const Value: IChild). We also defined a class helper around the TObject class.but it will slow SAD .'ZEROed Weak'). aObjectInterfaceField: PIInterface.Thread safety . 2013 procedure SetWeakZero(aObject: TObject. aWeakRef=weakref is true when SetWeak() has been called. The mORMot implementation tries to implement: . const aValue: IInterface).Best performance possible when processing the Zeroing feature. . procedure TChild.Value). end.de/blog/2009/06/weak-interface-references. so will only slow down the exact class which is used as a weak reference. . 2013 down all TObject.1. . See the TSetWeakZeroClass and TSetWeakZeroInstance implementation in mORMot. i. In the future. .1. 16. two features are to be available when handling interfaces: . .pas for the details. Dependency injection A direct implementation of dependency injection at a class level can be implemented in Delphi as such: .FreeInstance calls (i. The implementation included within mORMot uses several genuine patterns.blogspot. and not others (also its inherited classes won't be overridden) .An external factory could be used to retrieve an interface instance.The unused vmtAutoTable VMT slot is used to handle the class-specific orientation of this feature (similar to TSQLRecordProperties lookup as implemented for DI # 2. we may implement automated dependency injection.More recently.4. without using generic definitions .see below (page 257).aspx.html. 16. we will use the more direct constructor-based pattern for a simple "forgot my password" scenario. . or class constructor shall receive the dependencies as parameters. a generic-based solution (not thread-safe nor optimized for speed).e. Interfaces in practice: dependency injection.hashing will start when it will be worth it.Stubbing and mocking of interfaces for proper testing. within Free / Destroy) and won't allow any overridden FreeInstance method implementation.3). We will show now how mORMot provides all needed features for such patterns.4.Vincent Parrett proposed at http://www.All external dependencies shall be defined as abstract interface.com/Resources/Blogs/PostId/410/WeakRefence-in-Delphi-solving-circularinterfac.Synopse mORMot Framework Software Architecture Design 1. Stefan Glienke published at http://delphisorcery.It makes use of our TDynArrayHashed wrapper to provide a very fast lookup of instances and references. not requiring to inherit from a base class.Dependency injection. but requiring to inherit from a base class for any class that can have a weak reference pointing to it. when compared to existing solutions: . SAD . 1. Here. for best speed and memory use. another generic-based solution..It will hack the TObject. stubs and mocks In order to fulfill the SOLID design principles (page 239). then transmitted via SMS.FreeInstance. and its record shall be updated in the database. but not thread-safe and suffering from the same limitations related to TObject..18 Date: June 16.18 Page 247 of 1055 . .FreeInstance at the class VMT level.finalbuilder.e.Rev.mORMot Framework . Using an external factory can be made within mORMot via TServiceFactory . for any list storing more than 32 items.and it will allow custom override of the virtual FreeInstance method.fr/2012/06/weak-interface-references. testing a simple "forgot my password" scenario: a password shall be computed for a given user name. public constructor Create(const aUserRepository: IUserRepository. U.Password := Int32ToUtf8(Random(MaxInt)). then compute a new password. we won't use TSQLRecord nor any other classes. The dependencies are defined with the following two interfaces(only the needed methods are listed here. begin U := fUserRepository. Password: RawUTF8. it is supposed to persist (save) the new user information SAD . const aSmsSender: ISmsSender). fSmsSender: ISmsSender. end.18 Page 248 of 1055 . end.Send('Your new password is '+U.Password. fSmsSender := aSmsSender. const aSmsSender: ISmsSender). procedure Save(const User: TUser). end. if fSmsSender. begin fUserRepository := aUserRepository.Synopse mORMot Framework Software Architecture Design 1.MobilePhoneNumber) then fUserRepository.ILoginController) protected fUserRepository: IUserRepository. It can also be independent to the persistency layer. end.Create(const aUserRepository: IUserRepository. but a real interface may have much more members. The difference between Data Transfer Objects and business objects or Data Access Objects (DAO) like our TSQLRecord is that a DTO does not have any behavior except for storage and retrieval of its own data. ID: Integer. var U: TUser. end. 2013 This is the class we want to test: TLoginController = class(TInterfacedObject. Now. to follow the interface segregation SOLID principle): IUserRepository = interface(IInvokable) ['{B21E5B21-28F4-4874-8446-BD0B06DAA07F}'] function GetUserByName(const Name: RawUTF8): TUser. let's come back to our TLoginController class. 1.18 Date: June 16. just plain records.Save(U). ISmsSender = interface(IInvokable) ['{8F87CB56-5E2F-437E-B2E6-B3020835DC61}'] function Send(const Text. which will be used as neutral means of transmission.U. but not too much. On success. Using a record in Delphi ensure it won't be part of a complex business logic. end. Here. procedure ForgotMyPassword(const UserName: RawUTF8). and send it via SMS to the user's mobile phone.ForgotMyPassword(const UserName: RawUTF8). as implemented underneath our business domain.GetUserByName(UserName). but will remain used as value objects.Rev. Note also that all those code will use a plain record as Data Transfer Object (DTO): TUser = record Name: RawUTF8. Number: RawUTF8): boolean.mORMot Framework . MobilePhoneNumber: RawUTF8. Here is the method we want to test: procedure TLoginController. It will retrieve a TUser instance from its repository. The constructor will indeed inject its dependencies into its own instance: constructor TLoginController. by defining two dedicated classes. and we would need a true mobile phone or Internet gateway to send the password.ForgetThePassword.Mocks are described as a fake object that helps decide if a test failed or passed. Everything else is defined as a stub.3. var SmsSender: ISmsSender.4. you define the stubs needed to let your test pass.4. named TInterfaceStub and TInterfaceMock. 16. we only want to ensure that when the "forgot my password" scenario is executed. Why use fake / emulated interfaces? Using the real implementation of IUserRepository would expect a true database to be available. and define one mock which will pass or fail the test depending on the feature you want to test. .2. ready to be set with our stubbed / mocked implementation classes. Thus a fake object merely provides a set of method stubs. the user record modification is persisted to the database. and our two local variables. Stubs and mocks In the book "The Art of Unit Testing" (Osherove. since sending a SMS does cost money. In order to maximize your ROI. it is created via the TInterfaceStub generator. 16. with as many stubs as necessary to let the test pass.Synopse mORMot Framework Software Architecture Design 1. Therefore the name. One possibility could be to define two new dedicated classes. able to define easily the behavior of such classes. with some potential issues on existing data. But it will be obviously time consuming and error-prone. a distinction is drawn between stub and mock objects: . there should be only one mock per test.mORMot Framework .18 Date: June 16. The TSynTestCase child method could start as such: procedure TMyTest. Roy .18 Page 249 of 1055 . 16.Rev. 2013 to the database. UserRepository: IUserRepository. Our mORmot framework follows this distinction. the mORMot framework proposes a simple and efficient way of creating "fake" implementations of any interface. just by defining the minimum behavior needed to run the test. Defining stubs Let's implement our "forgot my password" scenario test.4. by verifying if an interaction on an object occurred or not. 1. This is all we need: one dedicated test case method. In mORMot.Stubs are the simpler of the two families of fake objects. the class implementing ISmsSender in the final project should better not to be called during the test phase. This may be typical case when writing the test could be more complex than writing the method to be tested. Using a mocking/stubbing framework allows quick on-the-fly generation of interface with unique behavior dedicated to a particular test. implementing both IUserRepository and ISmsSender interfaces. In mORMot. it is created via the TInterfaceMock generator.4.2009). In short.see below (page 307). simply implementing the same interface as the object that they represent and returning pre-arranged responses. and allow you to focus on your business logic. which will link the fake object to an existing TSynTestCase instance . SAD . For our testing purpose. In practice. Similarly. 18 Date: June 16. When the UserRepository generated instance is released. .Check() be called with a boolean condition reflecting the test validation status of every rule. What is nice with this subbing / mocking implementation is that: . Let's put all this together. it is as simple as: TInterfaceStub.SmsSender) do try ForgotMyPassword('toto'). and let them return default values. the associated TInterfaceStub data will also be freed (and in case a mock. Running the test Since we have all the expected stub and mock at hand.5.Password. if fSmsSender.mORMot Framework .Save(U).Create(UserRepository. without any actual coding in Delphi.SmsSender). With mORMot. let's run the test itself: with TLoginController. 16.MobilePhoneNumber) then fUserRepository. We provide the TMyTest instance as self to the TInterfaceMock constructor. U.qoEqualTo.Password := Int32ToUtf8(Random(MaxInt)).Rev. ExpectsCount('Save'. we run the actual implementation method. and. finally Free.Send('Your new password is '+U.UserRepository. to indicate a successful sending. with additional line of code needed.ForgotMyPassword(const UserName: RawUTF8). It will create a fake class (here called a "stub") emulating the whole ISmsSender interface. and the mORMot generator class will be TInterfaceMock: TInterfaceMock. begin U := fUserRepository. That is. in this case. nor class definition.Synopse mORMot Framework Software Architecture Design 1. end. end.18 Page 250 of 1055 .4. var U: TUser. Defining a mock Now we will define another fake class. which will call our fake methods: procedure TLoginController.GetUserByName(UserName). Returns('Send'.1). We should ensure that it returns true.[true]).self). 16. we will need to implement ISmsSender. That is. to associate the mocking aspects with this test case.1). any registered Expects*() rule will let TMyTest. 2013 First of all. store it in the local SmsSender variable.4. The ExpectsCount() method is indeed where mocking is defined. only Send matters for us: TInterfaceStub will create all those methods. so it is called a "mock".Create(TypeInfo(IUserRepository).6. SAD . 1.The "fluent" style of coding makes it easy to write and read the class behavior. check that the Save method has been called exactly one time (qoEqualTo. TInterfaceMock will check all the Expects*() rules. and let its Send method return true.U. any expectations will be verified).Send method. which may fail the test. .Memory allocation will be handled by the framework: when SmsSender instance will be released.Create(TypeInfo(ISmsSender).Even if ISmsSender has a lot of methods. UserRepository: IUserRepository. we remembered to call the Save() method properly: procedure TMyTest.Verify('Save'). end. Spy := TInterfaceMockSpy. Features and motivations Our mORMot framework is therefore able to stub or mock any Delphi interface. ICalc.qoEqualTo. the best way to explain what a library does is to look at the code using it. You can even mix the two aspects in the same instance! It is just a matter of taste and opportunity for you to use the right pattern. If you want to follow the "test spy" pattern (i.ICalc.SmsSender). Spy.UserRepository. With mORMot.Create(UserRepository. then use it as intended. Spy: TInterfaceMockSpy. Here is an example (similar to the one shipped with RhinoMocks) of verifying that when we execute the "forgot my password" scenario. And.Create(TypeInfo(IUserRepository).self).mORMot Framework . UserRepository: IUserRepository. no expectation defined a priori.[true]). with TLoginController. var SmsSender: ISmsSender. end.1).20).1.1).Synopse mORMot Framework Software Architecture Design 1.Rev.SmsSender) do try ForgotMyPassword('toto').18 Page 251 of 1055 . but manual check after the execution).Create(TypeInfo(IUserRepository).Create(UserRepository. This is something unique with our library: you can decide if you want to use the classic "expect-run-verify" pattern.Create(TypeInfo(ISmsSender).UserRepository.5.30) If you want to follow the "test spy" pattern. you can use: SAD .Multiply(10.self).Create(TypeInfo(ICalculator).ForgotMyPassword. 2013 16. end. finally Free.self). ICalc. finally Free.. you pick up your mocking class (either TInterfaceMock or TInterfaceMockSpy).18 Date: June 16.Add(10. that's all. with TLoginController.5. since the verification will take place when IUserRepository instance will be released.20]. Stubs and Mocks in mORMot 16. begin TInterfaceStub. ExpectsCount('Save'.SmsSender) do try ForgotMyPassword('toto'). or the somewhat more direct "run-verify" / "test spy" pattern. As usual.[10.ForgotMyPassword.Create(TypeInfo(ISmsSender).qoEqualTo. you can use: procedure TMyTest. TInterfaceMock.[true]). For another easier pattern.qoEqualTo. ExpectsCount('Multiply'. begin TInterfaceStub.SmsSender). end. like the one in the Mockito home page: TInterfaceMock.e. ExpectsCount('Add'. var SmsSender: ISmsSender.. 1. Returns('Send'.1). Returns('Send'. Stubbed methods can use delegates or event callbacks with TInterfaceStub. . .2. not only the function result (as other Delphi implementations does.Clear distinction between mocks and stubs.Mocks are directly linked to mORMot's unitary tests / test-driven classes .mORMot Framework . on which mORMot does not rely). . even in other languages / platforms like the two above. ICalc. or by supplying JSON arrays (needed e. depending on your testing expectations.18 Page 252 of 1055 .ForgotMyPassword(const UserName: RawUTF8).Verify('Add'). you will find out that the features included in mORMot are quite complete: .Verify('Multiply'.Handle methods with var. with TInterfaceStub.ICalc.e.30) Mock. .self). .30]).Returns(). for the whole method or following parameters/arguments matchers.pas features.[10. when the interface is no longer required.Mocking validation against number of execution of a method. var U: TUser.see below (page 307).Stubbing of any method. ICalc. Stubbing complex return values Just imagine that the ForgotMyPassword method does perform an internal test: procedure TLoginController. with two dedicated classes.Fails() definitions. 16. . . for the whole method or following parameters/arguments matchers. and avoid potential memory leaks. 2013 Mock := TInterfaceMockSpy.20).Most common parameters and results can be defined as simple array of const in the Delphi code. If you compare with existing mocking frameworks. . begin SAD . if this is the behavior to be tested. due to a limitation of the TVirtualInterface standard implementation.Mocking via "expect-run-verify" or "run-verify" (aka "test spy") patterns. which does not rely on the slow and limited TVirtualInterface.Auto-release of the TInterfaceStub TInterfaceMock TInterfaceMockSpy generator instance.g.Add(10. with When clauses). returning default values for results. for more complex structures like record values).18 Date: June 16.Execution trace retrieval in easy to read or write text format (and not via complex "fluent" interface e.5. 1.Very good performance (the faster Delphi mocking framework. on choice. or the global execution trace .Executes() rule definitions.Works from Delphi 6 up to XE4 .i. to run a more complex process. or a method with arguments/parameters matchers. . for the whole method or following parameters/arguments matchers. including easy definition of returned results values. . . named TInterfaceStub and TInterfaceMock.Raises() rule definitions.Multiply(10. nor the RTTI. out or function result returned values . .Mocked methods can trigger test case failure with TInterfaceMock. for sure). due to very low overhead and its reuse of mORMot's low-level interface-based services kernel using JSON serialization. Mock.Definition of the stubbed behavior via a simple fluent interface.since no use of syntax sugar like generics.Stubbed methods can also raise exceptions with TInterfaceStub.Create(TypeInfo(ICalculator).Rev. but all outgoing values.in this case. pass count can be compared with operators like < <= = <> > >= and not only the classic exact-number-of-times and at-least-once verifications. for the whole method or following parameters/arguments matchers.g. . as an array of values. to minimize the code to type. .Synopse mORMot Framework Software Architecture Design 1. Name=UserName). to ensure it will return a TUser value matching U.Name='toto': var UserRepository: IUserRepository. 16. Executes('Subtract'. without the need of writing a whole implementation class.18 Page 253 of 1055 .GetUserByName(UserName). as expected by mORMot's data marshaling. 1.the easiest and safest to work with.3.Password := Int32ToUtf8(Random(MaxInt)). .IntSubtractVariant( Ctxt: TOnInterfaceStubExecuteParamsVariant).qoEqualTo.RecordSaveJSON(U. begin result := n1-n2.Password. it could be very handy to define a complex process for a given method.Via some Named[] variant properties (which are the default for the Ctxt callback parameter) .. with three parameters marshaling modes: .'"toto"'.18 Date: June 16. The callback function can be defined as such: procedure TTestServiceOrientedArchitecture..U. Assert(U.Save(U).5.self). callback shall use Ctxt[''] property to access the parameters and result as variant values.Name := 'toto'. Let's emulate the following behavior: function TServiceCalculator.Name will equal ''. GetUserByName stubbed method will return a valid but void record. end. Delegate with named variant parameters You can stub a method using a the Named[] variant arrays as such: TInterfaceStub. TInterfaceMock.Directly as a JSON array text (the fastest.5.3. since by default.5. Returns('GetUserByName'.Substract(10.. A delegate or event callback can be specified to implement this process.1. 16. (. Stubbing via a custom delegate or callback In some cases. end. . ExpectsCount('Save'. so the highlighted line will raise an EAssertionFailed exception.Create(TypeInfo(IUserRepository). n2: double): double.Send('Your new password is '+U.ICalc). This will fail the test for sure. since native to the mORMot core). Here is how we may enhance our stub.IntSubtractVariant).MobilePhoneNumber) then fUserRepository.Via some Input[] and Output[] variant properties.. 2013 U := fUserRepository.Synopse mORMot Framework Software Architecture Design 1. SAD .1. The only trick in the above code is that we use RecordSaveJSON() function to compute the internal JSON representation of the record.1). U. That is.Create(TypeInfo(ICalculator). It means that U.mORMot Framework . if fSmsSender.UserRepository.TypeInfo(TUser))).) Check(ICalc.5)=9). begin Ctxt['result'] := Ctxt['n1']-Ctxt['n2']. (.) U.Rev.Subtract(n1. end. U: TUser. 5'. .Named['n2'].Substract(100.18 Date: June 16.. Ctxt. if you add or rename a parameter).18 Page 254 of 1055 .Input[0] = 100.]) and in the variant arrays: Ctxt. Delegate with JSON parameters You can stub a method using a JSON array as such: TInterfaceStub. but only var or out parameters. begin with Ctxt do Output[0] := Input[0]-Input[1]. MyStub.Result = '[79.. Executes('Subtract'.Named['n1']-Ctxt. you have in TOnInterfaceStubExecuteParamsJSON: Ctxt. in most cases.Synopse mORMot Framework Software Architecture Design 1. The callback shall be defined as such: procedure TTestServiceOrientedArchitecture.3. 2013 In fact.Error() method with an associated error message to notify the stubbing process of such a failure. If the method is defined as a procedure and not as a function.Params = '100.. // =n1 at method call // =n2 at method call // =result after method call In case of additional var or out parameters. which is always the function result. // result := n1-n2 end.g.. (.Named[] default property.1. It should be (a bit) faster to execute: procedure TTestServiceOrientedArchitecture. 16.Input[1] = 20. That is.Output[0] = 79.mORMot Framework . we use the Ctxt.n2: double): double. var P: PUTF8Char. 16. and Output[] index follows the exact order of var and out parameters plus any function result. // at method call Ctxt. Using named parameters has the advantage of being more explicit in case of change of the method signature (e.Rev. Just as with TOnInterfaceStubExecuteParamsJSON implementation.20.ICalc). Input[] index follows the exact order of const and var parameters at method call.5.Returns([. directly by using the Input[] and Output[] indexed properties. those should be added to the Output[] array before the last one. It should be the preferred way of implementing such a callback. of course there is no last Output[] item.3.5]'.) Check(ICalc. it shall execute Ctxt. Ctxt.3. so it is exactly as the following line: Ctxt.5.Named['result'] := Ctxt.IntSubtractJSON( Ctxt: TOnInterfaceStubExecuteParamsJSON).20).IntSubtractJSON). Delegate with indexed variant parameters There is another way of implementing such a callback method.2. SAD .IntSubtractVariant( Ctxt: TOnInterfaceStubExecuteParamsVariant).5.. 1.Substract(10.5. If the execution fails. if you call: function Subtract(n1.5.Create(TypeInfo(ICalculator).5)=9). // after Ctxt. Create(TypeInfo(ICalculator).Rev. ExpectsTrace(Hash32('Add(10.ToTextFunc(2.Check(Ctxt.Hash32('Add(10.Sender instance. ExpectsTrace('Multiply'. Input parameter order in Ctxt. Check(I. as such: TInterfaceMock.'toto').2)=[0]. an additional callback-private parameter containing 'toto' has been specified at TInterfaceMock definition.30)=60).'30').Subtract(2.'+ 'Multiply(2.mORMot Framework . Executes('Subtract'..35)=[70].18 Page 255 of 1055 . in the context of an interface mock: TInterfaceMock.Params follows the exact order of const and var parameters at method call.Multiply(10. 2013 begin // result := n1-n2 P := pointer(Ctxt.Create(TypeInfo(ICalculator).Result follows the exact order of var and out parameters plus any function result. 16. begin Ctxt. A more complex trace verification could be defined for instance.20)=0. and store the result values as a JSON array in Ctxt.Multiply(2. Ctxt. Check(I.I. ExpectsCount('Multiply'. we retrieved the whole call stack. Here.Returns([]) or Ctxt. Ctxt['result'] := Ctxt['n1']-Ctxt['n2'].Hash32('Multiply(10. SAD .30)=[30]')).[10.Add(10. including returned results..30)=30). and output parameter order in Ctxt.5. This is indeed the root feature of its "test spy" TInterfaceMockSpy.4.qoEqualTo. Returns('Multiply'.EventParams='toto').30)=[60]')).Multiply(10. Accessing the test case when mocking In case of mocking.'Default result').) procedure TTestServiceOrientedArchitecture. ExpectsTrace('Multiply'.IntSubtractVariant. Check(Stub. Check(I. ExpectsCount('ToTextFunc'.self).['default']). end.Returns([GetNextItemDouble(P)-GetNextItemDouble(P)]).30)=[60].I).35)=[70]')). it will raise an exception to use the Ctxt. If the caller is not a TInterfaceMock.Params).3)=["default"]')). Returns('ToTextFunc'.Synopse mORMot Framework Software Architecture Design 1.2).qoGreaterThan.35]. Returns('Add'. as an easy to read text content. mORMot is able to log all interface calls into internal TInterfaceStub's structures. (. // Ctxt. end.LogAsText='Add(10.Hash32('Multiply(10.Result := '['+DoubleToStr(GetNextItemDouble(P)-GetNextItemDouble(P))+']'.30]. it shall parse incoming parameters from Ctxt.0).Params.1. Then its content is checked on the associated test case via Ctxt.[2.20)=[0]').TestCase property.qoLessThan. 1.Add(10. Returns('Multiply'.4.self). That is. Here above.3.[60]).Result.30)=[30].2). Stub := TInterfaceStub. SetOptions([imoLogMethodCallsAndResults]).Verify() methods.TestCase.5.ICalc.IntSubtractVariant( Ctxt: TOnInterfaceStubExecuteParamsVariant).18 Date: June 16. Calls tracing As stated above. ExpectsTrace('Add'.Create(TypeInfo(ICalculator). you may add additional verifications within the implementation callback.3.[70]).30)=[60]. ExpectsCount('Subtract'. 16. Check(I. and the retrieved result values. via the two TInterfaceStub. which is a good way of minimizing data in memory or re-use a value retrieved at execution time for further regression testing. SAD . You can take a look at TTestServiceOrientedArchitecture.Log and LogCount properties. The ExpectsTrace() methods are able to add some checks non only about the number of calls of a method.35)=70). Those methods expect Hash32() functions to define the hash value of the expected trace.3)='default').18 Date: June 16.ToTextFunc(2. You have even a full access to the internal execution trace. 1.'Default result'). This will allow any validation of mocked interface calls logic.Synopse mORMot Framework Software Architecture Design 1.1.3.2)=0. beyond ExpectsTrace() possibilities.mORMot Framework . but the order of the command executions.Rev.Multiply(2. for a whole coverage of all the internal features.Subtract(2. 2013 Check(I. Check(I.MocksAndStubs regression tests.18 Page 256 of 1055 . when a workflow is to be handled during the application process (you have to code some kind of state machine on both sides. all expected SOA features are now available in the current implementation of the mORMot framework (including service catalog aka "broker").Synopse mORMot Framework Software Architecture Design 1. For a detailed introduction and best practice guide to SOA .Rev.g.mORMot Framework .It is difficult to synchronize several service calls within a single context. the Client-Server services via methods (page 229) implementation pattern has some drawbacks: .18 Date: June 16. Implemented features Here are the key features of the current implementation of services using interfaces in the Synopse mORMot framework.you can consult this classic article: http://www. so you will have to code explicitly data marshaling twice. You can get rid of those limitations with the interface-based service implementation of mORMot.Session* members). or should be checked by hand in the implementation method (using the Ctxt. e. .18 Page 257 of 1055 .Most content marshaling is to be done by hand. Client-Server services via interfaces Adopt a mORMot In real world. especially when your application relies heavily on services. . for both client and server (DataSnap and WCF both suffer from a similar issue..1.pas unit: SAD . so may introduce implementation issues. . and are listed as a plain list. 17. 2013 17. as implemented in mORMot. by which client classes shall be coded separately. 1. According to this document.see Service-oriented architecture (page 63) .Client and server side code does not have the same implementation pattern. which is not very convenient. most time generated by a Wizard).Security is handled globally for the user.com/developerworks/webservices/library/ws-soa-design1. and define all session handling by hand).ibm. .The services do not have any hierarchy. Alive as long as the client-side interface is not released.see below (page 293) Multi-hosted (with DMZ) Services are hosted by default within the main ORM server. variants) from Delphi 6 up to XE4 Flexible Methods accept per-value or per-reference parameters Instance lifetime An implementation class can be: . records. TCP/IP-HTTP JSON based Transmitted data uses JavaScript Object Notation Routing choice Services are identified either at the URI level (the RESTful way). direct in-process connection.18 Page 258 of 1055 . on the client side. sets and enumerations) and high-level types (objects.mORMot Framework .Rev. and will handle simple types (strings.Created on every call. . . named pipes. or in a JSON-RPC model (the AJAX way) AJAX and RESTful JSON and HTTP combination allows services to be consumed from AJAX rich clients Light & fast Performance and memory consumption are very optimized. .g. dynamic arrays.Shared for a particular user or group.Synopse mORMot Framework Software Architecture Design 1.Shared among all calls. 1. in order to ensure scalability and ROI SAD . but can have their own process. with a dedicated connection to the ORM core Broker ready Service meta-data can be optionally revealed by the server Multiple transports All Client-Server protocols of mORMot are available.Dedicated to the thread it runs on.Or as long as an authentication session exists Stateless Following a standard request/reply pattern Signed The contract is checked to be consistent before any remote execution Secure Every service and/or methods can be enabled or disabled on need Safe Using extended RESTful authentication . i. . numbers. dates.e. collections.18 Date: June 16. remotely calling the server to execute the process Auto marshaling The contract is transparently implemented: no additional code is needed e. GDI messages. . 2013 Feature Remarks Service Orientation Allow loosely-coupled relationship Design by contract Data Contracts are defined in Delphi code as standard interface custom types Factory driven Get an implementation instance from a given interface Server factory You can get an implementation on the server side Client factory You can get a "fake" implementation on the client side. mORMot Framework . sets and enumerations) and high-level types (objects. numbers. It will help writing SOLID code. Defining a data contract In a SOA. services tend to create a huge list of operations. with a GUID. the inherited methods will be part of the child interface. so IInvokable is a good parent type. Define an interface The data contract is to be defined as a plain Delphi interface type.Methods can have a result. collections.Build a client application.Any interface inheriting from IInvokable. In order to facilitate implementation and maintenance. .3. . . under the "ICalculator" service (which will be named internally 'Calculator' by convention). it is worth applying the Service-oriented architecture (page 63) main principles.2. In fact. can be used . This operation will expect two numbers as input.1. but this won't be a restriction since the interface definition is dedicated to Delphi code scope.we expect the RTTI to be available. enhance maintenability.You can inherit an interface from an existing one: in this case. 1. The current implementation of service has the following expectations: .Synopse mORMot Framework Software Architecture Design 1.see below for the details.18 Page 259 of 1055 .nor stdcall nor cdecl is available yet. How to make services The typical basic tasks to perform are the following: .Simple types (strings. When you define mORMOt contracts.e. .3. dates.Only plain ASCII names are allowed for the type definition (as it is conventional to use English spelling for service and operation naming).Define the service contract.g. end.Calling convention shall be register (the Delphi's default) . you'll certainly be asked to replace one of your service with a third-party existing implementation of the corresponding feature: you shall at least ensure that your own implementation would be easily re-coded with external code. SAD . 17.see Interfaces (page 236) .n2: integer): integer. ensure that this contract will stay un-coupled with other contracts. loosely-coupled relationship. Before defining how such services are defined within mORMot. and allow introducing other service providers on demand (some day or later. parameters expectations are the following: . In fact. This ICalculator. a SOAP/WSDL gateway). using e.18 Date: June 16.can be used directly: type ICalculator = interface(IInvokable) ['{9A60C8ED-CEB2-4E09-87D4-4A16F496E5FE}'] /// add two signed 32 bit integers function Add(n1. . and accept per-value or per-reference parameters. and then return the sum of those numbers. 2013 17. the sample type as stated above . 17.Add method will define one "Add" operation. records and dynamic arrays) are handled .Rev. operations shall be grouped within common services. and will be expected to be implemented (just as with standard Delphi code).Implement the contract.Configure and host the service. . i. . We will describe those items. g. the framework will ensure that both client and server sides use the same ANSI code page . 17.see TObjectList serialization (page 190) SAD .procedure or function kind of method definition are allowed.Special TServiceCustomAnswer kind of record can be used as function result to specify a custom content (with specified encoding. 1.so you should better use RawUTF8 everywhere RawJSON UTF-8 buffer transmitted with no serialization (wheras a RawUTF8 will be escaped as a JSON string) . e. Available types for methods parameters Handled types of parameters are: Delphi type Remarks boolean Transmitted as JSON true/false integer cardinal Int64 double currency TDateTime Transmitted as JSON numbers enumerations Transmitted as JSON number set Transmitted as JSON number . the TCollection kind of parameter is not directly handled by the framework: you shall define a TInterfacedCollection class.2.They can be defined as const.in this case. . and var and out parameters values will be returned as JSON from the server.in fact.g.In fact.Only exception is that you can't have a function returning a class instance (how will know when to release the instance in this case?).mORMot Framework . 2013 . but prior to Delphi 2009.one bit per element (up to 32 elements) RawUTF8 WideString SynUnicode Transmitted as JSON text (UTF-8 encoded) string Transmitted as UTF-8 JSON text.see below (page 262) TObjectList Transmitted as a JSON array of JSON objects. for AJAX or HTML consumers) .Rev. var or out . to be used e. with a "ClassName": "TMyClass" field to identify the type . overriding its GetClass abstract virtual method (otherwise the server side won't be able to create the kind of collection as expected).Synopse mORMot Framework Software Architecture Design 1. no var nor out parameters values shall be defined in the method (only the BLOB value is returned).expects to contain valid JSON content. . but such instances can be passed as const. RegisterCollectionForJSON() TInterfacedCollection Transmitted as a JSON array of JSON objects . const and var parameters values will be sent from the client to the server as JSON. for TSQLTableJSON requests TPersistent Published properties will be transmitted as JSON object TSQLRecord All published fields (including ID) will be transmitted as JSON object TCollection Not allowed direcly: inherit from TInterfacedCollection or call TJSONSerializer.3. .18 Date: June 16.18 Page 260 of 1055 . var or out parameters (and published properties will be serialized within the JSON message). . but will serialize those simple types in a more AJAX compatible way. mORMot does not allow a method function to return a class instance. you can't define such a method: SAD . And simple types of dynamic arrays (like TIntegerDynArray.mORMot Framework .3. sets and records. TRawUTF8DynArray. also on the client side. Note how SpecialCall and ComplexCall methods have quite complex parameters definitions. in this case. fields: TSynTableFieldTypes.3.n2: Int64): Int64. const Rec1: TVirtualTableModuleProperties. /// multiply two signed 64 bit integers function Multiply(n1.e.Synopse mORMot Framework Software Architecture Design 1. sets and enumerates parameters. 17. var Str2: TWideStringDynArray. just like with regular Delphi interface expectations . var Int: integer. including dynamic arrays. That is. /// test integer. end. var options: TSynTableFieldOptions): TSynTableFieldTypes.see Dynamic array wrapper (page 74) record Need to have RTTI (so a string or dynamic array field within). The framework will handle const and var parameters as expected.18 Date: June 16.18 Page 261 of 1055 .transmitted as binary with Base-64 encoding or custom JSON serialization . var V2: variant): variant. AJAX) You can therefore define complex interface types. /// convert a currency value into text procedure ToText(Value: Currency.n2: double): double.Rev. /// do some work with strings.see Record serialization (page 185) variant Transmitted as JSON text or numerical value . V1: variant. and any other service consumers (e. together with records function ComplexCall(const Ints: TIntegerDynArray.variant arrays or non standard value types are not handled TServiceCustomAnswer If used as a function result (not as parameter). the supplied content will be transmitted directly to the client (with no JSON serialization). field: TSynTableFieldTypes. or TWideStringDynArray) will be serialized as plain JSON arrays . /// test variant kind of parameters function TestVariants(const Text: RawUTF8. /// convert a floating-point value into text function ToTextFunc(Value: double): string. var Rec2: TSQLRestCacheEntryValue): TSQLRestCacheEntryValue.the framework is able to handle any dynamic array definition. /// substract two floating-point values function Subtract(n1. 1.g. i. var Card: cardinal. as input/output parameters.n2: integer): integer. TPersistent / TSQLRecord parameters As stated above. no var nor out parameters are allowed in the method it will be compatible with both our TServiceFactoryClient implementation. Strs1: TRawUTF8DynArray. var Result: RawUTF8). 2013 any TObject See TObject serialization (page 189) dynamic arrays Transmitted as JSON arrays . as such: type ICalculator = interface(IInvokable) ['{9A60C8ED-CEB2-4E09-87D4-4A16F496E5FE}'] /// add two signed 32 bit integers function Add(n1. strings and wide strings dynamic arrays. // testing also var (in/out) parameters and set as a function result function SpecialCall(Txt: RawUTF8. Even if older versions of Delphi are not able to generate the needed RTTI information for such serialization. NewCutomerID := Repository. Note that the callback signature used for records matches the one used for dynamic arrays serializations . 17. Note that here the out keyword does not indicate how the memory is allocated. then transmitted as a JSON string.18 Date: June 16. i. we use both Factory and Repository patterns. TCollection parameters SAD . and makes more natural service consumption with AJAX clients. The method will just read or write the instance published properties..Free. it will serialize the object at method return. and return it. the mORMot framework offers a common way of implementing any custom serialization of records.Save(Customer).e. // properly manage memory end. as proposed by below (page 304).FirstName := StringToUTF8(EditFirstName.mORMot Framework . allocated before the call and released after it.Create. and serialize them as JSON. it may be up to the method to instantiate the instance. 1. i. 2013 ICustomerFactory = interface(IInvokable) ['{770D009F-15F4-4307-B2AD-BBAE42FE70C0}'] function NewCustomer: TCustomer. end. in client-server mode? There is no standard allocation scheme.Text). In this example. Customer. any record parameter or function result will be serialized with a proprietary binary (and optimized) layout.Rev.5.see Dynamic array serialization (page 186) . See Record serialization (page 185). for such parameters. Record parameters By default.4.3. // get a new object instance Customer. end.e. Customer: TCustomer.Synopse mORMot Framework Software Architecture Design 1. So every TObject parameter instance shall be managed by the caller. 17..whereas for "normal" Delphi code. What you can define is such a method: ICustomerFactory = interface(IInvokable) ['{770D009F-15F4-4307-B2AD-BBAE42FE70C0}'] procedure NewCustomer(out aCustomer: TCustomer). after Base-64 encoding.3. but shows the communication direction of the remote service.Text). . try Factory. such a custom serialization format can be handy. The caller shall instantiate an instance before call . Then your client code can use it as such: var Factory: ICustomerFactory. When records are used as Data Transfer Objects within services (which is a good idea in common SOA implementation patterns).18 Page 262 of 1055 .NewCustomer(Customer).LastName := StringToUTF8(EditLastName. allowing us only to use an efficient but proprietary binary layout. Customer := TCustomer. Repository: ICustomerRepository. in Delphi. Who will be in charge of freeing the instance.as it will be shared between the two of them. // persist the object finally Customer. Therefore. CopyObject(List. virtual.2. Use of TCollection With mORMot services.Collections(Item: TCollTest. .Setting Item without var or out specification is doing the same as const: it will be serialized from client to server (and not back from server to client). var List: TCollTests. and back from server to the client. out Copy: TCollTests). then return a copy in the Copy content: .18 Date: June 16.5. virtual. Inherit from TInterfacedCollection A dedicated TInterfacedCollection abstract type has been defined: TInterfacedCollection = class(TCollection) protected class function GetClass: TCollectionItemClass.Add).3. And. 17. to define if it is passed by value or by reference).5. 1.18 Page 263 of 1055 .e.g. In order to use a collection of objects. Due to the current implementation pattern of the TCollection type in Delphi. public constructor Create.Setting List as var parameter will let this collection to be serialized from client to server. We will now describe both ways.mORMot Framework .Setting Copy as out parameter will let this collection to be serialized only from server to client. supplying the expected item class. it will append the supplied Item object to the provided List content. . 2013 17. on the server side. end. Typical implementation of this contract may be: procedure TServiceComplexCalculator. you are able to define such a contract.You can let your collection class inherit from the new TInterfacedCollection type. e. you will have to define at least the abstract method.Rev.You can call the TJSONSerializer. The framework propose two potential solutions: . begin CopyObject(Item.RegisterCollectionForJSON() method to register the collection type and its associated item class. abstract.Copy).3. the TServiceFactoryServer is unable to properly instantiate the object instances.List. var List: TCollTests. the TCollection constructor is defined as such: constructor Create(ItemClass: TCollectionItemClass).Synopse mORMot Framework Software Architecture Design 1. we do not know which kind of TCollectionItemClass is to be passed. In fact. . it was not possible to implement directly this kind of parameter. All class parameters shall be instantiated before method call: you can not pass any object parameter as nil (nor use it in a function result): it will raise an error. Note that const / var / out kind of parameters are used at the contract level in order to specify the direction of serialization. for a TCollTests collection of TCollTest items: procedure Collections(Item: TCollTest. and not as usual (i. reintroduce. for instance: SAD . end.1. out Copy: TCollTests). That is. Or. override. default. end.4. if you want a more complete / convenient implementation: TCollTests = class(TInterfacedCollection) private function GetCollItem(Index: Integer): TCollTest.3. Implementing the service contract In order to have an operating service.can be used directly: type TServiceCalculator = class(TInterfacedObject. Thanks to this internal registration table.5. mORMot will be able to serialize and unserialize plain TCollection type. Register a TCollection type The other way of using TCollection kind of parameters is to declare it explicitly to the framework.3.Create(TMyCollectionItem). the sample type as stated above . 17. ICalculator) SAD .RegisterCollectionForJSON() with the corresponding TCollection / TCollectionItem class type pair. you'll need to implement a Delphi class which matches the expected interface. end.18 Date: June 16. end. property Item[Index: Integer]: TCollTest read GetCollItem.GetClass: TCollectionItemClass. Consider a dedicated class: TMyCollection = type(TCollection) Note that a dedicated type is needed here. for instance. In fact.RegisterCollectionForJSON(TMyCollection. The following lines of code are the same: MyColl := TMyCollection. Server side 17. after calling: TJSONSerializer.Rev. class function TCollTests.1.18 Page 264 of 1055 .TMyCollectionItem). Then. public function Add: TCollTest.see Interfaces (page 236) .mORMot Framework . You should call JSONSerializer. override.Synopse mORMot Framework Software Architecture Design 1. All other methods and properties (like GetColItem / Add / Items[]) are to be defined as usual. begin result := TCollTest. The last two will retrieve the associated TMyCollectionItem class type from the previous registration. 17. You just can't use this registration over a plain TCollection. MyColl := ClassInstanceCreate(TMyCollection) as TMyCollection. protected class function GetClass: TCollectionItemClass. 1. 2013 TCollTests = class(TInterfacedCollection) protected class function GetClass: TCollectionItemClass.4. MyColl := ClassInstanceCreate('TMyCollection') as TMyCollection. an implementation class is to be available.n2: integer): integer. The code line above will register the TServiceCalculator class to implement the ICalculator service. with a single shared instance life time (specified via the sicShared parameter).e.18 Date: June 16.2. 17. n2: integer): integer. you'll need to initialize a server-side factory.Rev. This setting must be the same on both client and server sides (it will be checked by the framework). Here the class inherits from TInterfacedObject. so you'll be sure that your code meets the service contract expectations.. a TSQLRestServerFullMemory class which is enough for hosting services with authentication). end.mORMot Framework . begin result := n1+n2.18 Page 265 of 1055 . And.[TypeInfo(ICalculator)].Add(n1.This is the most expensive way of implementing the service. The Delphi IDE will check at compile time that the class really implements the specified interface definition. sicShared One object instance is used for all incoming calls and is not recycled subsequent to the calls SAD . The Server instance can be any TSQLRestServer inherited class. implementing any of the supported protocol of mORMot's Client-Server process (page 196).ServiceRegister(TServiceCalculator. a TSQLRestServerDB class) or a lighter in-memory engine (i. Exact match (like handling type of parameters) will be checked by the framework when the service factory will be initialized. but you could use any plain Delphi class: the only condition is that it implements the ICalculator interface. in order to automatically release a deprecated instance after some inactivity. embedding a full SQLite3 engine (i. 17.Synopse mORMot Framework Software Architecture Design 1. by specifying a TServiceInstanceImplementation value.ServiceRegister method. An optional time out value can be specified. 1. so you won't face any runtime exception due to a wrong definition.4. Set up the Server factory In order to have a working service. Whenever a service is executed. The life time of this implementation class is defined on both client and server side. Instances life time implementation The available instance management options are the following: Lifetime Description sicSingle One class instance is created per call: . .3. 2013 public function Add(n1. but is safe for simple workflows (like a one-type call). end. as such: Server.e. That is all we need..This is the default setting for TSQLRestServer. function TServiceCalculator.sicShared).4. 18 Page 266 of 1055 . sicPerSession. Object-Relational Mapping (page 88). for proper library initialization) In the current implementation of the framework. the sicSingle mode is preferred. .There is no built-in data durability yet: service implementation shall ensure that data remaining in memory between calls (i.g. It is therefore mandatory that it won't consume a lot of resource.18 Date: June 16. 1. the class instance is allocated in memory. For a more consuming operation (a process which may need memory and CPU power). but try to restrict the memory use to the minimum. 2013 sicClientDriven One object instance will be created in synchronization with the client-side lifetime of the corresponding interface: when the interface will be released on client (either when it comes out of scope or set to nil).g. Those implementation patterns will therefore only be available if the RESTful authentication is enabled between client and server. Note also that all those life-time modes expect the method implementation code to be thread-safe SAD . or guests) sicPerThread Thread-oriented process (e.a numerical identifier will be transmitted with all JSON requests sicPerSession One object instance will be maintained during the whole running session sicPerUser One object instance will be maintained and associated with the running user sicPerGroup One object instance will be maintained and associated with the running user's authorization group sicPerThread One object instance will be maintained and associated with the running thread Of course.g. it will be released on the server side .g.e. it is very likely that a lot of such instances will be created.Synopse mORMot Framework Software Architecture Design 1. or requiring some global data sicClientDriven The best candidate to implement a Business Logic workflow sicPerSession To maintain some data specific to the client application sicPerUser Access to some data specific to one user sicPerGroup Access to some data shared by a user category (e. especially with long-term life time: e.mORMot Framework . sicPerUser and sicPerGroup modes will expect a specific user to be authenticated. administrators. when not defined in sicSingle mode) won't be missing in case of server shutdown. It is up to the class to persist the needed data . This has two consequences: .using e. you should not store any BLOB within these instances.In client-server architecture. Typical use of each mode may be the following: Lifetime Use case sicSingle An asynchronous process (may be resource consuming) sicShared Either a very simple process.Rev. 18 Page 267 of 1055 .IComplexNumber) private fReal: double. procedure Add(aReal. In practice. or force the execution in the main thread with opt*InMainThread options . In order to illustrate sicClientDriven implementation mode.GetImaginary: double.Add(aReal. to perform an addition operation. aImaginary: double). end. Purpose of this interface is to store a complex number within its internal fields. fImaginary: double. function GetImaginary: double. aImaginary: double). and sicPerThread.18 Date: June 16. property Imaginary: double read GetImaginary write SetImaginary.Rev. aImaginary: double). therefore it is recommended to protect all implementation class method process.Synopse mORMot Framework Software Architecture Design 1. procedure Add(aReal. begin result := fImaginary. and define a "Add" method. function GetReal: double.see below (page 279). the same user can open more than one connection. let's introduce the following interface and its implementation (extracted from the supplied regression tests of the framework): type IComplexNumber = interface(IInvokable) ['{29D753B2-E7EF-41B3-B7C3-827FEB082DC1}'] procedure Assign(aReal. function GetReal: double. to provide object-like behavior on Real and Imaginary fields. procedure SetImaginary(const Value: double). 2013 and reintrant on the server side . function TServiceComplexNumber. SAD . aImaginary: double). procedure SetReal(const Value: double). This interface is implemented on the server side by the following class: type TServiceComplexNumber = class(TInterfacedObject. function GetImaginary: double. fImaginary := fImaginary+aImaginary. 1. end. property Imaginary: double read GetImaginary write SetImaginary. aImaginary: double). end. We used properties. aImaginary: double). which will have its own running instance. property Real: double read GetReal write SetReal. begin fReal := fReal+aReal. then retrieve their values. begin fReal := aReal. fImaginary := aImaginary.Assign(aReal. { TServiceComplexNumber } procedure TServiceComplexNumber. with associated getter and setter methods.only exceptions are sicSingle mode. end. public procedure Assign(aReal. procedure TServiceComplexNumber. property Real: double read GetReal write SetReal. procedure SetReal(const Value: double). procedure SetImaginary(const Value: double).mORMot Framework . which will have its methods always run in the same thread context. in the code. for instance. a local copy or a PServiceRunningContext pointer should better be created.SessionGetUser) // . Note that this global threadvar is reset to 0 outside an interface-based service method call. function TServiceComplexNumber. current session or authentication parameters // (including e. 17. 1. procedure TServiceComplexNumber. /// the thread which launched the request // .g. You will have access to the following information.g. /// the currently runnning context which launched the method // .[TypeInfo(IComplexNumber)]. When used. begin fImaginary := Value. which could be useful for sicPerSession. also the client side will be able to have its own life time handled as expected.Rev. begin fReal := Value.ServiceRegister(TServiceComplexNumber. begin result := fReal.GetReal: double. A time-out driven garbage collector will delete any un-closed pending session. sicPerUser and sicPerGroup instance life time modes: TServiceRunningContext = record /// the currently running service factory // . both fReal and fImaginary field will remain allocated on the server side as long as needed. TSQLite3HttpServer or TSQLRestServerNamedPipeResponse RunningThread: TThread.18 Date: June 16. end. Accessing low-level execution context When any interface-based service is executed.mORMot Framework .SetImaginary(const Value: double). therefore release resources allocted in sicClientDriven mode.Synopse mORMot Framework Software Architecture Design 1. threadvar read won't work.4. user details via Factory. a global threadvar named ServiceContext can be accessed to retrieve the currently running context on the server side. If your code is compiled within some packages. even in case of a broken connection.18 Page 268 of 1055 .make available e. SAD . Using the sicClientDriven mode. This interface is registered on the server side as such: Server. end.SetReal(const Value: double). since accessing a threadvar has a non negligible performance cost.g. procedure TServiceComplexNumber. That is.BeginCurrentThread from multi-thread server // handlers . end.is set by TSQLRestServer. you have to call the following function instead of directly access the threadvar: function CurrentServiceContext: TServiceRunningContext. 2013 end.RestServer.e.it can be used within server-side implementation to retrieve the // associated TSQLRestServer instance Factory: TServiceFactoryServer.low-level RESTful context is also available in its Call member Session: ^TSQLRestServerCallBackParams.sicClientDriven). due to a Delphi compiler/RTL restriction (bug?). In such case. end. It would therefore be useless to read it from a method-based service.4. end.Get(CN) then exit. begin if Server. caching the instance may be source of confusion.5. especially if your software architecture has several layers (like in a Domain-Driven design (page 67)): your application services could be decoupled. or.5.in this case.18 Date: June 16. assert(SameValue(CN.Real := 0. end. end. you may code: var I: ICalculator. In a complex Service-oriented architecture (page 63).Services['Calculator']. it is very easy to use it in your code. Client side SAD . begin I := Server. since there will be one dedicated instance per thread. you'll have to consume services on the server side.18 Page 269 of 1055 . begin if not Server. 2013 17. i. CN. for a more complex service: var CN: IComplexNumber.200). You can of course cache your TServiceFactory instance within a local field. // here CN will be released For newer generic-aware versions of Delphi (i. You have several methods to retrieve a TServiceFactory instance. it is not a good practice to have services calling each other. or its index in the list.4. If the service has been defined as sicPerThread.Service<ICalculator>.e. Using services on the Server side Once the service is registered on the server side.01.Add(100.1415)).mORMot Framework .Rev. assert(SameValue(CN.Info(TypeInfo(IComplexNumber)). You can use the following method of your TSQLRest. if you wish. Delphi 2010 and up. according to the SOLID design principles (page 239).Real.Imaginary. Code decoupling is a key to maintainability here. In this case.20). the TInterfacedObject instances or even worse directly the low-level classes or functions). and could have nested calls.1415.e. since Delphi 2009 is buggy about generics).100. 17.Services. you'd better rely on abstraction in your code. But in some cases. either from the service name.01)). 1. which enables compile-time checking: var I: ICalculator. but the Domain-Driven services (those implementing the business model) could be on another Client-Server level.Add(10. the instance you will retrieve on the server side will also be specific to the running thread .20). you can use such a method. with a dedicated protocol.Imaginary := 3.Services instance (note that this method is available on both client and server sides as abstract TServiceFactory. CN.Synopse mORMot Framework Software Architecture Design 1. not call the service implementation (i.Get(I)) then result := I.Add(10. its GUID. so is the right access point to all services): function TServiceFactory. but the service abstract interface. if I<>nil then result := I.Get(out Obj): Boolean. That is.203.e. // IComplexNumber interface not found CN. mORMot Framework . you can use a generic-based method.Get(I)) then result := I. this registration step is indeed not mandatory on the client side.ServiceRegister([TypeInfo(IComplexNumber)].sicShared). you have to register the corresponding interface to initialize its associated factory.as with our Client-Server services via methods (page 229). RemObjects or WCF). begin if Client. 17.Rev. initialized as sicClientDriven: var CN: IComplexNumber.ServiceRegister([TypeInfo(ICalculator)]. 2013 There is no implementation at all on the client side. It is very close to the Server-side registration.Synopse mORMot Framework Software Architecture Design 1. This will create the corresponding TServiceFactoryClient instance.18 Page 270 of 1055 .e.sicClientDriven). begin I := Client. if I<>nil then result := I. our ICalculator type). 17. i.2.Services['Calculator']. in sicClientDriven implementation mode. This is the magic of mORMot's services: no Wizard to call (as in DataSnap. it is very easy to use it in your code.20).5. For Delphi 2010 and up. a hidden "fake" TInterfaceObject class will be created by the framework (including its internal VTable and low-level assembler code). In fact. you may code: var I: ICalculator. and used to interact with the remote server. which enables compile-time checking: var I: ICalculator. end. Note that the implementation mode (here sicShared) shall match the one used on the server side. is registered as such for the client: Client. nor client-side methods to write . That is. end. If you use the TServiceContainerClient. You just register the existing interface definition (e. as such: Client. An error will occur if this setting is not coherent. Using services on the Client side Once the service is registered on the client side.Add(10. ready to serve fake implementation classes to the client process. SAD . Implementation will remain on the server side. 1. despite the fact that we do not provide any implementation class here. executed on the server side.1.18 Date: June 16. IComplexNumber.Info() method.20). and you can remotely access to all its methods.5. the client-side implementation will auto-register the supplied interface. But you do not have to worry about this process: it is transparent to your code. For a more complex service.Add(10.Service<ICalculator>. You can use the same methods as on the server side to retrieve a TServiceFactory instance.g. To be more precise. Set up the Client factory On the client side. The other interface we talked about. 18 Date: June 16. it is not mandatory to call the Client. and the ROOT_NAME used for the ORM SAD . end. In fact. even if the service has been defined as sicPerThread. 17.Info(TypeInfo(IComplexNumber)) method execution.203. since the per-thread process will take place on the server side only.Real := 0. The shared contract First.Interface based services" folder of the supplied source code distribution. The only functional change is that the execution will take place on the server side (using the registered TServiceComplexNumber implementation class). As we stated in the previous paragraph.Add(100. you can safely cache and reuse the same instance. implementation end. CN. end. and the corresponding class instance will remain active until the CN local interface will be released on the client.Services.Get(CN) then exit.Info(TypeInfo(IComplexNumber)). since the IComplexNumber is to be executed as sicClientDriven.18 Page 271 of 1055 . const ROOT_NAME = 'service'. APPLICATION_NAME = 'RestService'. interface type ICalculator = interface(IInvokable) ['{9A60C8ED-CEB2-4E09-87D4-4A16F496E5FE}'] function Add(n1. it may be a good idea to explicitly register the interface on the client side also.100. // IComplexNumber interface not found CN. // here CN will be released on both client AND SERVER sides The code is just the same as on the server.6. 2013 begin if not Client. during Client.01)).Imaginary := 3.n2: integer): integer. shared by both client and server applications: unit Project14Interface.1. using interfaces. On the client side. over named pipe communication. assert(SameValue(CN.6. Unique purpose of this unit is to define the service interface.Synopse mORMot Framework Software Architecture Design 1. a dedicated sample about this feature.1415. Sample code You can find in the "SQLite3/Samples/14 . Purpose of this code is to show how to create a client-server service.Real. just to emphasize that this interface is about to be used.Services. CN. the registration will take place.Rev.200).Imaginary. 17.ServiceRegister method for this interface.mORMot Framework . PORT_NAME = '888'. if you wish. you'll find a common unit. assert(SameValue(CN. You can of course cache your TServiceFactory instance within a local field. if it has not been done explicitly before. 1.1415)). For code readability. and in which mode.01. Then a call to ServiceRegister() will define the ICalculator contract. since we need authentication.18 Date: June 16. 17. ICalculator) public function Add(n1.18 Page 272 of 1055 . end. // we need AuthGroup and AuthUser tables ServiceRegister(TServiceCalculator.true) do try CreateMissingTables.Rev. end. function TServiceCalculator. 1. begin result := n1+n2.[TypeInfo(ICalculator)]. and the TServiceCalculator class to be used as its implementation. Project14Interface. The server sample application The server is implemented as such: program Project14Server. var aModel: TSQLModel.Free. It will instantiate a TSQLRestServerDB class. In fact.ChangeFileExt(paramstr(0). and the APPLICATION_NAME used for named-pipe communication.dpr sample: SAD . end.'#10) else writeln('Error launching the server'#10). containing a SQLite3 database engine. we may use a TSQLRestServerFullMemory class instead of TSQLRestServerDB.ROOT_NAME). This is what is the purpose of the Project14ServerInMemory.'. finally aModel.Create([]. since the same implementation class can be shared during all calls (there is no shared nor private data to take care). readln.2. write('Press [Enter] to close the server.db').Create(aModel. both AuthGroup and AuthUser tables are expected to be available.6. mORMotSQLite3. type TServiceCalculator = class(TInterfacedObject. end. 2013 Model (and therefore RESTful URI scheme). The sicShared mode is used. {$APPTYPE CONSOLE} uses SysUtils.Synopse mORMot Framework Software Architecture Design 1. try with TSQLRestServerDB.mORMot Framework . begin aModel := TSQLModel. end.'). mORMot. n2: integer): integer. Note that since the database expectations of this server are basic (only CRUD commands are needed to handle authentication tables).n2: integer): integer.Add(n1. finally Free.sicShared). if ExportServerNamedPipe(APPLICATION_NAME) then writeln('Background server is running. 6. exit.ROOT_NAME). 17.sicShared).Synopse mORMot Framework Software Architecture Design 1.'synopse').Create(aModel.Create([].18 Page 273 of 1055 . Client.) Using this class will include the CreateMissingTables call to create both AuthGroup and AuthUser tables needed for authentication.b) statement. the local I: ICalculator variable instance is retrieved. 17.) with TSQLRestServerFullMemory.ServiceRegister([TypeInfo(ICalculator)]. val(edtB.The connection is authenticated with the default 'User' rights. if Client=nil then begin if Model=nil then Model := TSQLModel.err). which OnClick event is implemented as: procedure TForm1.Rev. The client sample application The client is just a simple form with two TEdit fields (edtA and edtB). if err<>0 then begin edtB. begin val(edtA. for a full service provider.The ICalculator interface is defined in the client's internal factory.SetUser('User'.mORMot Framework .APPLICATION_NAME).Services['Calculator']. But the resulting executable will be lighter: only 200 KB when compiled with Delphi 7 and our LVCL classes.Text. Once the client is up and ready.18 Date: June 16. end. (.Create(Model.[TypeInfo(ICalculator)]. .Add(a.err). I: ICalculator.Add(a.3..true) do try ServiceRegister(TServiceCalculator. Client.4. err: integer.btnCallClick(Sender: TObject). end. if err<>0 then begin edtA.sicShared).SetFocus. end. end. and a "Call" button. You can imagine how easy and safe it will be to implement a Service-oriented architecture (page 63) for your future applications.Execute SQL via services folder of mORMot source code a Client-Server sample able to access any external database via JSON and HTTP. var a. Enhanced sample: remote SQL access You will find in the SQLite3\Samples\16 . It is a good SAD . if ExportServerNamedPipe(APPLICATION_NAME) then (. using mORMot.A TSQLRestClientURINamedPipe instance is created. 2013 program Project14ServerInMemory.. .6.b.Get(I) then lblResult. and the remote service is called directly via a simple I.Caption := IntToStr(I. // here local I will be released The client code is initialized as such: .b)).a.. Client := TSQLRestClientURINamedPipe.'test. exit.SetFocus. if Client. in sicShared mode (just as in the server). with an associate TSQLModel and the given APPLICATION_NAME to access the proper server via a named pipe communication..b: integer.false.json'.Text. 1. 1. aDatabaseName. it will probably be faster to work with such plain HTTP / JSON services. aPassWord: RawUTF8). It will also show how our SynDB classes have a quite abstract design.18 Page 274 of 1055 . public // implements IRemoteSQL methods procedure Connect(aEngine: TRemoteSQLEngine. end. which is in fact a sub-type of RawUTF8. On the contrary. and are easy to work with. Purpose of this service is: . aExpectResults. aUserID. the mORMot Client-Server process is optimized for such kind of connection. or a Delphi client (e. returning the content as JSON array. rseSQlite3. rseJet. In fact. const aServerName. ready to be consumed by AJAX applications (if aExpanded is true). The corresponding service contract has been defined: TRemoteSQLEngine = (rseOleDB. Benefit of this service is that no database connection is required on the client side: a regular HTTP connection is enough. via a TSQLTableJSON and the mORMotUI unit). . which are typical on the Internet. 2013 demonstration of how to use a non-trivial interface-based service between a client and a server. aUserID.18 Date: June 16.To Connect() to any external database. instead of a database connection through a VPN. escaping some JSON array within a JSON string is quite verbose. aPassWord: RawUTF8).g. In fact. given the parameters as expected by a standard TSQLDBConnectionProperties.Create() constructor call. No need to neither install nor configure any database provider. rseOracle. aDatabaseName. SAD . aExpectResults. function Execute(const aSQL: RawUTF8. with no translation to a JSON string. aExpanded: Boolean): RawJSON. aExpanded: Boolean): RawJSON. public destructor Destroy. override. . function GetTableNames: TRawUTF8DynArray.Rev.Execute any SQL statement. { TServiceRemoteSQL } procedure TServiceRemoteSQL. IRemoteSQL) protected fProps: TSQLDBConnectionProperties. database connections are made to work on a local network.Synopse mORMot Framework Software Architecture Design 1. end. That is.Retrieve all table names of this external database as a list. this service will be defined in sicClientDriven mode. the framework will be able to manage a client-driven TSQLDBProperties instance life time. Due to mORMot optimized JSON serialization. Its purpose is to transmit the UTF-8 encoded content directly. Note that the Execute() method returns a RawJSON kind of variable. function Execute(const aSQL: RawUTF8.Connect(aEngine: TRemoteSQLEngine. whatever database provider you need to use. Of course. Using RawJSON in this case ensure the best client-side and server-side speed. and do not like high-latency connections. rseODBC. const aServerName. as would be the case with a RawUTF8 variable. The server part is quite easy to follow: type TServiceRemoteSQL = class(TInterfacedObject. function GetTableNames: TRawUTF8DynArray. IRemoteSQL = interface(IInvokable) ['{9A60C8ED-CEB2-4E09-87D4-4A16F496E5FE}'] procedure Connect(aEngine: TRemoteSQLEngine.mORMot Framework . rseMSSQL). and also reduce the transmission bandwidth. The services are initialized on the server side with the following code: var aModel: TSQLModel. Any exception during SynDB process.Create([]. begin if fProps=nil then raise Exception.Destroy.[optExecInMainThread. aUserID.Create('Connect called more than once'). end.[TypeInfo(IRemoteSQL)].Create(aModel. rseSQlite3. 2013 const aServerName.aUserID. if res=nil then result := '' else result := res.false.aDatabaseName. EchoToConsole := LOG_VERBOSE.optFreeInMainThread]). // log all events to the console end. const // rseOleDB. begin FreeAndNil(fProps).Synopse mORMot Framework Software Architecture Design 1. var res: ISQLDBRows. function TServiceRemoteSQL. // fProps should better be executed and released in the one main thread SetOptions([]. rseODBC. SAD . destructor TServiceRemoteSQL. aDatabaseName.ServiceRegister(TServiceRemoteSQL.18 Date: June 16. rseOracle. begin if fProps=nil then raise Exception.aExpectResults).true). TextColor(ccLightGray). // create a Data Model aModel := TSQLModel. aExpanded: Boolean): RawJSON. try // register our IRemoteSQL service on the server side aServer.aPassWord). TSQLDBOracleConnectionProperties. function TServiceRemoteSQL. begin if fProps<>nil then raise Exception.mORMot Framework . try // initialize a TObjectList-based database engine aServer := TSQLRestServerFullMemory. TSQLDBSQLite3ConnectionProperties.ROOT_NAME). just as expected.FetchAllAsJSON(aExpanded). TODBCConnectionProperties. end.json'. fProps.GetTableNames(result).Create('Connect call required before Execute').sicClientDriven).18 Page 275 of 1055 .Family do begin Level := LOG_VERBOSE. rseJet. // manual switch to console mode AllocConsole. 1.ExecuteInlined(aSQL.Create(aServerName. inherited.Rev. rseMSSQL TYPES: array[TRemoteSQLEngine] of TSQLDBConnectionPropertiesClass = ( TOleDBConnectionProperties. end. so all we need is to release its pointer in the service implementation destructor. fProps := TYPES[aEngine]. res := fProps. end. aPassWord: RawUTF8). begin // define the log level with TSQLLog. or raised manually in case of wrong use case will be transmitted to the client. aExpectResults. TOleDBJetConnectionProperties. aServer: TSQLRestServer.GetTableNames: TRawUTF8DynArray. TOleDBMSSQL2008ConnectionProperties). The fProps instance life-time is handled by the client.'users. aHTTPServer: TSQLHttpServer.Execute(const aSQL: RawUTF8.Create('Connect call required before GetTableNames'). '#10).18 Date: June 16. This is a typical mORMot server initialization. Close.AccessControlAllowOrigin := '*'. for OleDB / MS SQL or Oracle providers). since all external process will take place at the SQL level. the ORM core will by itself add the TSQLAuthUser and TSQLAuthGroup tables to the model no need to add them explicitly. finally aModel. as stated by the useHttpApiRegisteringURI flag). Close. ConsoleWaitForEnterKey. Our IRemoteSQL service will be accessed in sicClientDriven mode.Create('localhost'. end. end.'+'.Free.18 Page 276 of 1055 . In this sample. In the above code.Synopse mORMot Framework Software Architecture Design 1.e.'Remote service not available on server'). published over the HTTP communication protocol (with auto-registration feature.SetUser method). writeln('Press [Enter] to close the server.'synopse')) or (not fClient. no table has been defined within the ORM model.with a proper call to SetUser(). exit. From the client point of view. // for AJAX requests to work writeln(#10'Background server is running.ServerTimeStampSynchronize then begin ShowLastClientError(fClient. It means that all methods will be executed in the main process thread.SetUser('User'. if not fClient. From now on.FormShow(Sender: TObject). Since we won't use ORM for any purpose but authentication. try aHTTPServer.ServiceRegisterClientDriven(TypeInfo(IRemoteSQL). finally aHTTPServer.) fModel := TSQLModel. since SynDB database access may open one connection per thread (e. exit. a fast TObjectList-based engine (i.exe'). fClient := TSQLHttpClient.see below (page 293) . As we need authentication (see the call to fClient. so here we need to initialize RESTful authentication . TSQLRestServerFullMemory) is enough for this sample purpose. end.'Please run Project16ServerHttp. It is not necessary. it will be consumed as such: procedure TMainForm. 1. you can note that IRemoteSQL service is defined with the optExecInMainThread and optFreeInMainThread options.fModel)..Free.[aServer]. end. In practice. 2013 // launch the HTTP server aHTTPServer := TSQLHttpServer. we have a fService: IRemoteSQL instance available to connect and process any SAD .'888'.useHttpApiRegisteringURI).fService)) then begin ShowLastClientError(fClient.Create([].'#10).. (. and still will perform with decent speed (since all the internal marshaling and communication will be multi-threaded in the framework units). Note the use of ShowLastClientError() function of mORMotUILogin unit.Rev.mORMot Framework . it may use a lot of memory.Create('888'. finally aServer. end. if possible.ROOT_NAME). end.Free. which is able to use our SynTaskDialog unit to report standard and detailed information about the latest error. Forcing the database execution in the main thread will lower the resource consumption. end. if (not fClient.g. using a TSQLTableJSON instance to un-serialize the returned JSON content.see below (page 293).g. or a custom cypher within HTTP content-encoding.GetTableNames.1.e.False. . Security As stated in the features grid of Client-Server services via interfaces (page 257).Cursor := crDefault.pointer(fTableJSON). all services and operations (i.False). a complete security pattern is available when using client-server services. introducing. except on E: Exception do ShowException(E). finally Screen.. SAD . TSQLTableToGrid. Implementation details 17.ServerName.we'll discuss this part now.Synopse mORMot Framework Software Architecture Design 1.e. 17.At interface or method (service/operation) level . Group and User notions.PassWord).True.Rev.Length(fTableJSON)).Items.Execute(SQL. end. var TableNames: TRawUTF8DynArray. from the mORMotUI unit. TableNames := fService.For communication stream . wrong SQL statement). cbbTableNames..btnOpenClick(Sender: TObject). By default.Create(). 2013 remote SQL request. all interfaces and methods) are allowed to execution. securing messages between clients and services is essential to protecting data. try try if isSelect(pointer(SQL)) then begin fTableJSON := fService. end. (.) with fSettings do fService.At RESTful / URI authentication level . begin SQL := trim(StringToUTF8(mmoQuery. end else fService.7. or server side error.mORMot Framework .Text)). procedure TMainForm. 1. var SQL: RawUTF8.Text := UTF8ToString(RawUTF8ArrayToCSV(TableNames. e.Cursor := crHourGlass.btnExecuteClick(Sender: TObject).7. end.False). will "inject" the returned data to a standard TDrawGrid. (.Create(drwgrdData. the ShowExecption() method is used to notify the user with appropriate information. Note that in case of any exception (connection failure. In a Service-oriented architecture (page 63).DatabaseName.g. TSQLTableJSON.UserID.18 Date: June 16. Security is implemented at several levels: ..#13#10)). Here. TSQLTableToGrid. Screen.SQL.) Now we are connected to the database via the remote service. when using HTTPS protocol at the Client-Server process (page 196). .fClient).18 Page 277 of 1055 .Connect(Engine. Session. Then a particular SQL statement can be executed as such: procedure TMainForm.Create([]. and we retrieved the table names in a TComboBox..Execute(SQL. Your service can therefore provide some basic features. The first four methods will affect everybody.. S.DenyAllByID([GroupID+1]). S.5].'DenyAll will reset all settings').DenyAllByName() and DenyByName() to disable methods execution by Group names.. .DenyAll() and Deny() to disable methods execution globally. S.Services property) provides the following methods to change the security policy for each interface: .MainFieldID(TSQLAuthGroup. 4=ToText.DenyAllByID([GroupID]).3.AllowAllByName() and AllowByName() to enable methods execution by Group names.'by default. . S.5].3.'AllowAll should change nothing').4.2. In fact. you can use some kind of "fluent interface" in your code to set the security policy. // default user for Security tests Since TSQLRestServer.3.4. Test([].mORMot Framework ..2. the execution can be authorized for a particular group of authenticated users.DenyAllByID() and DenyByID() to disable methods execution by Group IDs.2. . on the server side (it's an implementation detail).3. Test([1.'exclude another method for the current user').ServiceRegister method returns the first created TServiceFactoryServer instance. Test([1.2. Test([1.[TypeInfo(ICalculator)]. Since the User / Group policy is fully customizable in our RESTful authentication scheme .'exclude a specific method for the current user').'restore allowed for everybody').Synopse mORMot Framework Software Architecture Design 1.ID values). TSQLAuthGroup.) The Test() procedure is used to validate the corresponding methods of ICalculator (1=Add.DenyByID(['Add'].AllowAllByID() and AllowByID() to enable methods execution by Group IDs.AllowAll.DenyByID(['totext']. Test([1. In this above code. S. 1.GroupID).see below (page 293).Ident property values. S. .4.e. DenyAll.3.AllowAll. And the current authenticated user is member of the 'User' group: fClient. and since all Allow* / AllowAll* / Deny* / DenyAll* methods return also a TServiceFactoryServer instance. 2013 Then.18 Page 278 of 1055 .Server.Services['Calculator'] as TServiceFactoryServer.. (.18 Date: June 16. mORMot provides a versatile and inter-operable security pattern.) S := fClient.'our current user shall be denied'). the GroupID value is retrieved as such: GroupID := fClient.3. and then enables advanced features for administrators or supervisors only. where as the *ByName() methods will handle TSQLAuthGroup..3.ServiceRegister(TServiceCalculator. S.'User').4.sicShared). the TServiceFactoryServer instance (available from TSQLRestServer. Test([1. Test([2.).5]. 2=Multiply.'back to full acccess for everybody'). as such: Server.5].5].AllowAll() and Allow() to enable methods execution globally.5]. The next *ByID() four methods accept a list of authentication Group IDs (i.AllowAll.SetUser('User'. Test([2.'synopse').'this group ID won''t affect the current user').AllowAllByName(['Supervisor']).2.4..5]. Test([].DenyAll. .Rev. SAD . S. 3=Subtract. Here is some extract of the supplied regression tests: (.GroupID).4. all methods are allowed'). e.g. 1. in you are in sicPerClient execution mode. service methods are called within the thread which received them. See in Enhanced sample: remote SQL access (page 273) some sample code implementing a IRemoteSQL service.Rev. the SetOptions() method follows a call signature similar to the one used for defining the service security.Synopse mORMot Framework Software Architecture Design 1. In fact. it could make sense to use a dedicated method with proper parameters to initialize your instance. your implementation class will inherit from TInterfacedObject. SetOptions(['Add']. you can write: Server.unless it has been defined with sicSingle or sicPerThread instance lifetime modes.2.18 Page 279 of 1055 .g. you can define: Server. That is. you can inherit from the TInterfacedObjectWithCustomCreate class. you could in fact inherit from any plain Delphi class: the only condition is that it implements the expected interface. 17. e.g. Setting optExecInMainThread option will force the specified method(s) to be called within a RunningThread. Implementation class types Most of the time.ServiceRegister(TServiceCalculator. and has a GUID. If you want all the methods of your TServiceCalculator class to be executed in the main thread. Server-side execution options When a service is registered on the server side.SetOptions() method.[TypeInfo(ICalculator)]. By default.g. 17.e.7. if your implementation rely heavily on COM servers. using the TServiceFactoryServer. It allows better response time and CPU use. This is the technical reason why service implementation methods have to handle multi-threading safety carefully. As stated above. 2013 This will allow access to the ICalculator methods only for the Supervisor group of users. when hosted by multi-threaded server instances (e.[optExecInMainThread]). The optFreeInMainThread will also allow side service class instance release in the main thread (i. which can be quite difficult to deal with.sicShared). ready to be overridden with your customized initialization: TInterfacedObjectWithCustomCreate = class(TInterfacedObject) public /// this virtual constructor will be called at instance creation constructor Create.3. TSQLite3HttpServer or TSQLRestServerNamedPipeResponse). by using TRTLCriticalSection mutex on purpose. with a dedicated Connect() method to be called before all other methods to initialize a sicClientDriven instance.ServiceRegister(TServiceCalculator.[optExecInMainThread]). end. SAD . its Free method called via Synchronize). Or if only the TServiceCalculator. virtual.7. without the need to worry about thread safety. But if you need a special process to take place during the class instance initialization.Synchronize() call .it can be used e.mORMot Framework .Add method has to be protected. SetOptions([].18 Date: June 16.[TypeInfo(ICalculator)]. some options can be defined in order to specify its execution details. but drawback is that the method implementation shall be thread-safe. But from the SOA point of view. or if you want to ensure that your code will work correctly.sicShared). the method context can be re-entrant . which provides the following virtual constructor. if the message body is left void.Routing property.. One benefit of using URI is that it will be more secure in our RESTful authentication scheme .7. The pure Delphi client implementation will use only POST. the needed instance ID is appended to the URI: POST /root/ComplexNumber.Add: POST /root/Calculator.][.) [1..18 Date: June 16. in sicClientDriven mode.see below (page 293): each method (and even any client driven session ID) will be signed properly. In conjunction with SAD .18 Page 280 of 1055 .2] Here we use a POST verb. defined by TServiceRoutingMode. 17. In this rmREST mode..Method[/ClientDriv enID] /Model/Interface Body content JSON array of parameters {"method":"MethodName". from a ).) [20.Rev. Here is typical request for ICalculator.2] on the server side. which is used to track the instance life-time..Add/1234 (.e. This is not used from a Delphi client (since it will be more complex and therefore slower).Add?+%5B+1%2C2+%5D In the above line."id":ClientDrivenID]} Security RESTful authentication for each method RESTful authentication for the whole service (interface) Speed 10% faster 10% slower In the default rmREST mode. the server is also able to retrieve the parameters from the URI. all const and var parameters). 1234 is the identifier of the server-side instance ID. if needed (e.4."params" :[. according to the requested URI. For a sicClientDriven mode service.7. but it can be used for a client. there are two mode of routing.mORMot Framework .Add (. rmREST rmJSON_RPC Description URI-based layout JSON-RPC mode Default Yes No URI scheme /Model/Interface.30] Here. at the application level. if needed: POST root/Calculator. Request format As stated above. 1.4. interface and method) are identified within the URI. but the framework will also allow GET.. And the message body is a standard JSON array of the supplied parameters (i. +%5B+1%2C2+%5D will be decoded as [1.Synopse mORMot Framework Software Architecture Design 1. Transmission content All data is transmitted as JSON arrays or objects.e.1.g.. We'll discuss how data is expected to be transmitted. The routing to be used is defined globally in the TSQLRest. both service and operation (i. 2013 17. ComplexCall (.g. Response format 17. whatever the routing mode used. var Str2: TWideStringDynArray.1231886296]."params":[1.4. 2013 the use of a GET verb."id":1234} This mode will be a little bit slower.) [1. Strs1: TRawUTF8DynArray.... since it has no purpose in sicShared mode.) {"method":"Add". const Rec1: TVirtualTableModuleProperties.three"].. POST /root/Calculator (. const Rec1: TVirtualTableModuleProperties.2.mORMot Framework . 1.4. Standard answer as JSON object The framework will always return the data in the same format.. It's up to you to select the right routing scheme to be used. but will probably be more AJAX ready. If rmJSON_RPC mode is used.) [[288722014.Add (."id":0} The result array contains all var and out parameters values (in their declaration order). For a sicClientDriven mode service: POST /root/ComplexNumber (."three"]. and the client driven "id": value (e."DEF". "Xow1EdkXbUkDYWJj"] will be answered as such: '{"result":[ ["ABC". this is a JSON object. ["ABC".. For instance. it may be more suitable for a remote AJAX connection. "BgAAAAAAAAAAAAAAAAAAACNEOlxEZXZcbGliXFNRTGl0ZTNcZXhlXFRlc3RTUUwzLmV4ZQ==". "id":0}' It matches the var / const / out parameters declaration of the method: function ComplexCall(const Ints: TIntegerDynArray.Rev.2. and then the method name will be inlined with parameters.18 Date: June 16. here is a transmission stream for a ICalculator.ComplexCall request in rmREST mode: POST root/Calculator.7. the URI will define the interface.g."DEF". SAD ."params":[20. And its implementation: function TServiceCalculator. e."two".."id":0} Here. and then the method main result.) {"method":"Add". 17.2].1."GHIJK". var Rec2: TSQLRestCacheEntryValue): TSQLRestCacheEntryValue. var Str2: TWideStringDynArray."GHIJK"]. the "id" field can be not set (and even not existing). ["one". Strs1: TRawUTF8DynArray.30]. "X4w1EdgXbUkUMjg4NzIyMDE0LDEyMzE4ODYyOTY=". with one nested "result": property. Basically..ComplexCall(const Ints: TIntegerDynArray.Synopse mORMot Framework Software Architecture Design 1.two."one. always 0 in sicShared mode): POST /root/Calculator.18 Page 281 of 1055 .2] will be answered as such: {"result":[3].7. "Xow1EdkXbUkjRDpcRGV2XGxpYlxTUUxpdGUzXGV4ZVxUZXN0U1FMMy5leGU="]. Str2[i] := UTF8ToWideString(RawUTF8ArrayToCSV(Strs1)). whereas complex records (like TSQLRestCacheEntryValue) have been Base-64 encoded. IComplexCalculator = interface(ICalculator) ['{8D0F3839-056B-4488-A616-986CF8D4DEB7}'] /// purpose of this unique method is to substract two complex numbers // . The framework is able to handle class instances as parameters. reintroduce.Synopse mORMot Framework Software Architecture Design 1. In case of an error. the result is declared as out parameter.Substract (. SetLength(Str2. 1. 2013 var Rec2: TSQLRestCacheEntryValue): TSQLRestCacheEntryValue. begin result := Rec2. TRawUTF8DynArray and TWideStringDynArray values were marshaled as JSON arrays.) [{"Real":2. out Result: TComplexNumber)."Imaginary":-27}]. published property Real: Double read fReal write fReal.ID).. inc(Rec2. end."Imaginary":30}] will be answered as such: {"result":[{"Real":-18. property Imaginary: Double read fImaginary write fImaginary.Rev. for instance with the following interface. aImaginary: double)."Imaginary":3}. end.using class instances as parameters procedure Substract(n1.18 Date: June 16. Note that TIntegerDynArray.JSON := StringToUTF8(Rec1. the standard message object will be returned: { "ErrorCode":400.JSON := IntegerDynArrayToCSV(Ints. var i: integer.18 Page 282 of 1055 . published properties of TComplexNumber parameters will be serialized as standard JSON objects: POST root/ComplexCalculator.length(Ints)). result. "ErrorText":"Error description" } The following error descriptions may be returned by the service implementation from the server side: SAD .TimeStamp).FileExtension). public constructor Create(aReal. end.{"Real":20.n2: TComplexNumber.mORMot Framework . During the transmission. so can be generated and consumed directly in any AJAX client. using a TPersistent child class with published properties (it would be the same for TSQLRecord ORM instances): type TComplexNumber = class(TPersistent) private fReal: Double. dec(Rec2.. i := length(Str2). it is not possible to return a class as a result of a function (who will be responsible of handling its life-time?).i+1). fImaginary: Double. Rec2."id":0} Those content have perfectly standard JSON declarations. As stated above. So in this method declaration. instance id:? not found or deprecated The supplied "id": parameter points to a wrong instance (in sicPerSession / sicPerUser / sicPerGroup mode) ExceptionClass: Exception Message (with 500 Internal Server Error) An exception was raised during method execution 17. aExpanded: Boolean): RawJSON. 1. end.mORMot Framework ..4. if you want to transmit a JSON content with interface-based services. aExpanded: Boolean): RawUTF8. For instance. if you define such a method: function TServiceRemoteSQL. That is. aExpectResults. and increase transmission bandwidth.3.see Security above .Execute SQL via services" for some working code using this feature.Create('Connect call required before Execute'). Therefore. defining the method as followed will increase process speed and reduce used bandwidth: function TServiceRemoteSQL. var res: ISQLDBRows.2. 17.4..FetchAllAsJSON(aExpanded). 2013 ErrorText Description Method name required rmJSON_RPC call without "method": field Unknown method rmJSON_RPC call with invalid method name (in rmRest mode. using RawJSON will also make the transmitted content much more AJAX friendly. The FetchAllAsJSON() method will return a JSON array content.ExecuteInlined(aSQL. Returns direct JSON content By default. and not a JSON string which would need JavaScript "unstringification".Execute(const aSQL: RawUTF8. A dedicated RawJSON type has been defined. and will specify to the mORMot core that the UTF-8 text is a valid JSON content. res := fProps. there is no specific message. This will slow down the process on both server and client side. Custom returned content Note that even if the response format is a JSON object by default.18 Page 283 of 1055 . since the returned value will be a valid JSON array or object.aExpectResults). and expected as such by our SAD . if res=nil then result := '' else result := res. and should not be escaped.2.Rev. but will be escaped as a JSON string when transmitted via a RawUTF8 variable.18 Date: June 16. begin if fProps=nil then raise Exception. As a consequence. See sample "16 .7. using a RawUTF8 will convert it to a JSON string.7.Synopse mORMot Framework Software Architecture Design 1. any JSON special characters (like " or \ or [) will be escaped.Execute(const aSQL: RawUTF8.2. aExpectResults. since it may be a valid request) Parameters required The server expect at least a void JSON array (aka []) as parameters Unauthorized method This method is not allowed with the current authenticated user group . HTML or even binary content.TestBlob(n: TComplexNumber): TServiceCustomAnswer.[C3.TestBlob(C3) do begin Check(Header=TEXT_CONTENT_TYPE_HEADER). Note that since there is only one BLOB content returned. Of course. 2013 TServiceContainerClient implementation. there is a way of returning any content from a remote request. Result.n. Here is a short reference table of WCF / mORMot SOA features and implementation patterns. with no JSON serialization.microsoft. In order to implement such method. This will return not a JSON object. Comparison with WCF Microsoft Windows Communication Foundation is the unified programming model provided by Microsoft for building service-oriented applications see http://msdn. in conjunction with rmREST mode and URI-encoded parameters. You may also be able to use this feature to implement custom UTF-8 HTML creation. end. begin Result. 17.Imaginary]). This may be implemented for instance as such: function TServiceComplexCalculator.Synopse mORMot Framework Software Architecture Design 1.Content := FormatUTF8('%. setting the Header value to HTML_CONTENT_TYPE_HEADER constant. you can use the following TServiceCustomAnswer record type as the result of an interface function: TServiceCustomAnswer = record Header: RawUTF8.e. end. no var nor out parameter will be transmitted (since there is no JSON result array any more). In order to specify a custom format. but a plain TEXT content.%'. Then the Content value will be transmitted back directly to the client. Check(Content=FormatUTF8('%. The Header field shall be not null (i. and contains the expected content type header (e. and will save client-server bandwidth when transmitting some BLOB data (since it won't serialized the content with Base64 encoding). Regression tests will make the following process: with CC. 1. If this is the case..com/en-us/library/dd456779. to specify your request. an exception will be raised during the interface registration step.C3.Rev. no var nor out parameters are allowed to be defined for this method. Content: RawByteString.8. TEXT_CONTENT_TYPE_HEADER or HTML_CONTENT_TYPE_HEADER). Feature WCF SAD . i. end. But you can define any const parameter needed.Header := TEXT_CONTENT_TYPE_HEADER. It may be used by AJAX or HTML applications to return any kind of data.%'. not equal to ''). Our TServiceFactoryClient instance is also able to handle such requests. you may define such an interface: IComplexCalculator = interface(ICalculator) ['{8D0F3839-056B-4488-A616-986CF8D4DEB7}'] function TestBlob(n: TComplexNumber): TServiceCustomAnswer.Real.[n.e.18 mORMot Page 284 of 1055 . but pure text. not only JSON results.g. end.Real.18 Date: June 16.Imaginary])).mORMot Framework . 18 Date: June 16. client-driven Configuration .config file or code code or any custom file Client acccess Layer source should be generated No layer.18 Page 285 of 1055 . but direct registration End points One end-point per contract Unique or shared end-point Operation synchronous/asynchronous synchronous (REST) Session available (optional) available (optional) Encryption at Service level at communication level Compression at Service level at communication level Serialization XML/binary/JSON JSON (customizable) Communication protocol HTTP/HTTPS/TCP/pipe/MSMQ HTTP/HTTPS/TCP/pipe/GDI/in-pr ocess HTTP/HTTPS server http. 2013 Internal design SOAP RESTful Hosting exe/service/ISS/WAS in-process/exe/service Scalability/balancing up to WAS by dedicated hosting MetaData WSDL JSON contract Data contract class class/record ORM integration separated integrated in the model Service contract interface + attributes interface + shared Model Versioning XML name-space interface signature Message protocol SOAP/custom RESTful Messaging single/duplex stateless (REST) Sequence attributes on methods interface life time Transactional fully transactional on implementation side Instance life time per call. per session.Rev.Synopse mORMot Framework Software Architecture Design 1. 1. single. per group. per session.mORMot Framework . per user. single per call.sys/native (winsock) Security Attribute driven User group driven Threading By attributes At service level Weight Middle Low Speed Good High SAD .sys http. per thread. But WCF also suffers from it: due to this ground-up message design. which is a web services package for FPC. or GDI local communication) are even unique to mORMot. Of course. it is not the easier way to go! At this time. You do not have to play with WSDL or unit wrappers. in order to handle transactions on the SOA side. note that in WCF InstanceContextMode. meaning that one instance is used per call. sicClientDriven is pretty convenient when implementing a Service Oriented Architecture. as such: . you will find out how the WCF plumbing is over-sized and over-complicated: imagine that WCF allows only one end-point per interface/contract . Some features (like per user. JSON.Single is in fact the same as sicShared within mORMot context: only one instance is used for all incoming calls and is not recycled subsequent to the calls. WCF features its SOAP-based architecture. 2013 Extensibility verbose but complete customizable Standard De facto KISS design (e. the only missing feature of mORMot's SOA is transactional process. . you can easily create a SOAP gateway from Delphi. Lazarus and Delphi.mORMot Framework .PerCall in WCF.Rev. we choose to not re-invent the wheel this time.org/Web_Service_Toolkit.Synopse mORMot Framework Software Architecture Design 1.in a SOLID design principles (page 239) world. and expects some plumping according to its format (especially when services are provided from C# or Java). within the service implementation (e. In fact.. where interface segregation should reign. even for a young and Open Source project.g. Event Sourcing and Unit Of Work design patterns have been added to the mORMot official road map. but not SAD .freepascal.18 Page 286 of 1055 . Since SOAP features a lot of requirements. or if you version of Delphi does not include SOAP process.Net framework (+ISS/WAS) None (blank OS) About instance life time. which is "Simple" only by name. the RESTful / JSON approach gives much better performance and ease of use.g. 1. If you need to communicate with an external service provider.1 compatible solution.18 Date: June 16. with explicit commit or rollback). relying on ORM for its data persistence. If you need a cross-platform SOAP 1.Publish the interface as a mORMot server-side implementation class. We may be tempted to say that mORMot SOA architecture is almost complete. per group or client-driven instance life time. sicSingle mode (which is mORMot's default) maps InstanceContextMode. Once you have used the ServiceRegister() methods of mORMot. Therefore. which must be handled on server side. But for service communication within the mORMot application domain. you may take a look at http://wiki. HTTP) Source code Closed Published License Proprietary Open Price Depends Free Support Official + community Community Runtime required . not by reputation. it will always endure its SOAP overweight. and rely on existing Delphi libraries (available within the Delphi IDE) for this purpose.Import the WSDL (Web Service Definition Language) definition of a web service and turn it into a Delphi import unit. just share some interface definition between clients and servers. 18 Page 287 of 1055 .. transactions should better be implemented at SOA level. and we do not want to rely on the DB layer for this feature).see http://bliki.mORMot Framework . 2013 depending on database transactional abilities.Rev. In fact. Event Sourcing sounds to be a nice pattern to implement a strong and efficient transactional process in our framework . 1. SAD .18 Date: June 16.com/event-sourcing/why. as we do want transactions to be database agnostic (SQLite3 has a limited per-connection transactional scheme.Synopse mORMot Framework Software Architecture Design 1.abdullin. Rev. the easiest is to have your main TSQLRestServer class handling the service.Client / Server (page 50) about this generic Client-Server architecture. . on demand. and a separate safe database and logic instance. . you should want to use a dedicated process (or even dedicated hardware) to split the database and the service process.mORMot Framework .18 Date: June 16. See General mORMot architecture . and would like to have a DMZ hosting only services. SAD .Synopse mORMot Framework Software Architecture Design 1. in conjunction with other Client-Server process (like ORM). But you may find out some (good?) reasons which main induce another design: . Hosting Adopt a mORMot About hosting.To implement an efficient solution for the most complex kind of application. 2013 18. this is perfectly working and scalable.18 Page 288 of 1055 .Services are not the main part of your business. 1. . 18. Shared server This is the easiest configuration: one HTTP server instance.1.Whatever your IT or managers want mORMot to. and you would like to enable or disable on need the exposed services.For security reasons. which serves both ORM and Services. . you want to expose only services to your Internet clients. On practice.For better scalability. as provided by Domain-Driven design (page 67). direct access will be the faster solution.Setting the group user rights properly .see below (page 293) . .Rev. as such: .shared server You can tune this solution. 1. "HTTP server 1" is used by both PC 1 and Services to access the ORM.but allow rich Delphi clients (like PC1) to access the ORM. and vice-versa: if your services and ORM are deeply inter-dependent.1 PC 1 Client 1 (Delphi) Internet (VPN) JSON + REST over HTTP/1. 18.You can have direct in-process access to the service interfaces from the ORM. two physical servers are available: .18 Date: June 16.you can disable the remote ORM access from the Internet.18 Page 289 of 1055 .Both "PC Client 1" and the ORM core are able to connect to Services via a dedicated "HTTP server 3".1 Local Network PC Server HTTP server ORM Service Service Hosting on mORMot .A network DMZ is opened to serve only service content over the Internet. for the AJAX Clients .2. .Then on the local network. 2013 PC 2 Client 2 (AJAX) JSON + REST over HTTP/1. Two servers In this configuration.Synopse mORMot Framework Software Architecture Design 1. SAD . via "HTTP server 2". .mORMot Framework . the database will be located on "PC Server internal". 2013 PC 2 PC 1 Client 2 (AJAX) Client 1 (Delphi) JSON + REST over HTTP/1. ."PC Client 1" will access to the ORM via "HTTP server 1".Rev. In this case.1 Local Network PC Server DMZ HTTP server 2 PC Server internal HTTP server 3 Services HTTP server 1 ORM Service Hosting on mORMot . 1. SAD . i. since ORM and Services are on the same computer.3.two servers Of course. only one physical server is deployed: .1 Internet (VPN) JSON + REST over HTTP/1. Two instances on the same server This is the most complex configuration. whereas Services will serve their content to the ORM via "Named Pipe server 1". using named pipes (or even local GDI messages) instead of slower HTTP-TCP/IP is a good idea: in such case.A dedicated "HTTP server 2" instance will serve service content over the Internet (via a DMZ configuration of the associated network card). 18. In order to access the remote ORM features.e. and the Services will be one regular client: so we may use CRUD level cache (page 217) on purpose to enhance performance.18 Date: June 16. ORM will access services via "Named Pipe server 2".mORMot Framework .Synopse mORMot Framework Software Architecture Design 1. the one hosting the ORM. and provide a communication endpoint to the embedded services. a TSQLRestServerRemoteDB kind of server class can be used.For performance reasons. .18 Page 290 of 1055 . or to services via "HTTP server 3". and has therefore basic ORM needs (e.1 ORM Internet (VPN) Named Pipe server 2 HTTP server 3 HTTP server 2 Services Named Pipe server 1 Service Hosting on mORMot . 2013 PC 1 Client 1 (Delphi) JSON + REST over HTTP/1.18 Page 291 of 1055 . perhaps not worth it in this case. which will cooperate for better scaling and performance. you may need only CRUD statements for handling authentication). You can even create several ORM servers or Services servers (grouped per features family or per product). two instances Of course. 1. you may use the lighter TSQLRestServerFullMemory kind of server instead of a full TSQLRestServerDB.18 Date: June 16. which will embed a SQLite3 database engine. you can make any combination of the protocols and servers.mORMot Framework .g.1 Local Network PC Server PC 2 Client 2 (AJAX) HTTP server 1 JSON + REST over HTTP/1. SAD .Synopse mORMot Framework Software Architecture Design 1. to tune hosting for a particular purpose. If you consider implementing a stand-alone application for hosting your services.one server.Rev. Process safety. for SQL or Service remote execution. from very secure SHA-256 based challenging to weak but simple authentication.mORMot Framework . . .Object-relational mapping (page 65) associated to the Object pascal strong type syntax.see below (page 307) .Rev.Per-method execution policy for interface-based services.Atomicity of the SQLite3 database . 1.Authentication. . . . .Build-in optional authentication mechanism.General high-level security attributes. Process safety is implemented at every Multi-tier architecture (page 61) level: . .Extended test coverage .Authentication groups are used for proper authorization. SAD .Authorization. Security Adopt a mORMot The framework tries to implement security via: .Per-table access right functionalities built-in at lowest level of the framework. Authorization of a given process is based on the group policy.18 Page 292 of 1055 . allowing custom extension. . 2013 19. Process safety has already been documented (see links above). implementing both per-user sessions and individual REST Query Authentication. after proper authentication: .18 Date: June 16.see ACID and speed (page 153). . .Class-based architecture.Synopse mORMot Framework Software Architecture Design 1. Authentication allows user identification: .REST is Stateless (page 193) architecture to avoid most synchronization issues.Several authentication schemes.of the framework core. 1. is used by most web services. from "author") is the act of confirming the truth of an attribute of a datum or entity. Each authentication scheme has its own PROs and CONs. 19. but has some known draw-backs.Synopse mORMot Framework Software Architecture Design 1. . It's easy to implement. . Authentication often involves verifying the validity of at least one form of identification. 2013 We will now give general information about both authentication and authorization in the framework. and the fact that the user-name and password SAD . or ensuring that a product is what its packaging and labeling claims to be. We'll have to adapt. This might involve confirming the identity of a person or software program. depending on the purpose of your security policy and software architecture: Criteria HTTPS basic auth Cookies+Session Query Auth. 1. available by default on all browsers. which will persist (there is no LogOut-like feature here).mORMot Framework . HTTP basic auth over HTTPS This first solution.1.Rev.1. tracing the origins of an artifact.Cookies and session management.HTTP basic auth over HTTPS. based on the standard HTTPS protocol. Principles How to handle authentication in a RESTful Client-Server architecture is a matter of debate.18 Page 293 of 1055 .Query Authentication with additional signature parameters. in the SOA over HTTP world via: . or even better mix those techniques. like the awful authentication window displayed on the Browser. 19. to match our framework architecture at best.1.18 Date: June 16. Browser integration Native Native Via JavaScript User Interaction Rude Custom Custom Web Service use (rough estimation) 95% 4% 1% Session handling Yes Yes No Session managed by Client Server N/A Password on Server Yes Yes/No N/A Truly Stateless Yes No Yes Truly RESTful No No Yes HTTP-free No No Yes 19.1. some server-side additional CPU consumption. Commonly. it can be achieved. Authentication Extracted from Wikipedia: Authentication (from Greek: "real" or "genuine".1. 1. 19.With per-user authentication and right management via defined security groups. theoretically speaking. the cookie is handled on the Server side (Client in fact don’t even try to interpret this cookie data: it just hands it back to the server on each successive request). so the client should manage it.18 Date: June 16. alphabetical order using the private credential as the signing token.1.18 Page 294 of 1055 . not at the URI level (thanks to our optimized implementation of GetJSONObjectAsSQL.2. and a per-query SAD .g. One possibility could be to maintain all data within the cookie content. for local access of data.2. 19.Rev. and can also been implemented with a light session management. It was defined as such in this article: All REST queries must be authenticated by signing the query parameters sorted in lower-case. and the THttpApiServer server class can send compatible content.Synopse mORMot Framework Software Architecture Design 1. In practice. And. Framework authentication Even if. See http://broadcast. the URI to SQL conversion is very fast). So adding this extra parameter doesn't break the cache mechanism. 2013 are transmitted (over HTTPS) into the Server (it should be more secure to let the password stay only on the client side. we may consider two way of using it: . here is a generic URI sample from the link above: GET /object?apiKey=Qwerty2010 should be transmitted as such: GET /object?timestamp=1261496500&apiKey=Qwerty2010&signature=abcdef0123456789 The string being signed is "/object?apikey=Qwerty2010&timestamp=1261496500" and the signature is the SHA256 hash of that string using the private component of the API key.oreilly.mORMot Framework . Since our framework does not provide only HTTP protocol. by design.With no authentication nor user right management (e. Server-side data caching is always available. 19.3. Query Authentication Query Authentication consists in signing each RESTful request via some additional parameters on the URI.. not the server. In our framework. our framework tries to implement a Client-Server design. but offers other ways of transmission. For instance. This technique is perhaps the more compatible with a Stateless architecture. or framework use over a secured network). so it's not truly RESTful.com/2009/12/principles-for-standardized-rest-authentication. Query Authentication sounds to be the better for implementing a truly RESTful architecture. and be stored as secure hash on the Server). in a pure Stateless world.1. Cookies were left at the baker's home.1.html.1.1. The supplied TSQLHttpClientWinHTTP and TSQLHttpClientWinINet clients classes are able to connect using HTTPS. But this cookie data is application state data. The cookie technique itself is HTTP-linked. a session managed on the Server is not truly Stateless. Session via Cookies To be honest. about this technique. . Signing should occur before URI encoding the query string. which should be protocol-independent. during keyboard entry. we cache the responses at the SQL level. the ability to execute INSERT / UPDATE / DELETE SQL statement via a RESTful POST command is never allowed by default with remote connections: only SELECT can be executed via this POST verb. All tables will be accessible by any client. defined by the TSQLAuthGroup and TSQLAuthUser classes will handle respectively per-group access rights. as stated in below (page 302). Here is the layout of the AuthGroup table. will allow the change of the MAX_SQLTABLES constant value. is defined as such: SAD . the following security features will be added: . Using the URI instead of cookies allows the signature process to work with all communication protocols.1. if the aHandleUserAuthentication parameter was set to false for the TSQLRestServer.18 Page 295 of 1055 . Using a CSV serialization. and the aHandleUserAuthentication parameter was set to true at the TSQLRestServer instance construction).Each CRUD statement is checked against the authenticated User security group. 1. and provide a valid UserName / Password pair (see next paragraph). Create constructor). A minimal "session-like" feature was introduced only to handle user authentication with very low overhead on both Client and Server side.18 Date: June 16. .mORMot Framework .Client should open a session to access to the Server. as expected by the TSQLRestServer. no authentication is performed. and user authentication. If authentication is enabled for the Client-Server process (i. and create a session. if both AuthGroup and AuthUser are available in the Server TSQLModel.Each REST request will expect an additional parameter. named session_signature. to every URL. via the AccessRights column and its GET / POST / PUT / DELETE per-table bit sets. . as defined by the TSQLAuthGroup class type: ID : integer AccessRights : RawUTF8 Ident : RawUTF8 SessionTimeout : integer AuthGroup Record Layout The AccessRights column is a textual CSV serialization of the TSQLAccessRights record content.e. The AuthUser table. instead of a binary serialization. a per-URI signature. i. for security reasons.Rev. . 19. Per-User authentication On the Server side. According to RESTful principle.1. accessible via the ModelRoot/Auth URI is to be called to register an User.Synopse mORMot Framework Software Architecture Design 1. as defined by the TSQLAuthUser class type. any SQL statement commands may be available via the RESTful POST verb for an user with its AccessRights group field containing AllowRemoteExecute=true.e.Thanks to Per-User authentication. a dedicated service. 2013 authentication. On the Server side. handling per-session data is not to be implemented in such architecture.URI method. If both AuthGroup and AuthUser are not available on the Server TSQLModel (i.2. As stated above. The main technique used for our security is therefore Query Authentication. two tables.e. not only HTTP. 0"} . a name to be entered at login.1-256."DisplayName":"Admin"."AccessRights":"10.1-256."PasswordHashHexa":"67aeea294e1cb515236fd7829 c55ec820ef888e8e221814d24d83b3dc4d825dd". {"RowID":3. 1.0. AllowRemoteExecute = true) and modify the Auth* tables (i. 'Admin' will be the only group able to execute remote not SELECT SQL statements for POST commands (i.0."GroupRights":2."PasswordHashHexa":"67aeea294e1cb515236fd7829c5 5ec820ef888e8e221814d24d83b3dc4d825dd"."GroupRights":1.Rev. {"AuthGroup":[ {"RowID":1.18 Date: June 16.0"}.0.0.0"}]}] Of course. the following security groups are created on a void database: AuthGroup POST SQL Auth Read Auth Write Tables R Tables W Admin Yes Yes Yes Yes Yes Supervisor No Yes No Yes Yes User No No No Yes Yes Guest No No No Yes No Then the corresponding 'Admin'."SessionTimeout":60. {"RowID":3.1-256.0. but not accessed by the framework. SAD ."Data":null}.3-256."SessionTimeout":10.3-256. {"RowID":2.1-256. 2013 ID : integer Data : TSQLRawBlob DisplayName : RawUTF8 GroupRights : TSQLAuthGroup LogonName : RawUTF8 PasswordHashHexa : RawUTF8 AuthGroup AuthUser Record Layout Each user has therefore its own associated AuthGroup table.3-256."DisplayName":"User". speaking about the TSQLAccessRights record layout. A custom Data BLOB field is specified for your own application use.3-256."GroupRights":3. with the default 'synopse' password."DisplayName":"Supervisor"."LogonName":"Supervisor"."Data":null}."LogonName":"Admin".mORMot Framework ."Ident":"User".0.1-256.3-256. A typical JSON representation of the default security user/group definitions are the following: [{"AuthUser":[ {"RowID":1.18 Page 296 of 1055 . to match your security requirements.0. You MUST override those default 'synopse' passwords for each AuthUser record to a custom genuine value. {"RowID":4.e. By default. This will implement both Query Authentication together with a group-defined per-user right management. a name to be displayed on screen or reports."Ident":"Supervisor".Synopse mORMot Framework Software Architecture Design 1. you can change AuthUser and AuthGroup table content.0.0. via the AccessRights column."LogonName":"User"."SessionTimeout":60. to have TSQLAccessRights.0. 'Supervisor' and 'User' AuthUser accounts are created.e."AccessRights":"10."Ident":"Admin"."Ident":"Guest"."SessionTimeout":60."AccessRights":"11.0.0" }.3-256."PasswordHashHexa":"67aeea294e1cb51 5236fd7829c55ec820ef888e8e221814d24d83b3dc4d825dd"."AccessRights":"0. as we stated above. AuthUser and AuthGroup) content. You can specify a per-table CRUD access. and application specifications.3-2 56. and a SHA-256 hash of its registered password. {"RowID":2.0."Data":null}]}.3-256. .SessionGetUser(aSessionID: Cardinal): TSQLAuthUser method. handling so called sessions.1. in a multi-client concurrent architecture.In-memory session allows very fast process and reactivity. The only access available is via the function TSQLRestServer.AcquireWrite / ReleaseWrite protected methods.Rev. Therefore.If a transaction began and another client session try to write on the DB. In mORMot. is to be used for user authentication. and use it to allow client-safe writing. for performance and security reasons. .2.If the server do not handle Session/Authentication.Synopse mORMot Framework Software Architecture Design 1. sessions are used to manage safe cross-client transactions: .e. Session handling A dedicated RESTful service.18 Date: June 16.The unique ModelRoot/Auth URI end-point will create a session after proper authorization. in order to explicitly close the corresponding session in the server memory (avoiding most re-play attacks).1. it will store the corresponding client Session ID. Note that each opened session has an internal TimeOut parameter (retrieved from the associated TSQLAuthGroup table content): after some time of inactivity. it's mandatory to release a transaction (via commit or rollback) as soon as possible.2. transactions can be unsafe. available from the ModelRoot/Auth URI. but rely on the SessionID identifier. until the transaction is released (via commit or rollback).URI. . Those sessions are in-memory TAuthSession class instances..Any further write to the DB (Add/Update/Delete) will be accessible only from this Session ID. Authentication schemes 19. and used on the Server-Side by TSQLRestServer. . The server methods should not have to access those instances directly.This global write locking is implemented in the TSQLRest. mORMot is not tied to cookies. on Server side..Destroy).An integer session identifier is used for all authorization process. .1. a very light in-memory set of sessions is implemented: . a GET ModelRoot/auth?UserName=.a timeout may occur if the server is not able to acquire the write status within some time. 2013 19. Note that this class does not inherit from a TSQLRecord table so won't be remotely accessible. sessions are closed on the Server Side. and its session process is much more generic).18 Page 297 of 1055 .&Session=. independently from the underlying authentication scheme (i. it will wait until the current transaction is released .3. 19..3.mORMot Framework .. In addition.1. Class-driven authentication Authentication is implemented in mORMot via the following classes: SAD . When the Client is about to close (typically in TSQLRestClientURI. 1.When a transaction is initiated by a client. . request is sent to the remote server. for performance reasons in a multi-client environment. Synopse mORMot Framework Software Architecture Design 1. based on user name All those classes will identify a TSQLAuthUser record from a user name.) In order to define one or several authentication scheme. The associated TSQLAuthGroup is then used later for authorization. You can add you own custom authentication scheme by defining your own class. both default secure mORMot authentication and Windows authentication are available.Rev. you can use one of the following RESTful authentication schemes: class Scheme TSQLRestServerAuthenticationDefault mORMot secure authentication scheme. based on a proprietary dual-pass challenge and SHA-256 hashing TSQLRestServerAuthenticationSSPI Windows authentication. aHandleUserAuthentication: boolean). the constructor executes the following: constructor TSQLRestServer. (.3.TSQLRestServerAuthenticationSSPI]).. By default..mORMot Framework .) if aHandleUserAuthentication then // default mORMot authentication schemes AuthenticationRegister([ TSQLRestServerAuthenticationDefault. mORMot secure RESTful authentication The TSQLRestServerAuthenticationDefault class implements a proprietary but secure RESTful Authentication (page 293). (. 19.Create(aModel: TSQLModel. 1.. you can call the AuthenticationRegister() and AuthenticationUnregister() methods of TSQLRestServer. via the logged user TSQLRestServerAuthenticationNone Weak but simple authentication. Here are the typical steps to be followed in order to create a new user session via mORMot authentication scheme: SAD .18 Page 298 of 1055 .Create().. no authentication is performed.18 Date: June 16. 2013 TSQLRestServerAuthenticationSSPI TSQLRestServerAuthenticationDefault TSQLRestServerAuthenticationSignedURI TSQLRestServerAuthenticationNone TSQLRestServerAuthenticationURI TSQLRestServerAuthentication TSQLRestServerAuthentication classes hierarchy In fact. In fact. If you set the aHandleUserAuthentication parameter to true when calling the constructor TSQLRestServer.1. inheriting from TSQLRestServerAuthentication.2. ..Client sends a GET ModelRoot/auth?UserName=. in which ClientNonce is a random value used as Client nonce. i. to enhance security with no performance penalty. and the URI parameters are not sorted alphabetically. Query Authentication is handled at the Client side in TSQLRestClientURI. using both Server and Client nonce as salt. that its matches the hashed password stored in its database and a time-valid Server nonce . Server will create a new in-memory session and return the session number and a private key to be used during the session (encoded as JSON result object). by computing the session_signature parameter for a given URL. In order to enhance security.Server answers with an hexadecimal nonce contents (valid for about 5 minutes). Such a classical 3 points signature will avoid most man-in-the-middle (MITM) or re-play attacks. encoded as JSON result object.if the value is not correct.On any further access to the Server.pointer(aURL).18 Date: June 16.18 Page 299 of 1055 ..e. .Client sends a GET ModelRoot/auth?UserName=.8). and 65D8D454 is the signature. and not the more secure (but much slower) SHA-256. either from a Delphi Client or from a AJAX / JavaScript client. The security involved by using crc32 will be enough for most common use.Rev. using the session private key. 1. the user hashed password. authentication fails. the URI signature will use fast crc32 hashing method. .Synopse mORMot Framework Software Architecture Design 1. this scheme is secure and very fast. the session_signature parameter is appended at the end of the URI. This should not be a problem. request to the remote server..aURLlength)=aSignature).&ClientNonce=. and the supplied Client Time Stamp as source for its crc32 hashing algorithm.PTimeStamp. perfect for a Delphi client.Server checks that the transmitted password is valid. SAD .A Client Time Stamp (in 256 ms resolution) which must be greater or equal than the previous time stamp received.. . and PassWord is computed from the log-on and password entered by the User. according to the TSQLRestServerAuthentication class used. . and will be checked against the valid sessions in order to validate the request.. 0000004C is the Session ID. In our implementation. encoded as 3 hexadecimal 32 bit cardinals: . Since our security model is not officially validated as a standard method (there is no standard for per URI authentication of RESTful applications).&PassWord=.. validated for both client and server side. For instance. the session_signature parameter will contain.mORMot Framework . 000F6BE3 is the client time stamp (aka nonce). Here is typical signature to access the root URL root?session_signature=0000004C000F6BE365D8D454 In this case. Note that the password hashing and the session opening will use SHA-256. request to the remote server. for better Server-side reaction.The URI signature. . .The Session ID (to retrieve the private key used for the signature).On success. using standard HTTPS with certificates signed by a trusted CA. On practice. as suggested by the reference article quoted above. 2013 .. the better security will be handled by encrypting the whole transmission channel. a RESTful GET of the TSQLRecordPeople table with RowID=6 will have the following URI: root/People/6?session_signature=0000004C000F6DD02E24541C For better Server-side performance. checked by the following Delphi expression: (crc32(crc32(fPrivateSaltHash. a &session_signature= parameter is added to the URL. .SessionSign method. 1.SetUser() method with a void aUserName parameter will try to use current logged name and password to perform a secure Client-Server authentication..e.'User').AuthenticationRegister(TSQLRestServerAuthenticationNone).4.mORMot Framework . Authentication using Windows credentials By default.18 Date: June 16. but not eligible to the application.3. Only prerequisite is that the TSQLAuthUser table shall contain a corresponding entry.. i. with its LogonName column equals to 'DomainName' value. It will implement a weak but simple authentication scheme. will be used.3. that it is available in the TSQLAuthGroup table . This may be an issue for corporate applications. but her/his Windows credentials. This data row won't be created automatically.Client sends a GET ModelRoot/auth?UserName=. any call to TSQLRestClientURI. Clients authentication SAD . Weak authentication The TSQLRestServerAuthenticationNone class can be used if you trust your client (e.18 Page 300 of 1055 . so should not be used for Delphi clients. .Server checks that the transmitted user name is valid. This will be transparent to the framework. a RESTful GET of the TSQLRecordPeople table with RowID=6 will have the following URI: root/People/6?session_signature=0000004C Here is some sample code about how to define this authentication scheme: // on the Server side: Server. It will in fact call the class function TSQLRestServerAuthenticationSSPI.4. which may be annoying. 19. Server will create a new in-memory session and returns the associated session number (encoded as hexadecimal in the JSON result object). . In this case. // on the Client side: TSQLRestServerAuthenticationNone. the hash of the user password is stored safely on the server side. since it is up to the application to allow or disallow access from an authenticated user: you can be member of the domain.On success. Since revision 1.1. a &session_signature= parameter is to be added to the URL with the correct session ID. and will be checked against the valid sessions in order to validate the request. since a new user name / password pair is to be defined by each client. via a https connection).Rev. If the SSPIAUTH conditional is defined (which is the default). as entered at Windows session startup.18 of the framework.if the value is not correct. mORMot is able to use Windows Authentication to identify any user.. and a regular session will be created on success.1.3. For instance..g.ClientSetUser() method. 2013 19. . the user does not need to enter any name nor password.1.On any further access to the Server. 19. request to the remote server.ClientSetUser(Client. authentication fails . That is. Here are the typical steps to be followed in order to create a new user session via this authentication scheme: . the aPassword parameter will just be ignored.Synopse mORMot Framework Software Architecture Design 1. The performance benefit is very small in comparison to TSQLRestServerAuthenticationDefault. 4.. This will allow checking of access right for all CRUD operations.4.2. In fact.URI(var Call: TSQLRestServerURIParams). and ask again for the User pseudo and password at any time to create a new session. the Open Source DWS (DelphiWebScript) compiler matches our needs see http://delphitools.php?pid=2995#p2995. In the future. it's up to the Client to react to an authentication error during any request.18 Date: June 16. Of course. according to the table invoked. Per-table access rights Even if authentication is disabled. See http://synopse. is sent as a member of the parameter to the unique access point of the server class: procedure TSQLRestServer. you may add a custom notification to register the corresponding user to the TSQLAuthUser table. and its GET / POST / PUT / DELETE fields. For multiple reasons (server restart..Synopse mORMot Framework Software Architecture Design 1. It will probably rely on pure-pascal implementation using such an Object-Pascal-to-JavaScript compiler . some "official" code will be available for such AJAX clients.Table=nil then begin (. as such: case URI.POST field is set.) the session can be closed by the Server without previous notice.. then call the SetUser method as such: Check(Client. not to break the ORM design. a pointer to a TSQLAccessRights record. 19. which implements the authentication schema as detailed above.1. the Client should just use create one instance of the TSQLRestClientURI classes as presented in JSON RESTful Client-Server (page 184). var aUserName.mORMot Framework . The current revision of the framework contains the code as expected by this JavaScript code especially the results encoded as JSON (page 184) objects.'synopse')).it does definitively make sense to have Delphi-like code on the client side. session timeout. any incoming POST command for TSQLRecordPeople will be allowed only if the 2nd bit in RestAccessRights^. if the table TSQLRecordPeople has 2 as index in TSQLModel. It uses jQuery. 2013 19. 19..Tables[]. For instance. and HTML 5 LocalStorage. if Windows Authentication is defined (see above). for storing session information on the Client side. For instance.info/forum/viewtopic. not cookies..1. For instance.info/tag/javascript. Authorization 19.1.Method of mPOST: begin // POST=ADD=INSERT if URI.2. Client interactivity Note that with this design.SetUser('User'. in order to ask the user to enter its login name and password: TOnAuthentificationFailed = function(Retry: integer.18 Page 301 of 1055 .) end else SAD . Authentication using AJAX Some working JavaScript code has been published in our forum by a framework user (thanks.1. aPassword: string): boolean.. this event handler shall be adapted as expected.Rev. // use default user Then an event handled can be associated to the TSQLRestClientURI. "RangerX"). 1. OnAuthentificationFailed property.2. AccessRights field if an authentication user session.18 Date: June 16. Be aware than this per-table access rights depend on the table order as defined in the associated TSQLModel. inline parameter to a GET request (with optional paging).AccessRights field. 19.. we recommend to write a dedicated server-side service (method-based or interface-based) to execute such statements. Table<>nil and TableIndex in [0.1. 1..2. the POST command with no table associated in the URI allows to execute any SQL statement directly. On the other hand.. from the bottom-most level of the framework. as implemented by Authentication (page 293).2. if the SQL statement is not a SELECT. 19. SQL remote execution In our RESTful implementation. So if you add some tables to your database model..OutStatus := HTML_FORBIDDEN else (... is used to override the access rights with the one defined in the TSQLAuthGroup. The reUrlEncodedDelete option is used to enable or disable this feature. Only direct access via TSQLRestClientDB will use FULL_ACCESS_RIGHTS. the SUPERVISOR_ACCESS_RIGHTS constant is transmitted for all handled communication protocols (direct access. This special command should be carefully tested before execution.e.RestAccessRights^. a WhereClause=. In fact.Synopse mORMot Framework Software Architecture Design 1.2. inline parameter can be added to a DELETE request. reUrlEncodedSQL or reUrlEncodedDelete in the TSQLAuthGroup. the security policy defined by this global parameter does not allow tuned per-user authorization.MAX_SQLTABLES-1] if not (URI. It adds some options to tune the security policy. Service execution SAD . will have AllowRemoteExecute parameter set to true. You can change the default safe policy by including reSQL. Additional safety A AllowRemoteExecute: TSQLAllowRemoteExecute field has been made available in the TSQLAccessRights record to tune remote execution.18 Page 302 of 1055 . By default. 19. The light session process. The reUrlEncodedSQL option is used to enable or disable this feature.2.2.POST) then // check User Call. is unsafe. named pipe or HTTP). 2013 // here.) Making access rights a parameter allows this method to be handled as pure stateless. But since remote execution of any SQL statements can be unsafe. It means that no remote call will be allowed but for safe read-only SELECT statements. this AllowRemoteExecute field value in SUPERVISOR_ACCESS_RIGHTS constant does not include reSQL.. depending on the authenticated user. i.TableIndex in Call. if it may affect the data content. please take care to add the new tables after the existing.. you will need to update the access rights values. since SQL misuses could lead into major security issues.2. for security reasons.mORMot Framework .Rev. Such execution on any remote connection. Last but not least. If you insert the new tables within current tables. Another possibility of SQL remote execution is to add a sql=. In the current implementation. GDI messages.2. thread-safe and session-free. you can set per-service and per-method Security (page 277). You can use TSQLRestServer. any method execution will be processed only for signed URI.e.18 Page 303 of 1055 . if authentication is enabled. it is the case for Auth and TimeStamp standard method services. SAD . 1.mORMot Framework .18 Date: June 16. For Client-Server services via methods (page 229).g.ServiceMethodByPassAuthentication() to disable the need of a signature for a given service method .Rev. 2013 The reService option can be used to enable or unable the Client-Server services via interfaces (page 257) feature of mORMot.Synopse mORMot Framework Software Architecture Design 1. In addition to this global parameter. Addison-Wesley. rich on behavior. Model-Driven Design define model with Ubiquitous Language process model with Services express model with Entities express model with Value Objects encapsulate with access with instantiated by Repositories Layered Architecture exclude RAD encapsulate with Aggregates access with isolate domain with instantiated by instantiated by Factories Domain Driven Design n-Tier Architecture . 2013 20. It is inspired from the one included in the Eric Evans's reference book.e. "Domain-Driven Design". Let us list the most high-level definitions of DDD objects: . or seats in a Rock concert. DDD objects For the definition of your objects or internal data structures (what good programmers care about).18 Page 304 of 1055 . you are encouraged to make a difference between several kind of objects. money bills. 1.Synopse mORMot Framework Software Architecture Design 1. Following DDD.g. 2004. generally speaking. therefore also of several families/species of objects. The following diagram is a map of the patterns presented and the relationships between them. according to your customer needs. This is were Domain-Driven design (page 67) (DDD) patterns are worth looking at.Implementation 20. Domain-Driven-Design We have now discovered how mORMot offers you some technical bricks to play with. as they are interchangeable. size) but no conceptual identity . SAD . Domain-level representation are.Value Objects contain attributes (value.18 Date: June 16.mORMot Framework . but it is up to you to build the house (castle?).1.Rev. Ubiquitous Language is where everything begins.Data Transfer Objects (DTO) are transmission objects. . since they communicate data about an event and they themselves encapsulate no behavior . especially at the application layer: . It encourages you to create gatekeepers that work to prevent non-domain concepts from leaking into your model. which purpose is to not send your domain across the wire (i. You may benefit in defining your own repository interface. Such abstraction helps testing . via our mORMot TSQLRecord and TSQLRest classes and their Client-Server ORM features. following the Anti-Corruption Layer pattern). . but you can not directly access to its internal objects). In addition to these domain-level objects.see Client-Server services via interfaces (page 257). separate your layers.18 Page 305 of 1055 .see Interfaces in practice: dependency injection. domain experts use company.Value objects are immutable by definition.Aggregates are collection of objects (Values and/or Entities) that are bound together by a root entity. you can link to an aggregate via its ID. DDD patterns DDD then favors some patterns to use those objects efficiently: . are you changing $20? No. In the real outside world. Main benefit is that alternative implementations may be easily interchanged.mORMot Framework .2.18 Date: June 16. They keep both domain and application layers clean.Commands and Events are some kind of DTO. it is critical that developers use the business language in code consciously and as a disciplined rule. 20. we shall find corresponding class names in the code. so should be handled as read-only. When you add $20 to $20. If the terms "class code" or "rate sets" or "exposure" are frequently used in conversation.but also introduces interface-based services . 2013 . i.e. . signified by an identity .g.Repository pattern is used to save and dispense each Aggregate root.Factory pattern is used to create object instances. Why is it important that they be immutable? With value objects. e. 1. they tend to be the main access point of all process. or seats in most planes. if the standard ORM / CRUD operations are not enough.e.Rev.saving data is indeed a concern orthogonal to the model itself. It matches the "Layer Supertype" pattern (see above). yet another concept borrowed by DDD. As developers. See Shared nothing architecture (or sharding) (page 102) which sounds like http://martinfowler. not domain. Typically.or industry-standard terminology.com/bliki/AggregateOrientedDatabase. Some architects claim that persistence is infrastructure.html. . aggregates are persisted in the database. as each one is unique and identified. some cross-cutting types may appear. persons. and the behavior matches accordingly. In the domain.Aggregate roots and entities. .Entity objects are defined by their attributes. SAD . since aggregate roots are the only kind of entity to which your software may hold a reference. for the other 10th kind of people how do not know about binary. but have a thread of continuity. stubs and mocks (page 247) . They are incapable of change once they are created.g. you are creating a new money descriptor of $40. otherwise known as an aggregate root.Synopse mORMot Framework Software Architecture Design 1. letting those types be implemented via interfaces. we try to let the framework do all the plumbing. we have to understand this vocabulary and not only use it when speaking with domain experts but also see the same terminology reflected in our code.e. In DDD. . and guarantee the consistency of changes by isolating its members from external objects (i. often end up as state machines..in mORMot.e. with all their methods. you're seeking side-effect-free functions. or via dedicated repository classes . avoiding the need to define them by hand. and.Object-Relational Mapping (page 88) can be used to persist your aggregate roots directly. definition. Do not leak your domain! In DDD. can be extremely valuable when using DDD techniques to refactor and tighten the highest value parts of your code. 2013 . that is. mORMot's DDD In practice. with methods (i. Legacy code and existing projects (page 53) will benefit from those DDD patterns. Domain Services give you a tool for modeling processes that do not have an identity or life-cycle in your domain. They tend to be named after verbs or business activities that domain experts introduce into the so-called Ubiquitous Language. your aggregates will be defined as TSQLRecord. you should define a dedicated persistence service. but tend to embody processes. in this case as object for older versions of Delphi). But if it tends to enforce you writing a lot of wrapping code. otherwise.e. mORMot's Client-Server architecture may be used as such: . place. In the first case. using RTTI and code generators. records are serialized as binary + Base64 encoding). Or automate the wrapper coding. Dedicated factories can be used on both Client and Server side. then use plain DTO (like Delphi record) or even publish the TSQLRecord types. You have to weigh the PROs and the CONs.can be used to publish methods corresponding to your aggregate roots defined as TSQLRecord. at the same time. directly serializable.see Record serialization (page 185) .Synopse mORMot Framework Software Architecture Design 1. . or you can use a repository service. on the server side. .see Client-Server services via interfaces (page 257) .Domain services pattern is used to model primary operations. This will make it pretty RESTful compatible. If you follow the interface segregation principle see SOLID design principles (page 239). ensuring the published properties do not have setters but just read F. . to make them read-only. SAD . It features so-called Persistence Ignorance. like always.. or thing in my application. Finding so-called seams. .Rev. . In this terminology. 20.Services via methods . forget about it.when targeting AJAX clients (by default.Services via interfaces . If your service interfaces are cleaner. it implements transactional process at Domain level. and may be implemented either at service or ORM level. In short.. It will be very fast.18 Page 306 of 1055 . meaning that your domain code may not be tied to a particular persistence implementation. You may also use TComponent or TSQLRecord classes.mORMot Framework .18 Date: June 16. and benefit of their automated serialization. services are not tied to a particular person. Don't be afraid of writing some translation layers between TSQLRecord and DTO records.BATCH sequences for adding/updating/deleting records (page 213) is a convenient implementation of the Unit of Work pattern.Unit Of Work can be used to maintain a list of objects affected by a business transaction and coordinates the writing out of changes and the resolution of concurrency problems. along with isolating your core domain.3. your domain services should be exposed as dedicated client-oriented methods. 1. to define your repositories and/or domain operations. that are not linked to one aggregate root. do not hesitate. or several. perhaps none. but the current implementation in mORMot should be enhanced to be more convenient to use on the server side. you develop your application layer services directly from the needs of your client applications..Value Objects are probably meant to be defined as record.can be used to publish all your processes.. But you would need to customize the JSON serialization . letting the Domain layer focus on the business logic and persistence tasks.see Client-Server services via methods (page 229) . that is code the interface with no implementation. implementing a complete Unitary testing mechanism similar to DUnit.Write a test code. .1.1.Write a void implementation of a feature.Launch the test . and repeat all previous tests every time you add a new feature.pas unit defines two classes (both inheriting from TSynTest). 1. .Synopse mORMot Framework Software Architecture Design 1. it help you write and optimize every implementation feature.18 Page 307 of 1055 . code compilation from Delphi 6 up to XE4. SAD .mORMot Framework . testing-driven coding can be encouraged: . How can you be confident that any change made to your software code won't create any error in other part of the software? Automated unit testing is a good candidate for avoiding any serious regression. and.Launch the test . . And even better.it must pass. Automated testing You know that testing is (almost) everything if you want to avoid regression problems in your application. no external dependency). The framework has been implemented using this approach. but such coding improve your code quality a lot.it must fail. with less code overhead. Involved classes in Unitary testing The SynCommons. It could sounds like a waste of time. .Add some features. and provide all the tools to write tests. and direct interface with the framework units and requirements (UTF-8 ready.18 Date: June 16. 21.Rev.1. Testing and logging Adopt a mORMot 21.Implement the feature. at least. . 2013 21. SAD . end.TSynTests.TSynTestCase.mORMot Framework . overload. 21. overload. A text report is created on the current console. So we create three classes one for the whole test suit. 2013 The following diagram defines this class hierarchy: TSynTests TSynTestCase TSynTest TSynTest classes hierarchy The main usable class types are: . end.B: integer): integer. end. providing statistics and Pass/Fail. function Multiply(A. end. . which is used to run a suit of test cases. begin result := A*B. one for testing addition. procedure TestDoubleMultiply. overload.18 Date: June 16. one for testing multiplication: type TTestNumbersAdding = class(TSynTestCase) published procedure TestIntegerAdd. First steps in testing Here are the functions we want to test: function Add(A. overload. begin result := A*B.Synopse mORMot Framework Software Architecture Design 1. In order to define tests.B: double): Double. begin result := A+B. end.Rev. and will be launched by a TSynTests instance to perform all the tests.2.B: double): Double. which is a class implementing a test case: individual tests are written in the published methods of this class. function Add(A.B: integer): integer. end. some TSynTestCase children must be defined. procedure TestDoubleAdd.18 Page 308 of 1055 . function Multiply(A. begin result := A+B. as defined with the previous class.1. TTestNumbersMultiplying = class(TSynTestCase) published procedure TestIntegerMultiply. 1. 2013 TTestSuit = class(TSynTests) published procedure MyTestSuit.dpr is expected to be available as a console program): with TTestSuit. end. The CheckSame() is necessary because of floating-point precision problem. And here is the test case implementation: procedure TTestSuit. each containing some tests to process.Test double multiply: 1000 assertions passed Total failed: 0 / 2000 . CheckSame(A+B.Numbers multiplying PASSED Generated with: Delphi 7 compiler Time elapsed for all tests: 1.1. and you'll get: Suit -----1. end.Create do try ToConsole := @Output.Test double add: 1000 assertions passed Total failed: 0 / 2000 . begin AddCase([TTestNumbersAdding. we can't trust plain = operator (i.Adding(A.B)) will fail because of rounding problems).mORMot Framework .Synopse mORMot Framework Software Architecture Design 1. begin for i := 1 to 1000 do begin A := Random. Numbers adding: .Numbers adding PASSED 1. The trick is to create published methods.Test integer multiply: 1000 assertions passed . Here is how one of these test methods are implemented (I let you guess the others): procedure TTestNumbersAdding. finally Free. i: integer.MyTestSuit.Test integer add: 1000 assertions passed .B)).2. // so we will see something on screen Run.18 Page 309 of 1055 .e.Rev.18 Date: June 16. end. Numbers multiplying: . end. 1. B := Random.TestDoubleAdd.96ms Tests performed at 23/07/2010 15:24:30 SAD . Check(A+B=Adding(A.B: double. var A. end.TTestNumbersMultiplying]). readln. And the main program (this . My test suit 1. Just run this program. Client and server RESTful URL methods via sllClient and sllServer levels. . 1.18). with and without our Enhanced Run Time Library. which implements the SQLite3 engine itself. Before any release all unitary regression tests are performed with the following compilers: .2.3. via sllException and sllExceptionOS levels. 2013 Total assertions failed for all test suits: 0 / 4000 All tests passed successfully. .18 Date: June 16. Logging The framework makes an extensive use of the logging features implemented in the SynCommons unit see Enhanced logging (page 78). as defined in mORMot. SAD . . . all ORM related code.000.SQL executed statements in the SQLite3 engine via the sllSQL level.Delphi XE2.e. with the exception of generic compilation).Delphi 7.mORMot Framework . . Then all sample source code (including the Main Demo and SynDBExplorer sophisticated tools) are compiled.Delphi XE4.Main errors triggered during process via sllError level. .Synopse mORMot Framework Software Architecture Design 1.Delphi 2007. In its current implementation. This test has been uploaded in the SQLite3\Sample\07 . Since mORMot units are decoupled (e.SynDBLog for all SynDB* units. .000 individual checks are performed for revision 1. 21. . Implemented tests The SAD # DI-2. excellent for core components (more than 11. the framework is able to log on request: .2.Security User authentication and session management via sllUserAuth.Delphi XE3. Database or ORM/SOA). sllWarning and sllInfo levels. it will work with Delphi 2009.SynSQLite3Log for the SynSQLite3 unit.Delphi 2010 (we assume that if it works with Delphi 2010. . . several variables have been defined.2 (page 1053) defines all classes released with the framework source code.Delphi 6. Those levels are available via the TSQLLog class. as such: . and that the test suit just follows the classes defined. Global testing coverage is good.18 Page 310 of 1055 .Some additional low-level information via sllDebug. .SQLite3Log for all mORMot* units. 21.JSON results when retrieved from the SQLite3 engine via the sllResult level.pas.SynTest folder of the Source Code Repository. . inheriting from TSynLog.Rev.1. all generic database code. . but there is still some User-Interface related tests to be written. You can see that all text on screen was created by "UnCamelCasing" the method names (thanks to our good old Camel). i.e. Three main TSynLogClass global variables are defined in order to use the same logging family for the whole framework. i. which covers all core aspects of the framework. .Any exceptions triggered during process. and user-level testing is performed against those applications.g. It is therefore tobe defined only for debugging purposes. Creating so much log content won't increase the processing time much. HighResolutionTimeStamp := true. if executed: with TSQLLog. whole regression tests process will spent only 2 seconds to write the additional logging.ROOT_NAME).pas sample is initialized: begin // define the log level with TSQLLog. (.Rev.dpr. . EchoToConsole := LOG_VERBOSE. // create a Data Model aModel := TSQLModel. Logging could be very handy for interactive debug of a client application..mORMot..Family do begin Level := LOG_VERBOSE. if you execute the following statement at the beginning of TestSQL3.mORMot Framework . there is no speed penalty noticeable. TSynLogTestLog := TSQLLog.18 Date: June 16. . which is the bottleneck of the hard disk writing.Family do begin Level := LOG_VERBOSE. 1.moRMotSQLite3. SAD .Interface based services\Project14ServerHttp. // log all events to the console end. On a recent laptop.mORMotDB.Create([]. you are able to see in real-time the incoming requests see for instance how 14 . and will create about 390 MB of log file content.pas unit initialization will set SynSQLite3Log := TSQLLog. If logging is turned off. this interactive console refresh slows down the process a lot.pas unit initialization will set SynDBLog := TSQLLog. redirection to the main TSQLLog class is done if you use some features within mORMot: . 2013 By default.Synopse mORMot Framework Software Architecture Design 1. not on production. As a result.) Of course. // share the same log file with whole mORMot end. most regression tests will produce some logging.pas unit will define SQLite3Log as its own TSQLLog class. You can set your own class type to SynDBLog / SynSQLite3Log if you expect separated logging. Since our TSynLog / TSQLLog class feature an optional ouput to a console.18 Page 311 of 1055 . see http://www.0. version 1.. a link to http://synopse.see http://www. Source code Adopt a mORMot 22.0 or later (GPL). 1.info.. while still maintaining copy-left on code Synopse wrote. This allows the use of the framework code in a wide variety of software projects.For commercial projects.Mozilla Public License.1 or later (LGPL). In all cases.18 Page 312 of 1055 .org/licenses/gpl-2. use the MPL License .html. version 2.For GPL projects. You do not have to pay any fee for using our MPL/GPL/LGPL libraries.gnu. . version 2. .18 Date: June 16..GNU General Public License.see http://www. use the forums and we may introduce a patch to the main framework trunk. which is the most permissive.For LGPL license.org/licenses/lgpl-2.1. SAD . If you need any additional feature. But please do not forget to put somewhere in your credit window or documentation.mozilla. use the LGPL license . if you use any of the units published under this tri-license. 2013 22.Synopse mORMot Framework Software Architecture Design 1.org/MPL/MPL-1.1.mORMot Framework .g.1.html. . any modification made to this source code should be published by any mean (e. License The framework source code is licensed under a disjunctive three-license giving the user the choice of one of the three following sets of free software/open source licensing terms: . even in case of MPL.html. a download link). use the GPL license .GNU Lesser General Public License. In short: .Rev.1 or later (MPL).gnu. .. synopse.You accept the license terms with no restriction .google. if you select the MPL license. documentation.You make appear some notice available in the program (About box. stating e.SynCrtSock.http://synopse.info/fossil/wiki?name=Downloads } Note that this documentation is under GPL license only. you may publish it with a comment similar to this one (as included in the great DelphiWebScript project by Eric Grange . Sample based on official mORMot's sample "SQLite3\Samples\09 . 2013 For instance. run the application at least once as administrator.g.dpr" Synopse mORMot framework.g.pas http://synopse. This software uses some third-party code of the Synopse mORMot framework (C) 2013 Arnaud Bouchez .html. .pas . 22.2. which were extracted then incorporated into this Software Architecture Design (SAD) document. in the following pages.sys stack.inc . SynTaskDialog. If you want to include part of the framework source code in your own open-source project. as stated in this document front page.Synopse. with a description of applied modifications.mORMot Framework .http://code.http://synopse.pas .sys-kernel-mode-server WARNING: you need to first register the server URI and port to the http. That is. modified source code is available at http://SoftwareCompany. See http://blog.g.com/MPL). 1. That is all interface definition of the units have special comments. and no removal of the original license header in source code.1.1/GPL 2.see http://www.com/MPL.1 You would need at least the following files from mORMot framework to be available in your project path: .pas) in a public web site (e. Obtaining the Source Code SAD . The source has been commented following the scheme used by our SynProject documentation tool.SynWinWock.mozilla. here are the requirements: .Synopse mORMot Framework Software Architecture Design 1.You have to publish any modified unit (e.Rev.under Mozilla Public License 1.SynCommons.pas . online help). Copyright (C) 2013 Arnaud Bouchez Synopse Informatique .pas . all source code of the framework is available.sys kernel mode high-performance HTTP server (available since XP SP2). 22.info Original tri-license: MPL 1.SynLZ. and latest version can be retrieved from our online repository at http://synopse.info .SynZip. . Availability As a true Open Source project.0/LGPL 2.org/MPL/2.info/post/2011/03/11/HTTP-server-using-fast-http..info/fossil. ): { Will serve static content and DWS dynamic content via http.com/p/dwscript. http://SoftwareCompany.1.18 Page 313 of 1055 . for additional information.18 Date: June 16..0/FAQ..2.HttpApi web server\HttpApiServer. see SynCommons unit (page 72). But cross-platform is on its way: it will probably use the Delphi XE2/XE3/XE4 FireMonkey library for User Interface generation. or other tools more neutral.Log in as anonymous.For Windows 32 bit and 64 bit platform (Delphi XE2 and up is expected when targeting Win64). The password is shown on screen. SynCommons.see http://www.pas or the External database access (page 166) units) are also compatible with Delphi 5. click on the "Zip Archive" link. 1.and found it to be impressive. and all over definitions global to all mORMot units .Click on the "Login" menu button. 22. right ahead to the "Other Links" title. downloading ZIP archives of every historical version.Pointer your web browser at http://synopse. So stay tuned! SAD . This is amazing to build the whole set of compilers and IDE. Follow these steps: .zip archive from the official http://synopse.com..zip archive containing a snapshot of the latest version of the whole source code tree directly from this repository.pilotlogic. Free Pascal Compiler (FPC) / Lazarus support.Select a version of the source code you want to download: a version is identified by an hexadecimal link (e. available at the end of the "Overview" header. using JavaScript and AJAX or both. Open SynCommons.Delphi 6 up to Delphi XE4 compiler and IDE (FPC support is not yet finished).. Just click on the "Fill out captcha" button then on the "Login" button. and works well. I like Lazarus stability and speed much more than Delphi. for several platforms (this is a cross-platform project). Expected compilation platform The framework source code tree will compile and is tested for the following platform: . instead of default VCL components . 2013 Each official release of the framework is available in a dedicated SynopseSQLite3. This link will build a . Some part of the library (e. it works. Note that you must successfully log in as "anonymous" in steps 1-3 above in order to see the link to the detailed version information.com/site/tmspack. The framework source code implementation and design tried to be as cross-platform as possible. even if the compiler is slower than Delphi's. just from the sources. you should defined the USEPACKAGES conditional in your project's options. I've tried for instance the CodeTyphon release (which is not the stable branch. but you may want to use the latest version available. are now very stable and easy to work with. but the latest version of both FPC and Lazarus) .18 Date: June 16. with a lot of components.tmssoftware. .inc for a description of this conditional. 6b684fb2).mORMot Framework .2.2.18 Page 314 of 1055 .g. At least. If you want to compile mORMot unit into packages. . to avoid an obfuscated [DCC Error] E2201 Need imported data reference ($G) to access 'VarCopyProc' error at compilation.Rev. Note that the framework is expected to create only Windows applications yet. . .Finally. and thereby soaking up all our bandwidth. The latest versions of the Free Pascal Compiler together with its great Lazarus IDE. . since the beginning. .see http://www.Click on the Timeline or Leaves link at the top of the page. The reason for requiring this login is to prevent spiders from walking the entire website. You can obtain a . . Preferred way is Leaves which will give you the latest available version.Synopse mORMot Framework Software Architecture Design 1.g.info web site. .GUI may be compiled optionally with third-party non Open-Source TMS Components..info/fossil.asp.zip archive of the complete source code and download it to your browser. 7z.obj files. from http://synopse. Please download the latest compiled version of these . Since there is no official Win64 library yet..e. we excluded the sqlite3*. containing common files HtmlView/ A fork of the freeware THtmlView component. this documentation In the Root folder.info/files/sqlite3obj.as available from Embarcadero web site. Folder layout As retrieved from our source code repository.2. but provide the full source code of the SQlite3 engine in the corresponding sqlite3.3. For native 64 bit applications (since Delphi XE2). you can use the one we supply at http://synopse.pas-based external database providers SynProject/ Source code of the SynProject tool. used to create e.info/files/SQLite3-64.18 Page 315 of 1055 . you'll find the following file layout.Rev. if you have the bcc32 C command-line compiler installed.4. Note about sqlite3*. root SQlite3 Samples SynDBDataset Documentation mORMot Source Code Folders Directory Description / Root folder.pas. 1. 22.obj files from this link.mORMot Framework . sqlite3. 2013 22.2. some common files are defined: SAD .bat file to compile from the original sqlite3.e. an external . mORMot itself) SynDBDataset/ DB. and not truly Unicode ready LVCL/ Light VCL replacement files for standard VCL (for Delphi 6-7 only) RTL7/ Enhanced RTL . Therefore. The free version works and was used to create both .obj files In order to maintain the source code repository in a decent size. C++Builder Compiler (bcc compiler) free download .obj storage in it..7z.obj files are available as a separated download.obj and sqlite3fts.dll file is needed. You can also use the supplied c. ready to be compiled with all conditional defined as expected by SynSQlite3Static.c file.Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16.c file available in the repository. used as a demo of the SynPdf unit .not finished. and FastMM4 memory manager to be used before Delphi 2006 SQLite3/ Contains all ORM / SOA related files of the framework (i.g.dcu for Delphi 7 (not mandatory at all). i. Synopse mORMot Framework Software Architecture Design 1. 2013 File Description CPort.pas class used to store huge amount of data with fast retrieval SynBz.obj low-level access to ZLib compression.inc generic header to be included in all units to set some global conditional definitions vista.pas SynLZO.* A resource file enabling theming under XP SAD .5 SynZipFiles.pas classes implementing HTTP/1.inc generic header included in the beginning of the uses clause of a .pas automated tests for mORMot Framework SynSQLite3.not finished yet SynSelfTests. in SynProject) for pre-Unicode Delphi only SynPdf.pas bunzipasm.1 client and server protocol SynCrypto.pas statically linked SQLite3 engine SynSSPIAuth.pas pascal implementation of BZ2 decompression SynCommons.* implement TaskDialog window (native on Vista/Seven.pas PDF file generation unit SynScaleMM. emulated on XP) SynWinSock.18 Page 316 of 1055 . 1.pas LZO compression decompression unit SynMemoEx.pas high-level access to .Rev.63 PasZip.pas SynLZ compression decompression unit .mORMot Framework .g. 2.pas ZIP/LZ77 Deflate/Inflate Compression in pure pascal SynBigTable.pas Synopse extended TMemo visual component (used e.18 Date: June 16.inc fast BZ2 compression/decompression SynBzPas.2.dpr source code SynGdiPlus.zip archive file compression Synopse.pas SQLite3 embedded Database engine SynSQLite3Static.pas deflate.* A fork of the freeware ComPort Library ver.pas low level access to network Sockets for the Win32 platform SynZip.pas multi-thread friendly memory manager unit .pas GDI+ library API access with anti-aliasing drawing SynLZ.used by SynCommons.pas fast cryptographic routines (hashing and cypher) SynDprUses.pas low level access to Windows Authentication for the Win32 platform SynTaskDialog.pas common functions used by most Synopse projects SynCrtSock.obj trees. 1. SynLZ.pas classes: File Description SynDBBDE.pas BDE access class SynDBNexusDB.pas Virtual Tables for ORM external SynDB access mORMotFastCgiServer. to be used with the SynDBDataset. SynPdf.* A resource file enabling theming under XP and Administrator rights under Vista In the same Root folder.pas Main unit of the ORM framework mORMotDB.pas ZeosLib / ZDBC direct access classes In a SynDBDataset folder. its ORM and SOA features (using SynCommons.pas Integrated Reporting engine SAD . SynGdiPlus.pas fast OleDB direct access classes SynDBODBC.pas fast ODBC direct access classes SynDBOracle. SynDB*.pas HTTP/1. 2013 vistaAdm.pas NexusDB access classes SynDBUniDAC. the files implementing the Synopse mORMot framework itself.pas HTTP/1. SynTaskDialog and SynZip from the Root folder): File Description Documentation/ Sub folder containing the source of the Synopse documentation Samples/ Sub folders containing some sample code mORMot.1 Server mORMotReport.Synopse mORMot Framework Software Architecture Design 1.pas FastCGI server . some external database providers are available.pas UniDAC library access class In the SQlite3/ folder.pas SQLite3 direct access classes SynDBDataset.e.18 Page 317 of 1055 . 1.Rev.pas DB VCL read-only dataset using SynDB data access SynDBZEOS.not fully tested mORMotHttpClient.mORMot Framework .1 Client mORMotHttpServer.18 Date: June 16. SynCrtSock. i.pas Oracle DB direct access classes (via OCI) SynDBSQLite3. SynSQLite3*. the external database-agnostic units are located: File Description SynDB.pas TDataSet / TQuery-like access classes (drivers included in SynDBDataset sub-folder) SynDBVCL.pas abstract database direct access classes SynOleDB. .Search path: (. compiled into *.rc Resource files.dpr mORMotSelfTests.dpr Main testing program of the Synopse mORMot framework TestSQL3Register. into a local directory of your computer (for instance.).. as available in the SQLite3\Samples sub-folder. generated from code mORMotUIQuery. you would need to download and install FastMM4 heap memory manager .D:\Dev\Lib.* General Options setting dialog.* Grid to display Database content mORMotUIEdit.* Record edition dialog. including all sub-folders.zip archive. You should be able to compile it and run all regression tests on your computer.txt file content supplied with the package! RTFM! In short. using our ORM RTTI to define search parameters and algorithms mORMotVCL.pas internationalization (i18n) routines and classes mORMotToolBar. so you do not need to download it. 1.18 Date: June 16.D:\Dev\Lib\SynDBDataset . 2013 mORMotService. used to edit record content on the screen mORMotUILogin. Enjoy! SAD .* Form handling queries to a User Interface Grid. mORMot units will work.existing path.. Please.c Source code of the SQLite3 embedded Database engine 22. You should be able to compile all sample programs.D:\Dev\Lib.pas Stand-alone Service mORMotSQLite3. but will be slower). Installation Just unzip the .mORMot Framework . add the following paths to your Delphi IDE (in Tools/Environment/Library menu): ..from http://sourceforge.D:\Dev\Lib\SQLite3. Open the TestSQL3. read the ReadMe. Then open the *.dpr program from the SQLite3 sub-folder.pas ORM ToolBar User Interface generation mORMotUI.for some samples to work (without it.bmp *.dpr in the MainDemo folder.res files TestSQL3.* some common User Interface functions and dialogs mORMotUIOptions.pas SQLite3 kernel bridge between mORMot. D:\Dev\Lib).Synopse mORMot Framework Software Architecture Design 1.Rev.pas DB VCL dataset using TSQLTable/TSQLTableJSON data access *.existing path.Library path: (.pas mORMoti18n.. or from the RTL7 sub folder of our repository .dpr files.sys on Vista/Seven c.pas and SynSQLite3.D:\Dev\Lib\SynDBDataset Note that before Delphi 2006.D:\Dev\Lib\SQLite3.bat sqlite3.18 Page 318 of 1055 ...net/projects/fastmm..pas Run as administrator for TestSQL3 to use http.. including SynFile.3. Starting with Delphi 2006. FastMM4 is already included within the system RTL.). x library direct access classes to be used with our SynDB architecture 553 SynDBOracle Oracle DB direct access classes (via OCI) 557 SynDBSQLite3 SQLite3 direct access classes to be used with our SynDB architecture 564 SynDBVCL DB VCL dataset using SynDB data access 570 SynDBZEOS ZEOS 7. 1. Units located in the "Lib\" directory: Source File Name Description Page SynCommons Common functions used by most Synopse projects 325 SynCrtSock Classes implementing HTTP/1.pas based) 571 SynGdiPlus GDI+ library API access 576 SynLZ SynLZ Compression routines 584 SynLZO Fast LZO Compression routines 586 SynOleDB Fast OleDB direct access classes 587 SynPdf PDF file generation 600 SAD .Rev.18 Date: June 16.pas TDataset-based direct access classes (abstract TQuery-like) 549 SynDBODBC ODBC 3.18 Page 319 of 1055 . 2013 23.mORMot Framework .1 client and server protocol 479 SynCrypto Fast cryptographic routines (hashing and cypher) 497 SynDB Abstract database direct access classes 509 SynDBDataset DB.x direct access classes for SynDB units (not DB. mORMot Framework source 23.Synopse mORMot Framework Software Architecture Design 1.1. mORMot Framework used Units The mORMot Framework makes use of the following units. obj for Windows 32 bit 696 SynSSPIAuth Low level access to Windows Authentication for the Win32/Win64 platform 698 SynTaskDialog Implement TaskDialog window (native on Vista/Seven.18 Page 320 of 1055 . 2013 Source File Name Description Page SynSelfTests Automated tests for common units of the Synopse mORMot Framework 642 SynSQLite3 SQLite3 Database engine direct access 647 SynSQLite3RegEx REGEXP function for SQLite3 Database using PCRE library 695 SynSQLite3Static SQLite3 Database engine .Synopse mORMot Framework Software Architecture Design 1. emulated on XP) 700 SynWinSock Low level access to network Sockets for the Win32 platform 706 SynZip Low-level access to ZLib compression (1.2. 1.mORMot Framework .Rev.18 Date: June 16.statically linked .5 engine version) 707 SAD . 1 Server implementation for mORMot 914 mORMotHttpClient HTTP/1. 1.18 Page 321 of 1055 . 2013 SynSQLite3RegEx SynCrypto SynSSPIAuth SynSQLite3 SynSQLite3Static SynSelfTests SynDBSQLite3 SynWinSock SynCrtSock SynDBODBC SynCommons SynDBDataset SynOleDB SynDB SynLZ SynDBZEOS SynGdiPlus SynDBVCL SynPdf SynDBOracle SynZip Unit dependencies in the "Lib" directory Units located in the "Lib\SQLite3\" directory: Source File Name Description Page mORMot Common ORM and SOA classes for mORMot 715 mORMotDB Virtual Tables for external DB access for mORMot 908 mORMotFastCgiServer FastCGI HTTP/1.1 RESTFUL JSON Client classes for mORMot 917 mORMotHttpServer HTTP/1.Synopse mORMot Framework Software Architecture Design 1.mORMot Framework .Rev.18 Date: June 16.1 RESTFUL JSON Server classes for mORMot 920 mORMoti18n Internationalization (i18n) routines and classes for mORMot 924 mORMotReport Reporting unit 934 SAD . Synopse mORMot Framework Software Architecture Design 1.18 Page 322 of 1055 . used to edit record content with mORMot 990 mORMotUILogin Some common User Interface functions and dialogs for mORMot 993 mORMotUIOptions General Options setting dialog for mORmot 997 mORMotUIQuery Form handling queries to a User Interface Grid for mORMot 999 mORmotVCL DB VCL dataset using TSQLTable/TSQLTableJSON data access 1001 SAD .mORMot Framework .18 Date: June 16. 1. 2013 Source File Name Description Page mORMotSelfTests Automated tests for common units of the Synopse mORMot Framework 951 mORmotService Win NT Service managment classes for mORMot 953 mORMotSQLite3 SQLite3 embedded Database engine used as the mORMot SQL kernel 959 mORMotToolBar ORM-driven Office 2007 Toolbar for mORMot 966 mORMotUI Grid to display database content for mORMot 980 mORMotUIEdit Record edition dialog.Rev. x direct access classes (embedded engine only) 1008 SynDBUniDAC UniDAC-based classes for SynDB units 1012 SAD .18 Date: June 16.18 Page 323 of 1055 . 2013 mORmotVCL mORMotUIOptions mORMoti18n mORMotUI mORMotUIQuery mORMotUIEdit SynTaskDialog mORMotUILogin SynSSPIAuth mORMot SynDB SynCommons mORMotToolBar mORMotDB SynGdiPlus mORmotService mORMotFastCgiServer SynPdf mORMotReport SynSQLite3 mORMotSQLite3 SynZip mORMotHttpServer SynCrtSock mORMotHttpClient SynLZ Unit dependencies in the "Lib\SQLite3" directory Units located in the "Lib\SynDBDataset\" directory: Source File Name Description Page SynDBBDE BDE access classes for SynDB units 1002 SynDBFireDAC FireDAC/AnyDAC-based classes for SynDB units 1005 SynDBNexusDB NexusDB 3.Synopse mORMot Framework Software Architecture Design 1. 1.Rev.mORMot Framework . Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16. 1.18 Page 324 of 1055 .Rev.mORMot Framework . 2013 SynDBFireDAC SynCommons SynDBBDE SynDB SynDBUniDAC SynDBDataset SynDBNexusDB Unit dependencies in the "Lib\SynDBDataset" directory SAD . licensed under a MPL/GPL/LGPL tri-license.pas unit .18 Date: June 16.Rev.1.this unit is a part of the freeware Synopse mORMot framework.licensed under a MPL/GPL/LGPL tri-license. SynCommons.18 Page 325 of 1055 .2.2 UTF-8 JSON format shall be used to communicate 1049 DI-2. 1. 2013 23.4 The framework shall provide some Cross-Cutting components 1051 Units used in the SynCommons unit: Unit Name Description Page SynLZ SynLZ Compression routines .Synopse mORMot Framework Software Architecture Design 1.pas unit Purpose: Common functions used by most Synopse projects .1.18 The SynCommons unit is quoted in the following items: SWRS # Description Page DI-2. version 1.18 584 SynCommons. version 1. pas unit .Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16.Rev. 2013 Exception ESynException ETableDataException IUnknown ISynLog TCustomMemoryStream TSynMemoryStream TSynMemoryStreamMapped TMemoryStream THeapMemoryStream TTextWriterEcho TTextWriter TJSONWriter TSynTest TSynTests TSynTableStatement TSynTestCase TSynTestsLogged TSynTableFieldProperties TSynTable TSynValidateText TSynValidatePassWord TSynSoundEx TSynValidateTable TSynValidateTableUniqueField TSynValidatePattern TSynValidatePatternI TSynNameValue TSynValidate TSynMapFile TSynValidateIPAddress TSynLogFamily TSynValidateEmail TSynLog TSynFilterUpperCaseU TSynFilterOrValidate TSynFilterUpperCase TSynFilter TSynCache TObject TSynAnsiConvert TSynFilterTrim TSynAnsiFixedWidth TSortedWordArray TRawUTF8List TSynFilterLowerCaseU TSynFilterLowerCase TRawUTF8ListHashed TPrecisionTimer TObjectListPropertyHashed TObjectListHashedAbstract TObjectListHashed TObjectHash TMemoryMapText TSynLogFile TMemoryMap TFileVersion TFileBufferWriter TFileBufferReader TDynArray TDynArrayHashed Iso8601 TStream TRawByteStringStream SynCommons class hierarchy Objects implemented in the SynCommons unit: SynCommons.18 Page 326 of 1055 . 1. Synopse mORMot Framework Software Architecture Design 1. but will use hashing for (much) faster IndexOf() method 354 TObjectListPropertyHa shed This class will hash and search for a sub property of the stored objects 354 TOSVersionInfoEx Not defined in older Delphi versions 370 TPrecisionTimer High resolution timer (for accurate speed statistics) 379 TRawByteStringStream A TStream using a RawByteString as internal storage 359 TRawUTF8List This class is able to emulate a TStringList with our native UTF-8 string type 355 TRawUTF8ListHashed A TRawUTF8List which will use an internal hash table for faster IndexOf() 357 TSortCompareTmp Internal value used by TSynTableFieldProperties. 1.18 Date: June 16.pas unit . for speed 370 TJSONWriter Simple writer to a Stream.Rev.18 Page 327 of 1055 .SortCompare() method to avoid stack allocation 372 TSortedWordArray Used to store and retrieve Words in a sorted array 334 TSynAnsiConvert An abstract class to handle Ansi to/from Unicode translation 330 SynCommons. specialized for the JSON format and SQL export 353 TMemoryMap Handle memory mapping of a file content used to store and retrieve Words in a sorted array 358 TMemoryMapText Able to read a UTF-8 text file using memory map 358 TObjectHash Abstract class able to use hashing to find an object in O(1) speed 344 TObjectListHashed This class behaves like TList/TObjectList. 2013 Objects Description Page ESynException Generic parent class of all custom Exception types of this unit 398 ETableDataException Exception raised by all TSynTable related code 398 Iso8601 Usefull object to type cast TTimeLog type into Iso-8601 or TDateTime 368 ISynLog A generic interface used for logging a method 386 TDynArray A wrapper around a dynamic array with one dimension 334 TDynArrayHashed Used to access any dynamic arrray elements using fast hash 342 TFileBufferReader This structure can be used to speed up reading from a file 362 TFileBufferWriter This class can be used to speed up writing to a file 360 TFileVersion To have existing RTTI for published properties used to retrieve version information from any EXE 369 THeapMemoryStream To be used instead of TMemoryStream. to improve reading speed 354 TSynFilter Will define a filter to be applied to a Record field content (typicaly a TSQLRecord) 367 TSynFilterLowerCase A custom filter which will convert the value into Lower Case characters 368 TSynFilterLowerCaseU A custom filter which will convert the value into Lower Case characters 368 TSynFilterOrValidate Will define a filter or a validation process to be applied to a database Record content (typicaly a TSQLRecord) 364 TSynFilterTrim A custom filter which will trim any space character left or right to the value 368 TSynFilterUpperCase A custom filter which will convert the value into Upper Case characters 367 TSynFilterUpperCaseU A custom filter which will convert the value into Upper Case characters 368 TSynHash Internal structure used to store one item hash 342 TSynLog A per-family and/or per-thread log file content 391 TSynLogCurrentIdent Used by ISynLog/TSynLog.pas unit . as decoded by TSynMapFile from a . into high-level data 395 TSynLogFileProc Used by TSynLogFile to refer to a method profiling in a .g. with TSynLog to provide additional debugging information 384 TSynMapSymbol A debugger symbol. to be used e. as used by TSynNameValue class 345 TSynSoundEx Fast search of a text value. using the Soundex searching mechanism 333 SynCommons.log file. e. as decoded by TSynMapFile from a .e. non MBCS) 332 TSynCache Implement a cache of some key/value pairs.18 Page 328 of 1055 . using fast memory mapping 360 TSynNameValue Pseudo-class used to store Name/Value RawUTF8 pairs 345 TSynNameValueItem Store one Name/Value pair.Enter methods to handle recursivity calls tracing 390 TSynLogExceptionConte xt Calling context of TSynLogExceptionToStr callbacks 397 TSynLogFamily Regroup several logs under an unique family name 387 TSynLogFile Used to parse a . 1. as created by TSynLog. 2013 Objects Description Page TSynAnsiFixedWidth A class to handle Ansi to/from Unicode translation of fixed width encoding (i.g.map file 384 TSynMapUnit A debugger unit.18 Date: June 16.map file 384 TSynMemoryStream A TStream pointing to some in-memory data.Rev. for instance UTF-8 text 359 TSynMemoryStreamMappe d A TStream created from a file content.map file content.log file 395 TSynMapFile Retrieve a .Synopse mORMot Framework Software Architecture Design 1. specialized for the TEXT format 346 TTextWriterEcho Writer to a Stream.pas unit . with each line sent to a custom Echo() method 352 TUpdateFieldEvent An opaque structure used for TSynTable. to implement a Database 377 TSynTableFieldPropert ies Store the type properties of a given field / database column 372 TSynTableStatement Used to parse a SELECT SQL statement 370 TSynTest A generic class for both tests suit and cases 380 TSynTestCase A class implementing a test case 381 TSynTests A class used to run a suit of test cases 382 TSynTestsLogged This overriden class will create a .UpdateFieldEvent method 375 SynCommons.Rev. 1.18 Page 329 of 1055 .18 Date: June 16.log file in case of a test case failure 395 TSynValidate Will define a validation to be applied to a Record (typicaly a TSQLRecord) field content 364 TSynValidateEmail IP address validation to be applied to a Record field content (typicaly a TSQLRecord) 365 TSynValidateIPAddress IP v4 address validation to be applied to a Record field content (typicaly a TSQLRecord) 364 TSynValidatePassWord Strong password validation for a Record field content (typicaly a TSQLRecord) 367 TSynValidatePattern Grep-like case-sensitive pattern validation of a Record field content (typicaly a TSQLRecord) 365 TSynValidatePatternI Grep-like case-insensitive pattern validation of a Record field content (typicaly a TSQLRecord) 366 TSynValidateTable Will define a validation to be applied to a TSynTableFieldProperties field 376 TSynValidateTableUniq ueField Will define a validation for a TSynTableFieldProperties Unique field 376 TSynValidateText Text validation to be applied to a Record field content (typicaly a TSQLRecord) 366 TTextWriter Simple writer to a Stream. 2013 Objects Description Page TSynTable Store the description of a table with records.Synopse mORMot Framework Software Architecture Design 1. Convert any Ansi Text into an Unicode String . SourceChars: Cardinal): PUTF8Char. SourceChars: Cardinal): RawUnicode.returns a value using our RawUnicode kind of string function AnsiToUnicodeString(Source: PAnsiChar.pas unit .will call AnsiBufferToUnicode() overloaded virtual method function AnsiBufferToUnicode(Dest: PWideChar.e. Convert any Ansi Text (providing a From converted) into Ansi Text function AnsiToAnsi(From: TSynAnsiConvert.returns a SynUnicode.this default implementation will use the Operating System APIs . 1. 2013 TSynAnsiConvert = class(TObject) An abstract class to handle Ansi to/from Unicode translation . Convert any Ansi buffer into an Unicode String . Source: PAnsiChar. overload.18 Page 330 of 1055 . Source: PAnsiChar. Source: PAnsiChar.a #0 char is appended at the end (and result will point to it) .18 Date: June 16. virtual. Direct conversion of a PAnsiChar buffer into a UTF-8 encoded string . Delphi 2009+ UnicodeString or a WideString SynCommons. SourceChars: cardinal): RawByteString. Direct conversion of a PAnsiChar buffer into an Unicode buffer .this default implementation will use the Operating System APIs function AnsiToAnsi(From: TSynAnsiConvert. overload. overload. overload. SourceChars: Cardinal): SynUnicode. but should better retrieve an instance using TSynAnsiConvert. virtual.implementations of this class will handle efficiently all Code Pages . overload. Convert any Ansi buffer (providing a From converted) into Ansi Text function AnsiToRawUnicode(const AnsiText: RawByteString): RawUnicode. virtual.Synopse mORMot Framework Software Architecture Design 1. const Source: RawByteString): RawByteString.Rev.Dest^ buffer must be reserved with at least SourceChars*2 bytes . overload. SourceChars: Cardinal): RawUTF8. i. virtual. which will initialize either a TSynAnsiFixedWidth or a TSynAnsiConvert instance on need constructor Create(aCodePage: integer). Convert any Ansi buffer into an Unicode String .Engine(). reintroduce. Direct conversion of a PAnsiChar buffer into a UTF-8 encoded buffer .Dest^ buffer must be reserved with at least SourceChars*3 bytes . Initialize the internal conversion engine function AnsiBufferToRawUTF8(Source: PAnsiChar.this default implementation will use the Operating System APIs function AnsiBufferToUTF8(Dest: PUTF8Char. overload.returns a value using our RawUnicode kind of string function AnsiToRawUnicode(Source: PAnsiChar.you should not create your own class instance by yourself. SourceChars: Cardinal): PWideChar. internaly calls UTF8BufferToAnsi virtual method property CodePage: Integer read fCodePage. Convert any UTF-8 encoded String into Ansi Text . Corresponding code page SynCommons. Source: PUTF8Char.this default implementation will rely on the Operating System for all non ASCII-7 chars function UnicodeBufferToAnsi(Source: PWideChar. Convert any UTF-8 encoded buffer into Ansi Text .18 Page 331 of 1055 . virtual.internaly calls AnsiBufferToUTF8 virtual method class function Engine(aCodePage: integer): TSynAnsiConvert.internaly calls UTF8BufferToAnsi virtual method function UTF8ToAnsi(const UTF8: RawUTF8): RawByteString. overload. Convert any UTF-8 encoded buffer into Ansi Text . virtual.therefore. Direct conversion of an Unicode buffer into an Ansi Text function UTF8BufferToAnsi(Dest: PAnsiChar. 2013 function AnsiToUTF8(const AnsiText: RawByteString): RawUTF8. overload.Synopse mORMot Framework Software Architecture Design 1.Dest^ buffer must be reserved with at least SourceChars*3 bytes . SourceChars: Cardinal): RawByteString. SourceChars: Cardinal.will return nil in case of unhandled code page function RawUnicodeToAnsi(const Source: RawUnicode): RawByteString. Convert any Unicode-encoded String into Ansi Text . SourceChars: Cardinal): RawByteString.internaly calls UTF8BufferToAnsi virtual method procedure UTF8BufferToAnsi(Source: PUTF8Char. SourceChars: Cardinal): PAnsiChar. Direct conversion of an Unicode buffer into a PAnsiChar buffer . overload.a global list of TSynAnsiConvert instances is handled by the unit . SourceChars: Cardinal): PAnsiChar. Direct conversion of an UTF-8 encoded buffer into a PAnsiChar buffer . 1. Source: PWideChar.Rev. caller should not release the returned instance . Returns the engine corresponding to a given code page . var result: RawByteString).internaly calls UnicodeBufferToAnsi virtual method function UnicodeBufferToAnsi(Dest: PAnsiChar. Convert any Ansi Text into an UTF-8 encoded String .Dest^ buffer must be reserved with at least SourceChars bytes function UTF8BufferToAnsi(Source: PUTF8Char.18 Date: June 16. overload.pas unit . overload. e.Dest^ buffer must be reserved with at least SourceChars*3 bytes . Length: integer): boolean. Return TRUE if the supplied unicode buffer only contains characters of the corresponding Ansi code page .returns a value using our RawUnicode kind of string function IsValidAnsi(WideText: PWideChar. and will consume more than 64 KB of memory: you should not create your own class instance by yourself. Return TRUE if the supplied unicode buffer only contains characters of the corresponding Ansi code page . 2013 TSynAnsiFixedWidth = class(TSynAnsiConvert) A class to handle Ansi to/from Unicode translation of fixed width encoding (i.like WinAnsi (1252) or Russian (1251) . Source: PAnsiChar. if the text can be displayed using this code page function IsValidAnsi(WideText: PWideChar): boolean.Dest^ buffer must be reserved with at least SourceChars*2 bytes function AnsiBufferToUTF8(Dest: PUTF8Char.18 Page 332 of 1055 .pas unit . which will initialize either a TSynAnsiFixedWidth or a TSynAnsiConvert instance on need . override. Source: PAnsiChar.this class has some additional methods (e. SourceChars: Cardinal): PWideChar. Direct conversion of a PAnsiChar buffer into an Unicode buffer . if the text can be displayed using this code page function IsValidAnsiU(UTF8Text: PUTF8Char): boolean. Direct conversion of a PAnsiChar buffer into a UTF-8 encoded buffer . override. SourceChars: Cardinal): PUTF8Char. non MBCS) .e. IsValid*) which take advantage of the internal lookup tables to provide some fast process constructor Create(aCodePage: integer).a #0 char is appended at the end (and result will point to it) function AnsiToRawUnicode(Source: PAnsiChar.i.e. overload.this class will handle efficiently all Code Page availables without MBCS encoding . override.e. Return TRUE if the supplied UTF-8 buffer only contains characters of the corresponding Ansi code page .18 Date: June 16. Convert any Ansi buffer into an Unicode String . Initialize the internal conversion engine function AnsiBufferToUnicode(Dest: PWideChar. overload.it will use internal fast look-up tables for such encodings . SourceChars: Cardinal): RawUnicode. override.this class could take some time to generate.i.g.Synopse mORMot Framework Software Architecture Design 1.i. 1. if the text can be displayed using this code page SynCommons.Rev.Engine(). but should better retrieve an instance using TSynAnsiConvert. this implementation is very fast and can be used e. which differs from default Soundex. no "tm" or such) within this code page function UnicodeBufferToAnsi(Dest: PAnsiChar. SourceChars: Cardinal): PAnsiChar.e. The goal is for homophones to be encoded to the same representation so that they can be matched despite minor differences in spelling . override. Conversion of a wide char into the corresponding Ansi character . Source: PUTF8Char.any unhandled WideChar will return ord('?') TSynSoundEx = object(TObject) Fast search of a text value.search prepared value at every word beginning in A^ function Prepare(UpperValue: PAnsiChar.return -1 for an unknown WideChar in the current code page property AnsiToWide: TWordDynArray read fAnsiToWide. Direct conversion of an UTF-8 encoded buffer into a PAnsiChar buffer . using the Soundex searching mechanism . SourceChars: Cardinal): PAnsiChar. 1.18 Date: June 16. i. Lang: TSynSoundExPronunciation=sndxEnglish): boolean.g.use this array like WideToAnsi: array[word] of byte . Return TRUE if the supplied UTF-8 buffer only contains 8 bits characters of the corresponding Ansi code page . if the text can be displayed with only 8 bit unicode characters (e.18 Page 333 of 1055 . as pronounced in a given language. Prepare for a Soundex search .g.Synopse mORMot Framework Software Architecture Design 1. Return true if prepared value is contained in a ANSI text buffer by using the SoundEx comparison algorithm .Dest^ buffer must be reserved with at least SourceChars*3 bytes . Direct access to the Unicode-To-Ansi lookup table . Source: PWideChar.this overriden version will use internal lookup tables for fast process function UTF8BufferToAnsi(Dest: PAnsiChar. 2013 function IsValidAnsiU8Bit(UTF8Text: PUTF8Char): boolean.Soundex is a phonetic algorithm for indexing names by sound.you can specify another language pronunciation than default english SynCommons. override.Dest^ buffer must be reserved with at least SourceChars bytes function WideCharToAnsiChar(wc: cardinal): integer.Rev.i.pas unit . English function Ansi(A: PAnsiChar): boolean. Direct access to the Ansi-To-Unicode lookup table .e. Direct conversion of an Unicode buffer into a PAnsiChar buffer .use this array like AnsiToWide: array[byte] of word property WideToAnsi: TByteDynArray read fWideToAnsi.This version also handles french and spanish pronunciations on request. to parse and search in a huge text buffer . search prepared value at every word beginning in U^ TSortedWordArray = object(TObject) Used to store and retrieve Words in a sorted array . 1.g.g.can be used to fast save/retrieve all memory content to a TStream . but will be as a record :( function Add(const Elem): integer.B): boolean.) .warning: Elem must be of the same exact type than the dynamic array. Compare the content of two elements.this method compares first using any supplied Compare property.Rev. due to a bug in Delphi 2009/2010 compiler (at least): this structure is not initialized if defined as an object on the stack. with FastMM4 or SynScaleMM.return -1 if not found TDynArray = object(TObject) A wrapper around a dynamic array with one dimension . by using the SoundEx comparison algorithm . but will be as a record :( function Add(aValue: Word): PtrInt. Return true if prepared value is contained in a text buffer (UTF-8 encoded).is defined either as an object either as a record.return -(foundindex+1) if this value is already in the Values[] array function IndexOf(aValue: Word): PtrInt.18 Date: June 16.can use external Count storage to make Add() and Delete() much faster (avoid most reallocation of the memory buffer) . then by content using the RTTI element description of the whole record SynCommons. . Add a value into the sorted array .. to access any existing dynamic array.note that the "const Elem" is not checked at compile time nor runtime: you must ensure that Elem matchs the element type of the dynamic array .18 Page 334 of 1055 .returns the index of the added element in the dynamic array .return the index of the new inserted value into the Values[] array .. Return the index if the supplied value in the Values[] array .. with a TList: the list is reallocated every time a record is added .note that because of dynamic array internal memory managment.provide TList-like methods using fast RTTI information .pas unit . 2013 function UTF8(U: PUTF8Char): boolean. adding will be a bit slower than e. It is therefore aimed to initialize a TDynArray wrapper on need.for even better speed.but in practice. and must be a reference to a variable (you can't write Add(i+10) e. returning TRUE if both values equal .Synopse mORMot Framework Software Architecture Design 1. you can also specify an external count variable in Init(.@Count) method function ElemEquals(const A.Note that TDynArray is just a wrapper around an existing dynamic array: methods can modify the content of the associated variable but the TDynArray doesn't contain any data by itself.is defined either as an object either as a record. there is no big speed penalty . Add an element to the dynamic array . due to a bug in Delphi 2009/2010 compiler (at least): this structure is not initialized if defined as an object on the stack. returns nil if aIndex is out of range .if an indexed lookup is not supplied (i.warning. overload.if the array is sorted.same as ElemLoad() + Find()/IndexOf() + ElemLoadClear() . 2013 function ElemLoad(Source: PAnsiChar): RawByteString. aCompare: TDynArraySortCompare): integer.if the array is not sorted.this method will use a custom comparison function. Search for an array element as saved by the ElemSave method .g.Rev. and not using this slower and more error prone method (such pointer access lacks of strong typing abilities) function ElemSave(const Elem): RawByteString. from an external indexed lookup table .will call generic IndexOf() method if no Compare property is set function ElemPtr(aIndex: integer): pointer.warning: Elem must be of the same exact type than the dynamic array. it will use slower iterating search . it must already be sorted: this function will then use fast binary search . 1.return the index found (0.return the index found (0. or -1 if Elem was not found . or -1 if Elem was not found . const aIndex: TIntegerDynArray. and must be a reference to a variable (you can't write Find(i+10) e. as created by the CreateOrderedIndex() method: it allows multiple search orders in the same dynamic array content . this function will use slower but accurate iterating search .) function Find(const Elem. Returns a pointer to an element of the array .pas unit . and must be a reference to a variable (you can't write Find(i+10) e.you can use ElemLoad method later to retrieve its content . Save an array element into a serialized buffer . it will use fast binary search . Search for an element value inside the dynamic array.Count-1).18 Page 335 of 1055 . overload.this method will use the Compare property function for the search .) function Find(const Elem): integer. with an external integer table.will call Find() method if Compare property is set .if an indexed lookup is supplied. Search for an element value inside the dynamic array ..warning: Elem must be of the same exact type than the dynamic array.18 Date: June 16. you should better use direct access to its wrapped variable.since TDynArray is just a wrapper around an existing array.Synopse mORMot Framework Software Architecture Design 1. Load an array element as saved by the ElemSave method ..Count-1). the lookup index should be synchronized if array content is modified (in case of adding or deletion) SynCommons.g.e aIndex=nil).this overloaded method will retrieve the element as a memory buffer and caller MUST call ElemLoadClear() method to finalize its content function ElemLoadFind(Source: PAnsiChar): integer. overload. can be used e.18 Page 336 of 1055 . set to SortDynArrayString). this item will be deleted from the array . it will use slower iterating search .return the index found (0.if the array is sorted. it will use fast binary search . the first string field (i.if no Elem content matches.g.warning: Elem must be of the same exact type than the dynamic array.if Elem content matches.Count-1). and must be a reference to a variable (you can't write Find(i+10) e.pas unit . it will use slower iterating search .this method will use the Compare property function for the search. aCompare: TDynArraySortCompare=nil): integer. Search for an element value.this method will use the Compare property function for the search.Rev.if the array is sorted. and must be a reference to a variable (you can't write Find(i+10) e. aCompare: TDynArraySortCompare=nil): integer. the first string field (i.. aIndex: PIntegerDynArray=nil. set to SortDynArrayString). you can fill the first string field with the searched value (if returned index is >= 0) .return the index found (0.Synopse mORMot Framework Software Architecture Design 1. the first string field (i. or the supplied indexed lookup table and its associated compare function . or the supplied indexed lookup table and its associated compare function .g. it will use fast binary search . set to SortDynArrayString). you can fill the first string field with the searched value (if returned index is >= 0) . aIndex: PIntegerDynArray=nil.g.g.warning: Elem must be of the same exact type than the dynamic array.) SynCommons.e.this method will use the Compare property function for the search.) function FindAndFill(var Elem. or the supplied indexed lookup table and its associated compare function . aCompare: TDynArraySortCompare=nil): integer. then fill all properties if match .g.. as a simple dictionary: if Compare will match e.Count-1).can be used e.e.g.if the array is not sorted. then delete it if match .18 Date: June 16. the item will added to the array . it will use fast binary search .if the array is not sorted. 1. or -1 if Elem was not found .e. then add it if none matched . Search for an element value.if the array is not sorted. and must be a reference to a variable (you can't write Find(i+10) e. it will use slower iterating search . or -1 if Elem was not found and the supplied element has been succesfully added .can be used e. all Elem fields will be filled with the record . as a simple dictionary: if Compare will match e.g.if the array is sorted. Search for an element value.g. as a simple dictionary: if Compare will match e.. 2013 function FindAndAddIfNotExisting(const Elem. aIndex: PIntegerDynArray=nil. or -1 if Elem was not found .Count-1).g.warning: Elem must be of the same exact type than the dynamic array.) function FindAndDelete(var Elem. you can fill the first string field with the searched value (if returned index is >= 0) .return the index deleted (0.if Elem content matches. g. 2013 function FindAndUpdate(const Elem. 1.255] of byte. nil on error SynCommons.g.18 Date: June 16.won't work with not packed types (like a shorstring.return the index found (0.warning: Elem must be of the same exact type than the dynamic array. Search for an element value. the padding data (i. and packed records with binary and string types within (like TFileVersion) . then update it if match .. and must be a reference to a variable (you can't write Find(i+10) e. the bytes between the aligned feeds can be filled as random. packed records with no reference-counted type within.Rev.g. Search for an element value inside the dynamic array . as a simple dictionary: if Compare will match e. the first string field (i. word. or -1 if Elem was not found .) function IsVoid: boolean.g.. this item will be updated with the supplied value ..will search for all properties content of the eLement: TList. or e. this method searches by content using the RTTI element description (and not the Compare property function) . array[0. string types (e.if the array is sorted.Count-1). or -1 if Elem was not found . aCompare: TDynArraySortCompare=nil): integer.return the index found (0.use the Find() method if you want the search via the Compare property function.will work with simple types: binaries (byte.g.g. set to SortDynArrayString). or the supplied indexed lookup table and its associated compare function . Currency.g. return the memory buffer pointer just after the read content . Check if the wrapper points to a dynamic array function LoadFrom(Source: PAnsiChar): PAnsiChar.Synopse mORMot Framework Software Architecture Design 1. to search only with some part of the element content .). Int64.if Elem content matches.in case of success.) function IndexOf(const Elem): integer. or a record with byte or word fields with {$A+}): in this case.warning: Elem must be of the same exact type than the dynamic array.this method will use the Compare property function for the search.. and there is no way with standard RTTI do know which they are) . it will use fast binary search .pas unit . aIndex: PIntegerDynArray=nil.) .return a pointer at the end of the data read from Source.e. it will use slower iterating search .Count-1).return nil if the Source buffer is incorrect (invalid type or internal checksum e.e. you can fill the first string field with the searched value (if returned index is >= 0) .can be used e.if the array is not sorted.. and must be a reference to a variable (you can't write IndexOf(i+10) e. Load the dynamic array content from a memory buffer . integer. array of string).18 Page 337 of 1055 .IndexOf() searches by address. Set all content of one dynamic array to the current array . Delete the whole dynamic array content procedure Copy(Source: TDynArray). overload. overload. TByteDynArray. 1.return a pointer at the end of the data read from P. Add an element to the dynamic array .pas unit . Add elements from a given dynamic array .both must be of the same exact type SynCommons.4]' or '["\uFFF0base64encodedbinary"]' .the supplied source DynArray MUST be of the same exact type as the current used for this TDynArray .Rev. i. Save the dynamic array content into a RawByteString function SaveToLength: integer. TInt64DynArray.typical handled content could be '[1. nil in case of an invalid input buffer . TDoubleDynArray.18 Date: June 16. TWordDynArray. aEndOfObject: PUTF8Char=nil): PUTF8Char.RegisterCustomJSONSerializer .expect the format as saved by TTextWriter.3. Load the dynamic array content from an UTF-8 encoded JSON buffer . TWideStringDynArray.this version add a void element to the array. TStringDynArray.e.2.Dest buffer must have been allocated to contain at least the number of bytes returned by the SaveToLength method . TRawUTF8DynArray. TSynUnicodeDynArray.Synopse mORMot Framework Software Architecture Design 1.warning: the content of P^ will be modified during parsing: please make a local copy if it will be needed later function New: integer. TCardinalDynArray. Save the dynamic array content into an allocated memory buffer . TWinAnsiDynArray.return a pointer at the end of the data written in Dest. aCount: integer=-1). nil in case of an invalid input buffer function SaveTo: RawByteString. TTimeLogDynArray and TDateTimeDynArray as JSON array . 2013 function LoadFromJSON(P: PUTF8Char. TCurrencyDynArray. and returns its index function SaveTo(Dest: PAnsiChar): PAnsiChar. Compute the number of bytes needed to save a dynamic array content procedure AddArray(const DynArray. aStartIndex: integer=0.AddDynArrayJSON method.18 Page 338 of 1055 . handling TIntegerDynArray.you can specify the start index and the number of items to take from the source dynamic array (leave as -1 to add till the end) procedure Clear.or any other kind of array as Base64 encoded binary stream precessed via JSON_BASE64_MAGIC (UTF-8 encoded \uFFF0 special code) .or any customized valid JSON serialization as set by TTextWriter. TRawByteStringDynArray. and must be a reference to a variable (you can't write Find(i+10) e. Release memory allocated by ElemLoad(): RawByteString SynCommons.you should provide either a void either a valid lookup table.18 Date: June 16. Will copy one element content procedure ElemLoad(Source: PAnsiChar.Synopse mORMot Framework Software Architecture Design 1. Load an array element as saved by the ElemSave method . its content will be recreated procedure Delete(aIndex: Integer).the deleted element is finalized if necessary procedure ElemClear(var Elem). Sort the dynamic array elements using a lookup array of indexes .g.pas unit . Will reset the element content procedure ElemCopy(const A. that is a table with one to one lookup (e.if the lookup table has less elements than the main dynamic array. created with FillIncreasing) . var Elem). var B). 1. 2013 procedure CreateOrderedIndex(var aIndex: TIntegerDynArray. aCompare: TDynArraySortCompare). Delete one item inside the dynamic array . overload.) procedure ElemLoadClear(var ElemLoaded: RawByteString).Rev. using the specified comparison function .g.it won't change the dynamic array content: only create or update the given integer lookup array.warning: Elem must be of the same exact type than the dynamic array.18 Page 339 of 1055 . A.). its content will be set to 0.a sample usage may be: var DA: TDynArray.but in this case.. with binaries and string properties .Count or Count instead of length(A) procedure InitSpecific(aTypeInfo: pointer. aCountPointer: PInteger=nil). begin DA.a sample usage may be (using a count variable): var DA: TDynArray.) // now you should use DA.no RTTI check is made over the corresponding array layout: you shall ensure that the aKind parameter matches the dynamic array element definition .djNone and djCustom are too vague. Add an element to the dynamic array at the position specified by Index .pas unit .. with some variable-length encoding of the string length procedure Reverse. aKind: TDynArrayKind.this version accepts to specify how comparison should occur. Initialize the wrapper with a one-dimension dynamic array .aCaseInsensitive will be used for djRawUTF8.g. because the dynamic array won't need to be resized each time . and must be a reference to a variable (you can't write Insert(10. (. array of strings or array of packed records. begin DA..if aCountPointer is set. ACount: integer. not the items count .i+10) e.will use a proprietary binary format.18 Date: June 16. A: TIntegerDynArray. 1.stream content must have been created using SaveToStream method . Initialize the wrapper with a one-dimension dynamic array . whatever the array length is.g. using TDynArrayKind kind of first field .Rev.Init(TypeInfo(TIntegerDynArray). Will reverse all array elements.18 Page 340 of 1055 . // MUCH faster using the ACount variable (. A: TIntegerDynArray.djSynUnicode comparison procedure Insert(Index: Integer. integer. const Elem).) procedure LoadFromStream(Stream: TCustomMemoryStream).if aCountPointer is set. in place SynCommons. you should use the Count property instead of length(array) or high(array) when accessing the data: in fact length(array) will store the memory size reserved. for i := 1 to 100000 do DA.A).Init(TypeInfo(TIntegerDynArray). var aValue. aCaseInsensitive: boolean=false). i: integer.) . 2013 procedure Init(aTypeInfo: pointer. aCountPointer: PInteger=nil. Load the dynamic array content from a (memory) stream ...the dynamic array must have been defined with its own type (e.will handle array of binaries values (byte. var aValue.@ACount). word.Add(i)... or the current aCountPointer^ value is . it will be used instead of length() to store the dynamic array items count .warning: Elem must be of the same exact type than the dynamic array. TIntegerDynArray = array of Integer) .it will be much faster when adding elements to the array.Synopse mORMot Framework Software Architecture Design 1. and would raise an exception . with some variable-length encoding of the string length . Add() will append after this count property Compare: TDynArraySortCompare read fCompare write SetCompare.is optimized for memory streams. and exchange all elements in order to be sorted in increasing order according to Compare function procedure Void. set a value to this property will affect the Count value.18 Page 341 of 1055 . SortDynArrayInteger. Select a sub-section (slice) of a dynamic array content procedure Sort. is the same as Count . SortDynArrayCardinal.same as length(DynArray) or SetLenght(DynArray) property ElemSize: PtrUInt read fElemSize.if no external Count pointer is set. integer.. Retrieve or set the number of elements of the dynamic array . SortDynArrayByte. word.18 Date: June 16. SortDynArrayAnsiString. but will work with any kind of TStream procedure Slice(var Dest.if an external Count pointer is set..by default. SortDynArrayString. .it will change the dynamic array content. with binaries and string properties . array of strings or array of packed records. no comparison function is set . The known type.g. The compare function to be used for Sort and Find methods . The internal buffer capacity . as retrieved from RTTI property KnownType: TDynArrayKind read fKnownType. using the Compare property function . possibly retrieved from dynamic array RTTI SynCommons. 2013 procedure SaveToStream(Stream: TStream).will use a proprietary binary format.Synopse mORMot Framework Software Architecture Design 1.Stream position will be set just after the added data . SortDynArrayInt64. aFirstIndex: cardinal=0).g. i. The internal in-memory size of one element. Save the dynamic array content into a (memory) stream . SortDynArrayWord.if no external Count pointer was set with Init. The internal type information of one element. SortDynArrayUnicodeStringI property Count: integer read GetCount write SetCount.).will handle array of binaries values (byte. Initialize the wrapper to point to no dynamic array property Capacity: integer read GetCapacity write SetCapacity. Sort the dynamic array elements.Rev.common functions exist for base types: e.e. you can set a value to this property before a massive use of the Add() method e. SortDynArrayUnicodeString. SortDynArrayStringI. 1. SortDynArrayAnsiStringI. as retrieved from RTTI property ElemType: pointer read fElemType. aCount: Cardinal.pas unit . SortDynArrayDouble. 18 Date: June 16. so that Find() won't try to use binary search in an usorted array.in order to have the better performance. The known RTTI information TSynHash = record Internal structure used to store one item hash . if the searched/hashed field in a record is a string as first field. binary sort could be used for searching items for TDynArray: using a hash is faster on huge arrays for implementing a dictionary .g. and miss its purpose property TypeInfo: pointer read fTypeInfo.ELem should be of the same exact type than the dynamic array.used e. 2013 property Sorted: boolean read fSorted write fSorted. 1.returns a pointer to the newly added element function FindHashed(const Elem): integer. some suffix is added to make it unique .expected element layout is to have a RawUTF8 field at first position .by default.Rev.g.this object extends the TDynArray type. and add it to the array . and if not the case. by TDynArrayHashed or TObjectHash via TSynHashDynArray Hash: cardinal. you should use an external Count variable.you MUST set this property to false if you modify the dynamic array content in your code.18 Page 342 of 1055 .Synopse mORMot Framework Software Architecture Design 1. you may use a string variable as Elem: other fields will be ignored .this version will set the field content with the unique value .Add/Delete/Insert/Load* methods will reset this property to false . Index of the item in the main storage array TDynArrayHashed = object(TDynArray) Used to access any dynamic arrray elements using fast hash .only TDynArrayHashed.returns -1 if not found.the aName is searched (using hashing) to be unique. modification (update or delete) of an element is not handled yet: you should rehash all content .pas unit . AND set the Capacity property to the expected maximum count (this will avoid most ReHash calls for FindHashedForAdding+FindHashedAndUpdate) function AddAndMakeUniqueName(aName: RawUTF8): pointer. Must be TRUE if the array is currently in sorted order according to the compare function .Sort method will set this property to true . Unsigned integer hash of the item Index: cardinal. Search for a given element name. make it unique. or the index in the dynamic array if found SynCommons.FindHashedForAdding / FindHashedAndUpdate / FindHashedAndDelete will refresh the internal hash . or at least matchs the fields used by both the hash function and Equals method: e. Search for an element value inside the dynamic array using hashing . since presence of Hashs[] dynamic array will increase code size if using TDynArrayHashed instead of TDynArray .in this current implementation.use internaly FindHashedForAdding method . not for filling the newly created entry in the array SynCommons. Elem is used only for searching..g. returns the index found (0. or the index newly created/added is the Elem value was not matching .return the index found (0. and add a void entry to the array if was not found .if AddIfNotExisting is TRUE.for faster process (avoid ReHash). Search for an element value inside the dynamic array using hashing. AddIfNotExisting: boolean): integer. aHashCode: cardinal=0): integer.if AddIfNotExisting is FALSE.add won't rehash all content . please set the Capacity property . out wasAdded: boolean. Search for an element value inside the dynamic array using hashing. and fill Elem with the found content .18 Page 343 of 1055 .g.return the index deleted (0.ELem should be of the same exact type than the dynamic array. the entry is left VOID: you must set the field content to expecting value . if the searched/hashed field in a record is a string as first field.in short. and delete it if matchs . 2013 function FindHashedAndDelete(var Elem): integer. Search for an element value inside the dynamic array using hashing.Count-1).Count-1).g.warning: in contrast to the Add() method.warning: Elem must be of the same exact type than the dynamic array.pas unit . please set the Capacity property . or at least matchs the fields used by both the hash function and Equals method: e. then update any matching item. or -1 if Elem was not found . you may use a string variable as Elem: other fields will be ignored .warning: Elem must be of the same exact type than the dynamic array.Count-1).this will rehash all content: this method could be slow in the current implementation . and must refer to a variable (you can't write FindHashedAndDelete(i+10) e.returns either the index in the dynamic array if found (and set wasAdded to false). and must refer to a variable (you can't write FindHashedAndUpdate(i+10) e.. or -1 if Elem was not found .g.) function FindHashedAndFill(var Elem): integer. Search for an element value inside the dynamic array using hashing. either the newly created index in the dynamic array (and set wasAdded to true) .Rev.. 1. and must be a reference to a variable (you can't write Find(i+10) e.) function FindHashedForAdding(const Elem. or add the item if none matched .Synopse mORMot Framework Software Architecture Design 1.for even faster process (avoid ReHash). returns the index found (0.) function FindHashedAndUpdate(var Elem.Count-1).. if an entry is added to the array (wasAdded=true).this method will use hashing for fast retrieval .18 Date: June 16.warning: Elem must be of the same exact type than the dynamic array. or -1 if Elem was not found update will force slow rehash all content . Initialize the wrapper with a one-dimension dynamic array .Synopse mORMot Framework Software Architecture Design 1. aHashElement: TDynArrayHashOne=nil. or after calling LoadFrom/Clear method) this is not necessary after FindHashedForAdding / FindHashedAndUpdate / FindHashedAndDelete methods property EventCompare: TEventDynArraySortCompare read fEventCompare write fEventCompare.can be called on purpose.e.all protected abstract methods shall be overriden and implemented function Find(Item: TObject): integer. 2013 procedure Init(aTypeInfo: pointer. compare 'a' and 'A' as equal) procedure InitSpecific(aTypeInfo: pointer. Retrieve the hash value of a given item. to allow object-oriented callbacks property Hash[aIndex: Integer]: Cardinal read GetHashFromIndex.if CaseInsensitive is set to TRUE.i.will be used instead of Compare.. it will use default Equals() method . var aValue. Custom hash function to be used for hashing of a dynamic array element TObjectHash = class(TObject) Abstract class able to use hashing to find an object in O(1) speed . Search one item in the internal hash array SynCommons. aCountPointer: PInteger=nil. using TDynArrayKind kind of first field .e.Init method to initialize the internal hash array .if no aCompare is supplied. aCompare: TDynArraySortCompare=nil. set to kr32() by default .djNone and djCustom are too vague. it will hash according to the RTTI.djSynUnicode comparison procedure ReHash(aHasher: TOnDynArrayHashOne=nil).this version accepts to specify how both hashing and comparison should occur.aCaseInsensitive will be used for djRawUTF8. var aValue. Alternative event-oriented Compare function to be used for Sort and Find .18 Page 344 of 1055 . aHasher: THasher=nil. and the first field for records (strings included) . Will compute all hash from the current elements of the dynamic array . aKind: TDynArrayKind. it will use the one supplied in DefaultHasher global variable.g.18 Date: June 16. aCompare to handle hash collision . strings or binary types.pas unit .is called within the TDynArrayHashed. Initialize the wrapper with a one-dimension dynamic array . i.this version accepts some hash-dedicated parameters: aHashElement to set how to hash each element. the well known Kernighan & Ritchie hash function . and would raise an exception . aCaseInsensitive: boolean=false).g. it will ignore difference in 7 bit alphabetic characters (e.Rev. in case of element deletion or update. aCountPointer: PInteger=nil.no RTTI check is made over the corresponding array layout: you shall ensure that the aKind parameter matches the dynamic array element definition .if no aHashElement is supplied. aCaseInsensitive: boolean=false).if no THasher function is supplied. from its index property HashElement: TDynArrayHashOne read fHashElement. 1. when modifications have been performed on the dynamic array content (e. not as a class: you can use this in any class.Synopse mORMot Framework Software Architecture Design 1. To be called when an item is added .is therefore faster than TRawUTF8List . Returns true if the Init() method has been called function Value(const aName: RawUTF8): RawUTF8. The internal Name/Value storage function Find(const aName: RawUTF8): integer.18 Date: June 16. 1.Rev.use internaly a TDynArrayHashed instance for fast retrieval . Any associated Pointer or numerical value Value: RawUTF8. To be called when an item is modified . Search for a Name. insert error) . as used by TSynNameValue class Name: RawUTF8.this property is hashed by TSynNameValue for fast retrieval Tag: PtrInt.return TRUE if has been added to the internal hash table .the index of the latest added item should be Count-1 procedure Invalidate. but will be as a record :( Count: integer.for Delete/Update will force a full rehash on next Find() call TSynNameValueItem = record Store one Name/Value pair. Search for a Name. The value of the Name/Value pair TSynNameValue = object(TObject) Pseudo-class used to store Name/Value RawUTF8 pairs .pas unit .is defined as an object. without the need to destroy the content . The number of Name/Value pairs List: TSynNameValueItemDynArray. The name of the Name/Value pair . return the associated Value SynCommons.e.return FALSE if this item is already existing (i.18 Page 345 of 1055 .is defined either as an object either as a record. return the index in List function Initialized: boolean. 2013 function JustAdded: boolean. due to a bug in Delphi 2009/2010 compiler (at least): this structure is not initialized if defined as an object on the stack. Rev. overload. overload. Escape: TTextWriterKind).TRawByteStringStream.18 Page 346 of 1055 . Can be used to set or retrieve all stored data as one BLOB content TTextWriter = class(TObject) Simple writer to a Stream. override.1.if aName already exists. then add all name=value pairs from a supplied . Reset content. 2013 procedure Add(const aName. Write some #0 ended UTF-8 text. The data will be written to an internal TRawByteStringStream . aValue: RawUTF8.g. Retrieve the data as a string . 1.2 (page 1049).will first call Init(false) to initialize the internal array . specialized for the TEXT format .1. Initialize the storage procedure InitFromIniSection(Section: PUTF8Char.2 (page 1049).Text to retrieve directly the content without any data move nor allocation destructor Destroy.only works if the associated Stream Inherits from TMemoryStream or TRawByteStringStream: will return '' if it is not the case procedure Add(Value: double). overload. Release fStream is is owned function Text: RawUTF8. constructor Create(aStream: TStream.pas unit . constructor CreateOwnedStream.Synopse mORMot Framework Software Architecture Design 1. it MUST be set before using any Add*() method .18 Date: June 16. The data will be written to the specified Stream .Section can be retrieved e.default internal buffer size if 8192 Used for DI-2. its associated Value will be updated procedure Init(aCaseSensitive: boolean).aStream may be nil: in this case.use an internal buffer. faster than string+string .ini file section content . via FindSectionFirstLine() property BlobData: RawByteString read GetBlobData write SetBlobData. Append a 32 bit signed Integer Value as text procedure Add(P: PUTF8Char. aTag: PtrInt=0). according to the specified format SynCommons.some dedicated methods is able to encode any data with JSON escape Used for DI-2. Add an element to the array . OnTheFlyConvert: TConvertRawUTF8=nil). Append a floating-point Value as a String procedure Add(Value: longint).DataString method will be used by TTextWriter. aBufSize: integer=8192). virtual. Write the same character multiple times procedure AddClassName(aClass: TClass). overload. according to the specified format procedure Add(Value: Int64). BinBytes: integer).up to 128 bytes may be converted procedure AddByteToHex(Value: byte). Write some #0 ended UTF-8 text.pas unit . Append an array of RawUTF8 as CSV procedure AddCSV(const Doubles: array of double). Escape: TTextWriterKind). from the main AnsiString type . Append the class name of an Object instance as text . Append an array of integers as CSV SynCommons. Escape: TTextWriterKind).c2: AnsiChar). Append an Integer Value as a 3 digits String without any added comma procedure Add4(Value: integer). Append some UTF-8 encoded chars to the buffer. Append an Integer Value as a 2 digits String with comma procedure Add3(Value: integer).18 Date: June 16. overload. Write a byte as hexa chars procedure AddChars(aChar: AnsiChar. aCount: integer). 2013 procedure Add(P: PUTF8Char. Append CR+LF chars procedure AddCSV(const Values: array of RawUTF8).Rev. Append one char to the buffer procedure Add(c1. overload.using this function with Bin^ as an integer value will encode it in big-endian order (most-signignifican byte first): use it for display . Append some binary data as hexadecimal text conversion procedure AddBinToHexDisplay(Bin: pointer. Len: integer). overload. overload. 1.use the current system code page for AnsiString parameter procedure AddBinToHex(P: Pointer. Append a 64 bit signed Integer Value as text procedure Add(c: AnsiChar). Append an array of doubles as CSV procedure AddCSV(const Integers: array of Integer). Fast conversion from binary data into hexa chars.Synopse mORMot Framework Software Architecture Design 1.18 Page 347 of 1055 . Len: PtrInt.aClass must be not nil procedure AddCR. Append two chars to the buffer procedure Add2(Value: integer). Append an Integer Value as a 4 digits String with comma procedure AddAnsiString(const s: AnsiString. overload. ready to be displayed . overload. TRawByteStringDynArray. TWinAnsiDynArray. as '"FieldName":' SynCommons. Append a dynamic array content as UTF-8 encoded JSON array . Append a Currency from its Int64 in-memory representation procedure AddCurr64(const Value: currency). creating a temporary TDynArray wrapper on the stack . TTimeLogDynArray.you can add some custom serializers via RegisterCustomJSONSerializer() class method.to be used e. Append a dynamic array content as UTF-8 encoded JSON array . TCurrencyDynArray. overload. and TDateTimeDynArray will be written as escaped UTF-8 JSON strings (and Iso-8601 textual encoding if necessary) .e. TCardinalDynArray. in a log-friendly format . expanded as Iso-8601 encoded text procedure AddDateTime(const Value: TDateTime). which is a good candidate for BLOB stream .3. overload. TSynUnicodeDynArray.TIntegerDynArray. overload. expanded as Iso-8601 encoded text procedure AddDynArrayJSON(aTypeInfo: pointer. 1.this method is very fast.TRawUTF8DynArray. TWordDynArray and TByteDynArray will be written as numerical JSON values . Append the current date and time. Append a TDateTime value. overload.e. with a JSON_BASE64_MAGIC prefix (UTF-8 encoded \uFFF0 special code) . overload. Append a RawUTF8 property name.Synopse mORMot Framework Software Architecture Design 1. TStringDynArray. Append a Currency from its Int64 in-memory representation procedure AddCurrentLogTime. overload. var aValue). Append an array of const as CSV procedure AddCurr64(const Value: Int64). 2013 procedure AddCSVConst(const Values: array of const).18 Date: June 16.pas unit . for custom record JSON serialization. TWideStringDynArray.g.2. append '20110325 19241502 ' . TDoubleDynArray.expect a dynamic array TDynArray wrapper as incoming parameter .Rev.typical content could be '[1. to serialize any dynamic array as valid JSON . array of bytes) content. Append a TDateTime value. QuoteChar: AnsiChar=#0).18 Page 348 of 1055 . and avoid most calculation or API calls procedure AddDateTime(Value: PDateTime. Append a Currency from its Int64 in-memory representation procedure AddCurr64(Value: PInt64). within a TDynArrayJSONCustomWriter callback procedure AddDynArrayJSON(const aDynArray: TDynArray). overload.any other non-standard or non-registered kind of dynamic array (including array of records) will be written as Base64 encoded binary stream.this will include TBytes (i.g. FirstChar: AnsiChar='T'. TInt64DynArray.just a wrapper around the other overloaded method.4]' or '["\uFFF0base64encodedbinary"]' procedure AddFieldName(const FieldName: RawUTF8). 5' and '-.'year'. Append some UTF-8 encoded chars to the buffer. overload.1.faster than AddJSONEscape(pointer(StringToUTF8(string)) . Append some UTF-8 encoded chars to the buffer .pas unit .very fast (avoid most temporary storage) Used for DI-2. procedure AddJSONEscape(const NameValuePairs: array of const).Rev.."year":1972}' .this encoding is faster than Base64.5' procedure AddInstanceName(Instance: TObject.1.data must be supplied two by two. as 'TObjectList(00425E68)'+SepChar . overload. from the main AnsiString type .escapes chars according to the JSON RFC SynCommons.18 Date: June 16. SepChar: AnsiChar).1972]) will append to the buffer: '{"name":"John". e. Encode the supplied data as an UTF-8 valid JSON object content .AddJSONEscape(['name'. Append an Instance name and pointer. Append an open array constant value to the buffer . Append some UTF-8 encoded chars to the buffer.2 (page 1049).Value pairs.use function Chars3ToInt18() to decode the textual content procedure AddJSONEscape(const V: TVarRec)."" will be added if necessary . from a generic string type .'John'. therefore wrongly) Used for DI-2. overload.2 (page 1049). Write a Int18 value (0.Instance must be not nil procedure AddInstancePointer(Instance: TObject.g.will correct on the fly '.escapes chars according to the JSON RFC Used for DI-2.5' -> '-0.escapes chars according to the JSON RFC .escapes chars according to the JSON RFC procedure AddJSONEscapeString(const s: string). procedure AddJSONEscape(P: Pointer.note that cardinal values should be type-casted to Int64() (otherwise the integer mapped value will be transmitted.2 (page 1049). Append an Instance name and pointer.Instance must be not nil procedure AddInt18ToChars3(Value: cardinal). as Name. and has spaces on the left side . SepChar: AnsiChar).5' -> '0.262143) as 3 chars .if Len is 0.Synopse mORMot Framework Software Architecture Design 1. procedure AddJSONEscapeAnsiString(const s: AnsiString). aWriter. 1. 2013 procedure AddFloatStr(P: PUTF8Char). Append a floating-point text buffer . Len: PtrInt=0). Len is calculated from zero-ended char . as '"TObjectList(00425E68)"'+SepChar .1.18 Page 349 of 1055 . Append some chars to the buffer in one line . Len: PtrInt). Add the pointer into hexa chars. not the byte size . Append some Unicode encoded chars to the buffer .escapes chars according to the JSON RFC procedure AddLine(const Text: shortstring). Append some UTF-8 encoded chars to the buffer. as '"PropName":' procedure AddRecordJSON(const Rec.will write #0. Len: PtrInt=0).will write #0. Append a record content as UTF-8 encoded JSON or custom serialization .will convert the Unicode chars into UTF-8 procedure AddNoJSONEscapeW(P: PWord. Len is calculated from zero-ended widechar . Append a line of text with CR+LF at the end procedure AddMicroSec(MS: cardinal). Append a time period.. WideCharCount: integer). Append some chars to the buffer in one line . overload.18 Page 350 of 1055 .#31 chars as spaces (so content will stay on the same line) procedure AddOnSameLine(P: PUTF8Char.will convert the Unicode chars into UTF-8 procedure AddOnSameLine(P: PUTF8Char).#31 chars as spaces (so content will stay on the same line) procedure AddOnSameLineW(P: PWord.Synopse mORMot Framework Software Architecture Design 1.don't escapes chars according to the JSON RFC . Append a ShortString property name. Len: integer=0). from a generic string type . Len is calculated from zero-ended char .. specified in micro seconds procedure AddNoJSONEscape(P: Pointer. Append some wide chars to the buffer in one line . ready to be displayed procedure AddPropName(const PropName: ShortString).don't escapes chars according to the JSON RFC .P should be ended with a #0 . Append some chars to the buffer ..will write #1. Len: PtrInt).18 Date: June 16. in case of a previous registration via RegisterCustomJSONSerializer() class method . 2013 procedure AddJSONEscapeW(P: PWord.Rev. Append some unicode chars to the buffer .from a dynamic array handling this kind of records. TypeInfo: pointer).#31 chars as spaces (so content will stay on the same line) procedure AddPointer(P: PtrUInt).don't escapes chars according to the JSON RFC procedure AddNoJSONEscapeString(const s: string). or directly from TypeInfo() of the record SynCommons.default serialization will use Base64 encoded binary stream.faster than AddNoJSONEscape(pointer(StringToUTF8(string)) .if Len is 0. or a custom serialization.if Len is 0. overload. 1.pas unit .WideCharCount is the unicode chars count. Synopse mORMot Framework Software Architecture Design 1. 1. Append a JSON value from its RTTI type . Rewind the Stream to the position when Create() was called procedure CancelLastChar.tkEnumeration. Append a void record content as UTF-8 encoded JSON or custom serialization . according to the specified format procedure CancelAll.e.write null for other types procedure AddU(Value: cardinal). The last char appended is canceled if it was a '. Append a TTimeLog value.tkDynArray. var aValue).setting both aReader=aWriter=nil will return back to the default binary + Base64 encoding serialization (i.e. expanded as Iso-8601 encoded text procedure AddTypedJSON(aTypeInfo: pointer. Write pending data to the Stream .by default.for a dynamic array. filled with #0 bytes) then save its content with default or custom serialization procedure AddW(P: PWord. virtual.tkRecord. undefine custom serializer) SynCommons. Len: PtrInt. some pending characters may be not yet copied to the Stream: you should call it before using the Stream property class procedure RegisterCustomJSONSerializer(aTypeInfo: pointer. The last char appended is canceled procedure CancelLastComma. aWriter: TDynArrayJSONCustomWriter). Append a String procedure AddTimeLog(Value: PInt64).for a record. Define a custom serialization for a given dynamic array or record . 2013 procedure AddShort(const Text: ShortString).any previous registration is overriden .this method will first create a void record (i.will append the internal memory buffer to the Stream . aReader: TDynArrayJSONCustomReader.18 Date: June 16. Escape: TTextWriterKind).pas unit . TIntegerDynArray and such known classes are processed as true JSON arrays: but you can specify here some callbacks to perform the serialization process for any kind of dynamic array .tkVariant types .will handle tkClass.18 Page 351 of 1055 .Rev. any matching dynamic array will also be registered .if you don't call Flush. the associated item record RTTI will be registered . Write some #0 ended Unicode text as UTF-8.' procedure Flush. Append a ShortString procedure AddString(const Text: RawUTF8). virtual.expects TypeInfo() from a dynamic array or a record (will raise an exception otherwise) . Append an Unsigned Integer Value as a String procedure AddVoidRecordJSON(TypeInfo: pointer). Synopse mORMot Framework Software Architecture Design 1. it can be forced via this property.this overriden method will send all pending buffer to Echo() . override. 1.18 Page 352 of 1055 . Append CR+LF chars .if withMagic is TRUE. or only write the class name and pointer if FullExpand is true . Len: cardinal. Callback used to echo each line of TTextWriterEcho class SynCommons.note that any manual #13#10 added without calling AddCR won't be notified to Echo() as individual line procedure Flush. Write some data Base64 encoded . to flush all pending characters to the stream .will avoid creation of a temporary RawUTF8 variable as for Text function procedure WrBase64(P: PAnsiChar.only works if the associated Stream Inherits from TMemoryStream or TRawByteStringStream: will return '' if it is not the case . until AddCR method is called property Echo: TOnTextWriterEcho read fEcho write fEcho.g.you should call the Flush method before using this TStream content. Options: TTextWriterWriteObjectOptions=[woDontStoreDefault]).if the TStream instance has not been specified when calling the TTextWriter constructor. withMagic: boolean). WriteObject method for full RTTI handling . Flush the internal buffer to the output TStream .Rev. TypeInfo: pointer). will write as '"\uFFF0base64encodedbinary"' procedure WriteObject(Value: TObject. 2013 procedure SetText(var result: RawUTF8).do not use this class instead of TTextWriter. since it could be much slower procedure AddCR. virtual.18 Date: June 16.this default implementation will write null. before any writting property TextLength: integer read GetLength.default implementation will write TList/TCollection/TStrings/TRawUTF8List as appropriate array of class name/pointer (if woFullExpand is set) procedure WrRecord(const Rec. to echo some log on the output console (see TSynLogFamily.EchoToConsole property) . Serialize as JSON the given object . Write some record content as binary.can be used e. Retrieve the data as a string . override.pas unit . Count of add byte to the stream TTextWriterEcho = class(TTextWriter) Writer to a Stream. Base64 encoded with our magic prefix property Stream: TStream read fStream write SetStream. The internal TStream used for storage .use TJSONSerializer. with each line sent to a custom Echo() method .this overriden method will store temporary the content. overload.val11' position in: { "fieldCount":1. contains the Stream position of the first usefull Row of data.if no Stream is supplied.18 Date: June 16. The first data row is erased from the content . specialized for the JSON format and SQL export . End the serialized JSON object .).aRowsCount: integer).only works if the associated storage stream is TMemoryStream ."values":["col1".val11."val12". item will be added to the generated JSON stream (for faster unserialization of huge content) procedure CancelAllVoid.i. i. const Fields: TSQLFieldBits=[]).. If not Expanded format. a "rowCount":.flush the internal buffer content procedure TrimFirstRow. Write or init field names for appropriate JSON Expand later use . Is set to TRUE in case of Expanded format property FieldMax: integer read fFieldMax write fFieldMax. 1.. Expand. a temporary memory stream will be created (it's faster to supply one..] } SynCommons.write non expanded postlog (.Synopse mORMot Framework Software Architecture Design 1. if needed . The data will be written to the specified Stream . 2013 TJSONWriter = class(TTextWriter) Simple writer to a Stream. withID: boolean. Read-Only access to the higher field index to be stored .18 Page 353 of 1055 .TempMemoryStream) procedure AddColumns(aKnownRowsCount: integer=0).' ."rowcount":. Rewind the Stream position and write void JSON object procedure EndJSONObject(aKnownRowsCount.g. any TSQLRest.Rev. e.cancel last '.pas unit .close the JSON object ']' or ']}' .expect not Expanded format property Expand: boolean read fExpand write fExpand. the highest bit set in Fields property Fields: TSQLFieldBits read fFields write fFields..if aKnownRowsCount is not null. faster than string+string ColNames: TRawUTF8DynArray.e.e..val21.ColNames[] must have been initialized before calling this procedure ."col2". Read-Only access to the field bits set for each column to be stored property StartDataPosition: integer read fStartDataPosition..use an internal buffer. Used internally to store column names and count for AddColumns constructor Create(aStream: TStream. '. 18 Date: June 16. Initialize the internal storage . e. i.internally make use of an efficient hashing algorithm for fast response (i.pas unit . override.Synopse mORMot Framework Software Architecture Design 1.returns the found/added index .used e. Called after a write access to the database to flush the cache .return '' if nothing found .e.return the associated Value otherwize.18 Page 354 of 1055 .returns -1 if not found TObjectListPropertyHashed = class(TObjectListHashedAbstract) This class will hash and search for a sub property of the stored objects SynCommons. 1. Find a Key in the cache entries . Number of entries in the cache TObjectListHashed = class(TObjectListHashedAbstract) This class behaves like TList/TObjectList.aMaxCacheRamUsed can set the maximum RAM to be used for values. aResultTag: PPtrInt): RawUTF8.g. aTag: PtrInt). using a fast hash table .e. 2013 property WithID: boolean read fWithID write fWithID.if added. hash is stored and Items[] := aObject function IndexOf(aObject: TObject): integer. Retrieve an object index within the list. override. but will use hashing for (much) faster IndexOf() method function Add(aObject: TObject.returns TRUE if was flushed. in bytes (default is 16 MB per cache): cache will be reset when so much value will be reached function Find(const aKey: RawUTF8. TSynNameValue will use the TDynArrayHashed wrapper mechanism) constructor Create(aMaxCacheRamUsed: cardinal=16384*1024).release all cache memory . Search and add an object reference to the list .set Count to 0 . Add a Key and its associated value (and tag) to the cache entries .g.Rev. Is set to TRUE if the ID field must be appended to the resulting JSON TSynCache = class(TObject) Implement a cache of some key/value pairs. by TSQLDataBase for caching the SELECT statements results in an internal JSON format (which is faster than a query to the SQLite3 engine) . if there was something in cache procedure Add(const aValue: RawUTF8.Count. to improve reading speed . and the associated integer tag if aResultTag address is supplied function Reset: boolean.you MUST always call Find() with the associated Key first property Count: integer read fNameValue. out wasAdded: boolean): integer. using a fast hash table . Finalize the internal objects stored . Initialize the class instance with the corresponding callback in order to handle sub-property hashing and search .Rev.returns the found/added index .set aOwnObjects=true to force memory object instance management destructor Destroy.if instance was created with aOwnObjects=true function Add(const aText: RawUTF8): PtrInt.pas unit as example: function WeakZeroClassSubProp(aObject: TObject): TObject.pas unit . HashAnsiStringI/SortDynArrayAnsiStringI for a RawUTF8) .if added.18 Date: June 16. only the hash is stored: caller has to set List[i] function IndexOf(aObject: TObject): integer. 2013 constructor Create(aSubPropAccess: TObjectListPropertyHashedAccessProp. from a given Name when stored as 'Name=Value' pairs .if aFreeItems is TRUE (default).g. out wasAdded: boolean): integer. Delete a stored RawUTF8 item.Synopse mORMot Framework Software Architecture Design 1. aCompare: TDynArraySortCompare=nil. begin result := TSetWeakZeroInstance(aObject).returns -1 if not found TRawUTF8List = class(TObject) This class is able to emulate a TStringList with our native UTF-8 string type . will behave like a TList function Add(aObject: TObject. aHashElement: TDynArrayHashOne=nil. any associated Objects[] are just weak references .returns -1 and raise no exception in case of self=nil function AddObject(const aText: RawUTF8. Search and add an object reference to the list . Store a new RawUTF8 item. override.18 Page 355 of 1055 . 1. aFreeItems: boolean=true).cross-compiler. end. . and its associated TObject. if aFreeItems is FALSE.by default.by default. i. reintroduce. from Delphi 6 up to XE2. and its associated TObject .returns -1 and raise no exception in case of self=nil function DeleteFromName(const Name: RawUTF8): PtrInt. Retrieve an object index within the list.e is Unicode Ready constructor Create(aOwnObjects: boolean=false). override. Store a new RawUTF8 item .fInstance. will behave like a TObjectList. aObject: TObject): PtrInt.see TSetWeakZeroClass in mORMot.raise no exception in case of out of range supplied index SynCommons. Initialize the class instance . aHashElement/aCompare will hash/search for pointers: you can specify the hash/search methods according to your sub property (e. override. Set all lines from an UTF-8 text file . then optinally delete the entry property Capacity: PtrInt read GetCapacity write SetCapacity. Delete a stored RawUTF8 item. var Value: RawUTF8. but will not expect one either procedure SetText(const aText: RawUTF8. 2013 function Get(Index: PtrInt): RawUTF8. and its associated TObject . ThenDelete: boolean). The OnChange event will be raised only when EndUpdate will be called procedure Clear.returns nil and raise no exception in case of out of range supplied index function GetText(const Delimiter: RawUTF8=#13#10): RawUTF8. Find a RawUTF8 item in the stored Strings[] list . const Delimiter: RawUTF8=#13#10).18 Date: June 16. Call the OnChange event if changes occured procedure LoadFromFile(const FileName: TFileName). Get a stored Object item . separated by the supplied delimiter procedure UpdateValue(const Name: RawUTF8. Retrieve the all lines. 1.this search is case sensitive function IndexOfName(const Name: RawUTF8): PtrInt. Erase all stored RawUTF8 items procedure Delete(Index: PtrInt).Rev.18 Page 356 of 1055 .returns '' and raise no exception in case of out of range supplied index function GetObject(Index: PtrInt): TObject. Find a TObject item index in the stored Objects[] list procedure AddRawUTF8List(List: TRawUTF8List).will ignore any trailing UTF-8 BOM in the file content.raise no exception in case of out of range supplied index procedure EndUpdate. Update Value from an existing Name=Value.expect the file is explicitly an UTF-8 file . Append a specified list to the current content procedure BeginUpdate. virtual. Access to the Value of a given 'Name=Value' pair function IndexOf(const aText: RawUTF8): PtrInt.pas unit . Find the index of a given Name when stored as 'Name=Value' pairs .Synopse mORMot Framework Software Architecture Design 1. separated by the supplied delimiter function GetValueAt(Index: PtrInt): RawUTF8. Set or retrive the current memory capacity of the RawUTF8 list SynCommons. Set all lines. Get a stored RawUTF8 item .search on Name is case-insensitive with 'Name=Value' pairs function IndexOfObject(aObject: TObject): PtrInt. Rev.returns nil and raise no exception in case of out of range supplied index property OnChange: TNotifyEvent read fOnChange write fOnChange. Initialize the class instance function IndexOf(const aText: RawUTF8): PtrInt.18 Date: June 16. then use it to retrieve the corresponding matching index SynCommons.lines are separated by #13#10 (CRLF) by default. Direct access to the memory of the Objects array property Objects[Index: PtrInt]: TObject read GetObject write PutObject.pas unit .equals '=' by default property ObjectPtr: PPointerArray read GetObjectPtr. override. use GetText and SetText methods if you want to use another line delimiter (even a comma) property Values[const Name: RawUTF8]: RawUTF8 read GetValue write SetValue. Find a RawUTF8 item in the stored Strings[] list . The char separator between 'Name=Value' pairs .returns '' and raise no exception in case of out of range supplied index property Text: RawUTF8 read GetTextCRLF write SetTextCRLF. Direct access to the memory of the RawUTF8 array property Names[Index: PtrInt]: RawUTF8 read GetName.search on Name is case-insensitive with 'Name=Value' pairs TRawUTF8ListHashed = class(TRawUTF8List) A TRawUTF8List which will use an internal hash table for faster IndexOf() . Event trigerred when an entry is modified property Strings[Index: PtrInt]: RawUTF8 read Get write Put.Synopse mORMot Framework Software Architecture Design 1. Return the count of stored RawUTF8 property ListPtr: PPUtf8CharArray read GetListPtr. Get or set a Object item . 2013 property Count: PtrInt read GetCount. Get or set a RawUTF8 item . 1.18 Page 357 of 1055 . Set or retrieve all items as text lines .this is a rather rough implementation: all values are re-hashed after change: but purpose of this class is to allow faster access of a static list of identifiers constructor Create(aOwnObjects: boolean=false). Retrieve the corresponding Name when stored as 'Name=Value' pairs property NameValueSep: AnsiChar read fNameValueSep write fNameValueSep.this overriden method will update the internal hash table (if needed). Access to the corresponding 'Name=Value' pairs . pas unit .every line beginning is stored into LinePointers[] destructor Destroy. Retrieve the memory buffer mapped to the file content property Size: cardinal read fBufSize.is FALSE by default. aIndex: Integer): Boolean.g.Synopse mORMot Framework Software Architecture Design 1. aCustomOffset: Int64=0): boolean. overload.LoadFromFile() . Map the file specified by its name . overload. 2013 property CaseInsensitive: boolean read fHashCaseInsensitive write SetHashCaseInsensitive. as for the default TRawUTF8List. override. the corresponding map view if created (by default. aFileSize: integer).18 Page 358 of 1055 .will ignore any trailing UTF-8 BOM in the file content. Retrieve the buffer size TMemoryMapText = class(TObject) Able to read a UTF-8 text file using memory map .every line beginning is stored into LinePointers[] . Specify if the IndexOf() hashed search is case sensitive or not . Read an UTF-8 encoded text file content .file will be closed when UnMap will be called function Map(aFile: THandle. Unmap the file property Buffer: PAnsiChar read fBuf. aCustomSize: cardinal=0. Set a fixed buffer for the content . Map the corresponding file handle . overload. overload. aBufferSize: cardinal).much faster than TStringList. Returns TRUE if the supplied text is contained in the corresponding line SynCommons.this overloaded constructor accept an existing memory buffer (some uncompressed data e.IndexOf() method TMemoryMap = object(TObject) Handle memory mapping of a file content used to store and retrieve Words in a sorted array function Map(const aFileName: TFileName): boolean.Rev.) constructor Create(const aFileName: TFileName). overload. but will not expect one either constructor Create(aFileContent: PUTF8Char.18 Date: June 16. Read an UTF-8 encoded text file . 1.emulated a memory-mapping from an existing buffer procedure UnMap. will map whole file) procedure Map(aBuffer: pointer.if aCustomSize and aCustomOffset are specified. Release the memory map and internal LinePointers[] function LineContains(const aUpperSearch: RawUTF8. this is faster than LineSize(aIndex)<aMinimalCount for big lines property Count: integer read fCount. Direct access to each text line . aMinimalCount: integer): boolean. and it does make sense to work with RawByteString in our UTF-8 oriented framework TSynMemoryStream = class(TCustomMemoryStream) A TStream pointing to some in-memory data. Create a TStream with the supplied data buffer . so it is not compatible with previous versions. Retrieve the number of UTF-8 chars of the given line . Retrieve a line content as UTF-8 .will return '' if aIndex is out of range TRawByteStringStream = class(TStream) A TStream using a RawByteString as internal storage .warning: there is no local copy of the supplied content: the source data must be available during all the TSynMemoryStream usage constructor Create(Data: pointer. The number of text lines property FileName: TFileName read fFileName write fFileName.a temporary UTF-8 string is created . 1.18 Date: June 16. The memory map used to access the raw file content property Strings[aIndex: integer]: string read GetString.Rev. overload. Check if there is at least a given number of UTF-8 chars in the given line . for instance UTF-8 text . but with #13 or #10 .pas unit .a temporary VCL string is created (after conversion for UNICODE Delphi) . The file name which was opened by this instance property LinePointers: PPointerArray read fLines.Synopse mORMot Framework Software Architecture Design 1. Retrieve a line content as generic VCL string type . since end of line will NOT end with #0.warning: no range check is performed about supplied index property Lines[aIndex: integer]: RawUTF8 read GetLine.will return '' if aIndex is out of range property Map: TMemoryMap read fMap.use LineSize() method to retrieve line length.Free SynCommons. DataLen: integer).warning: no range check is performed about supplied index function LineSizeSmallerThan(aIndex.warning: there is no local copy of the supplied content: the Data/DataLen buffer must be available during all the TSynMemoryStream usage: don't release the source Data before calling TSynMemoryStream.18 Page 359 of 1055 . 2013 function LineSize(aIndex: integer): integer.default TStringStream uses WideChars since Delphi 2009. pas unit . using an internal TMemoryStream . Create a TStream from a file content using fast memory mapping . RawUTF8 or RawByteString function Write(const Buffer. Release any internal mapped file instance TFileBufferWriter = class(TObject) This class can be used to speed up writing to a file . override. Count: Longint): Longint. aCustomOffset: Int64=0).Rev. the corresponding map view if created (by default. BufLen: integer=65536).big speed up if data is written in small blocks . overload. and specify a file handle to use for writing .18 Date: June 16. aCustomSize: cardinal=0.if aCustomSize and aCustomOffset are specified. using fast memory mapping constructor Create(aFile: THandle. Create a TStream with the supplied text data .use an internal buffer of the specified size constructor Create(aStream: TStream. overload. Create a TStream from a file content using fast memory mapping .Synopse mORMot Framework Software Architecture Design 1. e. the corresponding map view if created (by default.warning: there is no local copy of the supplied content: the aText variable must be available during all the TSynMemoryStream usage: don't release aText before calling TSynMemoryStream. Initialize the buffer.if aCustomSize and aCustomOffset are specified.use an internal buffer of the specified size constructor Create(aFile: THandle. Initialize the buffer. BufLen: integer=65536). and specify a TStream to use for writing .aText can be on any AnsiString format. overload. aCustomSize: cardinal=0.use Flush then TMemoryStream(Stream) to retrieve its content SynCommons. overload. and specify a file to use for writing .Free .use an internal buffer of the specified size constructor CreateInMemoryStream. Initialize the buffer.also handle optimized storage of any dynamic array of Integer/Int64/RawUTF8 constructor Create(const aFileName: TFileName. This TStream is read-only: calling this method will raise an exception TSynMemoryStreamMapped = class(TSynMemoryStream) A TStream created from a file content. BufLen: integer=65536). override. will map whole file) constructor Create(const aFileName: TFileName. will map whole file) destructor Destroy. overload.18 Page 360 of 1055 .g. overload. Initialize the buffer. 1. aCustomOffset: Int64=0). 2013 constructor Create(const aText: RawByteString). The associated writing stream property TotalWritten: Int64 read fTotalWritten. overload. overload. override. depending on the data layout procedure WriteVarUInt64DynArray(const Values: TInt64DynArray. ValuesCount: integer. Append a TStream content . all Objects[] properties will be stored as VarUInt32 procedure WriteStream(aStream: TCustomMemoryStream. Append the RawUTF8 dynamic array .Size is used . a fixed-sized record storage is also handled separately) property Stream: TStream read fStream. Get the byte count written since last Flush SynCommons. ValuesCount: integer).handled the fixed size strings array case in a very efficient way procedure WriteRawUTF8List(List: TRawUTF8List. DataLen: integer).. Append the RawUTF8List content . Append an integer value using 32-bit variable-length integer encoding of the by-two complement of the given value procedure WriteVarUInt32(Value: PtrUInt). Append some data at the current position procedure WriteRawUTF8DynArray(const Values: TRawUTF8DynArray. Append UInt64 values using 64-bit variable length integer encoding .pas unit .if Offset is TRUE.if StoreObjectsAsVarUInt32 is TRUE.Rev. the Stream. Offset: Boolean)... 2013 destructor Destroy.Synopse mORMot Framework Software Architecture Design 1.. ValuesCount: integer.18 Page 361 of 1055 . Write any pending data in the internal buffer to the file . Append cardinal values (NONE must be negative!) using 32-bit variable-length integer encoding or other specialized algorithm. Release internal TStream (after AssignToHandle call) function Flush: Int64.after a Flush. Append a cardinal value using 32-bit variable-length integer encoding procedure WriteVarUInt32Array(const Values: TIntegerDynArray. Append some UTF-8 encoded text at the current position procedure Write(Data: pointer.18 Date: June 16. aStreamSize: Integer=-1). StoreObjectsAsVarUInt32: Boolean=false). DataLayout: TFileBufferWriterKind).returns the number of bytes written between two FLush method calls procedure Write(const Text: RawUTF8). 1.the size of the content is stored in the resulting stream procedure WriteVarInt32(Value: PtrInt). then it will store the difference between two values using 32-bit variable-length integer encoding (in this case.is StreamSize is left as -1.) . it's possible to call FileSeek64(aFile. overload. Read some bytes from the given reading position .18 Date: June 16. Read some UTF-8 encoded text at the current position .18 Page 362 of 1055 . data will be copied into the temporary aTempData buffer before retrieval function ReadRawUTF8: RawUTF8.Rev.if StoreObjectsAsVarUInt32 was TRUE. all Objects[] properties will be retrieved as VarUInt32 SynCommons.Synopse mORMot Framework Software Architecture Design 1. Retrieve a pointer to the current position. Retrieve the current in-memory pointer .but sometimes. in bytes function Read(Data: pointer. which was written as fixed length . but will be as a record :( function CurrentMemory: pointer.WriteRawUTF8List .if the data is available in the current memory mapped file. Read one cardinal. Windows fails to allocate more than 512 MB for a memory map. overload.maximum handled file size has no limit (but will use slower direct file reading) .is defined either as an object either as a record. but returns 0 function ReadCardinal: cardinal. for a given data length . we fall back on direct file reading . don't raise any error.otherwise (i. Read one byte .if reached end of file. but returns 0 function ReadPointer(DataLen: PtrUInt.returns the resulting text function ReadRawUTF8List(List: TRawUTF8List): boolean. 2013 TFileBufferReader = object(TObject) This structure can be used to speed up reading from a file .pas unit .accept either TFileStream or TCustomMemoryStream kind of stream function Read(out Text: RawUTF8): integer. 1.use internaly memory mapped files for a file up to 2 GB (Windows has problems with memory mapped files bigger than this size limit .returns the number of bytes which was read function ReadByte: PtrUInt. DataLen: integer): integer. Retrieve the RawUTF8List content encoded with TFileBufferWriter. if the data is split between to 1GB memory map buffers). it will just return a pointer to it . due to a bug in Delphi 2009/2010 compiler (at least): this structure is not initialized if defined as an object on the stack.e. var aTempData: RawByteString): pointer. returns nil function OpenFrom(Stream: TStream): boolean.at least with 32 bit executables) .if file was not memory-mapped. don't raise any error.if reached end of file. Read some UTF-8 encoded text at the current position . Initialize the buffer from an already existing Stream . overload. because it does lack of contiguous memory space: in this case.returns the resulting text length. if memory mapping failed.the content size is either specified by DataLen>=0. either available at the current position. Initialize the buffer. Retrieved RawUTF8 values encoded with TFileBufferWriter. a separate memory map will be created (the returned instance is a TSynMemoryStreamMapped) function ReadVarInt32: PtrInt.returns TRUE if success. and the by-two complement function ReadVarRawUTF8DynArray(var Values: TRawUTF8DynArray): PtrInt. a TSynMemoryStream instance is returned.returns the number of items read into Values[] (may differ from length(Values)) function ReadVarUInt64: QWord. Retrieved cardinal values encoded with TFileBufferWriter. Raise an exception in case of invalid content procedure Open(aFile: THandle). methods will use default slower file API SynCommons.Synopse mORMot Framework Software Architecture Design 1.WriteVarUInt64DynArray .WriteRawUTF8DynArray .18 Date: June 16.WriteStream method . overload.18 Page 363 of 1055 . or FALSE if Offset is out of range function Seek(Offset: PtrInt): boolean.returns the number of items read into Values[] (may differ from length(Values)) function ReadVarUInt32: PtrUInt.if this content fit in the current 1GB memory map buffer.call Open() again to use the Read() methods procedure ErrorInvalidContent. as saved by TFileBufferWriter. and specify a file to use for reading . Read one integer value encoded using our 32-bit variable-length integer. with no data copy (faster) . Create a TMemoryStream instance from the current position .returns TRUE if success. from the beginning of the file . Change the current reading position.WriteVarUInt32Array . 2013 function ReadStream(DataLen: PtrInt=-1): TCustomMemoryStream.if this content is not already mapped in memory.will try to map the whole file content in memory . 1. Retrieved Int64 values encoded with TFileBufferWriter. Close all internal mapped files .pas unit . overload. from the beginning of the file . or FALSE if Offset is out of range procedure Close. Read one UInt64 value encoded using our 64-bit variable-length integer function ReadVarUInt64Array(var Values: TInt64DynArray): PtrInt. Change the current reading position.returns the number of items read into Values[] (may differ from length(Values)) function Seek(Offset: Int64): boolean. Read one cardinal value encoded using our 32-bit variable-length integer function ReadVarUInt32Array(var Values: TIntegerDynArray): PtrInt.Rev. The optional associated parameters. var ErrorMsg: string): boolean.the optional associated parameters are to be supplied JSON-encoded function Process(FieldIndex: integer.GetValue e. Initialize the filter or validation instance property Parameters: RawUTF8 read fParameters write SetParameters.Synopse mORMot Framework Software Architecture Design 1. must return FALSE and put some message in ErrorMsg (translated into the current language: you could e.if the validation failed.this versions expect no parameter function Process(aFieldIndex: integer.if the validation passed.the value is expected by be UTF-8 text. Read-only access to the global file size TSynFilterOrValidate = class(TObject) Will define a filter or a validation process to be applied to a database Record content (typicaly a TSQLRecord) .the optional associated parameters are to be supplied JSON-encoded constructor Create(const aParameters: RawUTF8='').fFileSize.pas unit .g.you can leave ErrorMsg='' to trigger a generic error message from clas name ('"Validate email" rule failed' for TSynValidateEmail class e. Initialize the buffer from an already existing memory block . const Value: RawUTF8.Format() call for automatic translation via the mORMoti18n unit . override.may be e.Rev. . abstract. supplied as JSON-encoded TSynValidate = class(TSynFilterOrValidate) Will define a validation to be applied to a Record (typicaly a TSQLRecord) field content .a typical usage is to validate an email or IP adress e. will return TRUE TSynValidateIPAddress = class(TSynValidate) IP v4 address validation to be applied to a Record field content (typicaly a TSQLRecord) . overload.g.g. . a resource or a TMemoryStream property FileSize: Int64 read fMap. aBufferSize: cardinal).g. as generated by TPropInfo. const Value: RawUTF8.) . 2013 procedure OpenFrom(aBuffer: pointer. virtual. 1.18 Date: June 16. Perform the validation action to the specified value .g. use a resourcestring and a SysUtils. var ErrorMsg: string): boolean. Perform the IP Address validation action to the specified value SynCommons.18 Page 364 of 1055 . [!abc] Matches anything but a or b or c at that position .Rev.com' or such property ForbiddenTLD: RawUTF8 read fForbiddenTLD write fForbiddenTLD.on. Perform the Email Address validation action to the specified value .*' would match match.. should be set as lower case values . expecting a CSV lis of Top-Level-Domain (TLD) names. 1.g.if accessed directly. but whole domains like 'cracks. should be set as lower case values . 'fr' TSynValidatePattern = class(TSynValidate) Grep-like case-sensitive pattern validation of a Record field content (typicaly a TSQLRecord) . e. mavch.org.net".parameter is NOT JSON encoded. .'ma?ch. const Value: RawUTF8.this will process a validation according to RFC 822 (calling the IsValidEmail() function) then will check for the TLD to be in one of the Top-Level domains ('.ru.org.pas unit .exe. A CSV list of forbidden TLD ."ForbiddenTLD":"fr"}' . override.g. and then will check the TLD according to AllowedTLD and ForbiddenTLD function Process(aFieldIndex: integer. etc.com' and such) or a two-char country.18 Page 365 of 1055 .call IsValidEmail() function and check for the supplied TLD property AllowedTLD: RawUTF8 read fAllowedTLD write fAllowedTLD.g.if accessed directly. '{"AllowedTLD":"com. var ErrorMsg: string): boolean.pattern check IS case sensitive (TSynValidatePatternI is not) .e.Synopse mORMot Framework Software Architecture Design 1.if accessed directly.dat. march.'this [e-n]s a [!zy]est' would match 'this is a test'. A CSV list of forbidden domain names .hotmail.[a-e] Matches a through e at that position . 2013 TSynValidateEmail = class(TSynValidate) IP address validation to be applied to a Record field content (typicaly a TSQLRecord) .this class is not as complete as PCRE regex for example. 'com.e.[^abc] Matches anything but a or b or c at that position .not only the TLD. A CSV list of allowed TLD . should be set as lower case values .18 Date: June 16.optional JSON encoded parameters are "AllowedTLD" or "ForbiddenTLD".[abc] Matches a or b or c at that position . but code overhead is very small SynCommons.[abcx-z] Matches a or b or c or x or y or or z.net' property ForbiddenDomains: RawUTF8 read fForbiddenDomains write fForbiddenDomains. as does [a-cx-z] . but is some basic grep-like pattern -? Matches any single characer -* Matches any contiguous characters . but would not match 'this as a test' nor 'this is a zest' . /:?%$="#@(){}+-*].default is 0.default is maxInt. any Left space allowed property MaxLength: cardinal read fProps[1] write fProps[1].pas unit . 1."MaxLength":10..g. override. digit [0-9].expects optional JSON parameters of the allowed text length range as '{"MinLength":5.default is maxInt. i.default is maxInt. MinLowerCount and MinUpperCount allow you to specify the minimal count of respectively alphabetical [a-zA-Z]. override.default is maxInt. punctuation [_!. Maximal space count allowed on the Left side . any space number allowed property MinAlphaCount: cardinal read fProps[2] write fProps[2]. but is NOT case sensitive TSynValidateText = class(TSynValidate) Text validation to be applied to a Record field content (typicaly a TSQLRecord) . Initialize the validation instance function Process(aFieldIndex: integer. Maximal space count inside the value text ."MinDigitCount":1. "MinPunctCount":1.pattern can be e. no maximum length is set property MaxRightTrimCount: cardinal read fProps[10] write fProps[10].e. but is some basic grep-like pattern . i."MinUpperCount":1} .e. i.e. const Value: RawUTF8.18 Page 366 of 1055 . any Right space allowed property MaxSpaceCount: cardinal read fProps[8] write fProps[8].default MinLength value is 1. var ErrorMsg: string): boolean. checking the current class TSynValidatePatternI = class(TSynValidatePattern) Grep-like case-insensitive pattern validation of a Record field content (typicaly a TSQLRecord) .parameter is NOT JSON encoded. const Value: RawUTF8.the length is calculated with Unicode glyphs.e."MinAlphaCount":1. '[0-9][0-9]:[0-9][0-9]:[0-9][0-9]' . Perform the text length validation action to the specified value property MaxLeftTrimCount: cardinal read fProps[9] write fProps[9].same as TSynValidatePattern. var ErrorMsg: string): boolean.Rev. MinPunctCount. 2013 function Process(aFieldIndex: integer."MinLowerCount":1. Maximal space count allowed on the Right side . i.this method will implement both TSynValidatePattern and TSynValidatePatternI. lower case or upper case characters constructor Create(const aParameters: RawUTF8=''). MinDigitCount.MinAlphaCount.Synopse mORMot Framework Software Architecture Design 1. Minimal alphabetical character [a-zA-Z] count . not with UTF-8 encoded char count . i.18 Date: June 16. MaxLength is maxInt: so you can specify a blank TSynValidateText to avoid any void textual field .e. no minimum set SynCommons.. Perform the pattern validation to the specified value . Maximal length value allowed for the text content . the optional associated parameters are to be supplied JSON-encoded procedure Process(aFieldIndex: integer. i."MaxSpaceCount":0}' .default is 0.g."MinAlphaCount":1.e.the length is calculated with Unicode glyphs. no minimum set property MinPunctCount: cardinal read fProps[4] write fProps[4]. with no space allowed inside TSynFilter = class(TSynFilterOrValidate) Will define a filter to be applied to a Record field content (typicaly a TSQLRecord) . Minimal length value allowed for the text content .default is 1. a void text will not pass the validation property MinLowerCount: cardinal read fProps[5] write fProps[5]. one upper case letter.pas unit . Minimal digit character [0-9] count .default is 0. i. i. 2013 property MinDigitCount: cardinal read fProps[3] write fProps[3].Rev.e.e. var Value: RawUTF8). virtual.this version expects no parameter SynCommons. abstract.18 Page 367 of 1055 .GetValue / TPropInfo.. 'a'. no minimum set property MinSpaceCount: cardinal read fProps[7] write fProps[7].the following parameters are set by default to '{"MinLength":5.e. Minimal alphabetical upper case character [A-Z] count ./:?%$="#@(){}+-*] count .. Minimal space count inside the value text .SetValue e.UpperCase conversion is made for ASCII-7 only. i.e.e.default is 0. with at least one digit. and one ponctuation sign. Minimal alphabetical lower case character [a-z] count . TSynFilterUpperCase = class(TSynFilter) A custom filter which will convert the value into Upper Case characters .default is 0.18 Date: June 16.the value is converted into UTF-8 text. Perform the filtering action to the specified value . "MinPunctCount":1. no minimum set property MinLength: cardinal read fProps[0] write fProps[0].e.you can specify some JSON encoded parameters to change this default values. no minimum set TSynValidatePassWord = class(TSynValidateText) Strong password validation for a Record field content (typicaly a TSQLRecord) .. one lower case letter.Synopse mORMot Framework Software Architecture Design 1. any space number allowed property MinUpperCount: cardinal read fProps[6] write fProps[6]. which will validate the text field only if it contains from 5 to 10 characters."MinDigitCount":1. as expected by TPropInfo."MinLowerCount":1."MinUpperCount":1. i.'z' characters . 1. i.default is 0. Minimal punctuation sign [_!. i. or trim any time or date value in a TDateTime field .a typical usage is to convert to lower or upper case."MaxLength":10. not with UTF-8 encoded char count . override.From() .From(): PIso8601(@aTime)^.typecast TTimeLog from PIso8601. 'A'. 1. i. var Value: RawUTF8). Perform the space triming conversion to the specified value Iso8601 = object(TObject) Usefull object to type cast TTimeLog type into Iso-8601 or TDateTime . override. 'E' acute will be converted to 'e' .UpperCase conversion is made for all latin characters in the WinAnsi code page only.Value is bit-oriented.this versions expect no parameter procedure Process(aFieldIndex: integer. Perform the case conversion to the specified value TSynFilterUpperCaseU = class(TSynFilter) A custom filter which will convert the value into Upper Case characters .g.18 Date: June 16.'Z' characters .. 2013 procedure Process(aFieldIndex: integer. not with Iso8601(Time).pas unit .since Iso8601.LowerCase conversion is made for all latin characters in the WinAnsi code page only. var Value: RawUTF8).Synopse mORMot Framework Software Architecture Design 1. var Value: RawUTF8).g. override. Perform the case conversion to the specified value TSynFilterTrim = class(TSynFilter) A custom filter which will trim any space character left or right to the value . Perform the case conversion to the specified value TSynFilterLowerCaseU = class(TSynFilter) A custom filter which will convert the value into Lower Case characters . simply use Time := Iso8601Now . override. 'e' acute will be converted to 'E' .Rev.e. you can't just use add or substract two TTimeLog values when doing such date/time computation: use a TDateTime temporary conversion in such case SynCommons.this version expects no parameter procedure Process(aFieldIndex: integer. var Value: RawUTF8).LowerCase conversion is made for ASCII-7 only. e.18 Page 368 of 1055 . override. var Value: RawUTF8). Perform the case conversion to the specified value TSynFilterLowerCase = class(TSynFilter) A custom filter which will convert the value into Lower Case characters .this version expects no parameter procedure Process(aFieldIndex: integer.to get current time. e.this version expects no parameter procedure Process(aFieldIndex: integer. DateOnly: Boolean=false).bits 12. overload. Convert to a delphi Date and Time function ToTime: TDateTime.18 Date: June 16. L: integer). Convert to a delphi Date function ToDateTime: TDateTime...bits 0.18 Page 369 of 1055 .pas unit . overload..5 = Seconds (0..D. overload.21 = Day-1 (0. Convert to a delphi Time procedure Expand(out Date: TSystemTime). FirstTimeChar: AnsiChar = 'T'): integer.MM. 2013 Value: Int64.38 = Year (0..59) .11) .bits 22..25 = Month-1 (0. The value itself . HH.bits 17.31) . 1. Convert to Iso-8601 encoded text function Text(Expanded: boolean.16 = Hours (0. overload. Convert to Iso-8601 encoded text function ToDate: TDateTime. Fill Value from specified TDateTime procedure FromNow.. overload..SS: cardinal)..Rev. Expanded: boolean. Executable release build number SynCommons. FirstTimeChar: AnsiChar = 'T'): RawUTF8.. Fill Value from Iso-8601 encoded text procedure From(FileDate: integer).23) . Extract the date and time content in Value into individual values procedure From(P: PUTF8Char.4095) function Text(Dest: PUTF8Char. overload. overload.M. Fill Value from Iso-8601 encoded text procedure From(const S: RawUTF8).bits 6. Fill Value from specified Date and Time procedure From(DateTime: TDateTime..11 = Minutes (0.bits 26. Fill Value from specified File Date procedure From(Y.59) .Synopse mORMot Framework Software Architecture Design 1. Fill Value from current local system Date and Time TFileVersion = class(TObject) To have existing RTTI for published properties used to retrieve version information from any EXE Build: Integer.. Build date and time of this exe file property Detailed: string read fDetailed write fDetailed. i. 1. Version info of the exe file as '3.e. Executable release version number constructor Create(const FileName: TFileName. 2013 BuildYear: integer.e a one Table SELECT with one optional "WHERE fieldname = value" statement . no complete SQL interpreter is implemented: only valid SQL command is "SELECT Field1. The fields selected for the SQL statement SynCommons.123' . Executable major version number Minor: Integer.allocates memory from Delphi heap (i." SQL statement . DefaultVersion: integer).return "string" type.return "string" type.will parse the "LIMIT number OFFSET number" end statement clause Fields: TSQLFieldBits.1' .Field2 FROM Table WHERE ID=120.e.". Build year of this exe file Main: string.18 Date: June 16. i.18 Page 370 of 1055 . FastMM4/SynScaleMM) and not GlobalAlloc() .handle basic REST commands.DefaultVersion is used if no information Version was included into the executable resources (on compilation time) . for speed . Retrieve application version from exe file name .uses bigger growing size of the capacity TSynTableStatement = class(TObject) Used to parse a SELECT SQL statement .pas unit .to retrieve version information from current executable. Version info of the exe file as '3.Rev.Release property BuildDateTime: TDateTime read fBuildDateTime write fBuildDateTime.e.handle also basic "SELECT Count(*) FROM TableName.Synopse mORMot Framework Software Architecture Design 1. Retrieve the version as a 32 bits integer with Major.0. UnicodeString for Delphi 2009+ Major: Integer. then use ExeVersion global variable function Version32: integer.1. Executable minor version number Release: Integer. UnicodeString for Delphi 2009+ TOSVersionInfoEx = record Not defined in older Delphi versions THeapMemoryStream = class(TMemoryStream) To be used instead of TMemoryStream. i. just call ExeVersionRetrieve function.Minor. SimpleFieldsBits: TSQLFieldBits=[0.Synopse mORMot Framework Software Architecture Design 1.g.SYNTABLESTATEMENTWHEREID=0 is ID.WhereValue is left '' if the SQL statement is not correct .if SYNTABLESTATEMENTWHERECOUNT=-2..if FieldProp is set. The number specified by the optional LIMIT . then use the WhereField value to retrieve the content .TableName.WhereValue .18 Page 371 of 1055 . The number specified by the optional OFFSET .set to 0 by default (meaning no OFFSET clause) IsSelectCountWhere: boolean..Rev. 1 for field # 0.e. The index of the field used for the WHERE clause ... and so on..SimpleFieldsBits is used for '*' field names ." clause TableName: RawUTF8.) WhereValueSBF: TSBFString.pas unit . then the WhereValueSBF property is initialized with the SBF equivalence of the WhereValue SynCommons.set to 0 by default (meaning no LIMIT clause) FoundOffset: integer. Optional associated writer constructor Create(const SQL: RawUTF8.the supplied GetFieldIndex() method is used to populate the Fields and WhereField parameters .WhereField. FieldProp: TSynTableFieldProperties=nil).. the caller must check for TableName to match the expected value. Parse the given SELECT SQL statement and retrieve the corresponding parameters into Fields. Is TRUE if ID/RowID was set in the WHERE clause Writer: TJSONWriter. WhereField = RTTI field index +1) .if WhereValue is set. 2 for field #1. (i.18 Date: June 16. clause .. clause . means SQL statement was "SELECT Count(*) FROM TableName" WhereValue: RawUTF8.MAX_SQLFIELDS-1]. GetFieldIndex: TSynTableFieldIndex. The value used for the WHERE clause WhereValueInteger: integer.. An integer representation of WhereValue (used for ID check e. 2013 FoundLimit: integer. Used to fast compare with SBF binary compact formatted data WithID: boolean. 1. The retrieved table name WhereField: integer.. TRUE if is "SELECT Count(*) FROM TableName WHERE . means all rows must be fetched (no WHERE clause: "SELECT * FROM TableName") .equal SYNTABLESTATEMENTWHEREALL=-1. -2 for a variable string FieldType: TSynTableFieldType. The field name Offset: integer.18 Date: June 16. its absolute will be the field number to be counted after TSynTable.used to speed up the record update procedure with huge number of records SynCommons. but the "physical" index. Options of this field OrderedIndex: TIntegerDynArray. in case of fixed-length field . Number of the field in the table (starting at 0) FieldSize: integer. the index value used to retrieve data from low-level (and faster) method OrderedIndexCount: integer.only available if tfoIndex is in Options .SortCompare() method to avoid stack allocation TSynTableFieldProperties = class(TObject) Store the type properties of a given field / database column FieldNumber: integer. All TSynValidate instances registered per each field Name: RawUTF8.18 Page 372 of 1055 . If allocated.i. Kind of field (defines both value type and storage to be used) Filters: TObjectList. If set to TRUE after an OrderedIndex[] refresh but with not sorting . Contains the offset of this field. fixed-length fields are stored in the beginning of the record storage: in this case.fFieldVariableOffset (-1 for first item) Options: TSynTableFieldOptions.if the value is < 0. The fixed-length size. a value >= 0 will point to the position of the field value of this field .e. 2013 TSortCompareTmp = record Internal value used by TSynTableFieldProperties. Number of items in OrderedIndex[] . i. . contains the storage indexes of every item.OrderedIndexSort(0.you should call OrderedIndexRefresh method to ensure it is sorted OrderedIndexReverse: TIntegerDynArray. OrderedIndexReverse[OrderedIndex[i]] := i. contains the reverse storage index of OrderedIndex .e.Rev. 1. or -1 for a varInt.OrderedIndexCount-1) must be called before using the OrderedIndex[] array .is set to 0 when the content has been modified (mark force recreate) OrderedIndexNotSorted: boolean. If allocated. in sorted order .Synopse mORMot Framework Software Architecture Design 1.pas unit .the index is not the per-ID index.normaly. 2013 Validates: TObjectList.18 Date: June 16. All TSynValidate instances registered per each field constructor CreateFrom(var RD: TFileBufferReader). 1. Decode the value from a record buffer into an currency value . override.will return the specified associated TSynFilterOrValidate instance . Read entry from a specified file reader destructor Destroy. Decode the value from a record buffer into an Boolean .GetData to retrieve then decode the field SBF content function GetValue(FieldBuffer: pointer): RawUTF8. Retrieve the binary length (in bytes) of some SBF compact binary format function GetRawUTF8(RecordBuffer: pointer): RawUTF8.will call Owner.will call Owner. Decode the value from a record buffer into an integer .18 Page 373 of 1055 .will call Owner.GetData to retrieve then decode the field SBF content function GetInt64(RecordBuffer: pointer): Int64.a TSynValidateTableUniqueField is always added by TSynTable. Decode the value from our SBF compact binary format into UTF-8 text .GetData to retrieve then decode the field SBF content function GetDouble(RecordBuffer: pointer): Double.AfterFieldModif if tfoUnique is set in Options function GetBoolean(RecordBuffer: pointer): Boolean.will call Owner.will call Owner. Decode the value from a record buffer into a RawUTF8 string .GetData to retrieve then decode the field SBF content function GetLength(FieldBuffer: pointer): Integer.Rev.this method does not check for FieldBuffer to be not nil -> caller should check this explicitely SynCommons.GetData to retrieve then decode the field SBF content function GetCurrency(RecordBuffer: pointer): Currency. Decode the value from a record buffer into an floating-point value . Release associated memory and objects function AddFilterOrValidate(aFilter: TSynFilterOrValidate): TSynFilterOrValidate.GetData to retrieve then decode the field SBF content function GetInteger(RecordBuffer: pointer): Integer. Decode the value from a record buffer into an Int64 .pas unit .this will be used by Filter() and Validate() methods .will call Owner.Synopse mORMot Framework Software Architecture Design 1. Register a custom filter or validation rule to the class for this field . overload.18 Page 374 of 1055 . var MatchIndex: TIntegerDynArray. Create some SBF compact binary format from a BLOB memory buffer . set Limit=1 to only retrieve the first match) .the Limit parameter is similar to the SQL LIMIT clause: if greater than 0.aOldRecordData and aNewRecordData can be specified in order to guess if the field data has really been modified (speed up the update a lot to only sort indexed fields if its content has been really modified) .call with both indexes = -1 will sort the existing OrderedIndex[] array .e. each index value used to retrieve data from low-level (and fast) GetData method function OrderedIndexUpdate(aOldIndex.e.Synopse mORMot Framework Software Architecture Design 1. integer. overload. the index value used to retrieve data from low-level (and fast) GetData method) . aOldRecordData.GetData property must have been set with a method returning a pointer to the field data for a given index (this index is not the per-ID index. cardinal. Create some SBF compact binary format from a Delphi binary value . won't duplicate them .if the indexes are already present in the list. but the "physical" index. aNewRecordData: pointer): boolean.pas unit . word. integer.the OrderedIndex[] array is first refreshed according to the aOldIndex.returns the resulting indexes as a a sorted list in MatchIndex/MatchIndexCount .WhereSBFValue must be a valid SBF formated field buffer content . or both >= 0 for update . aNewIndex=-1 for Delete. for tftWinAnsi .in this method. i.g.e.will encode any byte. Limit: Integer=0): Boolean. 2013 function OrderedIndexMatch(WhereSBFValue: pointer.is faster than a GetIteraring(). overload.returns FALSE if any parameter is invalid function SBF(const Value: RawUTF8): TSBFString. Create some SBF compact binary format from a Delphi binary value .will encode any byte.will return '' if the field type doesn't match tftBlobInternal function SBF(const Value: Int64): TSBFString.will return '' if the field type doesn't match an integer function SBF(const Value: Boolean): TSBFString. but the "physical" index. word. overload. i.will return '' if the field type doesn't match a string function SBF(Value: pointer. indexes are not the per-ID indexes. Will update then sort the array of indexes used for the field index . the index value used to retrieve data from low-level (and fast) GetData method) . overload. Retrieve one or more "physical" indexes matching a WHERE Statement . cardinal value . but the "physical" indexes. Create some SBF compact binary format from a Delphi binary value . ValueLen: integer): TSBFString.GetData property must have been set with a method returning a pointer to the field data for a given index (this index is not the per-ID index. var MatchIndexCount: integer.will return '' if the field type doesn't match an integer SynCommons. because will use binary search using the OrderedIndex[] array . 1. Int64 value .expect a RawUTF8 string: will be converted to WinAnsiString before storage. aNewIndex parameters: aOldIndex=-1 for Add.will return '' if the field type doesn't match a boolean function SBF(const Value: Integer): TSBFString. Create some SBF compact binary format from a Delphi binary value .Rev. an upper bound on the number of rows returned is placed (e.18 Date: June 16. i. aNewIndex: integer. to be called e. 1.pas unit .g.P1 and P2 must point to the values encoded in our SBF compact binary format function Validate(RecordBuffer: pointer. or the physical index of the updated record procedure OrderedIndexRefresh.g.UpdateFieldEvent method AvailableFields: TSQLFieldBits.18 Page 375 of 1055 .we can't use SBF() method name because of Currency/Double ambiguity function SBFFloat(const Value: Double): TSBFString. Will force refresh the OrderedIndex[] array .we can't use SBF() method name because of Currency/Double ambiguity function SBFFromRawUTF8(const aValue: RawUTF8): TSBFString. if you want to access to the OrderedIndex[] array procedure SaveTo(WR: TFileBufferWriter).P2: PUTF8Char): PtrInt. Convert any UTF-8 encoded value into our SBF compact binary format .RecordIndex=-1 in case of adding. Create some SBF compact binary format from a Delphi binary value .can be used e.WhereValue content using OrderedIndex[] . Check the registered constraints . Create some SBF compact binary format from a Delphi binary value . if a tftUnique constraint failed . Some default SBF compact binary format content TUpdateFieldEvent = record An opaque structure used for TSynTable.g. from a WHERE clause. The number of record added IDs: TIntegerDynArray.Rev.returns '' on success . 2013 function SBFCurr(const Value: Currency): TSBFString.IterateJSONValues . for fast comparison in TSynTableStatement.will return '' if the field type doesn't match a floating-point . Save entry to a specified file writer property SBFDefault: TSBFString read fDefaultFieldData. if OrderedIndexNotSorted = TRUE.this list is already in increasing order.is the reverse of GetValue/GetRawUTF8 methods above function SortCompare(P1. Low-level binary comparison used by IDSort and TSynTable.will return '' if the field type doesn't match a currency . RecordIndex: integer): string.returns an error message e. The list of IDs added .18 Date: June 16.Synopse mORMot Framework Software Architecture Design 1. because GetIterating was called with the ioID order SynCommons. The list of existing field in the previous data Count: integer. Where to write the updated data TSynValidateTable = class(TSynValidate) Will define a validation to be applied to a TSynTableFieldProperties field . The offset of every record added . Perform the unique field validation action to the specified value . Previous indexes: NewIndexs[oldIndex] := newIndex Offsets64: TInt64DynArray.it can be used in the overriden Process method TSynValidateTableUniqueField = class(TSynValidateTable) Will define a validation for a TSynTableFieldProperties Unique field . since we have already the ProcessField property set . The associated TSQLRest instance .Validate with its self value to be used for the validation .Rev.it will check that the field value is not void .a typical usage is to validate a value to be unique in the table (implemented in the TSynValidateTableUniqueField class) .is set to -1 in case of adding.it will check that the field value is not a duplicate function Process(aFieldIndex: integer.Validate() .the optional associated parameters are to be supplied JSON-encoded .18 Page 376 of 1055 . which will be filled before call by TSynTableFieldProperties.this value is filled by TSynTableFieldProperties.ProcessField and ProcessRecordIndex properties will be filled before Process method call by TSynTableFieldProperties.g.aFieldIndex parameter is not used here. var ErrorMsg: string): boolean.Synopse mORMot Framework Software Architecture Design 1. TSynTableFieldProperties. as converted from our SBF compact binary format via e. override.duplication value check will use the ProcessField and ProcessRecordIndex properties.18 Date: June 16. if tfoUnique is set in Options .here the Value is expected to be UTF-8 text. 1. const Value: RawUTF8.pas unit .this value is filled by TSynTableFieldProperties.implement constraints check e. The associated record index (in case of update) . 2013 NewIndexs: TIntegerDynArray.follows the IDs[] order WR: TFileBufferWriter.Validate .Validate() property ProcessField: TSynTableFieldProperties read fProcessField write fProcessField.g.GetValue / GetRawUTF8: this is mandatory to have the validation rule fit with other TSynValidateTable classes SynCommons. or the physical index of the updated record .it can be used in the overriden Process method property ProcessRecordIndex: integer read fProcessRecordIndex write fProcessRecordIndex. it will try to store fixed-sized record first.can be used with several storage engines. aType: TSynTableFieldType. e.AddFieldUpdate. to implement a Database . for instance TSynBigTableRecord . when a fixed-sized field has been added on a record containing variable-length fields) function UpdateFieldRecord(RecordBuffer: PUTF8Char. var AvailableFields: TSQLFieldBits): TSBFString.Rev. Index: integer.Synopse mORMot Framework Software Architecture Design 1. to refresh the data .warning: the class responsible of the storage itself must process the data already stored when a field is created. to refresh the data . aOptions: TSynTableFieldOptions=[]): TSynTableFieldProperties. Data: pointer. handly also field data order change in SBF record (e.physical order does not necessary follow the AddField() call order: for better performance. in TSynBigTableRecord. 2013 TSynTable = class(TObject) Store the description of a table with records. then variable-length after fixed-sized fields. Release used memory function AddField(const aName: RawUTF8. Add a field description to the table . Retrieve to the corresponding data address of a given field function UpdateFieldEvent(Sender: TObject. Update a record content after any AddfieldUpdate.it will work with either any newly added field. encoded in our SBF compact binary format function GetData(RecordBuffer: PUTF8Char. override. in all case. in which fixed-length fields are stored leftmost side.18 Date: June 16. ID. DataLen: integer): boolean. a field indexed will be put first function DataLength(RecordBuffer: pointer): integer. and will contain all parameters set by TSynBigTableRecord.g.a mandatory ID field must be handled by the storage engine itself . Field: TSynTableFieldProperties): pointer.pas unit .Opaque is in fact a pointer to a TUpdateFieldEvent record. then variable-length fields follow constructor Create(const aTableName: RawUTF8).AddFieldUpdate method . 1. Create a table definition instance destructor Destroy. This Event is to be called for all data records (via a GetIterating method) after any AddfieldUpdate. Opaque: pointer. Return the total length of the given record buffer.will handle the storage of records into our SBF compact binary format.18 Page 377 of 1055 . multiple of 4 bytes first (access is faster if dat is 4 byte aligned).each record can have up to 64 fields .g.AvailableFields must contain the list of existing fields in the previous data SynCommons. including a TFileBufferWriter instance to use to write the recreated data . following our SBF compact binary format encoding for this record procedure LoadFrom(var RD: TFileBufferReader). Check the registered constraints according to a record SBF buffer . Create a table definition instance from a specified file reader procedure SaveTo(WR: TFileBufferWriter). the corresponding aOldIndex will be replaced by aNewIndex value (i. Update a record content .if aOldIndex is >= 0 and aNewIndex is -1. it must match the field value kind .return the updated record data. called in case of a data Add) .e.if aOldIndex and aNewIndex are both >= 0.if NewFieldData is not specified. 1.all field values are filtered in-place.Synopse mORMot Framework Software Architecture Design 1.pas unit . Return a default content for ALL record fields . const NewFieldData: TSBFString=''). Filter the SBF buffer record content with all registered filters .OrderedIndex values . List of TSynTableFieldProperties added via all AddField() call .returns an error message e.if aOldIndex is -1 and aNewIndex is >= 0.this list will allow TSynBigTableRecord.will update then sort all existing TSynTableFieldProperties.RecordIndex=-1 in case of adding.Rev.the GetDataBuffer protected virtual method must have been overriden to properly return the record data for a given "physical/stored" index . called in case of a data Update) . if a tftUnique constraint failed . aNewIndex: integer. or the physical index of the updated record procedure FieldIndexModify(aOldIndex. a default 0 or '' value is appended .warning: this method will update result in-place. FieldIndex: integer. so RecordBuffer MUST be <> pointer(result) or data corruption may occur property AddedField: TList read fAddedField write fAddedField.aOldRecordData and aNewRecordData can be specified in order to guess if the field data has really been modified (speed up the update a lot to only sort indexed fields if its content has been really modified) procedure Filter(var RecordBuffer: TSBFString). aOldRecordData.18 Date: June 16. Event which must be called by the storage engine when some values are modified .uses our SBF compact binary format SynCommons.AddFieldUpdate to refresh the data on disk according to the new field configuration property DefaultRecordData: TSBFString read fDefaultRecordData. called in case of a data Delete) . aNewRecordData: pointer).if NewFieldData is set.e.returns '' on success . Save field properties to a specified file writer procedure UpdateFieldData(RecordBuffer: PUTF8Char. RecordBufferLen. var result: TSBFString.18 Page 378 of 1055 . in our SBF compact binary format .e. 2013 function Validate(RecordBuffer: pointer. RecordIndex: integer): string. aNewIndex refers to a just created item (i.g. aNewIndex refers to a just deleted item (i. Stop the timer.s) function PerSec(Count: cardinal): cardinal. field indexes won't work . 1. with appened time resolution (us. Offset of the first variable length value field property GetRecordData: TSynTableGetRecordData read fGetRecordData write fGetRecordData.18 Date: June 16. 2013 property Field[Index: integer]: TSynTableFieldProperties read GetFieldType. Retrieve the properties of a given field . Read-only access to the Field list property FieldVariableOffset: PtrUInt read fFieldVariableOffset. Event used for proper data retrieval of a given record buffer.s) SynCommons.Rev.returns -1 if the specified Index is out of range property FieldList: TObjectList read fField. Retrieve the index of a given field . with appened time resolution (us. returning the time elapsed. True if any field has a tfoUnique option set property TableName: RawUTF8 read fTableName write fTableName.will be mapped e.g.g.if not set.s) function Time: RawUTF8. Compute the time elapsed by count.returns nil if the specified Index is out of range property FieldCount: integer read GetFieldCount. Return the time elapsed.WARNING: this record MUST be aligned to 32 bits.ms. according to the physical/storage index value (not per-ID index) . Number of fields in this table property FieldFromName[const aName: RawUTF8]: TSynTableFieldProperties read GetFieldFromName. Retrieve the properties of a given field . from JSON or SQL) . to TSynBigTable. Compute the per second count function Stop: RawUTF8.pas unit .Synopse mORMot Framework Software Architecture Design 1. otherwise iFreq=0 function ByCount(Count: cardinal): RawUTF8.GetPointerFromPhysicalIndex property HasUniqueIndexes: boolean read fFieldHasUniqueIndexes. with appened time resolution (us.ms.returns nil if the specified Index is out of range property FieldIndexFromName[const aName: RawUTF8]: integer read GetFieldIndexFromName.ms.18 Page 379 of 1055 . The internal Table name used to identify it (e.similar to the SQL Table name TPrecisionTimer = object(TObject) High resolution timer (for accurate speed statistics) . the number of tests added by the Create() constructor from RTTI . Get the name of a specified test . Create the test instance . const aName: string). Stop the timer.sample code about how to use this test framework is available in the "Sample\07 . either a uncameled text from the class name property InternalTestsCount: integer read fInternalTestsCount. the class name is used.purpose of this ancestor is to have RTTI for its published methods.pas unit . accessible via the Count/TestName/TestMethod properties procedure Add(aMethod: TSynTestEvent.Rev.SynTest" folder .any TestName/TestMethod[] index higher or equal to this value has been added by a specific call to the Add() method property TestMethod[Index: integer]: TSynTestEvent read GetTestMethod.if an identifier is not supplied. 1. the number of registered tests by the Register() method PLUS the number of published methods defined within this class property Ident: string read GetIdent. Get the event of a specified test .Index range is from 0 to Count-1 (including) SynCommons. or uncamelcase its class name if no identifier was defined .18 Date: June 16. Resume a paused timer procedure Start. Register a specified test to this class instance property Count: Integer read GetCount.see @http://synopse. Start the high resolution timer TSynTest = class(TObject) A generic class for both tests suit and cases .either the Ident parameter supplied to the Create() method. The test name . ready to continue its time measure procedure Resume.i.18 Page 380 of 1055 .Synopse mORMot Framework Software Architecture Design 1.e. 2013 procedure Pause.info/forum/viewtopic.i.this constructor will add all published methods to the internal test list. Return the number of tests associated with this class . after T[Syn][Test] left trim and un-camel-case . and to handle a class text identifier.php?pid=277 constructor Create(const Ident: string = ''). Return the number of published methods defined within this class as tests .e.Index range is from 0 to Count-1 (including) property TestName[Index: integer]: string read GetTestName. const msg: string = ''): Boolean. Create a temporary string random content .it somewhat faster if CharCount is a multiple of 5 class function RandomUTF8(CharCount: Integer): RawUTF8. function CheckNot(condition: Boolean.if an identifier is not supplied. function CheckSame(const Value1. const Ident: string = ''). Used by the published methods to run a test assertion about two double values class function RandomString(CharCount: Integer): RawByteString. Used by the published methods to run a test assertion . const Precision: double=1E-12. override.function return TRUE if the condition failed. Clean up the instance .g. i.when a test failed SynCommons. in order to allow the caller to stop testing with such code: if CheckNot(A<>10) then exit. Create a temporary string random content . Create the test case instance .function return TRUE if the condition failed.18 Page 381 of 1055 .Rev. const msg: string = ''): Boolean.18 Date: June 16. 2013 TSynTestCase = class(TSynTest) A class implementing a test case . virtual.Value2: double. Used by the published methods to run a test assertion .pas unit . one or more tests . const msg: string = ''): Boolean.condition must equals TRUE to pass the test procedure TestFailed(const msg: string).condition must equals TRUE to pass the test . const msg: string = ''). This method is trigerred internaly . even if already done before function CheckFailed(condition: Boolean.Synopse mORMot Framework Software Architecture Design 1. by Check() . after T[Syn][Test] left trim and un-camel-case destructor Destroy. the class name is used. Used by the published methods to run a test assertion .should handle a test unit.e.it somewhat faster if CharCount is a multiple of 5 procedure Check(condition: Boolean. in order to allow the caller to stop testing with such code: if CheckFailed(A=10) then exit.condition must equals FALSE to pass the test .will call CleanUp.individual tests are written in the published methods of this class constructor Create(Owner: TSynTests. 1.must supply a test suit owner .e. Contains the run elapsed time TotalTimer: TPrecisionTimer.18 Page 382 of 1055 . .Rev.e.TestMethod[] which created this test property Owner: TSynTests read fOwner. Contains the run elapsed time constructor Create(const Ident: string = ''). accessible via the Count/TestName/TestMethod properties destructor Destroy. some debug messages will be reported to this text file .e. the class name is used.you can also use the SaveToFile() method to create an external file you can put here some text to be displayed at the end of the messages . Check() method call) for this test case property AssertionsFailed: integer read fAssertionsFailed. Create the test instance . The test suit which owns this test case property TestCaseIndex: integer read fTestCaseIndex. The index of the associated Owner. after T[Syn][Test] left trim and un-camel-case . use the following line to report to the console: ToConsole := @Output. If set to a text file address. override. starting at 0 for the associated MethodIndex TSynTests = class(TSynTest) A class used to run a suit of test cases CustomVersions: string. .every line of text must explicitly BEGIN with #13#10 RunTimer: TPrecisionTimer. Contains the run elapsed time TestTimer: TPrecisionTimer. 1.if an identifier is not supplied. e. The number of assertions (i. Check() method call) for this test case property Ident: string read GetIdent.18 Date: June 16.release all registered Test case instance SynCommons.either the Ident parameter supplied to the Create() method.g.for example. The test name . 2013 property Assertions: integer read fAssertions.this constructor will add all published methods to the internal test list. Finalize the class instance .Synopse mORMot Framework Software Architecture Design 1. The number of assertions (i. The index of the test case.pas unit .some internal versions. either an uncameled text from the class name property MethodIndex: integer read fMethodIndex. returns nil if this failure was not trigerred by a TSynTestCase. Save the debug messages into an external file .the published methods of the children must call this method in order to add test cases . The number of assertions (i. and will be freed by TSynTests. overload. the current Ident is used property Assertions: integer read fAssertions.an instance of the supplied class is created.e.18 Page 383 of 1055 . procedure AddCase(TestCase: TSynTestCase). 1. by running all published methods.Assertions and AssertionsFailed properties are reset and computed during the run procedure AddCase(const TestCase: array of TSynTestCaseClass). Check() method call) which failed in all tests . const FileName: TFileName=''). Call of this method will run all associated tests cases . procedure SaveToFile(const DestPath: TFileName.Destroy . The number of assertions (i. Retrieve the TSynTestCase instance associated with this failure .if no file name is specified.example of use (code from a TSynTests published method): AddCase(TOneTestCase.Rev. Retrieve the error message associated with this failure SynCommons. which must call the AddCase() method above to register test cases .example of use (code from a TSynTests published method): AddCase([TOneTestCase]).Create(self)). Register a specified Test case instance .this property is set by the Run method above property AssertionsFailed: integer read fAssertionsFailed. Register a specified Test case instance . Check() method call) in all tests . virtual.Synopse mORMot Framework Software Architecture Design 1.the Failed[] list is cleared at the beginning of the run . overload. Retrieve the ident of the case test associated with this failure property FailedCount: integer read GetFailedCount. 2013 function Run: Boolean.all failed test cases will be added to the Failed[] list . but directly by a method property FailedCaseIdent[Index: integer]: string read GetFailedCaseIdent.all these instances will be freed by the TSynTests. Number of failed tests after the last call to the Run method property FailedMessage[Index: integer]: string read GetFailedMessage.Destroy .function will return TRUE if all test passed .the TestCase[] list is created first.e.pas unit .this property is set by the Run method above property FailedCase[Index: integer]: TSynTestCase read GetFailedCase.the published methods of the children must call this method in order to add test cases .18 Date: June 16. map file Addr: TIntegerDynArray.Test cases are registered by the AddCase() method above.pas unit . 2013 property TestCase[Index: integer]: TSynTestCase read GetTestCase.mab file in a more optimized format SynCommons.map content can be saved as .18 Date: June 16. Symbol internal name Start: cardinal. to be used e.g. List of all mapped source code lines of this unit Symbol: TSynMapSymbol. Starting offset of this symbol in the executable Stop: cardinal.map file content.Destroy property TestCaseCount: Integer read GetTestCaseCount. Name. mainly by published methods of the children . with TSynLog to provide additional debugging information .map file Name: RawUTF8. Start code address of each source code lin FileName: RawUTF8. The number of items in the TestCase[] array TSynMapSymbol = record A debugger symbol.Synopse mORMot Framework Software Architecture Design 1. Start and Stop of this Unit TSynMapFile = class(TObject) Retrieve a . An array containing all registered Test case instances .Test cases instances are freed by TSynTests. End offset of this symbol in the executable TSynMapUnit = record A debugger unit. as decoded by TSynMapFile from a . Associated source file name Line: TIntegerDynArray.18 Page 384 of 1055 .original .Rev. 1. as decoded by TSynMapFile from a . exe and for . 1.this file content can be appended to the executable via SaveToExe method . will log as hexadecimal pointers. Addr: PtrUInt).the executable name must be specified. unit name.exe/.map or .mab .if aExeName is not specified.if no debugging information is available (. The associated file name property HasDebugInfo: boolean read fHasDebugInfo. All symbols associated to the executable property Units: TSynMapUnitDynArray read fUnit. because it's impossible to write to the executable of a running process . Retrieve an unit and source line.if aExeName is specified. will be read to retrieve all necessary debugging information .ocx) procedure SaveToStream(aStream: TStream). including line numbers.map is not not available.if nothing is available. associated to the executable SynCommons.if no file name is specified.mab). if necessary .18 Page 385 of 1055 .a . it will be saved as ExeName.mab file will be also created in the same directory (if MabCreate is TRUE) . will search for a .mab appended to the . will write the address as hexadecimal procedure SaveToExe(const aExeName: TFileName). Return the symbol location according to the supplied absolute address .will create a global TSynMapFile instance for the current process.mab or DllName.mab file . Add some debugging information according to the specified memory address .i. will use it in its search for . will search for the . symbol name and line number (if any).returns '' if no match found function FindSymbol(aAddr: cardinal): integer. Save all debugging information in the .dll .18 Date: June 16.mab is available.this function returns the created file name class procedure Log(W: TTextWriter. without debugging information function FindLocation(aAddr: Cardinal): RawUTF8.map matching the file name: if found. MabCreate: boolean=true).Rev. out LineNumber: integer): integer. Equals true if a . All units. Retrieve a symbol according to an absolute code address function FindUnit(aAddr: cardinal.map/. 2013 constructor Create(const aExeName: TFileName=''.it will first search for a .dll . according to an absolute code address function SaveToFile(const aFileName: TFileName=''): TFileName. will use the currently running .this method will work for . Append all debugging information to an executable (or library) .dll (or . Save all debugging informat in our custom binary format property FileName: TFileName read fMapFile. Get the available debugging information .if no .if .Synopse mORMot Framework Software Architecture Design 1.e.mab custom binary format .exe/. as plain text .mab .pas unit .map or .mab debugging information has been loaded property Symbols: TSynMapSymbolDynArray read fSymbol. aInstance: TObject=nil. Call this method to add the caller address to the log at the specified level . overload.18 Page 386 of 1055 . Instance: TObject). const Text: RawUTF8.if the debugging info is available from TSynMapFile. 2013 ISynLog = interface(IUnknown) A generic interface used for logging a method . overload. TSQLLog will be able to write TObject/TSQLRecord and sets content as JSON procedure Log(Level: TSynLogInfo. TextTruncateAtLength: integer=maxInt). associated symbol and source code line procedure Log(Level: TSynLogInfo. Instance: TObject=nil). with '--' for SQL statements) SynCommons. var aValue. Call this method to add the content of most low-level types to the log at a specified level . delimited by 13#10 (CRLF) . overload.you should create one TSynLog instance at the beginning of a block code using TSynLog.LinesToLog content will be added. Call this method to add some multi-line information to the log at a specified level .Instance).TSynLog will handle enumerations and dynamic array. 1.e. Call this method to add the content of an object to the log at a specified level .all logging expect UTF-8 encoded text. will behave the same as Log(Level. Call this method to add some information to the log at a specified level . usualy English text function Instance: TSynLog. aName: PWinAnsiChar.Enter() method first) . Retrieve the associated logging instance procedure Log(Level: TSynLogInfo=sllTrace).Synopse mORMot Framework Software Architecture Design 1.g. Instance: TObject=nil. marking it's executation end .if Instance is set and Text is ''.g.e.if a line starts with IgnoreWhenStartWith (already uppercase). one line per one line.pas unit . will log the unit name. i. aTypeInfo: pointer. it won't be added to the log content (to be used e. it will log the corresponding class name and address (to be used e.Rev. i.if Instance is set and Text is not ''.TSynLog will write the class and hexa address .TSQLLog will write the object JSON content procedure LogLines(Level: TSynLogInfo. if you didn't call TSynLog.18 Date: June 16. LinesToLog: PUTF8Char. write the Instance as JSON content procedure Log(Level: TSynLogInfo. overload. const IgnoreWhenStartWith: PUTF8Char=nil).Enter: the ISynLog will be released automaticaly by the compiler at the end of the method block. 18 Page 387 of 1055 .creates the TSynLog if not already existing for this current thread property ArchiveAfterDays: Integer read fArchiveAfterDays write fArchiveAfterDays.g.18 Date: June 16. PerThreadLog := ptOneFilePerThread.initialize the family settings before using them.g. a server application may want to log in separate files the low-level Communication.will be used by Destroy to call OnArchive event handler on time property ArchivePath: TFileName read fArchivePath write fArchivePath. is in the executable folder. end. like in this code: with TSynLogDB. Number of days before OnArchive event will be called to compress or delete deprecated files . override.will archive older DestinationPath\*. the same as DestinationPath .will be set by default to 7 days . 'ArchivePath\Log\YYYYMM\*. i. begin ILog := TSynLogDB. 2013 TSynLogFamily = class(TObject) Regroup several logs under an unique family name .log files.MyMethod. 1. Intialize for a TSynLog class family . var ILog: ISynLog. according to ArchiveAfterDays value and ArchivePath function SynLog: TSynLog.Synopse mORMot Framework Software Architecture Design 1.log. The folder where old log files must be compressed .by default. DestinationPath := 'C:\Logs'.Family do begin Level := LOG_VERBOSE.zip') SynCommons.Log(sllInfo.pas unit .Enter(self. the final path (e.the 'log\' sub folder name will always be appended to this value .you should usualy use one family per application or per architectural module: e. and the high-level process .synlz' or 'ArchivePath\Log\YYYYMM.then use the logging system inside a method: procedure TMyDB.'MyMethod'). . end.will then be used by OnArchive event handler to produce.Rev.add it in the global SynLogFileFamily[] list destructor Destroy.'method called'). with the current file date year and month. Release associated memory . the DB access.e. constructor Create(aSynLog: TSynLogClass). Retrieve the corresponding log file of this thread and family . // do some stuff ILog. is in the executable folder property EchoToConsole: TSynLogInfos read fEchoToConsole write SetEchoToConsole. The time (in seconds) after which the log content must be written on disk.this is less human readable. the log file will be written for every 4 KB of log . will log high-resolution time stamp instead of ISO 8601 date and time .Rev. every 10 seconds) property BufferSize: integer read fBufferSize write fBufferSize. the log file name will contain the Computer name .note that it will slow down the logging process a lot. you can call TSynLog. Index in global SynLogFileFamily[] and threadvar SynLogFileIndex[] lists property IncludeComputerNameInFileName: boolean read fIncludeComputerNameInFileName write fIncludeComputerNameInFileName. to LOG_VERBOSE in order to echo every kind of events property ExceptionIgnore: TList read fExceptionIgnore.can be set e.pas unit . The file extension to be used .18 Page 388 of 1055 .this property shall be set before any actual logging.this will ensure that the main application won't be slow down by logging . but may be convenient for interactive debugging of services.by default. If TRUE.18 Date: June 16. 1. If the some kind of events shall be echoed to the console .is set to 4096 by default (4 KB is the standard hard drive cluster size) property DefaultExtension: TFileName read fDefaultExtension write fDefaultExtension.Synopse mORMot Framework Software Architecture Design 1. otherwise it will have no effect .g. EConvertError may be added to the list property HighResolutionTimeStamp: boolean read fHRTimeStamp write fHRTimeStamp.set to FALSE by default.g.Enter methods) . The current level of logging information for this family .g.this is the number of bytes kept in memory before flushing to the hard drive. a background thread can be created and will be responsible of flushing all pending log content every period of time (e. If TRUE.is '. The folder where the log must be stored . to LOG_VERBOSE in order to log every kind of events SynCommons.as '(MyComputer)' property Level: TSynLogInfos read fLevel write SetLevel. You can add some exceptions to be ignored to this list .by default. or if RotateFileCount and RotateFileSizeKB are set (the high resolution frequency is set in the log file header) property Ident: integer read fIdent.Flush method or set AutoFlushTimeOut to true in order to force the writting to disk . for instance . The internal in-memory buffer size.log' by default property DestinationPath: TFileName read fDestinationPath write fDestinationPath.in order not to loose any log. but allows performance profiling of your application on the customer side (using TSynLog. in bytes . whatever the current content size is .can be set e. 2013 property AutoFlushTimeOut: cardinal read fAutoFlush write SetAutoFlush.for instance. The levels which will include a stack trace of the caller .synlz for RotateFileCount=9 (total count = 9. Define how thread will be identified during logging process .0.synlz (use FileUnSynLZ function to uncompress it) . 1.log file to archive.g.if you use SynZip. Event called to archive the .Synopse mORMot Framework Software Architecture Design 1.synlz .by default. sllLastError and sllStackTrace .7.zip only once) property PerThreadLog: TSynLogPerThreadMode read fPerThreadLog write fPerThreadLog.if set to a number > 1.18 Page 389 of 1055 . meaning no rotation . contains sllError.by default.g.this event handler will be called one time per .synlz backup will be created. so the main log file will be restarted from scratch when it reaches RotateFileSizeKB size .Destroy will parse DestinationPath folder for *. including 1 main log file and 8 .exceptions will always trace the stack property OnArchive: TSynLogArchiveEvent read fOnArchive write fOnArchive.the aDestinationPath parameter will contain 'ArchivePath\log\YYYYMM\' .log. 2013 property LevelStackTrace: TSynLogInfos read fLevelStackTrace write fLevelStackTrace.log file into our propertary SynLZ format: resulting file name will be ArchivePath\log\YYYYMM\*.EventArchiveZip. sllException. or EventArchiveSynLZ to compress the . sllExceptionOS.set to 0 by default. Auto-rotation of logging files .log content after a defined delay ..is not used if RotateFileCount is left to its default 0 property StackTraceLevel: byte read fStackTraceLevel write fStackTraceLevel.specify the maximum file size upon which .you can set this property to EventArchiveDelete in order to delete deprecated files. in kilo-bytes (per 1024 bytes) .if set to 1. no .used only if exceptions are handled.log files matching ArchiveAfterDays property value .synlz files) property RotateFileSizeKB: cardinal read fRotateFileSize write fRotateFileSize. then one last time with aOldLogFileName='' in order to close any pending archive (used e. and will be named e. by EventArchiveZip to open the .synlz rotation takes place .default value is 20. The recursive depth of stack trace symbol to write . in occurence order (so multi-thread process on server side may be difficult to interpret) .zip . sllFail. or by sllStackTrace level .can be set to a number of rotating files: rotation and compression will happen. Maximum size of auto-rotated logging files. as MainLogFileName. MainLogFileName.pas unit .18 Date: June 16. some rotated files will be compressed using the SynLZ algorithm. maximum is 255 SynCommons. and main file size will be up to RotateFileSizeKB number of bytes . ptMergedInOneFile will indicate that all threads are logged in the same file. the log files will be archived in ArchivePath\log\YYYYMM.Rev.will be ignored if RotateFileCount and RotateFileSizeKB are set (the internal thread list shall be defined within the same process) property RotateFileCount: cardinal read fRotateFileCount write fRotateFileCount. 18 Date: June 16.pas unit .e. shall not be displayed at Leave() RefCount: integer.e. will log the unit name with an object instance if available .the class will use low-level RtlCaptureStackBackTrace() API to retrieve the call stack: in some cases. you can disable this optional manual walk by setting it to stOnlyAPI .Rev. 1. Associated class instance to be displayed MethodName: PUTF8Char. therefore a manual walk of the stack can be processed . it is not able to retrieve it.default is stManualAndAPI. Internal reference count used at this recursion level by TSynLog. mnLeave). The caller address.18 Page 390 of 1055 .since this manual call can trigger some unexpected access violations or return wrong positions. Associated class type to be displayed EnterTimeStamp: Int64. i. The time stamp at enter time Instance: TObject. The associated TSynLog class property WithUnitName: boolean read fWithUnitName write fWithUnitName._AddRef SynCommons. use RtlCaptureStackBackTrace() API and perform a manual stack walk if the API returned no address (or <3) property SynLogClass: TSynLogClass read fSynLogClass.unit name is available from RTTI if the class has published properties . 2013 property StackTraceUse: TSynLogStackTraceUse read fStackTraceUse write fStackTraceUse. If TRUE.Synopse mORMot Framework Software Architecture Design 1. mnEnter. If the method name is local. How the stack trace shall use only the Windows API .Enter methods to handle recursivity calls tracing Caller: PtrUInt.set to FALSE by default TSynLogCurrentIdent = record Used by ISynLog/TSynLog. Method name (or message) to be displayed MethodNameLocal: (mnAlways. ready to display stack trace dump if needed ClassType: TClass. i. Family.18 Date: June 16. if no logging is written.the TSynLog instance won't be allocated in heap.'The % statement didn't work'.Log(llError.SQL).4 (page 1051). .WARNING: not to be called directly! Use Enter or Add class function instead destructor Destroy.1. and Enter/Leave labelling Used for DI-2.Rev.[SQL]). constructor Create(aFamily: TSynLogFamily=nil).pas unit . Retrieve the current instance of this TSynLog class .18 Page 391 of 1055 .is just a wrapper around Family.[SQL]). . override.PerThreadLog=ptOneFilePerThread) or global private log file instance .the same code will work: TSynLogDB.Log(llError.Add. without any Enter/Leave: TSynLogDB. 1.Log(llError.you should create a sub class per kind of log file TSynLogDB = class(TSynLog). without any Enter/Leave (one parameter version .can use available debugging information via the TSynMapFile class.SynLog . but will share a per-thread (if Family.SynLog.'The % statement didn't work'.to be used for direct logging. Intialize for a TSynLog class instance . SynCommons.Synopse mORMot Framework Software Architecture Design 1.to be used for direct logging. for stack trace logging for exceptions. and even during log write (using an internal TTextWriter) . . Release all memory and internal handles class function Add: TSynLog. sllStackTrace.just the same as previous): TSynLogDB.Add.'The % statement didn't work'.was very optimized for speed. 2013 TSynLog = class(TObject) A per-family and/or per-thread log file content . Enter(self). aMethodNameLocal: boolean=false): ISynLog.e.result]). // do some stuff end.pas unit . it will use the caller address.set aMethodNameLocal=TRUE if its points to a local RawUTF8 .SQLFlush. 1.Enter() will write the class name (and the unit name for classes with published properties.TMyDB. if TSynLogFamily.map content: if you want accurate profiling.SQLFlush.map file . 2013 class function Enter(aClassType: TClass. overload.HighResolutionTimeStamp is TRUE.if you just need to access the log inside the method block.'SQLFlush'). if TSynMapFile retrieved the . you may not need any ISynLog interface: class procedure TMyDB.note that supplying a method name is faster than using the .Synopse mORMot Framework Software Architecture Design 1. aMethodName: PUTF8Char=nil. high-resolution time stamp will be written instead of ISO 8601 date and time: this will allow performance profiling of the application on the customer side . end. . // do some stuff end.SQLValidate SynCommons. // do some stuff ILog.SQLValidate(const SQL: RawUTF8): boolean. begin TSynLogDB.the use of a ISynLog interface will allow you to have an automated log entry created when the method is left .TMyDB.Enter(self.this is the main method to be called within a class method: class function TMyDB.'SQL=% returned %'.map content): class procedure TMyDB.WithUnitName is true) for both enter (+) and leave (-) events: 20110325 19325801 + 20110325 19325801 info 20110325 19325801 - MyDBUnit.[SQL. begin ILog := TSynLogDB.18 Page 392 of 1055 .'SQLValidate'). . var ILog: ISynLog. and will write it as hexa and with full unit and symbol name.SQLValidate SQL=SELECT * FROM Table returned 1. . it's better to use a method name or not to use a . MyDBUnit. To be called and assigned to a ISynLog interface at the beginning of a method .18 Date: June 16. begin TSynLogDB.Enter(self. if the debugging information is available (i.if TSynLogFamily.Log(sllInfo.Rev.if no Method name is supplied. SQLFlush.map file .Enter() will write the class name (and the unit name for classes with published properties. if the debugging information is available (i.SQLFlush. and will write it as hexa and with full unit and symbol name.'SQLExecute'). begin TSynLogDB. // do some stuff end. 2013 class function Enter(aInstance: TObject=nil.map content: if you want accurate profiling.TMyDB(004E11F4). it's better to use a method name or not to use a . overload.Synopse mORMot Framework Software Architecture Design 1.HighResolutionTimeStamp is TRUE.e.pas unit . overload.Enter(self). // do some stuff ILog.[SQL]).SQLExecute SQL=SELECT * FROM Table.SQLExecute(const SQL: RawUTF8).if ForceDiskWrite is TRUE. Retrieve the family of this TSynLog class type procedure Flush(ForceDiskWrite: boolean).if it is a local variable. aMethodName: PUTF8Char=nil. if TSynMapFile retrieved the .TMyDB(004E11F4).the use of a ISynLog interface will allow you to have an automated log entry created when the method is left . and not a locally computed variable. since it may trigger some random GPF at runtime . end. high-resolution time stamp will be written instead of ISO 8601 date and time: this will allow performance profiling of the application on the customer side . begin ILog := TSynLogDB. it will use the caller address.18 Page 393 of 1055 .'SQLFlush').note that this method name shall be a constant. will wait until written on disk (slow) SynCommons. if TSynLogFamily.Log(sllInfo. Flush all log content to file .map content): procedure TMyDB.note that supplying a method name is faster than using the . aMethodNameLocal: boolean=false): ISynLog. var ILog: ISynLog.WithUnitName is true) for both enter (+) and leave (-) events: 20110325 19325801 + 20110325 19325801 info 20110325 19325801 - MyDBUnit.if no Method name is supplied.18 Date: June 16. you can set aMethodNameLocal=true . // do some stuff end.this is the main method to be called within a method: procedure TMyDB.Enter(self.Rev. you may not need any ISynLog interface: procedure TMyDB.'SQL=%'.SQLExecute class function Family: TSynLogFamily. .if TSynLogFamily. MyDBUnit. . begin TSynLogDB.if you just need to access the log inside the method block.Enter(self. . 1. Overloaded method which will log the . will behave the same as Log(Level. if you didn't call TSynLog. it will handle its class name and Message: 20110330 10010005 debug "EClassName(00C2129A)":"Exception message" .Add. TextTruncateAtLength: integer=maxInt). const IgnoreWhenStartWith: PUTF8Char=nil).for instance: TSynLog. TCollections and TStrings .GarbageCollector).this default implementation will just write the class name and its hexa pointer value. overload. i. const Text: RawUTF8. aInstance: TObject=nil. The associated file name containing the log .if aInstance is an Exception."TObjectList(00B1AE80)"]} .Add. one line per one line. will log the unit name.Rev.this overriden implementation will write the value content. associated symbol and source code line procedure Log(Level: TSynLogInfo.this is accurate only with the default implementation of the class: any child may override it with a custom logging mechanism SynCommons.Synopse mORMot Framework Software Architecture Design 1.g. var aValue. Instance: TObject=nil). write the Instance as JSON content procedure Log(Level: TSynLogInfo. written as human readable JSON procedure LogLines(Level: TSynLogInfo. Call this method to add the content of an object to the log at a specified level .g.Instance). Call this method to add some information to the log at the specified level . Call this method to add some multi-line information to the log at a specified level . it won't be added to the log content (to be used e. and handle TList.Log(sllDebug.if Instance is set and Text is ''. Call this method to add the caller address to the log at the specified level . aName: PWinAnsiChar. it will log the corresponding class name and address (to be used e.'GarbageCollector'.e.18 Page 394 of 1055 .GarbageCollector).pas unit .18 Date: June 16.Log(sllDebug. overload. with '--' for SQL statements) property FileName: TFileName read fFileName. aInstance: TObject=nil.use TSQLLog from mORMot.if Instance is set and Text is not ''.pas unit to add the record content. 2013 procedure Log(Level: TSynLogInfo. LinesToLog: PUTF8Char. will append this line to the log: 20110330 10010005 debug {"TObjectList(00B1AD60)":["TObjectList(00B1AE20)". aInstance: TObject).pas unit will be able to write TObject/TSQLRecord and sets content as JSON procedure Log(Level: TSynLogInfo).TSQLLog from mORMot.if the debugging info is available from TSynMapFile.Enter() method first) . Call this method to add the content of most low-level types to the log at a specified level . aTypeInfo: pointer. 1.if a line starts with IgnoreWhenStartWith (already uppercase). written as human readable JSON: handle dynamic arrays and enumerations . overload. delimited by 13#10 (CRLF) .for instance TSQLLog. overload. will append this line to the log: 0000000000002DB9 debug TObjectList(00425E68) GarbageCollector .LinesToLog content will be added. The associated time elapsed in this method (in micro seconds) . The associated logging family TSynTestsLogged = class(TSynTests) This overriden class will create a .inherits from TSynTestsLogged instead of TSynTests in order to add logging to your test suite (via a dedicated TSynLogTest instance) constructor Create(const Ident: string = '').Count is not the global text line numbers.log file in case of a test case failure . The index of the sllEnter event in the TSynLogFile.fLevels[] array ProperTime: cardinal. The .pas unit .Rev. The time elapsed in this method and not in nested methods . but the number of valid events within the file (LinePointers/Line/Strings will contain only event lines) . Create the test instance and initialize associated LogFile instance . 2013 property GenericFamily: TSynLogFamily read fFamily.returns 0 in case of an invalid supplied index SynCommons. map a sllEnter/sllLeave event in the . Retrieve the date and time of an event .log file .18 Date: June 16. will fill EventLevel[] for each line <> sllNone) .log file generator created if any test case failed TSynLogFileProc = record Used by TSynLogFile to refer to a method profiling in a .log file Index: cardinal.Synopse mORMot Framework Software Architecture Design 1. into high-level data .log file. Release associated memory property LogFile: TSynLog read fLogFile.log header is parsed explicitely function EventCount(const aSet: TSynLogInfos): integer. as created by TSynLog. Return the number of matching events in the log function EventDateTime(aIndex: integer): TDateTime.i.it will not be a concern.e. 1.this will allow logging of all exceptions to the LogFile destructor Destroy.computed from the sllLeave time difference (high resolution timer) TSynLogFile = class(TMemoryMapText) Used to parse a .18 Page 395 of 1055 .computed from Time property. minus the nested calls Time: cardinal. override.e. since the .this particular TMemoryMapText class will retrieve only valid event lines (i. Retrieve the level of an event .pas unit .PerThreadLog was ptIdentifiedInOnFile . The associated executable build date and time property ExecutableName: RawUTF8 read fExeName. The computer CPU in which the process was running on .equals 0 if date time resolution. High-resolution time stamp frequence. Retrieve the description text of an event . The associated executable version .1.returns e. '1*0-15-1027' property DetailedOS: RawUTF8 read fOSDetailed. '2.0. '0.18 Page 396 of 1055 . Sort the LogProc[] array according to the supplied order property ComputerHost: RawUTF8 read fHost.2600' for Windows XP property EventLevel: TSynLogInfoDynArray read fLevels.ini content SynCommons.returns e. 'C:\Dev\lib\SQLite3\exe\TestSQL3.0' property Freq: Int64 read fFreq. 2013 procedure LogProcSort(Order: TLogProcSortOrder).returns e.g. >0 if high-resolution time stamp property Headers: RawUTF8 read fHeaders.g.is calculated by Create() constructor property EventText[index: integer]: RawUTF8 read GetEventText.18 Date: June 16.returns '' if supplied index is out of range property EventThread: TWordDynArray read fThreads.0. as retrieved from log file header .3=5. to be searched as . The associated executable name (with path) . Retrieve all event thread IDs .returns e.Synopse mORMot Framework Software Architecture Design 1.exe' property ExecutableVersion: RawUTF8 read fExeVersion. The computer Operating System in which the process was running on . The computer host name in which the process was running on property CPU: RawUTF8 read fCPU. 1. Custom headers. the array will be void (EventThread=nil) property ExecutableDate: TDateTime read fExeDate.for ptMergedInOneFile (default) or ptOneFilePerThread logging process.EventLevel[] array index is from 0 to Count-1 property EventLevelUsed: TSynLogInfos read fLevelUsed. Retrieve all used event levels .contains something if TSynLogFamily.Rev.g.g.is calculated by Create() constructor . the associated instance name (with path) .returns e. number of items in the LogProc[] array property LogProcMerged: boolean read fLogProcIsMerged write SetLogProcMerged. with the associated elapsed time .for an executable.18 Page 397 of 1055 .i. All used event levels. The raised exception class SynCommons. 1. will be left void property LevelUsed: TSynLogInfos read fLevelUsed. The Operating System Service Pack number property StartDateTime: TDateTime read fStartDateTime. The current sort order property OS: TWindowsVersion read fOS. If the 32 bit process was running under WOW 64 virtual emulation TSynLogExceptionContext = record Calling context of TSynLogExceptionToStr callbacks EAddr: PtrUInt. For a library. The number of threads property ThreadsRows: TCardinalDynArray read fThreadsRows. The number of occurences of each thread ID property Wow64: boolean read fWow64.is calculated by Create() constructor . The date and time at which the log file was started property ThreadsCount: cardinal read fThreadMax.will contain the sllEnter index. The computer Operating System in which the process was running on property RunningUser: RawUTF8 read fUser.e. Number of profiled methods in this . 2013 property InstanceName: RawUTF8 read fInstanceName.pas unit . The computer user name who launched the process property ServicePack: integer read fOSServicePack. 'C:\Dev\lib\SQLite3\exe\TestLibrary. The address where the exception occured EClass: ExceptClass.Synopse mORMot Framework Software Architecture Design 1. as retrieved at log file content parsing property LogProc: PSynLogFileProcArray read fLogProcCurrent.log file .Rev. Profiled methods information . If the method information must be merged for the same method name property LogProcOrder: TLogProcSortOrder read fLogProcSortInternalOrder.number of items in the array is retrieved by the LogProcCount property property LogProcCount: integer read fLogProcCurrentCount.18 Date: June 16.g.dll' . The current logging level .could be $0EEDFAE0 of $0EEDFADE for Delphi-generated exceptions EInstance: Exception. A CPU-dependent signed integer type cast of a pointer / register . native under Free Pascal Compiler PPtrUInt = ^PtrUInt.should return TRUE if Context. The OS-level exception code . SynCommons. 1. A CPU-dependent unsigned integer type cast of a pointer of pointer .may be nil for external/OS exceptions Level: TSynLogInfo.used for 64 bits compatibility. virtual.EAddr and Stack trace is not to be written (i.Synopse mORMot Framework Software Architecture Design 1.used for 64 bits compatibility. Pointer to a RawByteString PtrInt = integer.Rev. Pointer to Iso8601 PPtrInt = ^PtrInt. A CPU-dependent signed integer type cast of a pointer of pointer .18 Page 398 of 1055 . const Context: TSynLogExceptionContext): boolean.this default implementation will call the DefaultSynLogExceptionToStr() function or the TSynLogExceptionToStrCustom global callback. The Delphi Exception instance . A CPU-dependent unsigned integer type cast of a pointer / register . native under Free Pascal Compiler PRawByteString = ^RawByteString.e.override this method to provide a custom logging content .used for 64 bits compatibility.used for 64 bits compatibility. native under Free Pascal Compiler PtrUInt = cardinal. as for any TSynLogExceptionToStr callback) ETableDataException = class(ESynException) Exception raised by all TSynTable related code Types implemented in the SynCommons unit: PIso8601 = ^Iso8601.pas unit . if defined . native under Free Pascal Compiler PUTF8Char = type PAnsiChar. 2013 ECode: DWord.18 Date: June 16.may be either sllException or sllExceptionOS ESynException = class(Exception) Generic parent class of all custom Exception types of this unit function CustomLog(WR: TTextWriter. Can be used to customize how the exception is logged . g. soGreaterThan. ccGreen. Define RawByteString.this type is native to the compiler. 1. without the charset conversion overhead . a RawUTF8 or a WinAnsiString RawUnicode = type AnsiString.mimic Delphi 2009 UTF8String. soGreaterThanOrEqualTo. ccYellow. it uses slow OLE compatible WideString (with our Enhanced RTL.18 Page 399 of 1055 . ccMagenta. ccRed. LightBlue. without the WideString or Ansi conversion overhead .pas unit .pointer(RawUnicode) is compatible with Win32 'Wide' API call .before Delphi 2009+.use this type if you don't want the Delphi compiler not to do any code page conversions when you assign a typed AnsiString to a RawByteString. so you can use Length() Copy() and such functions with it (this is not possible with RawUnicodeString type) . ccCyan.UTF8String.e. depending on the compiler used . soSoundsLikeSpanish ). 2013 A simple wrapper to UTF-8 encoded zero-terminated PAnsiChar . ccLightMagenta.to be used for byte storage into an AnsiString . which allow Copy On Write. WideString allocation can be made faster by using an internal caching mechanism of allocation buffers WideString allocation has been made much faster since Windows Vista/Seven) . Reference Counting and fast heap memory allocation TCompareOperator = ( soEqualTo. soNotEqualTo. SQL Query comparison operators . RawUTF8 is an UTF-8 String stored in an AnsiString . but is defined in FPC RawByteString = AnsiString. ccLightRed. i. ccBrown. RawUnicode is an Unicode String stored in an AnsiString .starting with Delphi 2009.18 Date: June 16. soSoundsLikeEnglish. it uses fastest UnicodeString type. ccLightCyan. ccDarkGray. soLessThan.PAnsiChar is used only for Win-Ansi encoded text .mimic Delphi 2009 UnicodeString. because all data is internaly stored and expected to be UTF-8 encoded QWord = Int64.use this type instead of System. which behavior changed between Delphi 2009 compiler and previous versions: our implementation is consistent and compatible with all versions of Delphi compiler . as it does exist in Delphi 2009+ . ccLightGray. for having a true WideChar(#0) at ending . soContains.the Synopse mORMot framework uses mostly this PUTF8Char type. which are allocated in Global heap (for COM) . SynCommons.Synopse mORMot Framework Software Architecture Design 1.all conversion to/from AnsiString or RawUTF8 must be explicit RawUTF8 = type AnsiString.Rev. SynUnicode is the fastest available Unicode native string type. soLessThanOrEqualTo.faster than WideString. Unsigned Int64 doesn't exist under older Delphi. soBeginWith.these operators are e.all conversion to/from AnsiString or RawUnicode must be explicit SynUnicode = WideString.an AnsiChar(#0) is added at the end. ccWhite ). ccLightGreen. soSoundsLikeFrench.length(RawUnicode) returns memory bytes count: use (length(RawUnicode) shr 1) for WideChar count (that's why the definition of this type since Delphi 2009 is AnsiString(1200) and not UnicodeString) . used by CompareOperator() functions TConsoleColor = ( ccBlack. ccBlue. g. 2013 Available console colors under Windows TConvertRawUTF8 = function(const text: RawUTF8): RawUTF8 of object. djRawUTF8.e. 1.18 Date: June 16. shall contain a managed type within its fields) .implementation code could call e. djCardinal. djWord. djTimeLog. // '. but also an object or an array) . djCurrency.RegisterCustomJSONSerializer() method . .this function must use the supplied hasher on the Elem data TDynArrayJSONCustomReader = function(P: PUTF8Char.Rev.implementation code shall follow the same exact format for the associated TDynArrayJSONCustomReader callback TDynArrayKind = ( djNone.. begin (.. GetJSONField() low-level function.Add/AddJSONEscapeString. if P=nil then exit.can be used also at record level. if the record has a type information (i. djInt64. if the record has a type information (i. . const aValue) of object. djSynUnicode. djDateTime.. djCustom ).can be used also at record level.RegisterCustomJSONSerializer() method .to be used with TTextWriter. djInteger.each element of the dynamic array will be called as aValue parameter of this callback . djWinAnsi.P)).implementation code could call aWriter. djByte. result := P. a number.e. aValid := true.implementation code shall follow TDynArrayJSONCustomWriter callback the same exact format for the associated TDynArrayJSONCustomWriter = procedure(const aWriter: TTextWriter.each element of the dynamic array will be called as aValue parameter of this callback .note that the generated JSON content will be appended after a '[' and before a ']' as a normal JSON arrray. A dynamic array of TDateTime values TDynArrayHashOne = function(const Elem. Method prototype for custom serialization of a dynamic array item . djString..' or ']' for last item of array end. Method prototype for custom unserialization of a dynamic array item . djWideString. and returns a pointer to the last handled element of the JSON input buffer.will be used e. a string. djDouble.) V.pas unit . Internal enumeration used to specify some standard Delphi arrays .18 Page 400 of 1055 . Event handler used to convert on the fly some UTF-8 text content TDateTimeDynArray = array of TDateTime. var aValue. Function prototype to be used for hashing of a dynamic array element . shall contain a managed type within its fields) . out aValid: Boolean): PUTF8Char of object.g.to be used with TTextWriter.e. to match JSON serialization or TDynArray search (see TDynArray and SynCommons.Detailed := UTF8ToString(GetJSONField(P. Hasher: THasher): cardinal. but each item can be any JSON structure (i.Synopse mORMot Framework Software Architecture Design 1. as such (aka EndOfBuffer variable as expected by GetJSONField): var V: TFV absolute aValue. SortDynArrayAnsiString.18 Page 401 of 1055 . SortDynArrayAnsiStringI..B): integer. SortDynArrayUnicodeString. soByOccurrence.wkVarInt32 will write the content using our 32-bit variable-length integer encoding and the by-two complement (0=0. A pointer to a PAnsiChar array SynCommons.a good candidate is our crc32() function in optimized asm in SynZip unit .pas unit . const Text: RawUTF8) of object. SortDynArrayUnicodeStringI. len: cardinal): cardinal. 1 if A>B TEventDynArraySortCompare = function(const A. SortDynArrayCardinal. SortDynArrayDouble. wkSorted. SortDynArrayString. soByProperTime ). which is the standard Kernighan & Ritchie hash function TLogProcSortOrder = ( soNone.4=-2. with as less collision as possible . soByTime. 1. wkOffsetI ).wkVarUInt32 will write the content using our 32-bit variable-length integer encoding .common functions exist for base types: see e. wkOffsetU. soByName.wkSorted will write an increasing array of integers.see also djPointer and djObject constant aliases for a pointer or TObject field hashing / comparison TDynArraySortCompare = function(const A.2=-1.Init will use kr32() if no custom function is supplied.1=1. handling constant difference (Unsigned or Integer) in an optimized manner THasher = function(crc: cardinal.must return 0 if A=B. -1 if A<B.) . handling the special case of a difference of 1 between two values (therefore is very optimized to store an array of IDs) . wkVarUInt32.3=2.wkOffsetU and wkOffsetI will write the difference between two successive values.LogProcSort method TObjectListPropertyHashedAccessProp = function(aObject: TObject): pointer. djSynUnicode match textual JSON values .g.djByte . SortDynArrayInteger. Used by TSynLogFile. Available kind of integer array storage. djTimeLog match numerical JSON values . Callback used to echo each line of TTextWriterEcho class TPAnsiCharArray = array[0. SortDynArrayWord. Function prototype to be used for hashing of an element ....djDateTime . corresponding to the data layout .any custom type (even records) can be compared then sort by defining such a custom function .Rev. Function prototype used to retrieve the hashed property of a TObjectListPropertyHashed list TOnDynArrayHashOne = function(const Elem): cardinal of object. Function prototype to be used for TDynArray Sort and Find method .TDynArrayHashed. Event oriented version of TDynArraySortCompare TFileBufferWriterKind = ( wkUInt32. buf: PAnsiChar.B): integer of object. SortDynArrayStringI . 2013 TDynArrayHash InitSpecific method) . SortDynArrayByte.. SortDynArrayInt64.MaxInt div SizeOf(PAnsiChar)-1] of PAnsiChar.18 Date: June 16.Synopse mORMot Framework Software Architecture Design 1.wkUInt32 will write the content as "plain" 4 bytes binary (this is the prefered way if the integers can be negative) .djCustom will be used for registered JSON serializer (invalid for InitSpecific methods call) .it must return a cardinal hash. wkVarInt32. Event handler to be used for hashing of a dynamic array element TOnTextWriterEcho = procedure(Sender: TTextWriter. false on error .. Generic parameter types.Synopse mORMot Framework Software Architecture Design 1.example of matching event handler are EventArchiveDelete/EventArchiveSynLZ or EventArchiveZip SynCommons. A dynamic array of PUTF8Char pointers TRawByteStringDynArray = array of RawByteString. A pointer to a PtrUInt array TPtrUIntDynArray = array of PtrUInt. as ExtractInlineParameters() functions recognized by TStringDynArray = array of string. sptFloat.used e.MAX_SQLFIELDS-1. aDestinationPath: TFileName): boolean. 256 bits uses 64 bytes of memory .should return true on success.Destroy identify some outdated files . A pointer to a RawUTF8 array TRawUTF8DynArray = array of RawUTF8.Rev. sptInteger. 1. Array of parameter types. for containing sqlite3_get_table() result TPUtf8CharDynArray = array of PUTF8Char.MaxInt div SizeOf(PtrUInt)-1] of PtrUInt.the aDestinationPath parameter will contain 'ArchivePath\log\YYYYMM\' . This event can be set for TSynLogFamily to archive any deprecated log into a custom compressed format . A dynamic array of UTF-8 encoded strings TSBFString = type RawByteString. as ExtractInlineParameters() functions recognized by SQLParamContent() and SQLParamContent() and TSQLParamTypeDynArray = array of TSQLParamType. sptDateTime ). A dynamic array of generic VCL strings TSynHashDynArray = array of TSynHash. sptText. 2013 TPtrUIntArray = array[0. by TDynArrayHashed or TObjectHash TSynLogArchiveEvent = function(const aOldLogFileName. A dynamic array of PtrUInt values TPUtf8CharArray = array[0. Used to store bit set for all available fiels in a Table ..will be called by TSynLogFamily when TSynLogFamily.. A Row/Col array of PUTF8Char.MaxInt div SizeOf(PUTF8Char)-1] of PUTF8Char.the aOldLogFileName will contain the .18 Page 402 of 1055 . Internal structure used to store hashs of items .g..18 Date: June 16. sptBlob.see also IsZero() and IsEqual() functions TSQLParamType = ( sptUnknown.with current MAX_SQLFIELDS value.MaxInt div SizeOf(RawUTF8)-1] of RawUTF8.pas unit . An custom RawByteString type used to store internaly a data in our SBF compact binary format TSQLFieldBits = set of 0. A dynamic array of RawByteString TRawUTF8Array = array[0.log file with full path . sllNewRun ). sllCustom2. map all sllEnter/sllLeave event in the .sllSQL is dedicated to trace the SQL statements .zip only once) TSynLogCurrentIdents = array[0.sllWarning will log unexpected values (not an error) . sllLastError.maxInt div sizeof(TSynLogCurrentIdent)-1] of TSynLogCurrentIdent. sllExceptionOS. JSON encoded .log file TSynLogInfo = ( sllNone.sllNewRun will be written when a process opens a rotated log TSynLogInfoDynArray = array of TSynLogInfo.sllFail was defined for TSynTestsLogged.sllServiceCall/sllServiceReturn to trace some remote service or library .Failed method. The available logging events. sllServer.sllException will log all exception raised . sllWarning. sllClient. sllCache. not errors) .sllUserAuth to trace user authentication (e.sllEnter will log every method start ..sllCache should be used to trace the internal caching mechanism .should return FALSE if Context. sllLeave. sllResult.LevelStackTrace like sllError. Used to store the identification of all recursivity levels TSynLogExceptionToStr = function(WR: TTextWriter.EAddr and Stack trace is to be appended TSynLogFileProcDynArray = array of TSynLogFileProc.e.sllError will log errors . sllException. as handled by TSynLog .sllExceptionOS will log all OS low-level exceptions (EDivByZero.18 Page 403 of 1055 .) . sllUserAuth.sllLastError will log the GetLastError OS message . sllEnter.pas unit .sllTrace will log low-level step by step debugging information .Synopse mORMot Framework Software Architecture Design 1. sllInfo.. 2013 in SynZip.i. sllDB.log file . sllServiceCall.sllDebug will log detailed debugging information .this event handler will be called one time per .pas .available since Windows XP . sllExceptionOS. sllError. Used by TSynLogFile to refer to global method profiling in a . for individual requests) . sllMemory. sllDebug.sllInfo will log general information events .sllStackTrace will log caller's stack trace (it's by default part of TSynLogFamily.18 Date: June 16. Global hook callback to customize exceptions logged by TSynLog .sllResult could trace the SQL results. const Context: TSynLogExceptionContext): boolean. sllSQL. by EventArchiveZip to open the . sllCustom3.. sllStackTrace. sllLastError and sllFail) .g. sllException. sllServiceReturn.Rev.sllMemory will log memory statistics . sllTrace. sllCustom1. sllHTTP.sllHTTP could be used to trace HTTP process .sllDB is dedicated to trace low-level database engine features .sllLeave will log every method quit . SynCommons. EAccessViolation. sllFail. and can be used to log some customer-side assertions (may be notifications. then one last time with aOldLogFileName='' in order to close any pending archive (used e.g. 1. sllCustom4.sllClient/sllServer could be used to trace some Client or Server process .log file to archive.sllCustom* items can be used for any purpose . ERangeError. with the corresponding ThreadID .Synopse mORMot Framework Software Architecture Design 1. 2013 A dynamic array of logging event levels TSynLogInfos = set of TSynLogInfo. tftUInt16. Available option types for a field property . in occurence order . Available pronunciations for our fast Soundex implementation TSynTableFieldBits = set of 0.if set to ptIdentifiedInOnFile.this option has an effect not only if tfoIndex or tfoUnique is set.pas unit . comparison is case-sensitive) .note that your application shall use a thread pool (just like all mORMot servers classes do).tfoUnique is set if field values must be unique (if set. maximum field count is 64 TSynTableFieldIndex = function(const PropName: RawUTF8): integer of object. a new column will be added for each log row.18 Date: June 16. if needed .map file TSynNameValueItemDynArray = array of TSynNameValueItem. ptMergedInOneFile will indicate that all threads are logged in the same file. How threading is handled by the TSynLogFamily . Name/Value pairs storage.by default.'ID' is handled separately: here must be available only the custom fields TSynTableFieldOption = ( tfoIndex. Used to define a logging level . otherwise some random hash collision may occur if Thread IDs are not recycled enough TSynLogStackTraceUse = ( stManualAndAPI.log file per thread . the tfoIndex will be always forced) .LogView tool will be able to display per-thread logging. ptOneFilePerThread. stOnlyManual ).i. tftBoolean. Function prototype used to retrieve the index of a specified property name . a combination of none or several logging event .e. tftInt32. but also for iterating search TSynTableFieldOptions = set of TSynTableFieldOption. as decoded by TSynMapFile from a .18 Page 404 of 1055 . 1. SynCommons.tfoIndex is set if an index must be created for this field .map file TSynMapUnitDynArray = array of TSynMapUnit.. tftUInt24.e.g. as used by TSynNameValue class TSynSoundExPronunciation = ( sndxEnglish. A dynamic array of symbols. it will create one . tfoCaseInsensitive ). sndxSpanish. tftInt64. A dynamic array of units. tftUInt8.Rev. tfoUnique. as decoded by TSynMapFile from a . use LOG_VERBOSE constant to log all events TSynLogPerThreadMode = ( ptMergedInOneFile. sndxFrench. stOnlyAPI. Used to store bit set for all available fiels in a Table . ptIdentifiedInOnFile ). sndxNone ).if set to ptOneFilePerThread.with current format.63. How stack trace shall be computed TSynMapSymbolDynArray = array of TSynMapSymbol. Set of option types for a field TSynTableFieldType = ( tftUnknown.tfoCaseInsensitive can be set to make no difference between 'a' and 'A' (by default. 18 Date: June 16.e.to be used with TSynTest descendants TSynUnicodeDynArray = array of SynUnicode. the index value used to retrieve data from low-level (and faster) method . tftVarUInt64.basic types are similar to SQLite3. tftVarInt64 ). handled by TSynTable like a RawByteString text storage). The available types for any TSynTable field property . tftDouble. tftVarUInt32. i. tftWinAnsi. can be used as published property field in TSQLRecord SynCommons.faster than Iso-8601 text and TDateTime . twOnSameLine ).this is used in our so-called SBF compact binary format (similar to BSON or Protocol Buffers) .those types are used for both storage and JSON conversion .storage can be of fixed size.18 Page 405 of 1055 . tftBlobExternal.e. Options set for TTextWriter. must be stored in a dedicated storage structure . i.e. Available options for TTextWriter.e.e. to make it more human eye friendly .pas unit . tftVarInt32. Fast integer-encoded date and time value . woStoreClassName ).you can specify to use WinAnsi encoding instead of UTF-8 for string storage (it can use less space on disk than UTF-8 encoding) . field TTextWriterWriteObjectOptions = set of TTextWriterWriteObjectOption. tftBlobInternal.woDontStoreDefault (which is set by default for WriteObject method) will avoid serializing properties including a default value (JSONToObject function will set the default values. Function prototype used to retrieve the RECORD data of a specified Index .WriteObject() method TTimeLog = type Int64. twJSONEscape.BLOB fields can be either internal (i. including instance class name and reference pointer (it is used in TSynLog) . tftUTF8. woFullExpand.e.g.g. another TSynBigTable instance) TSynTableFieldTypes = set of TSynTableFieldType. so it may help saving some bandwidth or storage) . 1.woHumanReadable will add some line feeds to the content. Kind of adding in a TTextWriter TTextWriterWriteObjectOption = ( woHumanReadable.Synopse mORMot Framework Software Architecture Design 1. or of variable length .woStoreClassName will add a "ClassName":"TMyClass".should return nil if Index is out of range . var aTempData: RawByteString): pointer of object.WriteObject() method . but the "physical" index. either external (i.woFullExpand will generate a log-friendly layout. A dynamic array of SynUnicode values TTextWriterKind = ( twNone. 2013 tftCurrency. woDontStoreDefault. Int64/Double/UTF-8/Blob . Set of available field types for TSynTable TSynTableGetRecordData = function( Index: integer.Rev.the index is not the per-ID index. The prototype of an individual test .caller must provide a temporary storage buffer to be used optionally TSynTestEvent = procedure of object. for Delphi 2009+ UnicodeString=String type djObject = djPointer.e.pas unit during TSQLTable rows sort and by TSQLQuery TVarDataDynArray = array of TVarData. A dynamic array of WinAnsi encoded strings TWindowsVersion = ( wUnknown.same as Iso8601ToSeconds() . A dynamic array of WideString values TWinAnsiDynArray = array of WinAnsiString. wSeven_64. which behavior changed between Delphi 2009 compiler and previous versions: our implementation is consistent and compatible with all versions of Delphi compiler . wVista_64. wServer2008_R2_64.) .all conversion to/from RawUTF8 or RawUnicode must be explicit Constants implemented in the SynCommons unit: CODEPAGE_US = 1252.since TTimeLog type is bit-oriented. wServer2012.used by TDynArray JSON serialization to handle textual serialization TUTF8Compare = function(P1.convenient for current date and time process (logging e.g.use internally for computation an abstract "year" of 16 months of 32 days of 32 hours of 64 minutes of 64 seconds . The recognized Windows versions WinAnsiString = type AnsiString. Function prototype used internally for UTF-8 buffer comparaison . wServer2003_R2.g. wVista. A dynamic array of TVarData values TWideStringDynArray = array of WideString.used in mORMot. WinAnsiString is a WinAnsi-encoded AnsiString (code page 1252) . Dynamic array of TTimeLog . 1. w2000. Best possible precision when rendering a "double" kind of float SynCommons.18 Date: June 16.use this type instead of System. you can't just use add or substract two TTimeLog values when doing such date/time computation: use a TDateTime temporary conversion in such case TTimeLogDynArray = array of TTimeLog.type cast any value of TTimeLog with the Iso8601 object below for easy access to its content .pas unit . 2013 . Internal Code Page for Unicode encoding . US English Windows Code Page. TDynArrayKind alias for a pointer field hashing / comparison DOUBLE_PRECISION = 15. wSeven. wXP. WinAnsi standard character encoding CP_UTF16 = 1200. TDynArrayKind alias for a TObject field hashing / comparison djPointer = djCardinal.String. wServer2008_64.used e. wServer2008_R2.Rev. wEight.18 Page 406 of 1055 .Synopse mORMot Framework Software Architecture Design 1. wEight_64. i. wServer2012_64 ). wXP_64. wServer2003. wServer2008.P2: PUTF8Char): PtrInt. 1. as defined in the corresponding RFC. '"' + UTF-8 encoded \uFFF0 special code JSON_BASE64_MAGIC_QUOTE_VAR: cardinal = JSON_BASE64_MAGIC_QUOTE.18 Date: June 16..g. and expected by SQLParamContent() and ExtractInlineParameters() functions JSON_SQLDATE_MAGIC_QUOTE = ord('"')+cardinal(JSON_SQLDATE_MAGIC) shl 8.as generated by DateToSQL/DateTimeToSQL functions. HTTP header.e.ord('Z')].Synopse mORMot Framework Software Architecture Design 1. charset=UTF-8'..ord('0'). for field or table name .this char set matches the classical pascal definition of identifiers IsWord: set of byte = [ord('0').can be used e.ord('z')..ord('9').SaveTo in JSON .Unicode special char U+FFF0 is UTF-8 encoded as EF BF B0 bytes JSON_BASE64_MAGIC_QUOTE = ord('"')+cardinal(JSON_BASE64_MAGIC) shl 8.ord('Z')]. JSON compatible representation of a boolean value JSON_CONTENT_TYPE = 'application/json.g. '"' + UTF-8 encoded \uFFF0 special code JSON_BOOLEAN: array[boolean] of RawUTF8 = ('false'.ord('a'). UTF-8 encoded \uFFF0 special code -> mark Base64 TDynArray. charset="UTF-8"'.Rev.ord('A'). HTTP header for MIME content type used for plain JSON JSON_SQLDATE_MAGIC = $b1bfef.pas unit .. and expected by SQLParamContent() and SynCommons. Used internaly for fast identifier recognition (32 bytes const) . 1. 2013 .2 (page 1049).ord('a').. HTTP header for MIME content type used for UTF-8 encoded HTML IsIdentifier: set of byte = [ord('_'). as defined in the corresponding RFC HEADER_CONTENT_TYPE_UPPER = 'CONTENT-TYPE: '.ord('9'). Used internaly for fast word recognition (32 bytes const) JSON_BASE64_MAGIC = $b0bfef. JSON_CONTENT_TYPE_HEADER = HEADER_CONTENT_TYPE+JSON_CONTENT_TYPE. UTF-8 encoded \uFFF1 special code -> mark ISO-8601 SQLDATE in JSON ..Unicode special char U+FFF1 is UTF-8 encoded as EF BF B0 bytes .can be used as parameter for ExtendedToString/ExtendedToStr HEADER_CONTENT_TYPE = 'Content-Type: '. MIME content type used for UTF-8 encoded HTML HTML_CONTENT_TYPE_HEADER = HEADER_CONTENT_TYPE+HTML_CONTENT_TYPE.ord('A').as generated by DateToSQL/DateTimeToSQL functions. MIME content type used for JSON communication (as used by the Microsoft WCF framework and the YUI framework) Used for DI-2.ord('z').'true'). '"' + UTF-8 encoded \uFFF1 special code .18 Page 407 of 1055 . HTTP header. in upper case HTML_CONTENT_TYPE = 'text/html. '"\uFFF12012-05-04"' pattern . g.e.a new . ' stack ' srvr '. and the available recursive stack has not been traced yet (if sllEnter if not in the current selected levels) LOG_VERBOSE: TSynLogInfos = [succ(sllNone). ' http '..6] -> e.for a more detailled soundex. Rotate local log file if reached this size (1MB by default) . ' SQL '. ' call rotat '). ' auth '. ' cust2 '. Maximum number of fields in a database Table . Best possible precision when rendering a "single" kind of float .used by AppendToTextFile() and LogToTextFile() functions (not TSynLog) MAX_SQLFIELDS = 64.EventArchiveSynLZ identify .default is 64.'. Sometimes. 192 and 256 optimized) . ' DB '. as created by LOG_STACKTRACE: TSynLogInfos = [sllError. which will compute up to 7 soundex chars in a cardinal (that's our choice) SYNOPSE_FRAMEWORK_VERSION = '1. TSynTableStatement.log. ' OSERR '. 2013 ExtractInlineParameters() functions LOG_LEVEL_TEXT: array[TSynLogInfo] of string[7] = ( ' '. Number of bits to use for each interresting soundex char . ' trace ' mem '.pas unit . ' debug '. Can be set to TSynLogFamily. use 4 bits resolution.synlz compressed files. which is the standard approach .i.18 Page 408 of 1055 .can be used as parameter for ExtendedToString/ExtendedToStr SOUNDEX_BITS = 4. ' clnt '. 1.bak file .log file will be save as . TSQLFieldBits.sllException.g.Level in order to log all available events MAXLOGSIZE = 1024*1024.e. TSynTable) . The corresponding version of the freeware Synopse framework SynCommons. ' cust4 '.is included in SynCommons so that all DB-related work will be able to share the same low-level types and functions (e. the ID field is included in a bits set MAX_SYNLOGFAMILY = 15.. as written in the log file .Synopse mORMot Framework Software Architecture Design 1. ' cust1 '. ' + '. ' cache '. ' warn '. TSynLog children classes can be defined SINGLE_PRECISION = 8. ' EXC '. ' cust3 '. 128. ' ERROR '.18 Date: June 16.18'. ' info '.sllExceptionOS].. The "magic" number used to TSynLogFamily. The text equivalency of each logging level. ' fail '. '. ' '. 4 soundex chars. but can be set to any value (64.this constant is used internaly to optimize memory usage in the generated asm code. Contains the logging levels for which stack trace should be dumped . i. TJSONWriter.log file is created .PCardinal(LOG_LEVEL_TEXT[L][3])^ will be used for fast level matching so text must be unique for characters [3. ' EXCOS '. Up to 16 TSynLogFamily. ' ret '. i.e. 'UST4' LOG_MAGIC = $ABA51051. when such a log event occur.default is to use 8 bits.log. ' res '.Rev. '. and statically allocate some arrays for better speed MAX_SQLFIELDS_INCLUDINGID = MAX_SQLFIELDS+1. ' .high(TSynLogInfo)]. '22'.'68'.'74'.'32'.'46'.'38'. '20'.'25'.'98'.'72'.'67'.'19'.'71'.'86'.'16'.'61'.'41'. Used by TSynTableStatement.'91'.'28'. 1.'82'.'83'.'08'.Synopse mORMot Framework Software Architecture Design 1.'94'.'84'.'45'.'77'.'57'.'02'.'53'.'89'.pas SYNTABLESTATEMENTWHEREALL = -1. '80'.'48'..'35'.'56'. '90'.'87'.'66'.'03'.'78'.'97'.'63'.18 Date: June 16.'12'.'62'.'55'. MIME content type used for plain UTF-8 text TEXT_CONTENT_TYPE_HEADER = HEADER_CONTENT_TYPE+TEXT_CONTENT_TYPE. Fast lookup table for converting any decimal number from 0 to 99 into their ASCII equivalence .'06'.'64'.'73'.'09'.'14'.'11'.. HTTP header for MIME content type used for plain UTF-8 text TwoDigitLookup: packed array[0.'31'.'93'. '50'.'75'.'85'.'29'.'52'.'47'. '60'.'05'.'18'.'24'.pas unit .our enhanced SysUtils.'26'.'15'.'92'.Rev.18 Page 409 of 1055 .WhereField for "SELECT .'44'.'81'.'04'.'88'.'36'. FROM TableName WHERE ID=?" TEXT_CONTENT_TYPE = 'text/plain.'39'.'76'. charset="UTF-8"'. 2013 .WhereField for "SELECT Count(*) FROM TableName" SYNTABLESTATEMENTWHEREID = 0.. '40'.'96'.'21'.a similar constant shall be defined in SynCrtSock. '70'.WhereField for "SELECT * FROM TableName" SYNTABLESTATEMENTWHERECOUNT = -2.99] of array[1.'42'.'95'.'23'.'33'.'79'.'49'.'34'. Used by TSynTableStatement.'54'. '30'.'01'.2] of AnsiChar = ('00'.'65'. Delphi 5 doesn't have those base types defined :( Functions or procedures implemented in the SynCommons unit: Functions or procedures Description Page AddInteger Add an integer value at the end of a dynamic array of integers 429 AddInteger Add an integer value at the end of a dynamic array of integers 429 AddPrefixToCSV Append some prefix to all CSV values 429 AddRawUTF8 True if Value was added successfully in Values[] 429 AddSortedInteger Add an integer value in a sorted dynamic array of integers 429 AddSortedRawUTF8 Add a RawUTF8 value in an alphaticaly sorted dynamic array of RawUTF8 429 Ansi7ToString Convert any Ansi 7 bit encoded String into a generic VCL Text 429 Ansi7ToString Convert any Ansi 7 bit encoded String into a generic VCL Text 429 SynCommons.'58'.'51'.pas (normal and LVCL) contains the same array varInt64 = $0014. Used by TSynTableStatement.'59'.'69'.'27'.'13'. '10'.'99').'17'.'07'.'43'.'37'. ready to be displayed 431 CardinalToHex Fast conversion from a Cardinal data into hexa chars. 2013 Functions or procedures Description Page AnsiCharToUTF8 Convert an AnsiChar buffer (of a given code page) into a UTF-8 string 429 AnsiIComp Fast WinAnsi comparaison using the NormToUpper[] array for all 8 bits values 429 AnsiICompW Fast case-insensitive Unicode comparaison 430 AppendBufferToRawUTF8 Fast add some characters to a RawUTF8 string 430 AppendCSVValues Append some text lines with the supplied Values[] 430 AppendRawUTF8ToBuffer Fast add some characters from a RawUTF8 string into a given buffer 430 AppendToTextFile Log a message to a local text file 430 Base64Decode Direct decoding of a Base64 encoded buffer 430 Base64ToBin Fast conversion from Base64 encoded text into binary data 430 Base64ToBin Fast conversion from Base64 encoded text into binary data 430 Base64ToBinLength Retrieve the expected length of a Base64 encoded buffer 430 BinToBase64 Fast conversion from binary data into Base64 encoded text 430 BinToBase64 Fast conversion from binary data into Base64 encoded text 430 BinToBase64URI Fast conversion from binary data into Base64-like URI-compatible encoded text 430 BinToBase64WithMagic Fast conversion from binary data into Base64 encoded text with JSON_BASE64_MAGIC prefix (UTF-8 encoded \uFFF0 special code) 431 BinToBase64WithMagic Fast conversion from binary data into Base64 encoded text with JSON_BASE64_MAGIC prefix (UTF-8 encoded \uFFF0 special code) 431 BinToHex Fast conversion from binary data into hexa chars 431 BinToHex Fast conversion from binary data into hexa chars 431 BinToHexDisplay Fast conversion from binary data into hexa chars.pas unit . 1.Rev.AddInt18ToChars3() method 431 CharSetToCodePage Convert a char set to a code page 431 CodePageToCharSet Convert a code page to a char set 431 CompareMem Use our fast asm version of CompareMem() 431 CompareOperator Low-level text comparison according to a specified operator 432 SynCommons.Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16.18 Page 410 of 1055 . ready to be displayed 431 Chars3ToInt18 Revert the value as encoded by TTextWriter. then sort it.pas unit .Rev.18 Page 411 of 1055 . able to receive GDI messages for fast local communication 433 CSVOfValue Return a CSV list of the iterated same value 433 CSVToIntegerDynArray Add the strings in the specified CSV text into a dynamic array of integer 433 CSVToRawUTF8DynArray Add the strings in the specified CSV text into a dynamic array of UTF-8 strings 433 Curr64ToPChar Convert an INTEGER Curr64 (value*10000) into a string 433 Curr64ToStr Convert an INTEGER Curr64 (value*10000) into a string 433 Curr64ToString Convert a currency value from its Int64 binary representation into its numerical text equivalency 433 DateTimeToIso8601 Basic Date/Time conversion into ISO-8601 433 DateTimeToIso8601Text Write a TDateTime into strict ISO-8601 date and/or time text 433 DateTimeToSQL Convert a date/time to a ISO-8601 string format for SQL '?' inlined parameters 434 DateToIso8601 Basic Date conversion into ISO-8601 434 DateToIso8601 Basic Date conversion into ISO-8601 434 DateToIso8601PChar Write a Date to P^ Ansi buffer 434 DateToIso8601PChar Write a Date to P^ Ansi buffer 434 DateToIso8601Text Convert a date into 'YYYY-MM-DD' date format 434 DateToSQL Convert a date to a ISO-8601 string format for SQL '?' inlined parameters 435 DateToSQL Convert a date to a ISO-8601 string format for SQL '?' inlined parameters 435 DefaultSynLogExceptio nToStr Default exception logging callback 435 SynCommons. low values first 432 CreateInternalWindow This function can be used to create a GDI compatible window. 1.Synopse mORMot Framework Software Architecture Design 1. processing the internal GDI message loop and any Synchronize() pending notification 432 ContainsUTF8 Return true if up^ is contained inside the UTF-8 buffer p^ 432 ConvertCaseUTF8 Fast conversion of the supplied text into 8 bit case sensitivity 432 CopyAndSortInteger Copy an integer array.18 Date: June 16. 2013 Functions or procedures Description Page CompareOperator Low-level floating-point comparison according to a specified operator 432 CompareOperator Low-level integer comparison according to a specified operator 432 ConsoleWaitForEnterKe y Will wait for the ENTER key to be pressed. if not already done 437 ExistsIniName Return TRUE if Value of UpperName does exist in P.log files using our proprietary SynLZ format 436 ExcludeTrailingPathDe limiter Alias to ExcludeTrailingBackslash() function 437 ExeVersionRetrieve Initialize ExeVersion global variable. 1.Rev. till end of current section 437 ExistsIniNameValue Return TRUE if one of the Value of UpperName exists in P.18 Date: June 16.pas unit .AddDynArrayJSON 436 EventArchiveDelete A TSynLogArchiveEvent handler which will delete older . 2013 Functions or procedures Description Page DeleteInteger Delete any integer in Values[] 435 DeleteInteger Delete any integer in Values[] 435 DeleteRawUTF8 Delete a RawUTF8 item in a dynamic array of RawUTF8 435 DeleteSection Delete a whole [Section] 435 DeleteSection Delete a whole [Section] 435 DirectoryDelete Delete the content of a specified directory 435 DirectoryExists DirectoryExists returns a boolean value that indicates whether the specified directory exists (and is actually a directory) 436 DoubleToStr Convert a floating-point value to its numerical text equivalency 436 DoubleToString Convert a floating-point value to its numerical text equivalency 436 DynArray Initialize the structure with a one-dimension dynamic array 436 DynArrayLoadJSON Fill a dynamic array content from a JSON serialization as saved by TTextWriter.log files 436 EventArchiveSynLZ A TSynLogArchiveEvent handler which will compress older .18 Page 412 of 1055 . till end of current section 437 ExtendedToStr Convert a floating-point value to its numerical text equivalency 437 ExtendedToString Convert a floating-point value to its numerical text equivalency 437 ExtractInlineParamete rs This function will extract inlined :(1234): parameters into Types[]/Values[] 437 FastFindIndexedPUTF8C har Retrieve the index of a PUTF8Char in a PUTF8Char array via a sort indexed 437 FastFindIntegerSorted Fast binary search of an integer value in a sorted integer array 437 FastFindPUTF8CharSort ed Retrieve the index where is located a PUTF8Char in a sorted PUTF8Char array 438 SynCommons.Synopse mORMot Framework Software Architecture Design 1. . till end of current section 440 FindIniNameValueInteg er Find the integer Value of UpperName in P.INI file 439 FindIniEntryInteger Find a Name= numeric Value in a [Section] of a INI RawUTF8 Content and return it as an integer. till end of current section 440 FindNextUTF8WordBegin Points to the beginning of the next word stored in U 440 FindObjectEntry Retrieve a property value in a text-encoded class 440 FindObjectEntryWithou tExt Retrieve a filename property value in a text-encoded class 440 FindRawUTF8 Return the index of Value in Values[].18 Date: June 16.Synopse mORMot Framework Software Architecture Design 1. -1 if not found 440 SynCommons. or 0 if not found 439 FindIniNameValue Find the Value of UpperName in P.i+Count-1 439 FindAnsi Return true if UpperValue (Ansi) is contained in A^ (Ansi) 439 FindCSVIndex Return the index of a Value in a CSV string 439 FindIniEntry Find a Name= Value in a [Section] of a INI RawUTF8 Content 439 FindIniEntryFile Find a Name= Value in a [Section] of a .18 Page 413 of 1055 .Z.0. 1...Rev. working with huge files 439 FileSize Get the file size 439 FileSynLZ Compress a file content using the SynLZ algorithm a file content 439 FileUnSynLZ Compress a file content using the SynLZ algorithm a file content 439 FillChar Faster implementation of FillChar() for Delphi versions with no FastCode inside 439 FillIncreasing Fill some values with i.i+1.. 2013 Functions or procedures Description Page FastFindPUTF8CharSort ed Retrieve the index where is located a PUTF8Char in a sorted PUTF8Char array 438 FastLocateIntegerSort ed Retrieve the index where to insert an integer value in a sorted integer array 438 FastLocatePUTF8CharSo rted Retrieve the index where to insert a PUTF8Char in a sorted PUTF8Char array 438 FastLocatePUTF8CharSo rted Retrieve the index where to insert a PUTF8Char in a sorted PUTF8Char array 438 FieldNameValid Returns TRUE if the given text buffer contains A.9 characters 438 FileAgeToDateTime Get the file date and time 438 FileFromString Create a File from a string content 438 FileSeek64 FileSeek() overloaded function.pas unit .i+2. 18 Date: June 16.pas unit . triming any left 'T'.18 Page 414 of 1055 .Rev. starting at Index=0 for first one 443 SynCommons.Synopse mORMot Framework Software Architecture Design 1. 1. handling % and ? parameters 441 FromVarInt32 Convert a 32-bit variable-length integer buffer into an integer 441 FromVarInt64 Convert a 64-bit variable-length integer buffer into a Int64 441 FromVarString Retrieve a variable-length text buffer 441 FromVarUInt32 Convert a 32-bit variable-length integer buffer into a cardinal 441 FromVarUInt32High Convert a 32-bit variable-length integer buffer into a cardinal 441 FromVarUInt32Up128 Convert a 32-bit variable-length integer buffer into a cardinal 441 FromVarUInt64 Convert a 64-bit variable-length integer buffer into a UInt64 441 GarbageCollectorFreeA ndNil A global "Garbage collector" for some TObject global variables which must live during whole main executable process 442 GetBit Retrieve a particular bit status from a bit array 442 GetBit64 Retrieve a particular bit status from a Int64 bit array (max aIndex is 63) 442 GetBitCSV Convert a set of bit into a CSV content 442 GetBitsCount Compute the number of bits set in a bit array 442 GetCaptionFromClass UnCamelCase and translate the class name. 2013 Functions or procedures Description Page FindSectionFirstLine Find the position of the [SEARCH] section in source 440 FindSectionFirstLineW Find the position of the [SEARCH] section in source 440 FindUnicode Return true if Uppe (Unicode encoded) is contained in U^ (UTF-8 encoded) 440 FindUTF8 Return true if UpperValue (Ansi) is contained in U^ (UTF-8 encoded) 440 FindWinAnsiIniEntry Find a Name= Value in a [Section] of a INI WinAnsi Content 440 FormatUTF8 Fast Format() function replacement. optimized for RawUTF8 441 FormatUTF8 Fast Format() function replacement. 'TSQL' or 'TSQLRecord' 442 GetCaptionFromEnum UnCamelCase and translate the enumeration item 442 GetCaptionFromPCharLe n UnCamelCase and translate a char buffer 442 GetCardinal Get the unsigned 32 bits integer value stored in P^ 442 GetCardinalDef Get the unsigned 32 bits integer value stored in P^ 442 GetCardinalW Get the unsigned 32 bits integer value stored as Unicode string in P^ 442 GetCSVItem Return n-th indexed CSV string in P. 'TSyn'. 2013 Functions or procedures Description Page GetCSVItemString Return n-th indexed CSV string in P. nil if no more 445 GetNextItemCardinal Return next CSV string as unsigned integer from P.18 Page 415 of 1055 .Rev. without its extension 443 GetFileVersion GetFileVersion returns the most significant 32 bits of a file's binary version number 443 GetHighUTF8UCS4 Internal function.18 Date: June 16.Create) 444 GetLineSize Compute the line length from source array of chars 444 GetLineSizeSmallerTha n Returns true if the line length from source array of chars is not less than the specified count 444 GetMimeContentType Retrieve the MIME content type from a supplied binary buffer 445 GetModuleName Retrieve the full path name of the given execution module (e. 0 if no more 445 GetNextItemDouble Return next CSV string as double from P. library) 445 GetNextItem Return next CSV string from P. 0 if no more 445 GetNextItemCardinalSt rict Return next CSV string as unsigned integer from P.0 if no more 445 SynCommons.g. then compare with a comma separated list of extensions 443 GetFileNameWithoutExt Extract file name.pas unit . 0. 0 if no more 445 GetNextItemCardinalW Return next CSV string as unsigned integer from P. used to retrieve a UCS4 char (>127) from UTF-8 443 GetInt64 Get the 64 bits integer value stored in P^ 444 GetInt64 Get the 64 bits integer value stored in P^ 444 GetInteger Get the signed 32 bits integer value stored in P^ 444 GetInteger Get the signed 32 bits integer value stored in P^ 444 GetJSONField Decode a JSON field in an UTF-8 encoded buffer (used in TSQLTableJSON. 1. starting at Index=0 for first one 443 GetDelphiCompilerVers ion Return the Delphi Compiler Version 443 GetDisplayNameFromCla ss Will get a class name as UTF-8 443 GetEnumName Helper to retrieve the text of an enumerate item 443 GetExtended Get the extended floating point value stored in P^ 443 GetExtended Get the extended floating point value stored in P^ 443 GetFileNameExtIndex Extract a file extension from a file name.Synopse mORMot Framework Software Architecture Design 1. Synopse mORMot Framework Software Architecture Design 1. nil if no more 445 GetNextUTF8Upper Retrieve the next UCS4 value stored in U.simply return the value ignore Hasher() parameter 447 SynCommons.' '] 446 GotoNextVarInt Jump a value in the 32-bit or 64-bit variable-length integer buffer 446 GotoNextVarString Jump a value in variable-length text buffer 446 Hash32 Our custom hash function. 2013 Functions or procedures Description Page GetNextItemShortStrin g Return next CSV string from P. nil if no more 445 GetNextLine Extract a line from source array of chars 445 GetNextLineBegin Return line begin from source array of chars..Rev. specialized for Text comparaison 447 Hash32 Our custom hash function.pas unit .simply return the value ignore Hasher() parameter 447 HashInt64 Hash one Int64 value with the suppplied Hasher() function 447 HashInteger Hash one Integer value . and go to next line 445 GetNextStringLineToRa wUnicode Return next string delimited with #13#10 from P.18 Date: June 16.simply return the value ignore Hasher() parameter 447 HashCardinal Hash one Cardinal value . specialized for Text comparaison 447 HashAnsiString Hash one AnsiString content with the suppplied Hasher() function 447 HashAnsiStringI Case-insensitive hash one AnsiString content with the suppplied Hasher() function 447 HashByte Hash one Byte value .18 Page 416 of 1055 . nil if no more 445 GetNextItemString Return next CSV string from P. then update the U pointer 446 GetSectionContent Retrieve the whole content of a section as a string 446 GetSectionContent Retrieve the whole content of a section as a string 446 GetUTF8Char Get the WideChar stored in P^ (decode UTF-8 if necessary) 446 GotoEndOfQuotedString Get the next character after a quoted buffer 446 GotoJSONStringEnd Ignore a JSON "string \"field" 446 GotoNextJSONItem Reach the positon of the next JSON item in the supplied UTF-8 buffer 446 GotoNextJSONObjectOrA rray Reach the position of the next JSON object of JSON array 446 GotoNextNotSpace Get the next character not in [#1. 1. pas unit .18 Date: June 16.Synopse mORMot Framework Software Architecture Design 1. 2013 Functions or procedures Description Page HashPtrUInt Hash one PtrUInt (=NativeUInt) value with the suppplied Hasher() function 447 HashUnicodeString Hash one UnicodeString content with the suppplied Hasher() function 447 HashUnicodeStringI Case-insensitive hash one UnicodeString content with the suppplied Hasher() function 447 HashWord Hash one Word value .simply return the value ignore Hasher() parameter 447 HexDisplayToBin Fast conversion from hexa chars into a pointer 447 HexDisplayToCardinal Fast conversion from hexa chars into a cardinal 447 HexToBin Fast conversion from hexa chars into binary data 448 IdemFileExt Returns true if the file name extension contained in p^ is the same same as extup^ 448 IdemPChar Returns true if the beginning of p^ is the same as up^ 448 IdemPCharAndGetNextLi ne Return true if IdemPChar(source.search). 1.Rev.18 Page 417 of 1055 .SaveTo 449 IntegerDynArrayToCSV Return the corresponding CSV text from a dynamic array of integer 449 IntegerScan Fast search of an unsigned integer position in an integer array 449 SynCommons. and go to the next line of source 448 IdemPCharArray Returns the index of a matching beginning of p^ in upArray[] 448 IdemPCharU Returns true if the beginning of p^ is the same as up^ 448 IdemPCharW Returns true if the beginning of p^ is same as up^ 448 IdemPropName Case unsensitive test of P1 and P2 content 449 IdemPropName Case unsensitive test of P1 and P2 content 449 IdemPropNameU Case unsensitive test of P1 and P2 content 449 IncludeTrailingPathDe limiter Alias to IncludeTrailingBackslash() function 449 InsertInteger Insert an integer value at the specified index position of a dynamic array of integers 449 Int32ToUtf8 Use our fast RawUTF8 version of IntToStr() 449 Int64ToUInt32 Copy some Int64 values into an unsigned integer array 449 Int64ToUtf8 Use our fast RawUTF8 version of IntToStr() 449 IntegerDynArrayLoadFr om Wrap an Integer dynamic array BLOB content as stored by TDynArray. 18 Page 418 of 1055 .18 Date: June 16. from a supplied binary buffer 450 IsHTMLContentTypeText ual Returns TRUE if the supplied HTML Headers contains 'Content-Type: text/.IntToStr implementation 450 IntToString Faster version than default SysUtils. 1.' or 'Content-Type: application/json' 451 IsIso8601 Test if P^ contains a valid ISO-8601 text encoded value 451 IsMatch Return TRUE if the supplied content matchs to a grep-like pattern 451 Iso8601FromDateTime Get TTimeLog value from a given Delphi date and time 451 Iso8601FromFile Get TTimeLog value from a file date and time 451 Iso8601Now Get TTimeLog value from current date and time 451 Iso8601ToDateTime Date/Time conversion from ISO-8601 451 Iso8601ToDateTimePUTF 8Char Date/Time conversion from ISO-8601 451 Iso8601ToDateTimePUTF 8CharVar Date/Time conversion from ISO-8601 451 Iso8601ToSeconds Convert a Iso8601 encoded string into a "fake" second count 451 Iso8601ToSecondsPUTF8 Char Convert a Iso8601 encoded string into a "fake" second count 452 SynCommons...IntToStr implementation 450 IntToThousandString Convert an integer value into its textual representation with thousands marked 450 IsAnsiCompatible Return TRUE if the supplied buffer only contains 7-bits Ansi characters 450 IsAnsiCompatible Return TRUE if the supplied buffer only contains 7-bits Ansi characters 450 IsAnsiCompatible Return TRUE if the supplied text only contains 7-bits Ansi characters 450 IsAnsiCompatible Return TRUE if the supplied buffer only contains 7-bits Ansi characters 450 IsAnsiCompatible Return TRUE if the supplied buffer only contains 7-bits Ansi characters 450 IsBase64 Check if the supplied text is a valid Base64 encoded stream 450 IsBase64 Check if the supplied text is a valid Base64 encoded stream 450 IsContentCompressed Retrieve if some content is compressed. 2013 Functions or procedures Description Page IntegerScanExists Fast search of an unsigned integer position in an integer array 450 IntegerScanIndex Fast search of an unsigned integer position in an integer array 450 IntToString Faster version than default SysUtils.Synopse mORMot Framework Software Architecture Design 1.pas unit .Rev.IntToStr implementation 450 IntToString Faster version than default SysUtils. 18 Date: June 16.Rev. either 'ROWID' 452 IsRowIDShort Returns TRUE if the specified field name is either 'ID'.18 Page 419 of 1055 .pas unit . 2013 Functions or procedures Description Page Iso8601ToSQL Convert an Iso8601 date/time (bit-encoded as Int64) to a ISO-8601 string format for SQL '?' inlined parameters 452 IsRowID Returns TRUE if the specified field name is either 'ID'. according to the JSON encoding schema 452 IsValidEmail Return TRUE if the supplied content is a valid email address 453 IsValidIP4Address Return TRUE if the supplied content is a valid IP v4 address 453 IsWinAnsi Return TRUE if the supplied unicode buffer only contains WinAnsi characters 453 IsWinAnsi Return TRUE if the supplied unicode buffer only contains WinAnsi characters 453 IsWinAnsiU Return TRUE if the supplied UTF-8 buffer only contains WinAnsi characters 453 IsWinAnsiU8Bit Return TRUE if the supplied UTF-8 buffer only contains WinAnsi 8 bit characters 453 IsZero Returns TRUE if all bytes equal zero 453 IsZero Returns TRUE if no bit inside this TSQLFieldBits is set 453 JSONDecode Decode the supplied UTF-8 JSON content for the one supplied name 454 JSONDecode Decode the supplied UTF-8 JSON content for the supplied names 454 JSONDecode Decode the supplied UTF-8 JSON content for the supplied names 454 JSONEncode Encode the supplied data as an UTF-8 valid JSON object content 454 JSONEncodeArray Encode the supplied RawUTF8 array data as an UTF-8 valid JSON array content 454 JSONEncodeArray Encode the supplied integer array data as a valid JSON array 454 JSONEncodeArray Encode the supplied floating-point array data as a valid JSON array 454 JSONEncodeArrayOfCons t Encode the supplied array data as a valid JSON array content 455 SynCommons. 1. either 'ROWID' 452 isSelect Return true if the parameter is void or begin with a 'SELECT' SQL statement 452 IsString Test if the supplied buffer is a "string" value or a numerical value (floating point or integer). either 'ROWID' 452 IsRowID Returns TRUE if the specified field name is either 'ID'.Synopse mORMot Framework Software Architecture Design 1. according to the characters within 452 IsStringJSON Test if the supplied buffer is a "string" value or a numerical value (floating or integer). Synopse mORMot Framework Software Architecture Design 1... or "RowID":.18 Page 420 of 1055 .change one PtrUInt in the code segment 456 PointerToHex Fast conversion from a pointer data into hexa chars. field value from a JSON object buffer 455 JSONRetrieveStringFie ld Retrieve a pointer to JSON string field content 455 KB Convert a size to a human readable value 455 kr32 Standard Kernighan & Ritchie hash from "The C programming Language". low values first 457 QuickSortRawUTF8 Sort a dynamic array of RawUTF8 items 457 SynCommons. 1. via an external array of indexes 457 QuickSortInteger Sort an Integer array..PosEx 456 PosI A non case-sensitive RawUTF8 version of Pos() 456 PosIU A non case-sensitive RawUTF8 version of Pos() 456 PtrUIntScanIndex Fast search of a pointer-sized unsigned integer position in an pointer-sized integer array 457 QuickSortIndexedPUTF8 Char Sort a dynamic array of PUTF8Char items.pas unit . 2013 Functions or procedures Description Page JSONEncodeArrayOfCons t Encode the supplied array data as a valid JSON array content 455 JSONRetrieveIDField Retrieve a "ID":. 3rd edition 455 LogToTextFile Log a message to a local text file 455 LowerCase Fast conversion of the supplied text into lowercase 455 LowerCaseU Fast conversion of the supplied text into 8 bit lowercase 455 LowerCaseUnicode Accurate conversion of the supplied UTF-8 content into the corresponding lower-case Unicode characters 456 MicroSecToString Convert a micro seconds elapsed time into a human readable value 456 Move Faster implementation of Move() for Delphi versions with no FastCode inside 456 NextUTF8UCS4 Get the UCS4 char stored in P^ (decode UTF-8 if necessary) 456 NowToString Retrieve the current Date.18 Date: June 16. ready to be displayed 456 PosChar Fast retrieve the position of a given character 456 PosEx Faster RawUTF8 Equivalent of standard StrUtils. in the ISO 8601 layout. but expanded and ready to be displayed 456 PatchCode Self-modifying code .change some memory buffer in the code segment 456 PatchCodePtrUInt Self-modifying code .Rev.. 18 Date: June 16.Synopse mORMot Framework Software Architecture Design 1.pas unit .Rev.18 Page 421 of 1055 .SaveTo 459 ReadStringFromStream Read an UTF-8 text from a TStream 459 RecordClear Clear a record content 459 RecordCopy Copy a record content from source to Dest 459 SynCommons. 1. 2013 Functions or procedures Description Page QuotedStr Format a text content with quotes 457 QuotedStr Format a buffered text content with quotes 457 QuotedStr Format a buffered text content with quotes 457 RawByteStringArrayCon cat Fast concatenation of several AnsiStrings 457 RawUnicodeToString Convert any Raw Unicode encoded buffer into a generic VCL Text 457 RawUnicodeToString Convert any Raw Unicode encoded buffer into a generic VCL Text 457 RawUnicodeToString Convert any Raw Unicode encoded string into a generic VCL Text 457 RawUnicodeToSynUnicod e Convert any Raw Unicode encoded String into a generic SynUnicode Text 458 RawUnicodeToSynUnicod e Convert any Raw Unicode encoded String into a generic SynUnicode Text 458 RawUnicodeToUtf8 Convert a RawUnicode PWideChar into a UTF-8 string 458 RawUnicodeToUtf8 Convert a RawUnicode PWideChar into a UTF-8 buffer 458 RawUnicodeToUtf8 Convert a RawUnicode string into a UTF-8 string 458 RawUnicodeToUtf8 Convert a RawUnicode PWideChar into a UTF-8 string 458 RawUnicodeToUtf8 Convert a RawUnicode PWideChar into a UTF-8 string 458 RawUnicodeToWinAnsi Convert a RawUnicode PWideChar into a WinAnsi (code page 1252) string 458 RawUnicodeToWinAnsi Convert a RawUnicode string into a WinAnsi (code page 1252) string 458 RawUnicodeToWinPChar Direct conversion of a Unicode encoded buffer into a WinAnsi PAnsiChar buffer 458 RawUTF8ArrayToCSV Return the corresponding CSV text from a dynamic array of UTF-8 strings 458 RawUTF8ArrayToQuotedC SV Return the corresponding CSV quoted text from a dynamic array of UTF-8 strings 458 RawUTF8DynArrayEquals True if both TRawUTF8DynArray are the same 458 RawUTF8DynArrayLoadFr omContains Search in a RawUTF8 dynamic array BLOB content as stored by TDynArray. add an asm JUMP to a redirected function 460 RedirectCodeRestore Self-modifying code .18 Page 422 of 1055 . 1. with case sensitivity 461 SortDynArrayAnsiStrin gI Compare two "array of AnsiString" elements. no banker rounding of a Currency value to only 2 digits 461 SortDynArrayAnsiStrin g Compare two "array of AnsiString" elements.Rev.AddRecordJSON 460 RecordSaveLength Compute the number of bytes needed to save a record content using the RecordSave() function 460 RedirectCode Self-modifying code .18 Date: June 16.AddRecordJSON 459 RecordSave Save a record content into a RawByteString 460 RecordSave Save a record content into a destination memory buffer 460 RecordSaveJSON Save record into its JSON serialization as saved by TTextWriter.restore a code from its RedirectCode() backup 460 ReleaseInternalWindow Delete the window resources used to receive GDI messages 460 RemoveCommentsFromJSO N Remove comments from a text buffer before passing it to JSON parser 460 ReplaceSection Replace a whole [Section] content by a new content 461 ReplaceSection Replace a whole [Section] content by a new content 461 SameTextU SameText() overloaded function with proper UTF-8 decoding 461 SameValue Compare to floating point values.SaveTo 461 SimpleRoundTo2Digits Simple. with no case sensitivity 462 SynCommons. with IEEE 754 double precision 461 SetBit Set a particular bit into a bit array 461 SetBit64 Set a particular bit into a Int64 bit array (max aIndex is 63) 461 SetBitCSV Retrieve the next CSV separated bit index 461 SetInt64 Get the 64 bits integer value stored in P^ 461 ShortStringToAnsi7Str ing Direct conversion of an ANSI-7 shortstring into an AnsiString 461 SimpleDynArrayLoadFro m Wrap a simple dynamic array BLOB content as stored by TDynArray.Synopse mORMot Framework Software Architecture Design 1. 2013 Functions or procedures Description Page RecordEquals Check equality of two records by content 459 RecordLoad Fill a record content from a memory buffer as saved by RecordSave() 459 RecordLoadJSON Fill a record content from a JSON serialization as saved by TTextWriter.pas unit . .pas unit . to be used with PUTF8Char 463 StrCompL Use our fast version of StrCompL(). with case sensitivity 462 SortDynArrayUnicodeSt ringI Compare two "array of WideString/UnicodeString" elements.Rev. to be used with PUTF8Char 463 StrCompIL Use our fast version of StrCompIL().): format 463 StrComp Use our fast version of StrComp(). ignoring all blanks and comments 463 SQLParamContent Guess the content type of an UTF-8 SQL value.. with no case sensitivity 462 SortDynArrayUnicodeSt ring Compare two "array of WideString/UnicodeString" elements. 1.18 Date: June 16. with no case sensitivity 462 SortDynArrayWord Compare two "array of word" elements 462 SoundExAnsi Retrieve the Soundex value of a text word. in :(.18 Page 423 of 1055 . 2013 Functions or procedures Description Page SortDynArrayByte Compare two "array of byte" elements 462 SortDynArrayCardinal Compare two "array of cardinal" elements 462 SortDynArrayDouble Compare two "array of double" elements 462 SortDynArrayInt64 Compare two "array of Int64 or array of Currency" elements 462 SortDynArrayInteger Compare two "array of integer" elements 462 SortDynArrayPointer Compare two "array of TObject/pointer" elements 462 SortDynArrayString Compare two "array of generic string" elements. to be used with PUTF8Char 463 StrCompW Use our fast version of StrComp().Synopse mORMot Framework Software Architecture Design 1. from UTF-8 buffer 462 Split Split a RawUTF8 string into two strings. from Ansi buffer 462 SoundExUTF8 Retrieve the Soundex value of a text word. with case sensitivity 462 SortDynArrayStringI Compare two "array of generic string" elements. to be used with PWideChar 463 StrCurr64 Internal fast INTEGER Curr64 (value*10000) value to text conversion 463 StreamSynLZ Compress a data content using the SynLZ algorithm from one stream into another 464 StreamUnSynLZ Uncompress using the SynLZ algorithm from one file into another 464 StreamUnSynLZ Uncompress using the SynLZ algorithm from one stream into another 464 StrIComp Use our fast version of StrIComp() 464 SynCommons.. according to SepStr separator 463 SQLBegin Go to the beginning of the SQL statement. OldPattern.18 Page 424 of 1055 .pas unit . to be used with PUTF8Char 466 StrLenW Our fast version of StrLen(). in the ISO 8601 layout 467 SynCommons. NewPattern.Rev.[rfReplaceAll]).Synopse mORMot Framework Software Architecture Design 1. 2013 Functions or procedures Description Page StringBufferToUtf8 Convert any generic VCL Text buffer into an UTF-8 encoded buffer 464 StringFromFile Read a File content into a String 464 StringReplaceAll Fast replacement of StringReplace(S. 464 StringReplaceChars Fast replace of a specified char into a given string 464 StringToAnsi7 Convert any generic VCL Text into Ansi 7 bit encoded String 464 StringToRawUnicode Convert any generic VCL Text into a Raw Unicode encoded String 465 StringToRawUnicode Convert any generic VCL Text into a Raw Unicode encoded String 465 StringToSynUnicode Convert any generic VCL Text into a SynUnicode encoded String 465 StringToUTF8 Convert any generic VCL Text into an UTF-8 encoded String 465 StringToUTF8 Convert any generic VCL Text into an UTF-8 encoded String 465 StringToWinAnsi Convert any generic VCL Text into WinAnsi (Win-1252) 8 bit encoded String 465 StrInt32 Internal fast integer val to text conversion 465 StrInt64 Internal fast Int64 val to text conversion 466 StrLen Our fast version of StrLen(). to be used with PWideChar 466 StrToCurr64 Convert a string into its INTEGER Curr64 (value*10000) representation 466 StrToCurrency Convert a string into its currency representation 466 StrUInt32 Internal fast unsigned integer val to text conversion 466 SynUnicodeToString Convert any SynUnicode encoded string into a generic VCL Text 466 SynUnicodeToUtf8 Convert a SynUnicode string into a UTF-8 string 466 TextBackground Change the Windows console text background color 466 TextColor Change the Windows console text writing color 466 TimeToIso8601 Basic Time conversion into ISO-8601 466 TimeToIso8601PChar Write a Time to P^ Ansi buffer 467 TimeToIso8601PChar Write a Time to P^ Ansi buffer 467 TimeToString Retrieve the current Time (whithout Date).18 Date: June 16. 1. ) 468 TrimRight Trims trailing whitespace characters from the string by removing trailing newline.pas unit . 1.18 Page 425 of 1055 . 2013 Functions or procedures Description Page ToSBFStr Convert any AnsiString content into our SBF compact binary format storage 467 ToVarInt32 Convert an integer into a 32-bit variable-length integer buffer 467 ToVarInt64 Convert a Int64 into a 64-bit variable-length integer buffer 467 ToVarUInt32 Convert a cardinal into a 32-bit variable-length integer buffer 467 ToVarUInt32Length Return the number of bytes necessary to store a 32-bit variable-length integer 467 ToVarUInt32LengthWith Data Return the number of bytes necessary to store some data with a its 32-bit variable-length integer legnth 467 ToVarUInt64 Convert a UInt64 into a 64-bit variable-length integer buffer 467 TRawUTF8DynArrayFrom Quick helper to initialize a dynamic array of RawUTF8 from some constants 467 Trim Use our fast asm RawUTF8 version of Trim() 467 TrimLeft Trims leading whitespace characters from the string by removing new line. space.g. and tab characters 468 TruncTo2Digits Truncate a Currency value to only 2 digits 468 TryEncodeTime Try to encode a time 468 UCS4ToUTF8 UTF-8 encode one UCS4 character into Dest 468 UInt32ToUtf8 Optimized conversion of a cardinal into RawUTF8 468 UnCamelCase Convert a CamelCase string into a space separated one 468 UnCamelCase Convert a CamelCase string into a space separated one 468 UnicodeBufferToString Convert an Unicode buffer into a generic VCL string 468 UnicodeBufferToWinAns i Convert an Unicode buffer into a WinAnsi (code page 1252) string 469 UnQuoteSQLString Unquote a SQL-compatible string 469 UnSetBit Unset/clear a particular bit into a bit array 469 UnSetBit64 Unset/clear a particular bit into a Int64 bit array (max aIndex is 63) 469 SynCommons.18 Date: June 16.) 468 TrimLeftLowerCaseShor t Trim first lowercase chars ('otDone' will return 'Done' e. and tab characters 468 TrimLeftLowerCase Trim first lowercase chars ('otDone' will return 'Done' e.Synopse mORMot Framework Software Architecture Design 1.Rev.g. space. Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16.pas unit . 1...18 Page 426 of 1055 . 2013 Functions or procedures Description Page UpdateIniEntry Update a Name= Value in a [Section] of a INI RawUTF8 Content 469 UpdateIniEntryFile Update a Name= Value in a [Section] of a .INI file 469 UpperCase Fast conversion of the supplied text into uppercase 469 UpperCaseCopy Fast conversion of the supplied text into uppercase 469 UpperCaseU Fast conversion of the supplied text into 8 bit uppercase 469 UpperCaseUnicode Accurate conversion of the supplied UTF-8 content into the corresponding upper-case Unicode characters 469 UpperCopy Copy source into dest^ with 7 bits upper case conversion 470 UpperCopy255 Copy source into dest^ with 7 bits upper case conversion 470 UpperCopy255W Copy WideChar source into dest^ with upper case conversion 470 UpperCopy255W Copy WideChar source into dest^ with upper case conversion 470 UpperCopyShort Copy source into dest^ with 7 bits upper case conversion 470 UpperCopyWin255 Copy source into dest^ with WinAnsi 8 bits upper case conversion 470 UrlDecode Decode a string compatible with URI encoding into its original value 470 UrlDecode Decode a string compatible with URI encoding into its original value 470 UrlDecodeCardinal Decode a specified parameter compatible with URI encoding into its original cardinal numerical value 470 UrlDecodeExtended Decode a specified parameter compatible with URI encoding into its original floating-point value 471 UrlDecodeInt64 Decode a specified parameter compatible with URI encoding into its original Int64 numerical value 471 UrlDecodeInteger Decode a specified parameter compatible with URI encoding into its original integer numerical value 471 UrlDecodeNeedParamete rs Returns TRUE if all supplied parameters does exist in the URI encoded text 471 UrlDecodeNextNameValu e Decode the next Name=Value&.Rev.. pair from input URI 471 UrlDecodeNextValue Decode a URI-encoded Value from an input buffer 471 UrlDecodeValue Decode a specified parameter compatible with URI encoding into its original textual value 472 UrlEncode Encode a string to be compatible with URI encoding 472 UTF16CharToUtf8 UTF-8 encode one UTF-16 encoded UCS4 character into Dest 472 SynCommons. e. UTF-8 encoded in source^ 473 UTF8ToWideChar Convert an UTF-8 encoded text into a WideChar array 474 UTF8ToWideChar Convert an UTF-8 encoded text into a WideChar array 474 UTF8ToWideString Convert any UTF-8 encoded String into a generic WideString Text 474 UTF8ToWideString Convert any UTF-8 encoded String into a generic WideString Text 474 UTF8ToWideString Convert any UTF-8 encoded String into a generic WideString Text 474 Utf8ToWinAnsi Direct conversion of a UTF-8 encoded zero terminated buffer into a WinAnsi String 474 Utf8ToWinAnsi Direct conversion of a UTF-8 encoded string into a WinAnsi String 474 SynCommons.18 Page 427 of 1055 . the glyph count).18 Date: June 16. 2013 Functions or procedures Description Page Utf8DecodeToRawUnicod e Convert a UTF-8 encoded buffer into a RawUnicode string 472 Utf8DecodeToRawUnicod e Convert a UTF-8 string into a RawUnicode string 472 Utf8DecodeToRawUnicod eUI Convert a UTF-8 string into a RawUnicode string 472 Utf8DecodeToRawUnicod eUI Convert a UTF-8 string into a RawUnicode string 472 UTF8DecodeToString Convert any UTF-8 encoded buffer into a generic VCL Text 472 UTF8DecodeToString Convert any UTF-8 encoded buffer into a generic VCL Text 472 Utf8FirstLineToUnicod eLength Calculate the character count of the first line UTF-8 encoded in source^ 473 UTF8IComp Fast UTF-8 comparaison using the NormToUpper[] array for all 8 bits values 473 UTF8ILComp Fast UTF-8 comparaison using the NormToUpper[] array for all 8 bits values 473 Utf8ToRawUTF8 Direct conversion of a UTF-8 encoded zero terminated buffer into a RawUTF8 String 473 UTF8ToShortString Direct conversion of a UTF-8 encoded buffer into a WinAnsi shortstring buffer 473 UTF8ToString Convert any UTF-8 encoded String into a generic VCL Text 473 UTF8ToSynUnicode Convert any UTF-8 encoded buffer into a generic SynUnicode Text 473 UTF8ToSynUnicode Convert any UTF-8 encoded String into a generic SynUnicode Text 473 UTF8ToSynUnicode Convert any UTF-8 encoded String into a generic SynUnicode Text 473 Utf8ToUnicodeLength Calculate the Unicode character count (i.Rev.pas unit .Synopse mORMot Framework Software Architecture Design 1. 1. 18 Date: June 16. Value: integer. using the NormToUpper[] array for all 8 bits values. 2013 Functions or procedures Description Page UTF8ToWinPChar Direct conversion of a UTF-8 encoded buffer into a WinAnsi PAnsiChar buffer 474 UTF8UpperCopy Copy WideChar source into dest^ with upper case conversion.18 Page 428 of 1055 .Rev.true if Value was added successfully in Values[]. encoding the result as UTF-8 474 VariantToUTF8 Convert any Variant into UTF-8 encoded String 475 VariantToUTF8 Convert any Variant into UTF-8 encoded String 475 VarRecToUTF8 Convert an open array (const Args: array of const) argument to an UTF-8 encoded text 475 WideCharToUtf8 UTF-8 encode one UTF-16 character into Dest 475 WideCharToWinAnsi Conversion of a wide char into a WinAnsi (CodePage 1252) char index 475 WideCharToWinAnsiChar Conversion of a wide char into a WinAnsi (CodePage 1252) char 475 WideStringToUTF8 Convert a WideString into a UTF-8 string 475 WideStringToWinAnsi Convert a WideString into a WinAnsi (code page 1252) string 475 WinAnsiBufferToUtf8 Direct conversion of a WinAnsi PAnsiChar buffer into a UTF-8 encoded buffer 475 WinAnsiToRawUnicode Direct conversion of a WinAnsi (CodePage 1252) string into a Unicode encoded String 475 WinAnsiToUnicodeBuffe r Direct conversion of a WinAnsi (CodePage 1252) string into a Unicode buffer 475 WinAnsiToUtf8 Direct conversion of a WinAnsi (CodePage 1252) string into a UTF-8 encoded String 476 WinAnsiToUtf8 Direct conversion of a WinAnsi (CodePage 1252) string into a UTF-8 encoded String 476 WriteStringToStream Write an UTF-8 text into a TStream 476 YearToPChar Add the 4 digits of integer Y to P^ 476 function AddInteger(var Values: TIntegerDynArray. using the NormToUpper[] array for all 8 bits values.this overloaded function will use a separate Count variable (faster) . 1. overload. var ValuesCount: integer. Add an integer value at the end of a dynamic array of integers .Synopse mORMot Framework Software Architecture Design 1. NoDuplicates: boolean=false): boolean. in this case length(Values) will be increased SynCommons. encoding the result as UTF-8 474 UTF8UpperCopy255 Copy WideChar source into dest^ with upper case conversion.pas unit . PreTwo.returns the index where the Value was added successfully in Values[] .Synopse mORMot Framework Software Architecture Design 1. this index can be set to optional ForceIndex parameter . Value: integer. Add a RawUTF8 value in an alphaticaly sorted dynamic array of RawUTF8 . Convert any Ansi 7 bit encoded String into a generic VCL Text . ACP: integer). you can specify a custom compare function if needed in Compare optional parameter function Ansi7ToString(Text: PWinAnsiChar.'): RawUTF8.Rev. in this case length(Values) will be increased function AddPrefixToCSV(CSV: PUTF8Char.18 Date: June 16.Two. overload. exact (case-sensitive) match is used. const Prefix: RawUTF8. var ValuesCount: integer. NoDuplicates: boolean=false): boolean.by default.returns -1 if the specified Value was alredy present in Values[] (we must avoid any duplicate for binary search) .the Text content must contain only 7 bit pure ASCII characters function Ansi7ToString(const Text: RawByteString): string. Add an integer value in a sorted dynamic array of integers . its content will be moved to allow inserting a new value at CoValues[result] position function AddSortedRawUTF8(var Values: TRawUTF8DynArray.the Text content must contain only 7 bit pure ASCII characters procedure AnsiCharToUTF8(P: PAnsiChar. Fast WinAnsi comparaison using the NormToUpper[] array for all 8 bits values SynCommons.pas unit . True if Value was added successfully in Values[] function AddSortedInteger(var Values: TIntegerDynArray. NoDuplicates: boolean=false. Str2: PWinAnsiChar): PtrInt. 2013 function AddInteger(var Values: TIntegerDynArray. L: Integer. Add an integer value at the end of a dynamic array of integers .PreThree' function AddRawUTF8(var Values: TRawUTF8DynArray. CoValues: PIntegerDynArray=nil. Compare: TUTF8Compare=nil): PtrInt. Len: integer): string. Convert an AnsiChar buffer (of a given code page) into a UTF-8 string function AnsiIComp(Str1. const Value: RawUTF8. Value: integer. var ValuesCount: integer. var result: RawUTF8. CaseSensitive: boolean=true): boolean. overload. ForcedIndex: PtrInt=-1. its content will be moved to allow inserting a new value at CoValues[result] position . const Value: RawUTF8.if CoValues is set.18 Page 429 of 1055 . Append some prefix to all CSV values AddPrefixToCSV('One.returns -1 if the specified Value was alredy present in Values[] (we must avoid any duplicate for binary search) . CoValues: PIntegerDynArray=nil): PtrInt. 1. overload.Three'.a typical usage of CoValues is to store the corresponding ID to each RawUTF8 item .'Pre')='PreOne. Sep: AnsiChar = '.if CoValues is set.true if Value was added successfully in Values[]. Convert any Ansi 7 bit encoded String into a generic VCL Text .returns the index where the Value was added successfully in Values[] .if FastLocatePUTF8CharSorted() has been already called. Buffer: pointer.faster than SetString(tmp.otherwize. Fast conversion from binary data into Base64 encoded text function BinToBase64(Bin: PAnsiChar. len: PtrInt): RawByteString. overload. u2: PWideChar): PtrInt. Fast add some characters from a RawUTF8 string into a given buffer procedure AppendToTextFile(aLine: RawUTF8. Log a message to a local text file .Buffer. BufferLen: PtrInt). Fast conversion from binary data into Base64 encoded text with JSON_BASE64_MAGIC prefix (UTF-8 encoded \uFFF0 special code) SynCommons.. 1. overload. Append some text lines with the supplied Values[] . const aFileName: TFileName).will trim any right-sided '=' unsignificant characters. then the Msg on one line . compare 'a'. Fast conversion from binary data into Base64 encoded text function BinToBase64URI(Bin: PAnsiChar. len: PtrInt): PtrInt.Rev.this version expects u1 and u2 to be zero-terminated procedure AppendBufferToRawUTF8(var Text: RawUTF8.'z' as 'A'. Fast conversion from binary data into Base64-like URI-compatible encoded text .. overload. const Text: RawUTF8): PUTF8Char. const Values: array of string. Fast case-insensitive Unicode comparaison .'Z' . Text := Text+tmp.use the NormToUpperAnsi7Byte[] array. Fast conversion from Base64 encoded text into binary data function Base64ToBinLength(sp: PAnsiChar.rp: PAnsiChar. BinBytes: integer): RawByteString. len: PtrInt).18 Date: June 16.18 Page 430 of 1055 .pas unit . appends 'Caption: Value'. overload. const AppendBefore: string=#13#10). Fast conversion from Base64 encoded text into binary data function Base64ToBin(const s: RawByteString): RawByteString. with Caption taken from CSV function AppendRawUTF8ToBuffer(Buffer: PUTF8Char. Fast add some characters to a RawUTF8 string . Direct decoding of a Base64 encoded buffer function Base64ToBin(sp: PAnsiChar. procedure AppendCSVValues(const CSV: string.this version expect the filename to be specified . 2013 function AnsiICompW(u1.BufferLen).format contains the current date and time. i. and replace '+' or '/' by '_' or '-' function BinToBase64WithMagic(const s: RawByteString): RawByteString.e.date and time format used is 'YYYYMMDD hh:mm:ss' procedure Base64Decode(sp. BinBytes: integer): RawByteString. no line is added .Synopse mORMot Framework Software Architecture Design 1. var Result: string. Retrieve the expected length of a Base64 encoded buffer function BinToBase64(const s: RawByteString): RawByteString.if any Values[] item is ''. overload. SBF must point to the values encoded in our SBF compact binary format .if SBFEnd is not nil. Convert a char set to a code page function CodePageToCharSet(CodePage: Cardinal): Integer. tftUInt16. tftInt32.pas unit . SBF. DataLen: integer): RawByteString. ready to be displayed . Fast conversion from binary data into hexa chars . tftInt64 and tftCurrency field types . Fast conversion from binary data into hexa chars procedure BinToHexDisplay(Bin. Hex: PAnsiChar. SBFEnd: PUTF8Char. overload. Oper: TCompareOperator): boolean. Use our fast asm version of CompareMem() function CompareOperator(FieldType: TSynTableFieldType. Revert the value as encoded by TTextWriter. Fast conversion from binary data into hexa chars.soGreaterThanOrEqualTo operators .will work only for tftBoolean.. P2: Pointer. 2013 function BinToBase64WithMagic(Data: pointer. overload.returns true if both values match. Length: Integer): Boolean. 1. Value: Int64. Convert a code page to a char set function CompareMem(P1.BinBytes contain the bytes count to be converted: Hex^ must contain enough space for at least BinBytes*2 chars . BinBytes: integer).BinBytes contain the bytes count to be converted: Hex^ must contain enough space for at least BinBytes*2 chars .AddInt18ToChars3() method function CharSetToCodePage(CharSet: integer): cardinal. overload.use internally BinToHexDisplay() function Chars3ToInt18(P: pointer): cardinal. tftUInt24. Low-level integer comparison according to a specified operator .18 Date: June 16..Value can be a Currency accessed via a PInt64 .Rev.will handle only soEqualTo.18 Page 431 of 1055 . it will test for all values until SBF>=SBFEnd (can be used for tftArray) . BinBytes: integer). Hex: PAnsiChar. tftUInt8. ready to be displayed .Synopse mORMot Framework Software Architecture Design 1.using this function with BinBytes^ as an integer value will encode it in low-endian order (less-signignifican byte first): don't use it for display function BinToHex(const Bin: RawByteString): RawUTF8. overload.Value must contain the plain integer value .using this function with Bin^ as an integer value will encode it in big-endian order (most-signignifican byte first): use it for display function CardinalToHex(aCardinal: Cardinal): RawUTF8. Fast conversion from binary data into Base64 encoded text with JSON_BASE64_MAGIC prefix (UTF-8 encoded \uFFF0 special code) procedure BinToHex(Bin. Fast conversion from a Cardinal data into hexa chars. or false otherwise SynCommons. .returns true if both values match. then sort it.. ValueLen: integer. Copy an integer array. Value: PUTF8Char. Low-level text comparison according to a specified operator .for soSoundsLikeEnglish.pas unit . const Table: TNormTableByte): PtrInt. SBFEnd: PUTF8Char.search up^ at the beginning of every UTF-8 word (aka in Soundex) . var Dest: TIntegerDynArray). low values first SynCommons.if SBFEnd is not nil.Synopse mORMot Framework Software Architecture Design 1. processing the internal GDI message loop and any Synchronize() pending notification . for proper work of console applications with interface-based service implemented as optExecInMainThread function ContainsUTF8(p. as FieldType defined for the SBF value) . soContains and soSoundsLike*) but soSoundsLike* won't make use of the CaseSensitive parameter . SBFEnd: PUTF8Char.convert the text in-place.will work only for tftWinAnsi and tftUTF8 field types .18 Page 432 of 1055 . it will test for all values until SBF>=SBFEnd (can be used for tftArray) . 1...Value must contain the plain text value. Fast conversion of the supplied text into 8 bit case sensitivity .18 Date: June 16.up^ must be already Upper function ConvertCaseUTF8(P: PUTF8Char. or false otherwise function CompareOperator(FieldType: TSynTableFieldType. Oper: TCompareOperator): boolean. returns the resulting length .soGreaterThanOrEqualTo operators . soSoundsLikeFrench and soSoundsLikeSpanish operators.here a "word" is a Win-Ansi word.will not set the last char to #0 (caller must do that if necessary) procedure CopyAndSortInteger(Values: PIntegerArray. 'A'. Value: double. Oper: TCompareOperator. overload. SBF.e. Return true if up^ is contained inside the UTF-8 buffer p^ .will handle only soEqualTo. up: PUTF8Char): boolean.g. Value is not a real PUTF8Char but a prepared PSynSoundEx . or false otherwise procedure ConsoleWaitForEnterKey.SBF must point to the values encoded in our SBF compact binary format . in the same encoding (either WinAnsi either UTF-8. Low-level floating-point comparison according to a specified operator .will work only for tftDouble field type .if SBFEnd is not nil.to be used e. it will test for all values until SBF>=SBFEnd (can be used for tftArray) .it will decode the supplied UTF-8 content to handle more than 7 bit of ascii characters during the conversion (leaving not WinAnsi characters untouched) . Will wait for the ENTER key to be pressed.SBF must point to the values encoded in our SBF compact binary format . ValuesCount: integer.will handle all kind of operators (including soBeginWith. overload. i.Rev. CaseSensitive: boolean): boolean. 2013 function CompareOperator(SBF.returns true if both values match.'Z' .Value must contain the plain floating-point value . '0'.'9'. Dest: PUTF8Char): PtrInt. 1. define such a method in any object definition: procedure WMCopyData(var Msg : TWMCopyData). message WM_COPYDATA.'). FirstChar: AnsiChar='T'): RawUTF8. returns '' . returns the ISO-8601 date and time encoded as 'YYYY-MM-DDThh:mm:ss' . Convert a currency value from its Int64 binary representation into its numerical text equivalency function DateTimeToIso8601(D: TDateTime.g.18 Date: June 16. Count: cardinal. returns the date encoded as 'YYYY-MM-DD' .return the number of chars written to Dest^ function Curr64ToStr(Value: Int64): RawUTF8. Expanded: boolean.?.Rev. 2013 function CreateInternalWindow(const aWindowName: string.use 'YYYY-MM-DDThh:mm:ss' format if Expanded function DateTimeToIso8601Text(DT: TDateTime. 2 decimals.decimals are joined by 2 (no decimal. Write a TDateTime into strict ISO-8601 date and/or time text . Basic Date/Time conversion into ISO-8601 .this type is compatible with Delphi currency memory map with PInt64(@Curr)^ .otherwize.pas unit .NormalizeValue() methods SynCommons. Convert an INTEGER Curr64 (value*10000) into a string . Return a CSV list of the iterated same value .fast conversion. function CSVOfValue(const Value: RawUTF8. Sep: AnsiChar = '.g.Synopse mORMot Framework Software Architecture Design 1.fast conversion. Add the strings in the specified CSV text into a dynamic array of integer procedure CSVToRawUTF8DynArray(CSV: PUTF8Char. Convert an INTEGER Curr64 (value*10000) into a string . var Result: TRawUTF8DynArray.if DT=0. This function can be used to create a GDI compatible window. CSVOfValue('?'.GetValue() and TPropInfo.this type is compatible with Delphi currency memory map with PInt64(@Curr)^ . Add the strings in the specified CSV text into a dynamic array of UTF-8 strings function Curr64ToPChar(Value: Int64.used e. or the created HWND handle on success . 2 decimals. by TPropInfo. FirstChar: AnsiChar='T'): RawUTF8. using only integer operations .use 'YYYYMMDDThhmmss' format if not Expanded . 4 decimals) function Curr64ToString(Value: Int64): string.if DT contains only a time.decimals are joined by 2 (no decimal. var Result: TIntegerDynArray).'): RawUTF8. 4 decimals) .3)='?.). returns the time encoded as 'Thh:mm:ss' .will return 0 on failure (window name already existing e.?' procedure CSVToIntegerDynArray(CSV: PUTF8Char. able to receive GDI messages for fast local communication . const Sep: RawUTF8='.it will call the supplied message handler defined for a given GDI message: for instance.g.18 Page 433 of 1055 .e. aObject: TObject): HWND. using only integer operations .if DT contains only a date. D: cardinal).use 'YYYY-MM-DD' format if Expanded function DateToIso8601(Y.4))]). overload.[DateTimeToSQL(Now)]).CreateAndFillPrepare(Client. 'YYYY-MM-DD' date format is used function DateToIso8601Text(Date: TDateTime): RawUTF8.g.' pattern) . Y. Write a Date to P^ Ansi buffer . 'YYYY-MM-DD' date format is used procedure DateToIso8601PChar(P: PUTF8Char.. as in: aRec. SynCommons.M. Expanded: boolean.' pattern) .18 Page 434 of 1055 . returns the date encoded as '\uFFF1YYYY-MM-DD' .resulting text is compatible with all ISO-8601 functions function DateToSQL(Date: TDateTime): RawUTF8.therefore ':("\uFFF12012-05-04"):' pattern will be recognized as a sftDateTime inline parameter in SQLParamContent() / ExtractInlineParameters() functions (JSON_SQLDATE_MAGIC will be used as prefix to create '\uFFF1.'Datum=?'.. overload.Rev.use 'YYYYMMDD' format if not Expanded .to be used e.to be used e. returns '' . Expanded: boolean): RawUTF8.if Expanded is false.[DateToSQL(EncodeDate(2012..otherwize.5. Expanded: boolean). Convert a date into 'YYYY-MM-DD' date format .if DT=0. Basic Date conversion into ISO-8601 . 2013 function DateTimeToSQL(DT: TDateTime): RawUTF8.M.if Expanded is true.pas unit .18 Date: June 16. Convert a date to a ISO-8601 string format for SQL '?' inlined parameters .CreateAndFillPrepare(Client.use 'YYYYMMDD' format if not Expanded . returns the time encoded as '\uFFF1Thh:mm:ss' . Basic Date conversion into ISO-8601 .D: cardinal.g. P: PUTF8Char..'Datum<=?'. overload. overload. 1. as in: aRec. 'YYYYMMDD' date format is used .will return the date encoded as '\uFFF1YYYY-MM-DD' . Expanded: boolean): RawUTF8. 'YYYYMMDD' date format is used .use 'YYYY-MM-DD' format if Expanded procedure DateToIso8601PChar(Date: TDateTime.if Expanded is true. Convert a date/time to a ISO-8601 string format for SQL '?' inlined parameters .if DT contains only a date. function DateToIso8601(Date: TDateTime. Write a Date to P^ Ansi buffer . overload. returns the ISO-8601 date and time encoded as '\uFFF1YYYY-MM-DDThh:mm:ss' (JSON_SQLDATE_MAGIC will be used as prefix to create '\uFFF1.Synopse mORMot Framework Software Architecture Design 1.if Expanded is false.if DT contains only a time. Delete any integer in Values[] function DeleteRawUTF8(var Values: TRawUTF8DynArray.4)]). then the [Section] line is also deleted together with its content lines . Index: PtrInt). Index: integer.will return the date encoded as '\uFFF1YYYY-MM-DD' .to be used e. Delete the content of a specified directory .if CoValues is set.return TRUE if something was changed in Content .*'): Boolean.Day: cardinal): RawUTF8.if the exception inherits from ESynException . 2013 function DateToSQL(Year. const SectionName: RawUTF8. including any Exception. the integer item at the same index is also deleted function DeleteSection(var Content: RawUTF8. EraseSectionHeader: boolean=true): boolean.returns TRUE: caller will then append ' at EAddr' and the stack trace procedure DeleteInteger(var Values: TIntegerDynArray. var Content: RawUTF8.18 Page 435 of 1055 .only one level of file is deleted within the folder: no recursive deletion is processed by this function SynCommons. const Mask: TFileName='*. 1.CreateAndFillPrepare(Client. Index: PtrInt).therefore ':("\uFFF12012-05-04"):' pattern will be recognized as a sftDateTime inline parameter in SQLParamContent() / ExtractInlineParameters() functions (JSON_SQLDATE_MAGIC will be used as prefix to create '\uFFF1. overload.if EraseSectionHeader is TRUE (default).Rev. overload.' pattern) ..SectionFirstLine may have been obtained by FindSectionFirstLine() function above function DirectoryDelete(const Directory: TFileName. overload. then the [Section] line is also deleted together with its content lines .return FALSE if [Section] doesn't exist or is already void function DeleteSection(SectionFirstLine: PUTF8Char.g. as in: aRec.pas unit .18 Date: June 16. var ValuesCount: Integer. function DefaultSynLogExceptionToStr(WR: TTextWriter.'Datum=?'.[DateToSQL(2012.return TRUE if something was changed in Content .Message ..Month. const Context: TSynLogExceptionContext): boolean. Delete a RawUTF8 item in a dynamic array of RawUTF8 . EraseSectionHeader: boolean=true): boolean.5. Convert a date to a ISO-8601 string format for SQL '?' inlined parameters .if EraseSectionHeader is TRUE (default). Delete any integer in Values[] procedure DeleteInteger(var Values: TIntegerDynArray. Default exception logging callback . var ValuesCount: integer.will add the default Exception details.return FALSE if [Section] doesn't exist or is already void .Synopse mORMot Framework Software Architecture Design 1. Delete a whole [Section] . Delete a whole [Section] . CoValues: PIntegerDynArray=nil): boolean. overload. overload. EndOfObject: PUTF8Char=nil): PUTF8Char. var aValue. because the dynamic array won't need to be resized each time .pas unit .a typical usage could be: var A: TIntegerDynArray.the dynamic array must have been defined with its own type (e. but proprietary SynCommons.log files using our proprietary SynLZ format .to be used e. it will be used instead of length() to store the dynamic array items count it will be much faster when adding elements to the array.Rev.g..Value shall be set to the target dynamic array field .if aCountPointer is set. creating a temporary TDynArray wrapper on the stack . DirectoryExists returns a boolean value that indicates whether the specified directory exists (and is actually a directory) function DoubleToStr(Value: Double): RawUTF8. Convert a floating-point value to its numerical text equivalency function DoubleToString(Value: Double): string.log textual file . or the current aCountPointer^ value is . within a TDynArrayJSONCustomReader callback function EventArchiveDelete(const aOldLogFileName. aCountPointer: PInteger=nil): TDynArray.is just a wrapper around TDynArray. A TSynLogArchiveEvent handler which will delete older . Initialize the structure with a one-dimension dynamic array .LoadFromJSON(). Fill a dynamic array content from a JSON serialization as saved by TTextWriter. A TSynLogArchiveEvent handler which will compress older .g. TypeInfo: pointer. TIntegerDynArray = array of Integer) . 2013 function DirectoryExists(const Directory: string): Boolean. not the items count . you should use the Count property instead of length(array) or high(array) when accessing the data: in fact length(array) will store the memory size reserved.use UnSynLZ.synlz extension and will be located in the aDestinationPath directory. aDestinationPath: TFileName): boolean.e.if aCountPointer is set.. begin with DynArray(TypeInfo(TIntegerDynArray). for custom record JSON unserialization.but in this case. function DynArrayLoadJSON(var Value. 1. its content will be set to 0. Convert a floating-point value to its numerical text equivalency function DynArray(aTypeInfo: pointer.dpr tool to uncompress it into .log files function EventArchiveSynLZ(const aOldLogFileName. JSON: PUTF8Char. i.Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16.AddDynArrayJSON .A) do begin (. whatever the array length is. aDestinationPath: TFileName): boolean.18 Page 436 of 1055 .SynLZ is much faster than zip for compression content.ArchivePath+'\log\YYYYMM\' .) end.resulting file will have the . TSynLogFamily. pas unit .e. ItemComp: TUTF8Compare): PtrInt. var SortedIndexes: TCardinalDynArray. Return TRUE if Value of UpperName does exist in P. till end of current section . ['TEXT/'. Fast binary search of an integer value in a sorted integer array . R: PtrInt.recognized types are sptInteger. Precision: integer): RawUTF8. Count-1) .return -1 if Value was not found SynCommons. var Types: TSQLParamTypeDynArray. as 'CONTENT-TYPE: ' . till end of current section .'APPLICATION/JSON']). as used by IsHTMLContentTypeTextual() function: result := ExistsIniNameValue(htmlHeaders.Synopse mORMot Framework Software Architecture Design 1.') . Alias to ExcludeTrailingBackslash() function procedure ExeVersionRetrieve(DefaultVersion: integer=0).'). e. const UpperValues: array of RawUTF8): boolean. function ExtendedToStr(Value: Extended.expect UpperName as 'NAME=' function ExistsIniNameValue(P: PUTF8Char.return index of P^[index]=Value .g. var maxParam: integer. Value: Extended. sptDateTime ('\uFFF1.HEADER_CONTENT_TYPE_UPPER.g. Initialize ExeVersion global variable. if not already done function ExistsIniName(P: PUTF8Char.Rev.. Return TRUE if one of the Value of UpperName exists in P. Precision: integer): integer. 2013 function ExcludeTrailingPathDelimiter(const FileName: TFileName): TFileName. const UpperName: RawUTF8. Value: integer): PtrInt.expect UpperValues to be any upper value with left side matching. This function will extract inlined :(1234): parameters into Types[]/Values[] .sptUnknown is returned on invalid content function FastFindIndexedPUTF8Char(P: PPUTF8CharArray. var Nulls: TSQLFieldBits): RawUTF8. Convert a floating-point value to its numerical text equivalency function ExtendedToString(var S: ShortString. var Values: TRawUTF8DynArray. Convert a floating-point value to its numerical text equivalency . 1..18 Page 437 of 1055 .call internaly SQLParamContent() function for inline parameters decoding .returns the count of chars stored into S (S[0] is not set) function ExtractInlineParameters(const SQL: RawUTF8.will return the generic SQL statement with ? instead of :(1234): .R is the last index of available integer entries in P^ (i.. UpperName: PUTF8Char): boolean. sptUTF8Text and sptBlob ('\uFFF0.will set maxParam=0 in case of no inlined parameters .expect UpperName e. sptFloat.18 Date: June 16. R: PtrInt. Retrieve the index of a PUTF8Char in a PUTF8Char array via a sort indexed function FastFindIntegerSorted(P: PIntegerArray. Value: PUTF8Char.. Retrieve the index where to insert an integer value in a sorted integer array . const FileName: TFileName..R is the last index of available entries in P^ (i. overload. R: PtrInt.first char must be alphabetical.i.Z.returns -1 if the specified Value was found (i. R: PtrInt. Retrieve the index where to insert a PUTF8Char in a sorted PUTF8Char array .e. Retrieve the index where is located a PUTF8Char in a sorted PUTF8Char array .returns -1 if the specified Value was not found function FastFindPUTF8CharSorted(P: PPUTF8CharArray.R is the last index of available integer entries in P^ (i. FlushOnDisk: boolean=false): boolean.e. overload. adding will duplicate a value) function FieldNameValid(P: PUTF8Char): boolean. R: PtrInt.returns 0 if file doesn't exist function FileFromString(const Content: RawByteString. Value: integer): PtrInt.Rev. Retrieve the index where is located a PUTF8Char in a sorted PUTF8Char array . Returns TRUE if the given text buffer contains A. adding will duplicate a value) function FastLocatePUTF8CharSorted(P: PPUTF8CharArray.e.9 characters .returns -1 if the specified Value was found (i. Value: PUTF8Char): PtrInt.e.pas unit . overload.e.18 Date: June 16.string comparison is case-sensitive (so will work with any PAnsiChar) . Compare: TUTF8Compare): PtrInt. Retrieve the index where to insert a PUTF8Char in a sorted PUTF8Char array . can be tested via IdemPropName() functions . Count-1) . Count-1) . R: PtrInt. Get the file date and time .R is the last index of available entries in P^ (i. Value: PUTF8Char): PtrInt.returns -1 if the specified Value was not found function FastLocateIntegerSorted(P: PIntegerArray. adding will duplicate a value) function FastLocatePUTF8CharSorted(P: PPUTF8CharArray. Count-1) .0.uses RawByteString for byte storage.returns -1 if the specified Value was found (i. R: PtrInt. thatever the codepage is SynCommons..R is the last index of available entries in P^ (i. overload. Value: PUTF8Char.18 Page 438 of 1055 .string comparison is case-sensitive (so will work with any PAnsiChar) .e. Count-1) . 1.this overloaded function accept a custom comparison function for sorting . Count-1) .string comparison is case-sensitive (so will work with any PAnsiChar) . following chars can be alphanumerical function FileAgeToDateTime(const FileName: TFileName): TDateTime.e. 2013 function FastFindPUTF8CharSorted(P: PPUTF8CharArray.string comparison is case-sensitive (so will work with any PAnsiChar) .R is the last index of available entries in P^ (i. Compare: TUTF8Compare): PtrInt.Synopse mORMot Framework Software Architecture Design 1. Value: PUTF8Char.e. Create a File from a string content .e. Dest: TFileName. Find a Name= Value in a [Section] of a INI RawUTF8 Content .. find the Name= value before any [Section] function FindIniEntryFile(const FileName: TFileName. Section.this function scans the Content memory buffer. Dest: TFileName.returns 0 if file doesn't exist function FileSynLZ(const Source. Count: Integer. Find a Name= Value in a [Section] of a . Section. CaseSensitive: boolean=true): integer. 1. Count: integer). working with huge files .use internaly fast FindIniEntry() function above function FindIniEntryInteger(const Content.Delphi RTL will be patched in memory to run this faster version procedure FillIncreasing(Values: PIntegerArray. Magic: Cardinal): boolean.pas unit . const Value: RawUTF8. Faster implementation of FillChar() for Delphi versions with no FastCode inside . find the Name= value before any [Section] SynCommons. 2013 function FileSeek64(Handle: THandle. Return true if UpperValue (Ansi) is contained in A^ (Ansi) .'. not inside words function FindCSVIndex(CSV: PUTF8Char. Return the index of a Value in a CSV string . Sep: AnsiChar = '. Value: Byte).source file is split into 128 MB blocks for fast in-memory compression of any file size .INI file .Name: RawUTF8): integer.i+1.if Section equals ''.Name: RawUTF8): RawUTF8.find UpperValue starting at word beginning.Name: RawUTF8): RawUTF8. const Offset: Int64. Origin: cardinal): Int64.i+Count-1 function FindAnsi(A.if Section equals ''. Compress a file content using the SynLZ algorithm a file content . Magic: Cardinal): boolean. Get the file size .start at Index=0 for first one .Delphi FileSeek() is buggy -> use this function to safe access files > 2 GB (thanks to sanyin for the report) function FileSize(const FileName: TFileName): Int64. FileSeek() overloaded function. StartValue.18 Date: June 16. or 0 if not found .Rev. Find a Name= numeric Value in a [Section] of a INI RawUTF8 Content and return it as an integer.this function scans the Content memory buffer.return -1 if specified Value was not found in CSV items function FindIniEntry(const Content. and is therefore very fast (no temporary TMemIniFile is created) . Fill some values with i. const Section.18 Page 439 of 1055 .you should specify a Magic number to be used to identify the compressed file format procedure FillChar(var Dest. UpperValue: PAnsiChar): boolean.you should specify a Magic number to be used to identify the compressed file format function FileUnSynLZ(const Source.i+2..if Section equals ''. Compress a file content using the SynLZ algorithm a file content . find the Name= value before any [Section] . and is therefore very fast (no temporary TMemIniFile is created) .Synopse mORMot Framework Software Architecture Design 1. but the value is converted from WinAnsi into UTF-8 SynCommons. UpperValue: PAnsiChar): boolean.expect UpperName as 'NAME=' . CaseSensitive: boolean=true): integer.18 Date: June 16. Name: RawUTF8): RawUTF8.pas unit . i. search: PUTF8Char): boolean. Find the position of the [SEARCH] section in source . Retrieve a property value in a text-encoded class .ini . Return the index of Value in Values[].follows the Delphi serialized text object format.returns nil if reached the end of U (i.if the property is a string. and store pointer to the line after it in source . and store pointer to the line after it in source function FindSectionFirstLineW(var source: PWideChar. Points to the beginning of the next word stored in U .find UpperValue starting at word beginning.Name: RawUTF8): RawUTF8.return 0 if no NAME= entry was found function FindNextUTF8WordBegin(U: PUTF8Char): PUTF8Char. 2013 function FindIniNameValue(P: PUTF8Char. Return true if Uppe (Unicode encoded) is contained in U^ (UTF-8 encoded) . Name: RawUTF8): RawUTF8.expect UpperName as 'NAME=' function FindIniNameValueInteger(P: PUTF8Char. Upper: PWideChar. -1 if not found function FindSectionFirstLine(var source: PUTF8Char.18 Page 440 of 1055 . Return true if UpperValue (Ansi) is contained in U^ (UTF-8 encoded) .this version expect source^ to point to an Unicode char array function FindUnicode(PW: PWideChar. not standard .Rev. till end of current section . const Value: RawUTF8.here a "word" is a Win-Ansi word.ini . Find the Value of UpperName in P. Find a Name= Value in a [Section] of a INI WinAnsi Content .return true if [SEARCH] was found.any file path and any extension are trimmed function FindRawUTF8(const Values: TRawUTF8DynArray..e. 'A'. not standard . #0 char) .'Z' function FindObjectEntry(const Content.same as FindIniEntry(). Retrieve a filename property value in a text-encoded class . '0'. search: PUTF8Char): boolean.'9'. till end of current section .e.UTF-8 decoding is done on the fly (no temporary decoding buffer is used) function FindWinAnsiIniEntry(const Content.Synopse mORMot Framework Software Architecture Design 1. 1. not inside words . Section. UpperName: PUTF8Char): integer.return true if [SEARCH] was found. the simple quotes ' are trimed .. the simple quotes ' are trimed function FindObjectEntryWithoutExt(const Content. UpperName: PUTF8Char): RawUTF8. UpperLen: integer): boolean.will use the slow but accurate Operating System API to perform the comparison at Unicode-level function FindUTF8(U: PUTF8Char. Find the integer Value of UpperName in P. Find the position of the [SEARCH] section in source .if the property is a string.follows the Delphi serialized text object format. e. handling % and ? parameters . handling special "inlined" parameters. therefore wrongly) function FormatUTF8(Format: PUTF8Char.only supported token is %. function FromVarInt64(var Source: PByte): Int64. i. if result>$7f then result := (result and $7F) or FromVarUInt32Up128(Source).18 Date: June 16. Params: array of const): RawUTF8. Convert a 32-bit variable-length integer buffer into a cardinal . as exected by mORMot. which will be inlined in the resulting string according to each Args[] supplied item . const Args: array of const): RawUTF8.pas unit.18 Page 441 of 1055 . Retrieve a variable-length text buffer function FromVarUInt32(var Source: PByte): cardinal. therefore wrongly) function FromVarInt32(var Source: PByte): integer. optimized for RawUTF8 .e. i. Convert a 64-bit variable-length integer buffer into a Int64 function FromVarString(var Source: PByte): RawUTF8. overload.this version must be called if Source^ has already been checked to be > $7f function FromVarUInt32Up128(var Source: PByte): cardinal.2=-1. :(1234): for numerical values.resulting string has no length limit and uses fast concatenation . Fast Format() function replacement.note that cardinal values should be type-casted to Int64() (otherwise the integer mapped value will be transmitted.decode negative values from cardinal two-complement.note that cardinal values should be type-casted to Int64() (otherwise the integer mapped value will be transmitted.Rev. inc(Source).resulting string has no length limit and uses fast concatenation . Convert a 32-bit variable-length integer buffer into a cardinal . 2013 function FormatUTF8(Format: PUTF8Char.maximum count of supplied argument in Args is 12 . 1. overload.this version must be called if Source^ has already been checked to be > $7f result := Source^.4=-2.pas unit .will inline Params[] for every ? in Format.3=2.. Convert a 64-bit variable-length integer buffer into a UInt64 SynCommons. Fast Format() function replacement. Convert a 32-bit variable-length integer buffer into an integer . Convert a 32-bit variable-length integer buffer into a cardinal function FromVarUInt32High(var Source: PByte): cardinal. const Args. function FromVarUInt64(var Source: PByte): QWord.1=1.Synopse mORMot Framework Software Architecture Design 1. and :('quoted '' string'): for textual values .will include Args[] for every % in Format .. 0=0.maximum count of supplied argument in Args is 12 . to use native CPU register size (don't want any 32 bits overflow here) function GetCardinalDef(P: PUTF8Char.pas unit . 'TSyn'.several bits set to one can be regrouped via 'first-last. Retrieve a particular bit status from a Int64 bit array (max aIndex is 63) function GetBitCSV(const Bits.to be used. even if expected to be 32 bits. UnCamelCase and translate the class name. aIndex: PtrInt): boolean. not byte size function GetCaptionFromClass(C: TClass): string.' . function GetBit(const Bits. BitsCount: integer): RawUTF8. out result: string). Get the unsigned 32 bits integer value stored as Unicode string in P^ SynCommons. triming any left 'T'.this may be useful when used when targetting Delphi IDE packages. as: if SynAnsiConvertList=nil then GarbageCollectorFreeAndNil(SynAnsiConvertList.Create). i.Synopse mORMot Framework Software Architecture Design 1. 'TSQL' or 'TSQLRecord' .e.P is expected to be #0 ended . i.' syntax . UnCamelCase and translate the enumeration item procedure GetCaptionFromPCharLen(P: PUTF8Char. to circumvent the bug of duplicated finalization of units.18 Date: June 16. 1.'. returns Default function GetCardinalW(P: PWideChar): PtrUInt.Rev.0' is always appended at the end of the CSV chunk to mark its end function GetBitsCount(const Bits. Convert a set of bit into a CSV content .g.18 Page 442 of 1055 .TObjectList.this list expects a pointer to the TObject instance variable to be specified. e.Count is the bit count. UnCamelCase and translate a char buffer . UnicodeString for Delphi 2009+ function GetCardinal(P: PUTF8Char): PtrUInt. Count: PtrInt): integer. Instance: TObject). 2013 procedure GarbageCollectorFreeAndNil(var InstanceVariable. aIndex: integer): string. Get the unsigned 32 bits integer value stored in P^ . Compute the number of bits set in a bit array . Default: PtrUInt): PtrUInt. UnicodeString for Delphi 2009+ function GetCaptionFromEnum(aTypeInfo: pointer. and separated by a '. A global "Garbage collector" for some TObject global variables which must live during whole main executable process . Retrieve a particular bit status from a bit array function GetBit64(const Bits. Get the unsigned 32 bits integer value stored in P^ . and will be set to nil (like a FreeAndNil) . in the scope of global variables .each bit is stored as BitIndex+1.return "string" type.return generic VCL string type. aIndex: PtrInt): boolean.e.we use the PtrInt result type.if P if nil or not start with a valid numerical value. is used e.will return any matching extension. Get the extended floating point value stored in P^ .set the err content to the index of any faulty character.will encode the class name as UTF-8 (for Unicode Delphi versions) . starting at Index=0 for first one .this function return the generic string type of the compiler. then compare with a comma separated list of extensions . GetFileVersion returns the most significant 32 bits of a file's binary version number . GetFileNameExtIndex('test.'): string. 2013 function GetCSVItem(P: PUTF8Char. overload. 'TSQL' or 'TSQLRecord' left side of the class name . Will get a class name as UTF-8 .Synopse mORMot Framework Software Architecture Design 1.map')=1 . but from inlined higher-level functions .g.here U^ shall be always >= #80 SynCommons.Rev. this includes the major and minor version placed together in one 32-bit integer .extension match is case-insensitive function GetFileNameWithoutExt(const FileName: TFileName): TFileName. Return the Delphi Compiler Version .It returns Cardinal(-1) if it failed function GetHighUTF8UCS4(var U: PUTF8Char): cardinal. 'TSyn'. Extract a file extension from a file name. 0 if conversion was successful (same as the standard val function) function GetExtended(P: PUTF8Char): extended. CSVExt: TFileName): integer.not to be called directly. overload. function GetDisplayNameFromClass(C: TClass): RawUTF8. Get the extended floating point value stored in P^ . the VCL) function GetDelphiCompilerVersion: RawUTF8. Internal function. starting count at 0 . to extract the SQL table name for a TSQLRecord class function GetEnumName(aTypeInfo: pointer. Sep: Char = '. Index: PtrUInt. aIndex: integer): PShortString. without its extension function GetFileVersion(const FileName: TFileName): cardinal.log'.pas unit . used to retrieve a UCS4 char (>127) from UTF-8 . Return n-th indexed CSV string in P.will return -1 if no file extension match .will trim 'T'.this overloaded version returns 0 as a result if the content of P is invalid function GetFileNameExtIndex(const FileName.'): RawUTF8.pas unit function GetExtended(P: PUTF8Char. 1.e.It generally does not include the release or build numbers .you'd better use RTTI related classes of mORMot.'exe.e.g. out err: integer): extended. Extract file name. Index: PtrUInt.log.18 Page 443 of 1055 .Typically. starting at Index=0 for first one function GetCSVItemString(P: PChar. and therefore can be used with ready to be displayed text (i. Sep: AnsiChar = '. Return n-th indexed CSV string in P. Helper to retrieve the text of an enumerate item .g.returns 'Delphi 2007' or 'Delphi 2010' e.18 Date: June 16. ' ':' or '}' e. Get the 64 bits integer value stored in P^ . 0 if conversion was successful (same as the standard val function) function GetInt64(P: PUTF8Char): Int64.Create) .18 Date: June 16.end counting at either #0.g. not its exact index as for the val() function .Rev.null is decoded as nil . function GetLineSize(P.1. overload.works for both field names or values (e. overload.we use the PtrInt result type.any integer value is left as its ascii representation . or nil on any unexpected end .set the err content to the index of any faulty character. to use native CPU register size (don't want any 32 bits overflow here) function GetJSONField(P: PUTF8Char. Get the 64 bits integer value stored in P^ function GetInteger(P: PUTF8Char. even if expected to be 32 bits.so take care that it is an unique string .PDest points to the next field to be decoded. Decode a JSON field in an UTF-8 encoded buffer (used in TSQLTableJSON. 2013 function GetInt64(P: PUTF8Char.Synopse mORMot Framework Software Architecture Design 1. even if expected to be 32 bits.EndOfObject (if not nil) is set to the JSON value char ('. EndOfObject: PUTF8Char=nil): PUTF8Char. overload. and 1 if an invalid character was found.this function decodes in the P^ buffer memory itself (no memory allocation or copy). Compute the line length from source array of chars . #13 or #10 function GetLineSizeSmallerThan(P.PEnd: PUTF8Char): PtrUInt.'"strings"' are decoded as 'strings' .2 (page 1049). var err: integer): Int64.PEnd: PUTF8Char. overload. var err: integer): PtrInt.wasString is set to true if the JSON value was a "string" . Returns true if the line length from source array of chars is not less than the specified count SynCommons. Get the signed 32 bits integer value stored in P^ . out PDest: PUTF8Char.strings are JSON unescaped (and \u0123 is converted to UTF-8 chars) .this version return 0 in err if no error occured.we use the PtrInt result type. Get the signed 32 bits integer value stored in P^ .pas unit .g. aMinimalCount: integer): boolean. to use native CPU register size (don't want any 32 bits overflow here) function GetInteger(P: PUTF8Char): PtrInt. wasString: PBoolean=nil. 1.') .18 Page 444 of 1055 .) Used for DI-2. for faster process . '"FieldName":' or 'Value. Return line begin from source array of chars. Return next CSV string as double from P.OutBody). function GetModuleName(Module: HMODULE): TFileName.OutHead := HEADER_CONTENT_TYPE+ GetMimeContentType(pointer(Call. Sep: AnsiChar= '. nil if no more . Extract a line from source array of chars . 2013 function GetMimeContentType(Content: Pointer. for the VCL) function GetNextLine(source: PUTF8Char.return the MIME type.0 if no more procedure GetNextItemShortString(var P: PUTF8Char. 1.g.P^ will point to the first non digit character (the item separator.this version expect P^ to point to an Unicode char array function GetNextItemDouble(var P: PUTF8Char. out Dest: ShortString. and go to next line . or nil if source if ended function GetNextLineBegin(source: PUTF8Char. Retrieve the full path name of the given execution module (e. out next: PUTF8Char): PUTF8Char.can be used as such: Call.g. or nil if source if ended function GetNextStringLineToRawUnicode(var P: PChar): RawUnicode.OutBody). and therefore can be used with ready to be displayed text (e. nil if no more function GetNextItemString(var P: PChar.default is 'application/octet-stream' or 'application/extension' if FileName was specified .next will contain the beginning of next line.Rev.'): PtrUInt. e.Synopse mORMot Framework Software Architecture Design 1.' for CSV) function GetNextItemCardinalW(var P: PWideChar.org/wiki/Internet_media_type for most common values . Sep: AnsiChar= '. 0. Sep: AnsiChar= '.this function returns RawUnicode string type SynCommons.this function returns the generic string type of the compiler. Len: integer. Return next CSV string from P.18 Date: June 16. 0 if no more .Length(Call.'): string. Sep: WideChar= '. Return next CSV string as unsigned integer from P.'): PtrUInt. Return next string delimited with #13#10 from P.'): double. nil if no more function GetNextItemCardinal(var P: PUTF8Char.see @http://en.wikipedia.pas unit . nil if no more . Return next CSV string as unsigned integer from P. Sep: AnsiChar= '. Return next CSV string from P. 0 if no more . Retrieve the MIME content type from a supplied binary buffer . Return next CSV string as unsigned integer from P.18 Page 445 of 1055 .aFileName). library) function GetNextItem(var P: PUTF8Char.g. ready to be appended to a 'Content-Type: ' HTTP header . Return next CSV string from P.next will contain the beginning of next line. const FileName: TFileName=''): RawUTF8.'): RawUTF8. Sep: Char= '. 0 if no more function GetNextItemCardinalStrict(var P: PUTF8Char): PtrUInt.'). out next: PUTF8Char): RawUTF8. '. SectionFirstLine may have been obtained by FindSectionFirstLine() function above function GetSectionContent(const Content.any surrogate (UCS4>$ffff) will be returned as '?' function GotoEndOfQuotedString(P: PUTF8Char): PUTF8Char. Retrieve the next UCS4 value stored in U. SectionName: RawUTF8): RawUTF8.first char is expected to be either [ either { . } ] function GotoNextJSONObjectOrArray(P: PUTF8Char): PUTF8Char.pas unit .output points to nil (unexpected end) or the ending '"' character function GotoNextJSONItem(P: PUTF8Char. Reach the positon of the next JSON item in the supplied UTF-8 buffer . NumberOfItemsToJump: cardinal=1. either " function GotoJSONStringEnd(P: PUTF8Char): PUTF8Char. Ignore a JSON "string \"field" . overload.will return nil in case of parsing error or unexpected end (#0) .buffer can be either a JSON array (ending with ]) or a JSON object (ending with }) . EndOfObject: PAnsiChar=nil): PUTF8Char.e. it's used for Soundex and for ContainsUTF8 function) function GetSectionContent(SectionFirstLine: PUTF8Char): RawUTF8.returns nil if the specified number of items is not available in buffer .use SectionFirstLine() then previous GetSectionContent() function GetUTF8Char(P: PUTF8Char): cardinal.' '] function GotoNextVarInt(Source: PByte): pointer.Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16.. Get the next character not in [#1. Jump a value in variable-length text buffer SynCommons.incoming P^ should be a '"' character .will return '?' if the UCS4 value is higher than #255: so use this function only if you need to deal with ASCII characters (e.internal low-level function used during JSON parsing .i. 2013 function GetNextUTF8Upper(var U: PUTF8Char): cardinal.i.Rev. 1. Jump a value in the 32-bit or 64-bit variable-length integer buffer function GotoNextVarString(Source: PByte): pointer. } ] function GotoNextNotSpace(P: PUTF8Char): PUTF8Char. and optionaly the separator character in EndOfObject . Get the next character after a quoted buffer . Reach the position of the next JSON object of JSON array . may be .will return the next character after ending ] or { .E. Get the WideChar stored in P^ (decode UTF-8 if necessary) .the first character in P^ must be either '.returns the position in buffer after the item.18 Page 446 of 1055 . overload.g. Retrieve the whole content of a section as a string . Retrieve the whole content of a section as a string . may be .this function will decode the UTF-8 content before using NormToUpper[] . then update the U pointer . pas unit . BinBytes: integer): boolean. Our custom hash function. Len: integer): cardinal. Case-insensitive hash one AnsiString content with the suppplied Hasher() function function HashByte(const Elem. Hasher: THasher): cardinal. Our custom hash function. thatever the codepage is function Hash32(Data: pointer. or UnicodeString in Delphi 2009+ function HashWord(const Elem.is faster than CRC32 or Adler32.Rev. since use DQWord (128 bytes) aligned read . Hash one Integer value . Hasher: THasher): cardinal. Hash one Word value . overload. Hasher: THasher): cardinal. Hash one AnsiString content with the suppplied Hasher() function function HashAnsiStringI(const Elem. Hash one Cardinal value .18 Date: June 16.simply return the value ignore Hasher() parameter function HashCardinal(const Elem.work with WideString for all Delphi versions. Hash one Int64 value with the suppplied Hasher() function function HashInteger(const Elem. Hasher: THasher): cardinal.is faster than CRC32 or Adler32. Hasher: THasher): cardinal. since use DQWord (128 bytes) aligned read . 2013 function Hash32(const Text: RawByteString): cardinal.overloaded version for direct binary content hashing function HashAnsiString(const Elem.has less colision than Adler32 for short strings . Hasher: THasher): cardinal. Fast conversion from hexa chars into a cardinal SynCommons. Hasher: THasher): cardinal. specialized for Text comparaison . out aValue: cardinal): boolean. 1. Fast conversion from hexa chars into a pointer function HexDisplayToCardinal(Hex: PAnsiChar. Hasher: THasher): cardinal.Synopse mORMot Framework Software Architecture Design 1. specialized for Text comparaison .simply return the value ignore Hasher() parameter function HashPtrUInt(const Elem. Bin: PByte. Case-insensitive hash one UnicodeString content with the suppplied Hasher() function .uses RawByteString for binary content hashing. or UnicodeString in Delphi 2009+ function HashUnicodeStringI(const Elem. Hash one PtrUInt (=NativeUInt) value with the suppplied Hasher() function function HashUnicodeString(const Elem. Hasher: THasher): cardinal.has less colision than Adler32 for short strings . Hash one Byte value . overload.work with WideString for all Delphi versions.simply return the value ignore Hasher() parameter function HexDisplayToBin(Hex: PAnsiChar. Hasher: THasher): cardinal. Hash one UnicodeString content with the suppplied Hasher() function .18 Page 447 of 1055 .simply return the value ignore Hasher() parameter function HashInt64(const Elem. const upArray: array of PUTF8Char): integer. IdemPChar() is prefered.use it with properties only (A. if UTF-8 decoding is not mandatory . IdemPChar() is prefered.9 chars) SynCommons.pas unit .using this function with Bin^ as an integer value will decode in big-endian order (most-signignifican byte first) function IdemFileExt(p.Z. Fast conversion from hexa chars into binary data .search). extup: PUTF8Char): Boolean.18 Date: June 16.chars are compared as 7 bit Ansi only (no accentuated characters): but when you only need to search for field names e.BinBytes contain the bytes count to be converted: Hex^ must contain at least BinBytes*2 chars to be converted. overload.returns -1 if no item matched .extup^ must be already Upper .g. and go to the next line of source function IdemPCharArray(p: PUTF8Char. Returns true if the beginning of p^ is the same as up^ . Case unsensitive test of P1 and P2 content . Returns true if the beginning of p^ is the same as up^ .g. Returns true if the file name extension contained in p^ is the same same as extup^ . search: PUTF8Char): boolean.ignore case . will return TRUE function IdemPCharAndGetNextLine(var source: PUTF8Char. but the Hex^ format is checked ..chars are compared as 7 bit Ansi only (no accentuated characters): but when you only need to search for field names e.ignore case . if UTF-8 decoding is not mandatory function IdemPCharU(p. 1.ignore case . Return true if IdemPChar(source. because it'll be faster than IdemPCharU().this version expect p^ to point to an Unicode char array function IdemPropName(const P1. and Bin^ enough space . Bin: PByte.this version will decode the UTF-8 content before using NormToUpper[]. BinBytes: Integer): boolean. Returns the index of a matching beginning of p^ in upArray[] . no output data is written. 2013 function HexToBin(Hex: PAnsiChar.ignore case .if p is nil. but will handle WinAnsi accentuated characters (e.up^ must be already Upper .18 Page 448 of 1055 . so it will be slower than the IdemPChar() function above.Rev.g. Returns true if the beginning of p^ is same as up^ . not as UTF-8 function IdemPChar(p.ignore case .Synopse mORMot Framework Software Architecture Design 1.if up is nil. 'e' acute will be matched as 'E') function IdemPCharW(p: pWideChar.if Bin=nil.return false if any invalid (non hexa) char is found in Hex^ .P2: shortstring): boolean.up^ must be already Upper . up: PUTF8Char): boolean.up^ must be already Upper .. because it'll be faster than IdemPCharU(). up: PUTF8Char): boolean. will return FALSE .up^ must be already Upper . up: PUTF8Char): boolean.0.chars are compared as WinAnsi (codepage 1252). LoadFrom() with no memory allocation nor memory copy: so is much faster than creating a temporary dynamic array to load the data .only usefull if our Enhanced Runtime (or LVCL) library is not installed procedure Int64ToUInt32(Values64: PInt64Array. Use our fast RawUTF8 version of IntToStr() . Values32: PCardinalArray.SaveTo .18 Page 449 of 1055 .Count is the number of cardinal entries in P^ . var Count: integer): PIntegerArray. Wrap an Integer dynamic array BLOB content as stored by TDynArray. Value: Integer.Rev.returns P where P^=Value . 2013 function IdemPropName(const P1: shortstring. CoValues: PIntegerDynArray=nil): PtrInt.if Index is invalid. or a pointer to the integer array otherwise. Return the corresponding CSV text from a dynamic array of integer .without any slow UnicodeString=String->AnsiString conversion for Delphi 2009 . 1. P2Len: integer): boolean. ValuesCount: integer. Alias to IncludeTrailingBackslash() function function InsertInteger(var Values: TIntegerDynArray.18 Date: June 16.same as TDynArray. P2: PUTF8Char. const Suffix: RawUTF8=''): RawUTF8.only usefull if our Enhanced Runtime (or LVCL) library is not installed function IntegerDynArrayLoadFrom(Source: PAnsiChar.P2: RawUTF8): boolean.0. the Value is inserted at the end of the array function Int32ToUtf8(Value: integer): RawUTF8.0. with the items number stored in Count .Synopse mORMot Framework Software Architecture Design 1.9 chars) function IncludeTrailingPathDelimiter(const FileName: TFileName): TFileName.. Count: PtrInt.returns nil if Value was not found SynCommons. Insert an integer value at the specified index position of a dynamic array of integers . var ValuesCount: integer. Case unsensitive test of P1 and P2 content .. Index: PtrInt.Z. Copy some Int64 values into an unsigned integer array function Int64ToUtf8(Value: Int64): RawUTF8.use it with properties only (A. overload..you can set some custom Prefix and Suffix text function IntegerScan(P: PCardinalArray. Case unsensitive test of P1 and P2 content .Z.Count) function IntegerDynArrayToCSV(const Values: TIntegerDynArray.will return nil if no or invalid data. Use our fast RawUTF8 version of IntToStr() .a bit faster than SimpleDynArrayLoadFrom(Source.TypeInfo(TIntegerDynArray). Count: integer). Fast search of an unsigned integer position in an integer array .9 chars) .. const Prefix: RawUTF8=''. Value: cardinal): PCardinal.use it with properties only (A.pas unit .without any slow UnicodeString=String->AnsiString conversion for Delphi 2009 .this version expect P2 to be a PAnsiChar with a specified length function IdemPropNameU(const P1. overload. Return TRUE if the supplied buffer only contains 7-bits Ansi characters function IsAnsiCompatible(PC: PAnsiChar. overload.Count is the number of integer entries in P^ .Synopse mORMot Framework Software Architecture Design 1.returns false if Value was not found function IntegerScanIndex(P: PCardinalArray. Len: integer): boolean.Rev. const ThousandSep: RawUTF8='.ThousandSep is the character used to separate thousands in numbers with more than three digits to the left of the decimal separator function IsAnsiCompatible(PC: PAnsiChar): boolean.g. Return TRUE if the supplied buffer only contains 7-bits Ansi characters function IsBase64(const s: RawByteString): boolean. if the header in binary buffer "may" be compressed (this method can trigger false positives).IntToStr implementation function IntToString(Value: integer): string. Fast search of an unsigned integer position in an integer array . 1. overload. Faster version than default SysUtils.return -1 if Value was not found function IntToString(Value: Int64): string. Check if the supplied text is a valid Base64 encoded stream function IsContentCompressed(Content: Pointer. overload. Return TRUE if the supplied text only contains 7-bits Ansi characters function IsAnsiCompatible(PW: PWideChar.returns true if P^=Value within Count entries .IntToStr implementation function IntToThousandString(Value: integer. Convert an integer value into its textual representation with thousands marked .return index of P^[index]=Value . Check if the supplied text is a valid Base64 encoded stream function IsBase64(sp: PAnsiChar. e. overload. overload. Return TRUE if the supplied buffer only contains 7-bits Ansi characters function IsAnsiCompatible(PW: PWideChar): boolean. Count: PtrInt.18 Page 450 of 1055 . overload.18 Date: June 16. 2013 function IntegerScanExists(P: PCardinalArray. Value: cardinal): boolean. Count: PtrInt. Fast search of an unsigned integer position in an integer array .IntToStr implementation function IntToString(Value: cardinal): string. Faster version than default SysUtils. overload. begin with zip/gz/gif/wma/png/jpeg markers SynCommons. len: PtrInt): boolean. from a supplied binary buffer . Faster version than default SysUtils. overload.'): RawUTF8.returns TRUE. Retrieve if some content is compressed.pas unit . Len: integer): boolean. Value: cardinal): PtrInt. Return TRUE if the supplied buffer only contains 7-bits Ansi characters function IsAnsiCompatible(const Text: RawByteString): boolean. overload. Len: integer): boolean. it will be computed from StrLen(P) function Iso8601ToSeconds(const S: RawUTF8): Int64. but would not match 'this as a test' nor 'this is a zest' .. Date/Time conversion from ISO-8601 . L: integer): boolean.conversion is faster than Iso8601ToDateTime: use only binary integer math SynCommons.initial C version by Kevin Boylan. first Delphi port by Sergey Seroukhov function Iso8601FromDateTime(DateTime: TDateTime): Int64.'this [e-n]s a [!zy]est' would match 'this is a test'.[abcx-z] Matches a or b or c or x or y or or z.18 Page 451 of 1055 .*' would match match.dat. ..on. CaseInsensitive: boolean=false): boolean. Get TTimeLog value from a file date and time function Iso8601Now: Int64.pas unit .[!abc] Matches anything but a or b or c at that position [a-e] Matches a through e at that position .Rev.handle 'YYYYMMDDThhmmss' and 'YYYY-MM-DD hh:mm:ss' format function Iso8601ToDateTimePUTF8Char(P: PUTF8Char. as does [a-cx-z] . L: integer=0): TDateTime.if L is left to default 0.Synopse mORMot Framework Software Architecture Design 1. Return TRUE if the supplied content matchs to a grep-like pattern -? Matches any single characer -* Matches any contiguous characters . mavch. etc.'ma?ch. 1. Date/Time conversion from ISO-8601 . Returns TRUE if the supplied HTML Headers contains 'Content-Type: text/.exe. it will be computed from StrLen(P) procedure Iso8601ToDateTimePUTF8CharVar(P: PUTF8Char.use internally for computation an abstract "year" of 16 months of 32 days of 32 hours of 64 minutes of 64 seconds .' or 'Content-Type: application/json' function IsIso8601(P: PUTF8Char. Get TTimeLog value from current date and time function Iso8601ToDateTime(const S: RawUTF8): TDateTime.handle 'YYYYMMDDThhmmss' and 'YYYY-MM-DD hh:mm:ss' format .[^abc] Matches anything but a or b or c at that position . Convert a Iso8601 encoded string into a "fake" second count ..18 Date: June 16.[abc] Matches a or b or c at that position . Date/Time conversion from ISO-8601 .handle 'YYYYMMDDThhmmss' and 'YYYY-MM-DD hh:mm:ss' format . Test if P^ contains a valid ISO-8601 text encoded value .use this function only for fast comparaison between two Iso8601 date/time .if L is left to default 0. var result: TDateTime). Get TTimeLog value from a given Delphi date and time function Iso8601FromFile(const FileName: TFileName): Int64.calls internally Iso8601ToSecondsPUTF8Char() and returns true if contains at least a valid year (YYYY) function IsMatch(const Pattern. Text: RawUTF8. 2013 function IsHTMLContentTypeTextual(Headers: PUTF8Char): Boolean. march. L: integer. 1. as in: aRec. IsString('abc')=true.e. IsString('0')=false.ContainsNoTime optional pointer can be set to a boolean. Returns TRUE if the specified field name is either 'ID'.18 Page 452 of 1055 .e. overload. 2013 function Iso8601ToSecondsPUTF8Char(P: PUTF8Char.to be used e.returns 0 in case of invalid input string function Iso8601ToSQL(TimeStamp: TTimeLog): RawUTF8. '0' is excluded at the begining of a number) and '123' is not a string SynCommons. since doesn't change the data content function IsString(P: PUTF8Char): boolean.therefore ':("\uFFF12012-05-04T20:12:13"):' pattern will be recognized as a sftDateTime inline parameter in SQLParamContent() / ExtractInlineParameters() (JSON_SQLDATE_MAGIC will be used as prefix to create '\uFFF1. either 'ROWID' function IsRowIDShort(const FieldName: shortstring): boolean.e.CreateAndFillPrepare(Client. Convert an Iso8601 date/time (bit-encoded as Int64) to a ISO-8601 string format for SQL '?' inlined parameters .g.used to avoid code injection and to check if the cache must be flushed .pas unit .' pattern) .'Datum<=?'.this version will NOT recognize JSON null/false/true as strings .g. overload. according to the JSON encoding schema . L: integer. IsString('null')=true function IsStringJSON(P: PUTF8Char): boolean. Test if the supplied buffer is a "string" value or a numerical value (floating or integer). Returns TRUE if the specified field name is either 'ID'. TRUE for '2012-05-26') . '0123' is a string (i.conversion is faster than Iso8601ToDateTime: use only binary integer math .this version will recognize null/false/true as strings .will follow the JSON definition of number.'VACUUM' statement also returns true. either 'ROWID' function IsRowID(FieldName: PUTF8Char): boolean.use this function only for fast comparaison between two Iso8601 date/time . FieldLen: integer): boolean. either 'ROWID' function isSelect(P: PUTF8Char): boolean. Return true if the parameter is void or begin with a 'SELECT' SQL statement .use internally for computation an abstract "year" of 16 months of 32 days of 32 hours of 64 minutes of 64 seconds . IsString('0')=false.will return the date or time encoded as '\uFFF1YYYY-MM-DDThh:mm:ss' .[Iso8601ToSQL(Iso8601Now)]).e. according to the characters within . overload. IsString('abc')=true.Rev. i. IsString('null')=false ... Returns TRUE if the specified field name is either 'ID'. ContainsNoTime: PBoolean=nil): QWord.g. Convert a Iso8601 encoded string into a "fake" second count .18 Date: June 16.Synopse mORMot Framework Software Architecture Design 1. which will be set according to the layout in P (e.g. Test if the supplied buffer is a "string" value or a numerical value (floating point or integer). function IsRowID(FieldName: PUTF8Char. .18 Page 453 of 1055 .is optimized for 64. i. Return TRUE if the supplied unicode buffer only contains WinAnsi characters .e. overload. if the text can be displayed using ANSI_CHARSET function IsWinAnsiU8Bit(UTF8Text: PUTF8Char): boolean. overload.i.if HandleValuesAsObjectOrArray is TRUE. 192 and 256 max bits count (i.1. which is therefore modified: make a private copy first if you want to reuse the JSON content . Return TRUE if the supplied unicode buffer only contains WinAnsi characters . if the text can be displayed using ANSI_CHARSET function IsWinAnsi(WideText: PWideChar): boolean.['name'. according to the Names supplied e.returns a pointer to the next content item in the JSON buffer Used for DI-2.Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16. 2013 function IsValidEmail(P: PUTF8Char): boolean.g. Return TRUE if the supplied UTF-8 buffer only contains WinAnsi characters .'year'].e.g.i. const Names: array of PUTF8Char.e. if the text can be displayed using ANSI_CHARSET with only 8 bit unicode characters (e. MAX_SQLFIELDS) . overload.Values) -> Values[0]^='John'.i.will work also with any other value function IsZero(P: pointer. no "tm" or such) function IsZero(const Fields: TSQLFieldBits): boolean.follows RFC 822.Rev. the PUtf8Char array is created inside P.pas unit . JSONDecode(P. HandleValuesAsObjectOrArray: Boolean=false): PUTF8Char. 1. overload. to validate local-part@domain email format function IsValidIP4Address(P: PUTF8Char): boolean. Length: integer): boolean. var Values: TPUtf8CharDynArray.2 (page 1049).data will be set in Values.e. SynCommons. then this procedure will handle JSON arrays or objects . Length: integer): boolean. overload.e. Returns TRUE if all bytes equal zero function JSONDecode(P: PUTF8Char.i. Returns TRUE if no bit inside this TSQLFieldBits is set . Decode the supplied UTF-8 JSON content for the supplied names . Return TRUE if the supplied content is a valid IP v4 address function IsWinAnsi(WideText: PWideChar.if any supplied name wasn't found its corresponding Values[] will be nil . if the text can be displayed using ANSI_CHARSET function IsWinAnsiU(UTF8Text: PUTF8Char): boolean.e. 128. Return TRUE if the supplied content is a valid email address .this procedure will decode the JSON content in-memory. Values[1]^='1972'. Return TRUE if the supplied UTF-8 buffer only contains WinAnsi 8 bit characters . . then this procedure will handle JSON arrays or objects Used for DI-2.Values) -> Values[0]^='John'.1. Decode the supplied UTF-8 JSON content for the supplied names . const aName: RawUTF8='result'. overload.Synopse mORMot Framework Software Architecture Design 1. according to the Names supplied e.g. Encode the supplied data as an UTF-8 valid JSON object content .2 (page 1049).1. i.1972]) = '{"name":"John". 1. which is therefore modified: make a private copy first if you want to reuse the JSON content . HandleValuesAsObjectOrArray: Boolean=false): RawUTF8.18 Page 454 of 1055 . overload. wasString: PBoolean=nil.data must be supplied two by two.18 Date: June 16. var Values: TPUtf8CharDynArray.this procedure will decode the JSON content in-memory.if HandleValuesAsObjectOrArray is TRUE.2 (page 1049).2 (page 1049). JSONDecode(JSON. overload. Encode the supplied array data as a valid JSON array content . e. function JSONEncodeArray(const Values: array of integer): RawUTF8. so will unescape it in-place: it must be called only once with the same JSON data Used for DI-2. 2013 procedure JSONDecode(var JSON: RawUTF8."year":1972}' . Encode the supplied integer array data as a valid JSON array Used for DI-2. WithoutBraces: boolean. Encode the supplied RawUTF8 array data as an UTF-8 valid JSON array content Used for DI-2.g.data will be set in Values. function JSONDecode(var JSON: RawUTF8.1. JSONEncode(['name'. function JSONEncodeArray(const Values: array of RawUTF8): RawUTF8.this function will decode the JSON content in-memory.2 (page 1049). HandleValuesAsObjectOrArray: Boolean=false).'year']. const Names: array of PUTF8Char. var result: RawUTF8). procedure JSONEncodeArrayOfConst(const Values: array of const.Rev. therefore wrongly) SynCommons.'John'.if any supplied name wasn't found its corresponding Values[] will be nil . overload. therefore wrongly) Used for DI-2. overload. Encode the supplied floating-point array data as a valid JSON array Used for DI-2.'year'.note that cardinal values should be type-casted to Int64() (otherwise the integer mapped value will be transmitted. Decode the supplied UTF-8 JSON content for the one supplied name .1.pas unit .1.e. the PUtf8Char array is created inside JSON.note that cardinal values should be type-casted to Int64() (otherwise the integer mapped value will be transmitted.if WithoutBraces is TRUE. function JSONEncode(const NameValuePairs: array of const): RawUTF8.['name'. overload.1. no [ ] will be generated . function JSONEncodeArray(const Values: array of double): RawUTF8.2 (page 1049). as Name.2 (page 1049).Value pairs. Values[1]^='1972'. exe' .. 3rd edition . and will therefore by correct with true UTF-8 content function LowerCaseU(const S: RawUTF8): RawUTF8. but also accentuated latin characters ('E' acute into 'e' e. either '}'. out FieldLen: integer. Retrieve a pointer to JSON string field content ..this will not only convert 'A'.Rev. or returns the numerical field value .returns either ':' for name field.' for value field . using NormToLower[] array .returns 0 if no such field exist. so you can call it before using in-place escape process via JSONDecode() or GetJSONField() function JSONRetrieveStringField(P: PUTF8Char.it will convert decode the supplied UTF-8 content to handle more than 7 bit of ascii characters SynCommons. Log a message to a local text file ..this function won't touch the JSON buffer.'Z' into 'a'.format contains the current date and time. Encode the supplied array data as a valid JSON array content . ISO-8601)' function LowerCase(const S: RawUTF8): RawUTF8.this will only convert 'A'.. buf: PAnsiChar. 1.this function won't touch the JSON buffer.for MB and KB. Fast conversion of the supplied text into lowercase .note that cardinal values should be type-casted to Int64() (otherwise the integer mapped value will be transmitted. Standard Kernighan & Ritchie hash from "The C programming Language". so you can call it before using in-place escape process via JSONDecode() or GetJSONField() function KB(bytes: Int64): RawUTF8. ExpectNameField: boolean): PUTF8Char.log' extension instead of '. Convert a size to a human readable value .18 Date: June 16. or "RowID":.the text file is located in the executable directory.append MB. therefore wrongly) function JSONRetrieveIDField(P: PUTF8Char): integer.'z'.'z' (no NormToLower use). WithoutBraces: boolean=false): RawUTF8.e.. no [ ] will be generated ..not the best.date and time format used is 'YYYYMMDD hh:mm:ss (i.if WithoutBraces is TRUE. KB or B symbol .. and its name is simply the executable file name with the '. 2013 function JSONEncodeArrayOfConst(const Values: array of const. then the Msg on one line . out Field: PUTF8Char..18 Page 455 of 1055 . Fast conversion of the supplied text into 8 bit lowercase . len: cardinal): cardinal.pas unit . field value from a JSON object buffer . but simple and efficient code .'.perfect for THasher procedure LogToTextFile(Msg: RawUTF8).'Z' into 'a'.returns nil on JSON content error . add one fractional digit function kr32(crc: cardinal. Retrieve a "ID":.Synopse mORMot Framework Software Architecture Design 1.). overload.g. substr is expected to be already in upper case . in the ISO 8601 layout. Count: Integer). add two fractional digits procedure Move(const Source. Self-modifying code . Faster implementation of Move() for Delphi versions with no FastCode inside . A non case-sensitive RawUTF8 version of Pos() . function PointerToHex(aPointer: Pointer): RawUTF8.change some memory buffer in the code segment . but expanded and ready to be displayed procedure PatchCode(Old. LeaveUnprotected: boolean=false). const str: RawUTF8): Integer.this version will decode the UTF-8 content before using NormToUpper[] SynCommons.New: pointer. S: RawUTF8.if Backup is not nil. it should point to a Size array of bytes.this version handle only 7 bit ASCII (no accentuated characters) function PosIU(substr: PUTF8Char.1.18 Page 456 of 1055 .this version will use the Operating System API. Offset: cardinal=1): Integer. but will handle all kind of unicode characters function MicroSecToString(Micro: Int64): RawUTF8. Convert a micro seconds elapsed time into a human readable value .use internally BinToHexDisplay() function PosChar(Str: PUTF8Char. FirstTimeChar: AnsiChar = ' '): RawUTF8.pas unit . Fast conversion from a pointer data into hexa chars. ready to be displayed . Size: integer. LeaveUnprotected: boolean=false). Backup: pointer=nil. for further hook disabling procedure PatchCodePtrUInt(Code: PPtrUInt.Synopse mORMot Framework Software Architecture Design 1. 2013 function LowerCaseUnicode(const S: RawUTF8): RawUTF8. const str: RawUTF8): Integer. Value: PtrUInt. ready to contain the overriden code buffer. var Dest. ms or s symbol . Get the UCS4 char stored in P^ (decode UTF-8 if necessary) function NowToString(Expanded: boolean=true.4 (page 1051). Fast retrieve the position of a given character function PosEx(const SubStr.Delphi RTL will be patched in memory to run this faster version function NextUTF8UCS4(var P: PUTF8Char): cardinal. Accurate conversion of the supplied UTF-8 content into the corresponding lower-case Unicode characters .PosEx function PosI(substr: PUTF8Char. Chr: AnsiChar): PUTF8Char.Rev.18 Date: June 16.change one PtrUInt in the code segment Used for DI-2. A non case-sensitive RawUTF8 version of Pos() .substr is expected to be already in upper case . Self-modifying code . 1.for us and ms. Faster RawUTF8 Equivalent of standard StrUtils.append us. Retrieve the current Date. and will therefore be much slower than LowerCase/LowerCaseU versions. you can use FastFindIndexedPUTF8Char() for fast binary search procedure QuickSortInteger(ID: PIntegerArray. L: integer. overload." procedure QuotedStr(Text: PUTF8Char.pas unit .as in Pascal. CoValues: PIntegerDynArray=nil. Value: PtrUInt): PtrInt. R: PtrInt).as in Pascal. low values first procedure QuickSortRawUTF8(var Values: TRawUTF8DynArray.18 Date: June 16.this function implements what is specified in the official SQLite3 documentation: "A string constant is formed by enclosing the string in single quotes ('). 2013 function PtrUIntScanIndex(P: PPtrUIntArray.18 Page 457 of 1055 . Format a text content with quotes .return index of P^[index]=Value .as in Pascal.Count is the number of pointer-sized integer entries in P^ . L: integer): string. 1. via an external array of indexes .Synopse mORMot Framework Software Architecture Design 1. A single quote within the string can be encoded by putting two single quotes in a row . var result: string).UTF-8 version of the function available in SysUtils . A single quote within the string can be encoded by putting two single quotes in a row . overload. Sort a dynamic array of PUTF8Char items. you can specify a custom compare function if needed in Compare optional parameter function QuotedStr(Text: PUTF8Char. Quote: AnsiChar.this function implements what is specified in the official SQLite3 documentation: "A string constant is formed by enclosing the string in single quotes ('). Sort a dynamic array of RawUTF8 items .Rev." function QuotedStr(const S: RawUTF8. overload.this function implements what is specified in the official SQLite3 documentation: "A string constant is formed by enclosing the string in single quotes ('). Format a buffered text content with quotes . overload. the integer items are also synchronized .return -1 if Value was not found procedure QuickSortIndexedPUTF8Char(Values: PPUtf8CharArray. var SortedIndexes: TCardinalDynArray. ValuesCount: integer. CaseSensitive: boolean=false). Compare: TUTF8Compare=nil). Convert any Raw Unicode encoded buffer into a generic VCL Text function RawUnicodeToString(P: PWideChar. Sort an Integer array. Convert any Raw Unicode encoded buffer into a generic VCL Text SynCommons.by default. exact (case-sensitive) match is used.if CoValues is set. overload. Quote: AnsiChar=''''): RawUTF8. L. Count: PtrInt. Convert any Raw Unicode encoded string into a generic VCL Text procedure RawUnicodeToString(P: PWideChar. Format a buffered text content with quotes . A single quote within the string can be encoded by putting two single quotes in a row ." function RawByteStringArrayConcat(const Values: array of RawByteString): RawByteString. Quote: AnsiChar): RawUTF8. Fast concatenation of several AnsiStrings function RawUnicodeToString(const U: RawUnicode): string. overload. Fast search of a pointer-sized unsigned integer position in an pointer-sized integer array . Count: Integer. var result: RawUTF8). Quote: AnsiChar=''''): RawUTF8.pas unit . overload. WideCharCount: integer): SynUnicode.Rev.this version doesn't resize the resulting RawUTF8 string. Direct conversion of a Unicode encoded buffer into a WinAnsi PAnsiChar buffer function RawUTF8ArrayToCSV(const Values: array of RawUTF8. Convert a RawUnicode PWideChar into a UTF-8 string .apply QuoteStr() function to each Values[] item function RawUTF8DynArrayEquals(const A. Convert a RawUnicode PWideChar into a WinAnsi (code page 1252) string procedure RawUnicodeToWinPChar(dest: PAnsiChar. Convert a RawUnicode PWideChar into a UTF-8 string function RawUnicodeToUtf8(P: PWideChar. Convert a RawUnicode string into a UTF-8 string function RawUnicodeToUtf8(P: PWideChar. source: PWideChar. overload. Return the corresponding CSV quoted text from a dynamic array of UTF-8 strings . WideCharCount: integer): WinAnsiString. 2013 function RawUnicodeToSynUnicode(P: PWideChar. WideCharCount: integer. var result: RawUTF8). overload. but return the new resulting RawUTF8 byte count into UTF8Length function RawUnicodeToUtf8(const Unicode: RawUnicode): RawUTF8. WideCharCount: integer): RawUTF8. overload.18 Page 458 of 1055 . Convert a RawUnicode PWideChar into a UTF-8 string function RawUnicodeToUtf8(Dest: PUTF8Char. 1.18 Date: June 16. overload.comparison is case-sensitive SynCommons. Return the corresponding CSV text from a dynamic array of UTF-8 strings function RawUTF8ArrayToQuotedCSV(const Values: array of RawUTF8. True if both TRawUTF8DynArray are the same . WideCharCount: integer). SourceLen: PtrInt): PtrInt. overload. which is rather slow since Delphi 2009+ function RawUnicodeToWinAnsi(const Unicode: RawUnicode): WinAnsiString. out UTF8Length: integer): RawUTF8.Synopse mORMot Framework Software Architecture Design 1.replace system. Convert any Raw Unicode encoded String into a generic SynUnicode Text procedure RawUnicodeToUtf8(P: PWideChar. WideCharCount: integer. const Sep: RawUTF8= '. Source: PWideChar.UnicodeToUtf8 implementation. Convert a RawUnicode PWideChar into a UTF-8 buffer .'. const Sep: RawUTF8='. overload. DestLen: PtrInt.'): RawUTF8. overload. overload. Convert any Raw Unicode encoded String into a generic SynUnicode Text function RawUnicodeToSynUnicode(const Unicode: RawUnicode): SynUnicode.B: TRawUTF8DynArray): boolean. Convert a RawUnicode string into a WinAnsi (code page 1252) string function RawUnicodeToWinAnsi(P: PWideChar. word. word.return nil if the Source buffer is incorrect . EndOfObject: PUTF8Char=nil): PUTF8Char. with binaries (byte. integer. with binaries (byte. Check equality of two records by content .will use binary-level comparison: it could fail to match two floating-point values because of rounding issues (Currency won't have this problem) function RecordLoad(var Rec. 1. CaseSensitive: boolean): integer. return the memory buffer pointer just after the read content function RecordLoadJSON(var Rec. Fill a record content from a JSON serialization as saved by TTextWriter. JSON: PUTF8Char. integer. or the matched entry index function ReadStringFromStream(S: TStream. Read an UTF-8 text from a TStream .18 Date: June 16.will handle packed records.) and string types properties (but not with internal raw pointers. if you know how long the size should be procedure RecordClear(var Dest. TypeInfo: pointer): PAnsiChar.this unit includes a fast optimized asm version function RecordEquals(const RecA.18 Page 459 of 1055 . TypeInfo: pointer): boolean.you can set a MaxAllowedSize value. TypeInfo: pointer): PAnsiChar. and as UnicodeString (two bytes per char) since Delphi 2009: if you want to use this function between UNICODE and NOT UNICODE versions of Delphi.pas unit . Dest: PAnsiChar. Source: PAnsiChar. const Source. RecB.in case of success.same as search within TDynArray.format is Length(Integer):Text. Fill a record content from a memory buffer as saved by RecordSave() ...will return -1 if no match or invalid data. WinAnsiString or even RawUnicode SynCommons.will use a proprietary binary format. ValueLen: integer..Synopse mORMot Framework Software Architecture Design 1.will handle packed records.Rev.AddRecordJSON . Clear a record content procedure RecordCopy(var Dest.RegisterCustomJSONSerializer) function RecordSave(const Rec. overload. TypeInfo: pointer). 2013 function RawUTF8DynArrayLoadFromContains(Source: PAnsiChar. Value: PUTF8Char. i.will handle both default (Bin64 encoding of Record Save binary) and custom true JSON format (as set by TTextWriter.) and string types properties .e.will return '' if there is no such text in the stream . Copy a record content from source to Dest .Dest must be at least RecordSaveLength() bytes long . Search in a RawUTF8 dynamic array BLOB content as stored by TDynArray. MaxAllowedSize: integer=255): RawUTF8.LoadFrom() with no memory allocation nor memory copy: so is much faster . TypeInfo: pointer). the one used by WriteStringToStream .SaveTo . with some variable-length encoding of the string length .warning: will encode generic string fields as AnsiString (one byte per char) prior to Delphi 2009. TypeInfo: pointer. you should use some explicit types like RawUTF8. Save a record content into a destination memory buffer .. of course) . pas unit . pLastChar := JSONToObject(sc. 2013 function RecordSave(const Rec. you should use some explicit types like RawUTF8.must be called for each CreateInternalWindow() function .will handle packed records. Self-modifying code ...Rev.add an asm JUMP to a redirected function .. 1..handle two types of comments: starting from // till end of line or /* .create a new [Section] if none was existing . if it contains a variant or a dynamic array) procedure RedirectCode(Func.both parameter values are then reset to ''/0 procedure RemoveCommentsFromJSON(P: PUTF8Char). TypeInfo: pointer): integer. const NewSectionContent: RawUTF8).may be used to prepare configuration files before loading.SectionFirstLine may have been obtained by FindSectionFirstLine() function above SynCommons. procedure ReplaceSection(SectionFirstLine: PUTF8Char.g. Backup: PPatchCode=nil). RemoveCommentsFromJSON(@cfg[1]). Delete the window resources used to receive GDI messages .pointer(cfg). it should point to a Size array of bytes. and as UnicodeString (two bytes per char) since Delphi 2009: if you want to use this function between UNICODE and NOT UNICODE versions of Delphi. word. overload. const Backup: TPatchCode).. Replace a whole [Section] content by a new content .json and put some comments in this file then code for loading is: var cfg: RawUTF8. Save record into its JSON serialization as saved by TTextWriter. Self-modifying code . cfg := StringFromFile(ExtractFilePath(paramstr(0))+'Config. */ blocks anywhere in the text content . overload.json'). ready to contain the overriden code buffer. WinAnsiString or even RawUnicode function RecordSaveJSON(const Rec. RedirectFunc: Pointer. with some variable-length encoding of the string length . for example we store server configuration in file config. Compute the number of bytes needed to save a record content using the RecordSave() function .will use a proprietary binary format. var Content: RawUTF8.) and string types properties (but not with internal raw pointers. TypeInfo: pointer): RawUTF8.warning: will encode generic string fields as AnsiString (one byte per char) prior to Delphi 2009. of course) .configValid). Remove comments from a text buffer before passing it to JSON parser .will return 0 in case of an invalid (not handled) record type (e.if Backup is not nil.AddRecordJSON .Synopse mORMot Framework Software Architecture Design 1. with binaries (byte.will handle both default (Bin64 encoding of Record Save binary) and custom true JSON format (as set by TTextWriter.restore a code from its RedirectCode() backup function ReleaseInternalWindow(var aWindowName: string. TypeInfo: pointer): RawByteString.RegisterCustomJSONSerializer) function RecordSaveLength(const Rec. for further hook disabling procedure RedirectCodeRestore(Func: pointer. integer. var aWindow: HWND): boolean..18 Date: June 16.18 Page 460 of 1055 . Save a record content into a RawByteString . #. DoublePrec: double = 1E-12): Boolean. aTypeInfo: pointer. byte.g. SameText() overloaded function with proper UTF-8 decoding . Retrieve the next CSV separated bit index .e.same as TDynArray.if you know the precision range of A and B. for names retrieved from RTTI to convert them into RawUTF8 function SimpleDynArrayLoadFrom(Source: PAnsiChar.each bit was stored as BitIndex+1. integer.##+0.implementation will use fast Int64 math to avoid any precision loss due to temporary floating-point conversion function SortDynArrayAnsiString(const A.this version will decode the UTF-8 content before using NormToUpper[] function SameValue(const A. cardinal. with case sensitivity SynCommons.##51 will round to #. e. Wrap a simple dynamic array BLOB content as stored by TDynArray.create a new [Section] if none was existing function SameTextU(const S1. Direct conversion of an ANSI-7 shortstring into an AnsiString .18 Date: June 16. S2: RawUTF8): Boolean. ElemSize: integer): pointer.' syntax procedure SetInt64(P: PUTF8Char.the precision is calculated from the A and B value range . 2 for a TWordDynArray) function SimpleRoundTo2Digits(Value: Currency): Currency.can be used e.a "simple" dynamic array contains data with no reference count. i.will return nil if no or invalid data.Rev. Int64. no banker rounding of a Currency value to only 2 digits .several bits set to one can be regrouped via 'first-last. var result: Int64). Replace a whole [Section] content by a new content . aIndex: PtrInt). word. var P: PUTF8Char).SaveTo . const SectionName.g.use this function instead of raw = operator . 2013 procedure ReplaceSection(var Content: RawUTF8. NewSectionContent: RawUTF8). 0 to mark end of CSV chunk . overload. 1.18 Page 461 of 1055 . or a pointer to the data array otherwise. double or Currency . Simple. BitsCount: integer. var Count. Get the 64 bits integer value stored in P^ function ShortStringToAnsi7String(const source: shortstring): RawByteString. with the items number stored in Count and the individual element size in ElemSize (e. Compare two "array of AnsiString" elements. aIndex: PtrInt). it's faster to check abs(A-B)<range procedure SetBit(var Bits. B: Double.Synopse mORMot Framework Software Architecture Design 1.fast version using NormToUpper[] array for all Win-Ansi characters . Set a particular bit into a bit array procedure SetBit64(var Bits: Int64.LoadFrom() with no memory allocation nor memory copy: so is much faster than creating a temporary dynamic array to load the data . with IEEE 754 double precision .## .01 and #.g.##50 will be truncated to #. Set a particular bit into a Int64 bit array (max aIndex is 63) procedure SetBitCSV(var Bits. Compare to floating point values.faster equivalent than SameValue() in Math unit .B): integer.pas unit . from UTF-8 buffer . Compare two "array of WideString/UnicodeString" elements. Compare two "array of double" elements function SortDynArrayInt64(const A.B): integer. 1. with no case sensitivity function SortDynArrayByte(const A.the expected string type is the generic VCL string function SortDynArrayStringI(const A.Synopse mORMot Framework Software Architecture Design 1. Compare two "array of integer" elements function SortDynArrayPointer(const A.the expected string type is the generic VCL string function SortDynArrayUnicodeString(const A.Return the soundex value as an easy to use cardinal value. Compare two "array of generic string" elements.pas unit . Compare two "array of generic string" elements. Compare two "array of TObject/pointer" elements function SortDynArrayString(const A.B): integer.18 Page 462 of 1055 . with case sensitivity function SortDynArrayUnicodeStringI(const A. its value is set to the end of the encoded word (so that you can call again this function to encode a full sentence) .B): integer.B): integer. Compare two "array of WideString/UnicodeString" elements. 2013 function SortDynArrayAnsiStringI(const A. Compare two "array of word" elements function SoundExAnsi(A: PAnsiChar. from Ansi buffer .B): integer. 0 if the incoming string contains no valid word . its value is set to the end of the encoded word (so that you can call again this function to encode a full sentence) function SoundExUTF8(U: PUTF8Char.B): integer.very fast: all UTF-8 decoding is handled on the fly SynCommons. Compare two "array of byte" elements function SortDynArrayCardinal(const A.B): integer. with no case sensitivity . with no case sensitivity function SortDynArrayWord(const A.if next is defined.B): integer. with case sensitivity .B): integer. Lang: TSynSoundExPronunciation=sndxEnglish): cardinal. Retrieve the Soundex value of a text word. Compare two "array of cardinal" elements function SortDynArrayDouble(const A. next: PPUTF8Char=nil. 0 if the incoming string contains no valid word .B): integer. Retrieve the Soundex value of a text word.if next is defined. Lang: TSynSoundExPronunciation=sndxEnglish): cardinal. next: PPAnsiChar=nil.Return the soundex value as an easy to use cardinal value.18 Date: June 16.B): integer. Compare two "array of Int64 or array of Currency" elements function SortDynArrayInteger(const A.Rev. Compare two "array of AnsiString" elements.B): integer. 0000') .g.e.18 Date: June 16. to be used with PUTF8Char function StrCompL(P1.P2: PUTF8Char.. Use our fast version of StrComp(). e.): format . e.return the last written char position (write in reverse order in P^) . in :(.used to check the SQL statement command (e. Use our fast version of StrComp(). 2013 procedure Split(const Str. to be used with PUTF8Char function StrCompIL(P1.g.): without double quoting in case of sftUTF8Text .sftBlob will be recognized from the ':("\uFFF0base64encodedbinary"):' pattern.0001' 500->'0. JSON_SQLDATE_MAGIC-prefixed string as returned by DateToSQL() or DateTimeToSQL() functions . Split a RawUTF8 string into two strings. ignoring all blanks and comments . const Value: Int64): PAnsiChar. var LeftStr. SepStr: RawUTF8.. L. and return raw binary (for direct blob parameter assignment) .sftUnknown is returned on invalid content. 1.is called by Curr64ToPChar() and Curr64ToStr() functions SynCommons.Synopse mORMot Framework Software Architecture Design 1.. out ParamValue: RawUTF8. to be used with PWideChar function StrCurr64(P: PAnsiChar. Str2: PUTF8Char): PtrInt. by ExtractInlineParameters() to un-inline a SQL statement .g. out ParamType: TSQLParamType. is it a SELECT?) function SQLParamContent(P: PUTF8Char.pas unit .' character).g.sftUTF8Text is returned for :("text"): or :('text'):.0500' 25000->'2. Str2: PWideChar): PtrInt. then LeftStr and RightStr will be made uppercase function SQLBegin(P: PUTF8Char): PUTF8Char.if ToUpperCase is TRUE.P2: PUTF8Char. Default: Integer): PtrInt. 1->'0.will return 0 for Value=0. LeftStr=Str and RightStr='' .18 Page 463 of 1055 . or if wasNull is set to TRUE . Default: Integer): PtrInt. to be used with PUTF8Char function StrCompW(Str1. i. out wasNull: boolean): PUTF8Char. according to SepStr separator . the pointing RawUTF8 string is set with the value inside :(.. or a string representation with always 4 decimals (e.if ParamValue is not nil. RightStr: RawUTF8. Use our fast version of StrCompIL().Rev.sftFloat is returned for any floating point value (i.will be used e.34): or :(12E-34): . :(12.wasNull is set to TRUE if P was ':(null):' and ParamType is sftUnknwown function StrComp(Str1.if SepStr is not found.5000' 30000->'3.g. Use our fast version of StrCompL(). Go to the beginning of the SQL statement. some digits separated by a '. ToUpperCase: boolean=false). Guess the content type of an UTF-8 SQL value.expect the last available temporary char position in P .. L.sftDateTime will be recognized from ':(\uFFF1"2012-05-04"):' pattern. with double quoting inside the value . :(1234): .e.sftInteger is returned for an INTEGER value. Internal fast INTEGER Curr64 (value*10000) value to text conversion . NewChar: AnsiChar): RawUTF8. append several data blocks to the same stream) function StreamUnSynLZ(const Source: TFileName.Dest must be able to receive at least SourceChars*3 bytes .this function will also recognize the block at the end of the source stream (if was appended to an existing data .uses RawByteString for byte storage. overload. a . it will use the current RTL codepage. Use our fast version of StrIComp() function StringBufferToUtf8(Dest: PUTF8Char. function StringReplaceChars(const Source: RawUTF8.returns nil if source file is invalid (e. Fast replacement of StringReplace(S. Magic: cardinal): TMemoryStream.under older version of Delphi (no unicode). OldPattern.returns '' if file was not found or any read error occured . Magic: cardinal): TMemoryStream. as with WideString conversion (but without slow WideString usage) function StringFromFile(const FileName: TFileName): RawByteString.Synopse mORMot Framework Software Architecture Design 1. Source: PChar. SourceChars: PtrInt): PUTF8Char.this function will also recognize the block at the end of the source file (if was appended to an existing data . 1. OldPattern.pas unit . NewPattern: RawUTF8): RawUTF8. OldChar.[rfReplaceAll]).e. Magic: cardinal): integer. Uncompress using the SynLZ algorithm from one stream into another .g. Compress a data content using the SynLZ algorithm from one stream into another .you should specify a Magic number to be used to identify the block . overload.g.returns the number of bytes written to Dest .returns a newly create memory stream containing the uncompressed data .content can be binary or text .e. Uncompress using the SynLZ algorithm from one file into another .mab at the end of a .g.Rev. Convert any generic VCL Text buffer into an UTF-8 encoded buffer .18 Date: June 16. thatever the codepage is function StringReplaceAll(const S. Str2: PUTF8Char): PtrInt.g.the Text content must contain only 7 bit pure ASCII characters SynCommons.you should specify a Magic number to be used to identify the block function StreamUnSynLZ(Source: TStream. overload.it will work as is with Delphi 2009+ (direct unicode conversion) . NewPattern. 2013 function StreamSynLZ(Source: TCustomMemoryStream. a .18 Page 464 of 1055 .returns nil if source data is invalid .exe) function StrIComp(Str1. invalid name or invalid content) .mab at the end of a . Read a File content into a String . Source will point after all read data (so that you can e.you should specify a Magic number to be used to identify the block . Fast replace of a specified char into a given string function StringToAnsi7(const Text: string): RawByteString.on success.returns a newly create memory stream containing the uncompressed data . Dest: TStream.exe) . Convert any generic VCL Text into Ansi 7 bit encoded String . it will use the current RTL codepage.it's prefered to use TLanguageFile.Synopse mORMot Framework Software Architecture Design 1.under older version of Delphi (no unicode). overload. as with WideString conversion (but without slow WideString usage) procedure StringToUTF8(const Text: string. var result: RawUTF8). it will use the current RTL codepage.it will work as is with Delphi 2009+ (direct unicode conversion) .StringToUTF8() method in mORMoti18n. as with WideString conversion (but without slow WideString usage) function StringToSynUnicode(const S: string): SynUnicode.it will work as is with Delphi 2009+ (direct unicode conversion) .expect the last available temporary char position in P . as with WideString conversion (but without slow WideString usage) function StringToWinAnsi(const Text: string): WinAnsiString. Convert any generic VCL Text into a SynUnicode encoded String . it will use the current RTL codepage. which will handle full i18n of your application . overload. which will handle full i18n of your application .it will work as is with Delphi 2009+ (direct unicode conversion) .it's prefered to use TLanguageFile. 1. 2013 function StringToRawUnicode(const S: string): RawUnicode. begin P := StrInt32(@tmp[15]. Internal fast integer val to text conversion .StringToUTF8() method in mORMoti18n.not to be called directly: use IntToStr() instead SynCommons.15] of AnsiChar.return the last written char position (write in reverse order in P^) . which will handle full i18n of your application .StringToUTF8() method in mORMoti18n. overload. L: integer): RawUnicode. Convert any generic VCL Text into a Raw Unicode encoded String . SetString(result.pas unit . overload.under older version of Delphi (no unicode).under older version of Delphi (no unicode). var tmp: array[0.StringToUTF8() method in mORMoti18n.18 Page 465 of 1055 . P: PAnsiChar. Convert any generic VCL Text into an UTF-8 encoded String .18 Date: June 16. as with WideString conversion (but without slow WideString usage) function StringToRawUnicode(P: PChar.typical use: function Int32ToUTF8(Value : integer): RawUTF8. .this overloaded function use a faster by-reference parameter for the result function StringToUTF8(const Text: string): RawUTF8.it's prefered to use TLanguageFile. Convert any generic VCL Text into WinAnsi (Win-1252) 8 bit encoded String function StrInt32(P: PAnsiChar..it will work as is with Delphi 2009+ (direct unicode conversion) .Value).P.it's prefered to use TLanguageFile. which will handle full i18n of your application . Convert any generic VCL Text into a Raw Unicode encoded String .under older version of Delphi (no unicode). it will use the current RTL codepage.@tmp[15]-P).Rev. end. Convert any generic VCL Text into an UTF-8 encoded String . val: PtrInt): PAnsiChar. g. will be set to TRUE if there is no decimal.Synopse mORMot Framework Software Architecture Design 1. Change the Windows console text writing color . NoDecimal: PBoolean=nil): Int64. to be used with PWideChar function StrToCurr64(P: PUTF8Char.if NoDecimal is defined.return the last written char position (write in reverse order in P^) function SynUnicodeToString(const U: SynUnicode): string.expect the last available temporary char position in P . function TimeToIso8601(Time: TDateTime. Internal fast Int64 val to text conversion . Basic Time conversion into ISO-8601 .same calling convention as with StrInt32() above function StrLen(S: PUTF8Char): PtrInt. FirstChar: AnsiChar='T'): RawUTF8. Expanded: boolean.this type is compatible with Delphi currency memory map with PInt64(@Curr)^ .use 'Thh:mm:ss' format if Expanded SynCommons. Change the Windows console text background color procedure TextColor(Color: TConsoleColor).will call StrToCurr64() function StrUInt32(P: PAnsiChar. TextColor(ccLightGray). 2013 function StrInt64(P: PAnsiChar.use 'Thhmmss' format if not Expanded .Rev.18 Date: June 16. val: PtrUInt): PAnsiChar. Our fast version of StrLen(). to be used with PUTF8Char function StrLenW(S: PWideChar): PtrInt. AND the returned value will be an Int64 (not a PInt64(@Curr)^) function StrToCurrency(P: PUTF8Char): currency. using only integer operations . e. Our fast version of StrLen().18 Page 466 of 1055 . Convert a SynUnicode string into a UTF-8 string procedure TextBackground(Color: TConsoleColor). Convert a string into its currency representation .pas unit . Convert any SynUnicode encoded string into a generic VCL Text function SynUnicodeToUtf8(const Unicode: SynUnicode): RawUTF8.fast conversion. 1. via the following code: AllocConsole. if you manually intialized the Windows console.call this procedure to initialize internal console process. val: Int64): PAnsiChar. Internal fast unsigned integer val to text conversion . Convert a string into its INTEGER Curr64 (value*10000) representation . Return the number of bytes necessary to store some data with a its 32-bit variable-length integer legnth function ToVarUInt64(Value: QWord. Expanded: boolean.pas unit . procedure ToSBFStr(const Value: RawByteString. Convert a Int64 into a 64-bit variable-length integer buffer function ToVarUInt32(Value: PtrUInt. FirstChar: AnsiChar = 'T'). as: MyArray := TRawUTF8DynArrayFrom(['a'. Expanded: boolean.store negative values as cardinal two-complement.4=-2.M. the ToVarUInt32() buffer size function ToVarUInt32LengthWithData(Value: PtrUInt): PtrUInt. Use our fast asm RawUTF8 version of Trim() SynCommons. H.you can custom the first char in from of the resulting text time procedure TimeToIso8601PChar(P: PUTF8Char.g. P: PUTF8Char.if Expanded is true.18 Date: June 16.'c']). Write a Time to P^ Ansi buffer . Convert a cardinal into a 32-bit variable-length integer buffer function ToVarUInt32Length(Value: PtrUInt): PtrUInt. Convert any AnsiString content into our SBF compact binary format storage function ToVarInt32(Value: PtrInt. 'Thhmmss' time format is used .18 Page 467 of 1055 . Retrieve the current Time (whithout Date). 1. Convert a UInt64 into a 64-bit variable-length integer buffer function TRawUTF8DynArrayFrom(const Values: array of RawUTF8): TRawUTF8DynArray. i.S: cardinal. Dest: PByte): PByte.3=2. 'Thh:mm:ss' time format is used . Quick helper to initialize a dynamic array of RawUTF8 from some constants . 'Thhmmss' time format is used .Rev. function ToVarInt64(Value: Int64.i..2=-1.if Expanded is false. function Trim(const S: RawUTF8): RawUTF8.1=1. 2013 procedure TimeToIso8601PChar(Time: TDateTime. 'Thh:mm:ss' time format is used . out Result: TSBFString). FirstChar: AnsiChar = 'T').can be used e.if Expanded is true.usefull for direct on screen logging e.e. Dest: PByte): PByte. Return the number of bytes necessary to store a 32-bit variable-length integer .'b'. Dest: PByte): PByte.e. overload. Dest: PByte): PByte. overload.Synopse mORMot Framework Software Architecture Design 1. Convert an integer into a 32-bit variable-length integer buffer .you can custom the first char in from of the resulting text time function TimeToString: RawUTF8.if Expanded is false.. in the ISO 8601 layout .g. Write a Time to P^ Ansi buffer . 0=0. P: PUTF8Char): integer. UTF-8 encode one UCS4 character into Dest . space.e. and 'OnMyLINE' will return 'On my LINE' ..'OnLine' will return 'On line' e.) .return the char count written into D^ . Convert a CamelCase string into a space separated one .g. Truncate a Currency value to only 2 digits . Try to encode a time function UCS4ToUTF8(ucs4: cardinal. and 'OnMyLINE' will return 'On my LINE' .this method DOES handle UTF-16 surrogate pairs function UInt32ToUtf8(Value: cardinal): RawUTF8.' . Trim first lowercase chars ('otDone' will return 'Done' e.18 Date: June 16.18 Page 468 of 1055 . Min.return an RawUTF8 string: enumeration names are pure 7bit ANSI with Delphi 7 to 2007. Trims trailing whitespace characters from the string by removing trailing newline. Convert a CamelCase string into a space separated one .' .'OnLine' will return 'On line' e. and tab characters function TruncTo2Digits(Value: Currency): Currency.'__' chars are transformed into ': ' function UnCamelCase(const S: RawUTF8): RawUTF8.pas unit . from 1 up to 6) . and UTF-8 encoded with Delphi 2009+ function UnicodeBufferToString(source: PWideChar): string.Synopse mORMot Framework Software Architecture Design 1. and UTF-8 encoded with Delphi 2009+ function TrimRight(const S: RawUTF8): RawUTF8. 1. MSec: Word.D^ and P^ are expected to be UTF-8 encoded: enumeration and property names are pure 7bit ANSI with Delphi 7 to 2007. Sec. and tab characters function TrimLeftLowerCase(const V: RawUTF8): PUTF8Char.implementation will use fast Int64 math to avoid any precision loss due to temporary floating-point conversion function TryEncodeTime(Hour. Dest: PUTF8Char): integer.'_' char is transformed into ' . overload.return a PUTF8Char to avoid any memory allocation function TrimLeftLowerCaseShort(V: PShortString): RawUTF8. Trims leading whitespace characters from the string by removing new line.return an RawUTF8 string: enumeration names are pure 7bit ANSI with Delphi 7 to 2007.'__' chars are transformed into ': ' . var Time: TDateTime): Boolean.Rev.g.g. overload.'_' char is transformed into ' . Convert an Unicode buffer into a generic VCL string SynCommons.. Trim first lowercase chars ('otDone' will return 'Done' e.return the number of bytes written into Dest (i.) . space. 2013 function TrimLeft(const S: RawUTF8): RawUTF8. Optimized conversion of a cardinal into RawUTF8 function UnCamelCase(D. and UTF-8 encoded with Delphi 2009+ .g. but only for 7 bit procedure UpperCaseCopy(const Source: RawUTF8.INI file . and will therefore be much slower than UpperCase/UpperCaseU versions.Rev.'Z'.. Fast conversion of the supplied text into uppercase .'Z' (no NormToUpper use). 1.Value: RawUTF8).Value: RawUTF8).'text '' end' -> text ' end .'Z' (no NormToUpper use). var Dest: RawUTF8). const Section.this will only convert 'a'. Convert an Unicode buffer into a WinAnsi (code page 1252) string function UnQuoteSQLString(P: PUTF8Char.g. but also accentuated latin characters ('e' acute into 'E' e. out Value: RawUTF8): PUTF8Char.Name.the first character in P^ must be either '.. out Dest: WinAnsiString). Unset/clear a particular bit into a Int64 bit array (max aIndex is 63) procedure UpdateIniEntry(var Content: RawUTF8. but only for 7 bit function UpperCaseU(const S: RawUTF8): RawUTF8. Fast conversion of the supplied text into 8 bit uppercase .. aIndex: PtrInt). aIndex: PtrInt). 2013 procedure UnicodeBufferToWinAnsi(source: PWideChar. Unset/clear a particular bit into a bit array procedure UnSetBit64(var Bits: Int64..'z' into 'A'. using NormToUpper[] array .returns nil if P doesn't contain a valid SQL string .18 Date: June 16. update the Name= value before any [Section] procedure UpdateIniEntryFile(const FileName: TFileName.if Section equals ''. and is therefore very fast (no temporary TMemIniFile is created) . Accurate conversion of the supplied UTF-8 content into the corresponding upper-case Unicode characters . update the Name= value before any [Section] . Unquote a SQL-compatible string . but will handle all kind of unicode characters SynCommons.this will only convert 'a'.).this function scans and update the Content memory buffer..pas unit .this version will use the Operating System API.18 Page 469 of 1055 .'z' into 'A'.use internaly fast UpdateIniEntry() function above function UpperCase(const S: RawUTF8): RawUTF8.Synopse mORMot Framework Software Architecture Design 1.Name. and will therefore by correct with true UTF-8 content.it will decode the supplied UTF-8 content to handle more than 7 bit of ascii characters (so this function is dedicated to WinAnsi code page 1252 characters set) function UpperCaseUnicode(const S: RawUTF8): RawUTF8. either " then double quotes are transformed into single quotes . Update a Name= Value in a [Section] of a INI RawUTF8 Content .this will not only convert 'a'."text "" end" -> text " end . Update a Name= Value in a [Section] of a .'z' into 'A'.. const Section.returns a pointer just after the quoted text otherwise procedure UnSetBit(var Bits. and will therefore by correct with true UTF-8 content.if Section equals ''. Fast conversion of the supplied text into uppercase . returns final dest pointer .returns final dest pointer .if Upper is not found. and result is FALSE . const source: RawUTF8): PAnsiChar.Synopse mORMot Framework Software Architecture Design 1. const source: RawUTF8): PAnsiChar. Copy source into dest^ with 7 bits upper case conversion .returns final dest pointer . Next: PPUTF8Char=nil): boolean.returns final dest pointer . Copy source into dest^ with 7 bits upper case conversion . Value is not modified. overload.'OFFSET='.will copy up to 255 AnsiChar (expect the dest buffer to be array[byte] of AnsiChar) function UrlDecode(const s: RawUTF8..' and O=20 . and result is TRUE SynCommons. Decode a string compatible with URI encoding into its original value function UrlDecodeCardinal(U. const source: SynUnicode): PAnsiChar.len) function) function UrlDecode(U: PUTF8Char): RawUTF8.pas unit . Copy WideChar source into dest^ with upper case conversion . Upper: PUTF8Char. len: PtrInt = -1): RawUTF8. Copy source into dest^ with WinAnsi 8 bits upper case conversion . Decode a specified parameter compatible with URI encoding into its original cardinal numerical value UrlDecodeCardinal('offset=20&where=LastName%3D%27M%C3%B4net%27'. var Value: Cardinal. overload.will copy up to the source buffer end (so Dest^ should be big enough) function UpperCopy255(dest: PAnsiChar. overload.. Copy source into dest^ with 7 bits upper case conversion .Rev. L: integer): PAnsiChar.returns final dest pointer . i: PtrInt = 1.18 Page 470 of 1055 . const source: shortstring): PAnsiChar. 1.you can specify the decoding range (as in copy(s. Copy WideChar source into dest^ with upper case conversion .O.@N ext) will return Next^='where=.18 Date: June 16.this special version expect source to be a shortstring function UpperCopyWin255(dest: PWinAnsiChar. const source: RawUTF8): PWinAnsiChar. Decode a string compatible with URI encoding into its original value .if Upper is found.will copy up to 255 AnsiChar (expect the dest buffer to be array[byte] of AnsiChar) function UpperCopy255W(dest: PAnsiChar.i. 2013 function UpperCopy(dest: PAnsiChar.returns final dest pointer .will copy up to 255 AnsiChar (expect the dest buffer to be array[byte] of AnsiChar) function UpperCopyShort(dest: PAnsiChar. source: PWideChar. Value is modified with the supplied content. overload.will copy up to 255 AnsiChar (expect the dest buffer to be array[byte] of AnsiChar) function UpperCopy255W(dest: PAnsiChar. to 0 or '&') . out Value: RawUTF8): PUTF8Char. patterns) . Value is not modified. Upper: PUTF8Char.45&where=LastName%3D'.P.' and P=20.18 Page 471 of 1055 .Synopse mORMot Framework Software Architecture Design 1.UrlDecodeNeedParameters('price=20.pas unit . and result is TRUE function UrlDecodeInteger(U.if Upper is not found..if a pair is decoded.g. Next: PPUTF8Char=nil): boolean.Name is returned directly (should be plain ASCII 7 bit text) ..it is up to the caller to continue the process or not SynCommons.if Upper is found.Value is returned after URI decoding (from %... Next: PPUTF8Char=nil): boolean..@N ext) will return Next^='where=.if a pair is not decoded.@Next) will return Next^='where=. and result is TRUE function UrlDecodeNeedParameters(U. and result is FALSE . or points to #0 if all content has been processed . Decode the next Name=Value&. var Value: Int64.if Upper is found.'PRICE='. Decode a specified parameter compatible with URI encoding into its original Int64 numerical value UrlDecodeInt64('offset=20&where=LastName%3D%27M%C3%B4net%27'.Value: RawUTF8): PUTF8Char.if Upper is not found. Value is not modified. var Value: Extended.45 .O.. 1. Upper: PUTF8Char.'OFFSET='.'OFFSET='. Value is modified with the supplied content.' and O=20 .returns a pointer just after the decoded value (may points e.. return a PUTF8Char pointer to the next pair in the input buffer. Next: PPUTF8Char=nil): boolean. Value is not modified. and result is FALSE . Value is modified with the supplied content. Upper: PUTF8Char. CSVUpper: PUTF8Char): boolean.if Upper is found. Decode a specified parameter compatible with URI encoding into its original floating-point value UrlDecodeExtended('price=20.'PRICE. Returns TRUE if all supplied parameters does exist in the URI encoded text . Value is modified with the supplied content. and result is FALSE . return nil function UrlDecodeNextValue(U: PUTF8Char.18 Date: June 16. Decode a URI-encoded Value from an input buffer .@Ne xt) will return Next^='where=..Rev. pair from input URI .. Decode a specified parameter compatible with URI encoding into its original integer numerical value UrlDecodeInteger('offset=20&where=LastName%3D%27M%C3%B4net%27'.O. var Name.decoded value is set in Value out variable .WHERE') will return TRUE function UrlDecodeNextNameValue(U: PUTF8Char. 2013 function UrlDecodeExtended(U.' and O=20 . var Value: integer. and result is TRUE function UrlDecodeInt64(U.45&where=LastName%3D%27M%C3%B4net%27'.if Upper is not found.. V. which will handle full i18n of your application . Next: PPUTF8Char=nil): boolean.e. overload. L: integer): RawUnicode. overload. from 1 up to 6) . as with WideString conversion (but without slow WideString usage) procedure UTF8DecodeToString(P: PUTF8Char.return the number of bytes written into Dest (i. Convert a UTF-8 string into a RawUnicode string function Utf8DecodeToRawUnicode(P: PUTF8Char. Convert any UTF-8 encoded buffer into a generic VCL Text SynCommons. L is computed from zero terminated P buffer . var Source: PWord): integer.if Upper is found. L: integer): string. and result is FALSE . overload. it will use the current RTL codepage.Source will contain the next UTF-16 character ..Utf8Decode() which uses slow widestrings function Utf8DecodeToRawUnicodeUI(const S: RawUTF8. Convert a UTF-8 string into a RawUnicode string . overload.under older version of Delphi (no unicode). Convert any UTF-8 encoded buffer into a generic VCL Text .if DestLen is not nil.pas unit . Upper: PUTF8Char. Convert a UTF-8 string into a RawUnicode string .UTF8ToString() in mORMoti18n.@Next ) will return Next^='where=. var Value: RawUTF8.18 Page 472 of 1055 .'SELECT='. 1. overload. var result: string). UTF-8 encode one UTF-16 encoded UCS4 character into Dest . L: integer. and result is TRUE function UrlEncode(const svar: RawUTF8): RawUTF8.faster than System. Decode a specified parameter compatible with URI encoding into its original textual value UrlDecodeValue('select=%2A&where=LastName%3D%27M%C3%B4net%27'.this method DOES handle UTF-16 surrogate pairs function Utf8DecodeToRawUnicode(const S: RawUTF8): RawUnicode.Rev. var Dest: RawUnicode): integer. overload. overload..if L is 0. Value is modified with the supplied content.it will work as is with Delphi 2009+ (direct unicode conversion) . Convert a UTF-8 encoded buffer into a RawUnicode string .RawUnicode is ended by a WideChar(#0) .returns the resulting length (in bytes) will be stored within Dest function Utf8DecodeToRawUnicodeUI(const S: RawUTF8.Synopse mORMot Framework Software Architecture Design 1. the resulting length (in bytes) will be stored within function UTF8DecodeToString(P: PUTF8Char. Value is not modified.if Upper is not found.this version doesn't resize the length of the result RawUnicode and is therefore usefull before a Win32 Unicode API call (with nCount=-1) . 2013 function UrlDecodeValue(U. Encode a string to be compatible with URI encoding function UTF16CharToUtf8(Dest: PUTF8Char. DestLen: PInteger=nil): RawUnicode.18 Date: June 16.it's prefered to use TLanguageFile.' and V='*' . the glyph count). var result: SynUnicode).UTF8ToUnicode with dest=nil SynCommons. UTF-8 encoded in source^ . it will use the current RTL codepage. overload. Direct conversion of a UTF-8 encoded buffer into a WinAnsi shortstring buffer function UTF8ToString(const Text: RawUTF8): string. Fast UTF-8 comparaison using the NormToUpper[] array for all 8 bits values . Convert any UTF-8 encoded buffer into a generic SynUnicode Text function Utf8ToUnicodeLength(source: PUTF8Char): PtrUInt.18 Date: June 16. which will handle full i18n of your application . Calculate the Unicode character count (i.UTF8ToString() in mORMoti18n.Synopse mORMot Framework Software Architecture Design 1. 1.L2: cardinal): PtrInt.18 Page 473 of 1055 . Convert any UTF-8 encoded String into a generic VCL Text .faster than System.current implementation handles UTF-16 surrogates procedure Utf8ToRawUTF8(P: PUTF8Char.this version expects u1 and u2 not to be necessary zero-terminated. var result: RawUTF8).this version expects u1 and u2 to be zero-terminated .under older version of Delphi (no unicode).end the count at first #13 or #10 character function UTF8IComp(u1. Fast UTF-8 comparaison using the NormToUpper[] array for all 8 bits values . but uses L1 and L2 as length for u1 and u2 respectively .current implementation handles UTF-16 surrogates function UTF8ILComp(u1. source: PUTF8Char).use this function for SQLite3 collation (TSQLCollateFunc) .pas unit . Calculate the character count of the first line UTF-8 encoded in source^ . Convert any UTF-8 encoded String into a generic SynUnicode Text procedure UTF8ToSynUnicode(Text: PUTF8Char. u2: PUTF8Char): PtrInt. u2: PUTF8Char. overload.e. 2013 function Utf8FirstLineToUnicodeLength(source: PUTF8Char): PtrInt.this version will decode the UTF-8 content before using NormToUpper[] .it will work as is with Delphi 2009+ (direct unicode conversion) .Rev.this version will decode the UTF-8 content before using NormToUpper[] . var result: SynUnicode). L1. Direct conversion of a UTF-8 encoded zero terminated buffer into a RawUTF8 String procedure UTF8ToShortString(var dest: shortstring. Convert any UTF-8 encoded String into a generic SynUnicode Text procedure UTF8ToSynUnicode(const Text: RawUTF8. as with WideString conversion (but without slow WideString usage) function UTF8ToSynUnicode(const Text: RawUTF8): SynUnicode. Len: integer.it's prefered to use TLanguageFile. overload. excluding the ending WideChar(#0) procedure UTF8ToWideString(Text: PUTF8Char.18 Page 474 of 1055 .sourceBytes can by 0. 1. Direct conversion of a UTF-8 encoded zero terminated buffer into a WinAnsi String function UTF8ToWinPChar(dest: PAnsiChar. Copy WideChar source into dest^ with upper case conversion. Convert any UTF-8 encoded String into a generic WideString Text function UTF8ToWideString(const Text: RawUTF8): WideString.faster than System.will copy up to 255 AnsiChar (expect the dest buffer to be array[byte] of AnsiChar). source: PUTF8Char. var result: WideString). source: PUTF8Char.returns final dest pointer .current implementation handles UTF-16 surrogates function UTF8UpperCopy255(dest: PAnsiChar. excluding the ending WideChar(#0) function UTF8ToWideChar(dest: pWideChar. Convert an UTF-8 encoded text into a WideChar array . Source: PUTF8Char.faster than System. overload.Synopse mORMot Framework Software Architecture Design 1. overload. count: integer): integer.this overloaded function expect a MaxDestChars parameter . Len: integer. overload. Direct conversion of a UTF-8 encoded string into a WinAnsi String function Utf8ToWinAnsi(P: PUTF8Char): WinAnsiString. 2013 function UTF8ToWideChar(dest: pWideChar. const source: RawUTF8): PUTF8Char. with UTF-8 encoding SynCommons. Convert any UTF-8 encoded String into a generic WideString Text procedure UTF8ToWideString(const Text: RawUTF8. SourceChars: Cardinal): PUTF8Char.a WideChar(#0) is added at the end (if something is written) . Direct conversion of a UTF-8 encoded buffer into a WinAnsi PAnsiChar buffer function UTF8UpperCopy(Dest. sourceBytes: PtrInt=0): PtrInt. overload. overload.returns final dest pointer .sourceBytes can not be 0 for this function .returns the BYTE count written in dest.UTF8ToUnicode . Convert an UTF-8 encoded text into a WideChar array .enough place must be available in dest . using the NormToUpper[] array for all 8 bits values. Convert any UTF-8 encoded String into a generic WideString Text function Utf8ToWinAnsi(const S: RawUTF8): WinAnsiString. MaxDestChars.a WideChar(#0) is added at the end (if something is written) . encoding the result as UTF-8 . sourceBytes: PtrInt): PtrInt.enough place must be available in dest . Copy WideChar source into dest^ with upper case conversion.pas unit . using the NormToUpper[] array for all 8 bits values.Rev. encoding the result as UTF-8 . var result: WideString). overload.UTF8ToUnicode . therefore length is computed from zero terminated source .returns the byte count written in dest.18 Date: June 16. source: PUTF8Char. overload. 2 or 3) . Convert an open array (const Args: array of const) argument to an UTF-8 encoded text . by using a fixed pre-calculated array for individual chars conversion procedure WinAnsiToUnicodeBuffer(const S: WinAnsiString. by using a fixed pre-calculated array for individual chars conversion . Convert a WideString into a WinAnsi (code page 1252) string function WinAnsiBufferToUtf8(Dest: PUTF8Char. overload.Synopse mORMot Framework Software Architecture Design 1. var wasString: boolean).e. var result: RawUTF8. Conversion of a wide char into a WinAnsi (CodePage 1252) char . Direct conversion of a WinAnsi (CodePage 1252) string into a Unicode buffer . 1.18 Date: June 16.pas unit . Direct conversion of a WinAnsi (CodePage 1252) string into a UTF-8 encoded String . Direct conversion of a WinAnsi (CodePage 1252) string into a Unicode encoded String . DestLen: integer).return -1 for an unknown WideChar in code page 1252 function WideCharToWinAnsiChar(wc: cardinal): AnsiChar. UTF-8 encode one UTF-16 character into Dest .this method does NOT handle UTF-16 surrogate pairs function WideCharToWinAnsi(wc: cardinal): integer.very fast.return the number of bytes written into Dest (i. overload. therefore wrongly) function WideCharToUtf8(Dest: PUTF8Char. var result: RawUTF8). Convert any Variant into UTF-8 encoded String . Direct conversion of a WinAnsi PAnsiChar buffer into a UTF-8 encoded buffer .use VariantSaveJSON() instead if you need a conversion to JSON procedure VarRecToUTF8(const V: TVarRec. Convert any Variant into UTF-8 encoded String .Global(). 1.return '?' for an unknown WideChar in code page 1252 function WideStringToUTF8(const aText: WideString): RawUTF8. Conversion of a wide char into a WinAnsi (CodePage 1252) char index . and use a fixed pre-calculated array for individual chars conversion SynCommons.note that cardinal values should be type-casted to Int64() (otherwise the integer mapped value will be transmitted. Dest: PWordArray.use VariantSaveJSON() instead if you need a conversion to JSON .very fast. aWideChar: PtrUInt): integer. SourceChars: Cardinal): PUTF8Char.wasString is set if the V value was a text function VariantToUTF8(const V: Variant): RawUTF8. overload.Rev. Source: PAnsiChar.18 Page 475 of 1055 . Convert a WideString into a UTF-8 string function WideStringToWinAnsi(const Wide: WideString): WinAnsiString.faster than SysUtils: don't use Utf8Encode(WideString) -> no Windows. 2013 procedure VariantToUTF8(const V: Variant.Dest^ buffer must be reserved with at least SourceChars*3 function WinAnsiToRawUnicode(const S: WinAnsiString): RawUnicode.text will be truncated if necessary to avoid buffer overflow in Dest[] function WinAnsiToUtf8(const S: WinAnsiString): RawUTF8. not our Extended version .g. A conversion table from hexa chars into binary data .used e. const Text: RawUTF8). i. Direct conversion of a WinAnsi (CodePage 1252) string into a UTF-8 encoded String . A global "Garbage collector".is set to kr32() function above . SynCommons.18 Page 476 of 1055 .e.. GarbageCollector. by HexToBin() function CurrentAnsiConvert: TSynAnsiConvert.Z.e. but resourcestring caching itself is implemented in the mORMoti18n.used to avoid any memory leak with e. the one used by ReadStringFromStream procedure YearToPChar(Y: Word.should be set to faster and more accurate crc32() function if available (this is what mORMot. The default hasher used by TDynArrayHashed() .z range .this is the encoding as used by the AnsiString Delphi.g.this instance is global and instantied during the whole program life time DefaultHasher: THasher. and use a fixed pre-calculated array for individual chars conversion procedure WriteStringToStream(S: TStream.pas unit does in its initialization block) ExeVersion: record Global information about the current executable and computer .used only if a default system.g.returns 255 for any character out of 0..18 Date: June 16.A.e.faster than SysUtils: don't use Utf8Encode(WideString) -> no Windows.Create(InstanceFileName. resourcestring caching for faster use .a. P: PUTF8Char).format is Length(Integer):Text.Rev.Synopse mORMot Framework Software Architecture Design 1.Global(). so will be used before Delphi 2009 to speed-up VCL string handling (especially for UTF-8) . i. e. overload. Current LoadResString() cached entries count . WinAnsiLen: integer): RawUTF8. 1.9. if the ENHANCEDRTL conditional is not defined ConvertHexToBin: array[byte] of byte. 'class var RecordProps'.defined here.DefaultVersion).pas is used.i. 2013 function WinAnsiToUtf8(WinAnsi: PAnsiChar.pas unit.Add(Version). Add the 4 digits of integer Y to P^ Variables implemented in the SynCommons unit: CacheResCount: integer = -1. Global TSynAnsiConvert instance to handle current system encoding .call ExeVersionRetrieve before using it GarbageCollector: TObjectList.pas unit . some singleton or static objects .. for some classes instances which must live during whole main executable process .to be used. Write an UTF-8 text into a TStream . as: Version := TFileVersion. log file generated by TSynTestsLogged TwoDigitLookupW: packed[0. when ENHANCEDRTL is not defined . The NormToUpper[] array is defined in our Enhanced RTL: define it now if it was not installed .mORMoti18n.e.pas unit .18 Date: June 16. 2013 i18nDateText: function(Iso: TTimeLog): string = nil.'z' into 'A'. These procedure type must be defined if a default system.. 1. This table will convert 'a'. as retrieved for the current process OSVersionInfo: TOSVersionInfoEx.18 Page 477 of 1055 .Rev.so it will work with UTF-8 without decoding.handle 8 bit upper chars as in WinAnsi / code page 1252 (e. it will use the GetNativeSystemInfo() new API to retrieve the real top-most system information . Custom date to ready to be displayed text function . whereas NormToUpper[] expects WinAnsi encoding OSVersion: TWindowsVersion.already defined in our Extended system.e.used by TSQLTable. i. Is set to TRUE if the current process is running under WOW64 .DrawCell() IsWow64: boolean. UnicodeString for Delphi 2009+ .handle 8 bit upper chars as in WinAnsi / code page 1252 (e.pas unit will hack default LoadResString() procedure .g.'Z' .ExpandAsString() method. The kind of . The NormToLower[] array is defined in our Enhanced RTL: define it now if it was not installed . accents) NormToUpper: TNormTable. as retrieved for the current process SystemInfo: TSystemInfo. i.pas is used . accents) NormToUpperAnsi7: TNormTable.e.expect generic "string" type. Fast lookup table for converting any decimal number from 0 to 99 into their ASCII equivalence SynCommons. TSQLTableToGrid.WOW64 is the x86 emulator that allows 32-bit Windows-based applications to run seamlessly on 64-bit Windows LoadResStringTranslate: procedure(var Text: string) = nil.needed with FPC.Synopse mORMot Framework Software Architecture Design 1.g.note that the lpMinimumApplicationAddress field is replaced by a more optimistic/realistic value ($100000 instead of default $10000) TSynLogExceptionToStrCustom: TSynLogExceptionToStr = nil. i. as retrieved for the current process .. Allow to customize the Exception logging message TSynLogTestLog: TSynLogClass = TSynLog.you can override this pointer in order to display the text according to your current i18n settings ..99] of word absolute TwoDigitLookup.under a WOW64 process.pas unit . The current System information. Delphi 2009 and up.not needed with the LVCL framework (we should be on server side) NormToLower: TNormTable. The current Operating System version. The current Operating System information. Synopse mORMot Framework Software Architecture Design 1. 2013 WinAnsiConvert: TSynAnsiFixedWidth.Rev.18 Date: June 16.pas unit .this instance is global and instantied during the whole program life time SynCommons.18 Page 478 of 1055 . 1. Global TSynAnsiConvert instance to handle WinAnsi encoding (code page 1252) . 1.1 client and server protocol .1 protocol 1049 Units used in the SynCrtSock unit: Unit Name Description Page SynWinSock Low level access to network Sockets for the Win32 platform . 2013 23.18 The SynCrtSock unit is quoted in the following items: SWRS # DI-2.pas unit . licensed under a MPL/GPL/LGPL tri-license.4 Description Page HTTP/1.18 706 EWinINet Exception EWinHTTP ECrtSocket TWinINet TWinHttpAPI TWinHTTP TSynThreadPool TSynThreadPoolTHttpServer TObject THttpServerRequest THttpServerSocket TCrtSocket THttpSocket THttpClientSocket THttpServerResp TThread THttpServer THttpServerGeneric THttpApiServer SynCrtSock class hierarchy Objects implemented in the SynCrtSock unit: Objects Description Page ECrtSocket Exception thrown by the classes of this unit 480 SynCrtSock.2. version 1. 1.pas unit Purpose: Classes implementing HTTP/1.18 Page 479 of 1055 .1.this unit is a part of the freeware Synopse mORMot framework. version 1.Synopse mORMot Framework Software Architecture Design 1.Rev. SynCrtSock.this unit is a part of the freeware Synopse framework. licensed under a MPL/GPL/LGPL tri-license.3.18 Date: June 16. 1 compatible client class 486 THttpServer Main HTTP server Thread using the standard Sockets library (e.Rev. 1.pas unit .18 Date: June 16.18 Page 480 of 1055 .sys kernel-mode server 490 THttpClientSocket REST and HTTP/1. either WinHTTP API 492 TWinINet A class to handle HTTP/1.1 request using the WinINet API 493 ECrtSocket = class(Exception) Exception thrown by the classes of this unit SynCrtSock.1 request using either WinINet.g. used for fast handling HTTP requests of a THttpServer 487 TWinHTTP A class to handle HTTP/1.Synopse mORMot Framework Software Architecture Design 1.1 request using the WinHTTP API 494 TWinHttpAPI A class to handle HTTP/1.1 server class used by THttpServer main server Thread 485 THttpSocket Parent of THttpClientSocket and THttpServerSocket classes 484 THttpSocketCompressRe c Used to maintain a list of known compression algorithms 484 TSynThreadPool A simple Thread Pool. WinSock) 491 THttpServerGeneric Generic HTTP server 489 THttpServerRequest A generic input/output structure used for HTTP server requests 488 THttpServerResp HTTP response Thread 487 THttpServerSocket HTTP/1. 2013 Objects Description Page EWinHTTP WinHTTP exception type 494 EWinINet WinINet exception type 493 TCrtSocket Fast low-level Socket implementation 481 THttpApiServer HTTP server using fast http. used for fast handling HTTP requests 487 TSynThreadPoolTHttpSe rver A simple Thread Pool. Linux) network layer .use SockIn and SockOut (after CreateSock*) to read or write data as with standard Delphi text files (see SendEmail implementation) . it may be up to 10 times faster) . aTimeOut: cardinal=5000). virtual.s) to send a line to the opened socket TimeOut: cardinal. Connect to aServer:aPort destructor Destroy. After CreateSockOut.use direct access to low level Windows or Linux network layer . Close the opened socket.use Open constructor to create a client to be connected to a server .if app is multi-threaded. Total bytes sent Port: AnsiString. read loop will wait for incoming data till TimeOut milliseconds (default value is 10000) . one or both SockIn/SockOut .Rev. After CreateSockIn. use faster SockSend() instead of SockOut^ for direct write access to the socket. aLayer: TCrtSocketLayer=cslTCP. even on multi-threaded app (at least under Windows. but SockIn^ is much faster than SockRecv() thanks to its internal buffer.but you can decide whatever to use none.do not call directly.use Bind constructor to initialize a server . Initialized after Open() with Server name Sock: TSocket. 1.used also in SockSend() constructor Bind(const aPort: AnsiString.s) to read a line from the opened socket SockOut: ^TextFile. Common initialization of all constructors . but use Open / Bind constructors instead constructor Open(const aServer.18 Page 481 of 1055 . override. aLayer: TCrtSocketLayer=cslTCP). use Writeln(SockOut. Initialized after Open() with socket SockIn: ^TextFile.direct access to the OS (Windows.18 Date: June 16. use Readln(SockIn.Synopse mORMot Framework Software Architecture Design 1. aPort: AnsiString. Bind to aPort constructor Create. 2013 TCrtSocket = class(TObject) Fast low-level Socket implementation .pas unit .our classes are much faster than the Indy or Synapse implementation BytesIn: cardinal. Total bytes received BytesOut: cardinal. If higher than 0. Initialized after Open() with port number Server: AnsiString. and corresponding SockIn/SockOut SynCrtSock. 18 Date: June 16. Initialize SockIn for receiving with read[ln](SockIn^.multithread applications would also use this SockIn pseudo-text file .returns 0 if data can not be written .bypass the SockIn^ buffers .18 Page 482 of 1055 .it's a compiler feature . expect CR+LF as line feed (i. filled as the data is available .by default. Len: integer): boolean.. Fill the Buffer with Length bytes . wait until something is available function TrySndLow(P: pointer. the HTTP way) procedure CreateSockOut..use rather SockSend() + SockSendFlush to send headers at once e. 2013 function SockCanRead(aTimeOut: cardinal): integer.. Length: integer): integer.returns >0 if data can be written . it first gets data from SockIn^. then directly receive data from socket .e.Buffer.returns 1 if there is some data to be read .g.Synopse mORMot Framework Software Architecture Design 1..returns 0 if there is no data to be read . Read Length bytes from SockIn buffer + Sock if necessary .bypass the SndBuf or SockOut^ buffers function TrySockRecv(Buffer: pointer.data is buffered. Check the connection status of the socket function SockInRead(Content: PAnsiChar..use TimeOut milliseconds wait for incoming data .return false on any error. Wait till some data is pending in the receiving queue within TimeOut milliseconds .if the TimeOut parameter is 0. Returns the socket input stream as a string .specify the Max time to wait until some data is available for reading . true on success .returns <0 on any socket error function SockCanWrite(aTimeOut: cardinal): integer. true on success procedure CreateSockIn(LineBreak: TTextLineBreakStyle=tlbsCRLF).if SockIn is available. Wait till some data can be sent within TimeOut milliseconds ...Rev.return false on any error.returns <0 on any socket error function SockConnected: boolean. since writeln(SockOut^.) ..data is sent (flushed) after each writeln() .) . Initialize SockOut for sending with write[ln](SockOut^.read(char) or readln() is indeed very fast . 1.pas unit .) flush buffer each time SynCrtSock. Direct send data through network ..can be used also without SockIn: it will call directly SockRecv() in such case function SockReceiveString(aTimeOut : integer = 300): RawByteString. Length: integer): boolean. raise ECrtSocket exception on socket error procedure SockSend(const Line: RawByteString=''). Call readln(SockIn^.. overload.bypass the SndBuf or SockOut^ buffers .usefull on multi-treaded environnement (as in THttpServer. Direct send data through network . overload.char are read one by one .g. 1.Line) or simulate it with direct use of Recv(Sock.) . Call readln(SockIn^) or simulate it with direct use of Recv(Sock.char are read one by one . Direct send data through network .raise a ECrtSocket exception on any error . overload.call SockSendFlush to send it through the network via SndLow() procedure SndLow(P: pointer. Simulate writeln() with direct use of Send(Sock.18 Page 483 of 1055 .pas unit .Rev.) .use TimeOut milliseconds wait for incoming data .18 Date: June 16.use TimeOut milliseconds wait for incoming data .. 2013 procedure Snd(P: pointer. . Append P^ data into SndBuf (used by SockSend(). Integer parameters . ShortString. Length: integer).raise ECrtSocket exception on socket error .raise a ECrtSocket exception on any error . Flush all pending data to be sent procedure Write(const Data: RawByteString). .handle RawByteString. Len: integer). CROnly: boolean=false).Process) . .no temp buffer is used .raw Data is sent directly to OS: no CR/CRLF is appened to the block SynCrtSock. Simulate writeln() with a single line procedure SockSendFlush.bypass the SockIn^ buffers .by default. Fill the Buffer with Length bytes .Synopse mORMot Framework Software Architecture Design 1.line content is ignored procedure SockRecvLn(out Line: RawByteString.raise ECrtSocket exception on socket error procedure SockRecvLn. Len: integer).. but you can delimit lines using #13 if CROnly is TRUE procedure SockSend(const Values: array of const).) . will handle #10 or #13#10 as line delimiter (as normal text files).bypass the SndBuf or SockOut^ buffers procedure SockRecv(Buffer: pointer. overload. e.) .raise ECrtSocket exception on socket error .use TimeOut milliseconds wait for incoming data . Char. .if not set. Will contain the data retrieved from the server.but you won't be able to use an Internet Browser nor AJAX application for remote access any more function HeaderAdd(const aValue: RawByteString): integer. Same as HeaderValue('Content-Type').Rev. Same as HeaderValue('Connection')='close'. as in ACCEPT-ENCODING: header (gzip. Will contain the first header line: .1 compliant content . Add an header entry.deflate.synlz) THttpSocket = class(TCrtSocket) Parent of THttpClientSocket and THttpServerSocket classes .1' for a GET request with THttpServer.18 Date: June 16. as CRLF delimited text SynCrtSock. Will contain the header lines after a Request . you can specify a prefix which will be put before the first header line: in this case. Same as HeaderValue('Content-Length').can optionaly compress and uncompress on the fly the data. ConnectionClose: boolean. and will be ignored by most AntiVirus programs. e.g. and increase security . but retrieved during Request .pas unit .1 protocol .in order to make the TCP/IP stream not HTTP compliant.'GET /path HTTP/1.g. The compression name. returning the just entered entry index in Headers[]s function HeaderGetText: RawByteString.is overriden with real Content length during HTTP body retrieval ContentType: RawByteString.handle chunking of body content . virtual. TCP/IP prefix to mask HTTP protocol .0 200 OK' for a GET response after Get() e. the TCP/IP stream won't be recognized as HTTP. The function handling compression and decompression Name: AnsiString.'HTTP/1.18 Page 484 of 1055 .0 or HTTP/1. but retrieved during Request Content: RawByteString.use HeaderValue() to get one TCPPrefix: RawByteString. after the Request ContentLength: integer.Synopse mORMot Framework Software Architecture Design 1. will create full HTTP/1. but retrieved during Request Headers: array of RawByteString. Get all Header values at once.contain properties for implementing the HTTP/1. 2013 THttpSocketCompressRec = record Used to maintain a list of known compression algorithms Func: THttpSocketCompress. with standard gzip/deflate or custom (synlzo/synlz) protocols Command: RawByteString. 1. or if any exception occured during the process function HeaderGetText: RawByteString.caller will then use the GetRequest method below to get the request SynCrtSock. with standard gzip/deflate or custom (synlzo/synlz) protocols .will register the THttpSocketCompress functions from the server function GetRequest(withBody: boolean=true): boolean. True if the client is HTTP/1. as CRLF delimited text .) after GetRequest() constructor Create(aServer: THttpServer). URL. 2013 function HeaderValue(aName: RawByteString): RawByteString. Method.1 behavior is keep alive. Contains the URL ('/' e. 1. cf.pas unit . Create the socket according to a server .4' header procedure InitRequest(aClientSock: TSocket).1 and 'Connection: Close' is not set (default HTTP/1. Main object function called after aClientSock := Accept + Create: . Will register a compression algorithm . unless 'Connection: Close' is specified.1 applications that do not support persistent connections MUST include the "close" connection option in every message") Method: RawByteString.18 Date: June 16.18 Page 485 of 1055 . RFC 2068 page 108: "HTTP/1.get Command. Headers and Body (if withBody is TRUE) . function RegisterCompress(aFunction: THttpSocketCompress): boolean.Synopse mORMot Framework Software Architecture Design 1.g. Get all Header values at once. e. override. Main object function called after aClientSock := Accept + Create: .g.get sent data in Content (if ContentLength<>0) . from CRLF delimited text THttpServerSocket = class(THttpSocket) HTTP/1. HeaderValue('Content-Type')='text/html'.the first registered algorithm will be the prefered one for compression procedure HeaderSetText(const aText: RawByteString).g..) after GetRequest() URL: RawByteString. e.'POST'.3.1 server class used by THttpServer main server Thread KeepAliveClient: boolean.used e.return false if the socket was not connected any more.g.returns true on success. Set all Header values at once. to compress on the fly the data. false if this function or this ACCEPT-ENCODING: header was already registered . Contains the method ('GET'.this overriden version will add the 'RemoteIP: 1.Rev. reintroduce.get initialize the socket with the supplied accepted socket .2. KeepAlive: cardinal=0. return 200.port) function .5. KeepAlive: cardinal=0. return 200 if OK. After an Open(server. DataType: RawByteString.port).port). DataType: RawByteString.call by all REST methods above . http status error otherwize . const header.204 if OK. DataType: RawByteString. By default. 1. const header: RawByteString=''): integer. override.1 request .202.the REST commands (GET/POST/PUT/DELETE) are directly available .1 compatible client class . return 200.Rev.port).204 if OK. http status error otherwize function Request(const url. http status error otherwize function Put(const url.201. http status error otherwize .204 if OK.18 Page 486 of 1055 . this is faster. KeepAlive: cardinal. return 200 if OK.Synopse mORMot Framework Software Architecture Design 1. connection closed) will retry once to get the value .204 if OK. const header: RawByteString=''): integer. which is very friendly welcome by most servers :( . KeepAlive: cardinal=0. Data.after an Open(server. KeepAlive: cardinal=0.port). but Headers are set function Post(const url.18 Date: June 16. Data.if KeepAlive>0. according to RFC 2068 document .1 compatible. 2013 THttpClientSocket = class(THttpSocket) REST and HTTP/1. After an Open(server. After an Open(server. After an Open(server. and will be recursively called with true to retry once SynCrtSock. retry: boolean): integer. or recreate a new one if the former is outdated or reset by server (will retry only once). Low-level HTTP/1.port).only header is read from server: Content is always ''. method: RawByteString.open connection with the server with inherited Open(server. KeepAlive: cardinal=0.202. the client is identified as IE 5.don't forget to use Free procedure when you are finished UserAgent: RawByteString.201. the connection is not broken: a further request (within KeepAlive milliseconds) will use the existing connection if available. const header: RawByteString=''): integer.pas unit . const header: RawByteString=''): integer. return 200. After an Open(server.get the page data in Content function Head(const url: RawByteString.on any error (timeout. and is the recommended way to implement a HTTP/1.port). http status error otherwize . Data. uses less resources (especialy under Windows). http status error otherwize function Get(const url: RawByteString.this overriden method will set the UserAgent with some default value function Delete(const url: RawByteString.you can specify a custom value here constructor Create. Common initialization of all constructors . return 200.1 server . const header: RawByteString=''): integer.this component is HTTP/1.retry is false by caller. overload. if the incoming request is identified as HTTP/1. Shut down the Thread pool.this Thread Pool is implemented over I/O Completion Ports. with no pause/resume function Initialize(WorkerFunc: TThreadFunc.18 Date: June 16.will use private THttpServerWorkerFunction as WorkerFunc .Synopse mORMot Framework Software Architecture Design 1.) THttpServer. and resume them on request: I/O completion just has the thread running while there is pending tasks. 2013 THttpServerResp = class(TThread) HTTP response Thread .Request() function or.you don't have to overload the protected THttpServerResp Execute method: override THttpServer. private THttpServerWorkerFunction for handling a THttpServer request . which is a faster method than keeping a TThread list.WorkerFunc should be e.up to 64 threads can be associated to a Thread Pool SynCrtSock. reintroduce.will create a THttpServerResp response thread.Execute procedure get the request and calculate the answer . Release used socket and memory TSynThreadPool = object(TObject) A simple Thread Pool. Initialize a thread pool with the supplied number of threads . Initialize the response thread for the corresponding incoming socket .g. Initialize the response thread for the corresponding incoming socket . 1. e. used for fast handling HTTP requests . aServer: THttpServer). for such an incoming request constructor Create(aSock: TSocket. Initialize a thread pool with the supplied number of threads .this version will get the request directly from an incoming socket destructor Destroy.up to 64 threads can be associated to a Thread Pool function Shutdown: Boolean. NumberOfThreads: Integer=32): Boolean.Process() method itself constructor Create(aServerSock: THttpServerSocket.1 keep alive function Initialize(NumberOfThreads: Integer=32): Boolean. overload.18 Page 487 of 1055 .pas unit . releasing all associated threads TSynThreadPoolTHttpServer = object(TSynThreadPool) A simple Thread Pool. if you need a lower-level access (change the protocol.g.this version will handle KeepAlive. aServer: THttpServer).will handle multi-connection with less overhead than creating a thread for each incoming request .Rev. override. used for fast handling HTTP requests of a THttpServer . 18 Date: June 16. Prepare an incoming request .if OutContentType is HTTP_RESP_STATICFILE (i. Input parameter containing the caller message headers property Method: RawByteString read fMethod. some GET/POST/PUT JSON data can be specified here property InContentType: RawByteString read fInContentType.URL/Method/InHeaders/InContent properties are input parameters . Initialize the context. Input parameter defining the caller message body content type property InHeaders: RawByteString read fInHeaders.. then OutContent is the UTF-8 file name of a file which must be sent to the client via http. Output parameter to be sent back as the response message header property Server: THttpServerGeneric read fServer.Synopse mORMot Framework Software Architecture Design 1. Output parameter to define the reponse message body content type property OutCustomHeaders: RawByteString read fOutCustomHeaders write fOutCustomHeaders. '!STATICFILE'). aMethod. associated to a HTTP server instance procedure Prepare(const aURL. Input parameter containing the caller URI SynCrtSock.Rev.g.will reset output parameters property InContent: RawByteString read fInContent. 1. aInContentType: RawByteString).pas unit . Output parameter to be set to the response message body property OutContentType: RawByteString read fOutContentType write fOutContentType. Input parameter containing the caller message body . aInContent.) property OutContent: RawByteString read fOutContent write fOutContent ..sys (much faster than manual buffering/sending) constructor Create(aServer: THttpServerGeneric). Input parameter containing the caller method (GET/POST. aClientSock: TSocket): Boolean.will set input parameters URL/Method/InHeaders/InContent/InContentType . 2013 function Push(aServer: THttpServer. aInHeaders.OutContent/OutContentType/OutCustomHeader are output parameters . The associated server instance property URL: RawByteString read fURL.18 Page 488 of 1055 .OutCustomHeader will handle Content-Type/Location .e. Add an incoming HTTP request to the Thread Pool THttpServerRequest = class(TObject) A generic input/output structure used for HTTP server requests .e. Rev.4 (page 1049).default implementation is to call the OnRequest event (if existing) . function Request(Ctxt: THttpServerRequest): cardinal. in the thread context .if OutContentType is HTTP_RESP_STATICFILE (i.e.called in the thread context at first place in THttpServerGeneric.OnHttpThreadTerminate(Sender: TObject). then OutContent is the UTF-8 file name of a file which must be sent to the client via http. for instance via a method defined as such: procedure TMyServer.18 Page 489 of 1055 .g. virtual.the first registered algorithm will be the prefered one for compression property OnHttpThreadStart: TNotifyThreadEvent read fOnHttpThreadStart write fOnHttpThreadStart. procedure RegisterCompress(aFunction: THttpSocketCompress).used e.EndCurrentThread. e.OutContent/OutContentType/OutCustomHeader are output parameters .1.4 (page 1049). so it won't fit our purpose . Event handler called by the default implementation of the virtual Request method . 1.1.Synopse mORMot Framework Software Architecture Design 1.g. 2013 THttpServerGeneric = class(TThread) Generic HTTP server Used for DI-2.result of the function is the HTTP error code (200 if OK.4 (page 1049). to call CoUnInitialize from thread in which CoInitialize was made. '!STATICFILE'). Event handler called when the Thread is just initiated . Event handler called when the Thread is terminating.2.pas unit .1. property OnRequest: TOnHttpServerRequest read fOnRequest write fOnRequest.to be used e. with standard gzip/deflate or custom (synlzo/synlz) protocols .g.sys (much faster than manual buffering/sending) .1. SynCrtSock.2.OnTerminate event will be called within a Synchronize() wrapper.1. Override this function to customize your http server . to compress on the fly the data. Will register a compression algorithm .) .Execute property OnHttpThreadTerminate: TNotifyEvent read fOnHttpThreadTerminate write fOnHttpThreadTerminate.the TThread. begin // TSQLDBConnectionPropertiesThreadSafe fMyConnectionProps. virtual.18 Date: June 16.InURL/InMethod/InContent properties are input parameters .warning: this process must be thread-safe (can be called by several threads simultaneously) Used for DI-2.OutCustomHeader will handle Content-Type/Location . end.warning: this process must be thread-safe (can be called by several threads simultaneously) Used for DI-2.1.2. The HTTP Server API is supported on Windows Server 2003 operating systems and on Windows XP with Service Pack 2 (SP2). Register the URLs to Listen On .2. an error code if failed: under Vista and Seven.e. after all AddUrl() calls.Synopse mORMot Framework Software Architecture Design 1.1. as defined by Windows security policy SynCrtSock. and you can set CreateSuspended to TRUE . the URI will be registered (need adminitrator rights) . Applications can register to receive HTTP requests for particular URLs.if you will call AddUrl() methods later. AddUrl('root'. then call explicitely the Resume method. Https: boolean=false. and send HTTP responses.if aRegisterURI is TRUE. an IPv4 or IPv6 literal string.pas unit .18 Date: June 16. 1. Initialize the HTTP Service . . you could have ERROR_ACCESS_DENIED if the process is not running with enough rights (by default. Used for DI-2.Rev.sys is not available (e. default Create must have be called with CreateSuspended = TRUE and then call the Resume method after all Url have been added .aDomainName could be either a fully qualified case-insensitive domain name.1.'888') .if this method is not used within an overriden constructor.4 (page 1049). constructor Create(CreateSuspended: Boolean). set CreateSuspended to FALSE.AddUrlAuthorize class method during program setup . 2013 THttpApiServer = class(THttpServerGeneric) HTTP server using fast http. put the AddUrl() methods within.solution is to call the THttpApiServer.sys registration list) . It is also designed to work with I/O completion ports. override.if you override this contructor.will raise an exception if http. destructor Destroy. in order to start the server Used for DI-2. or a wildcard ('+' will bound to all domain names for the specified port. before Windows XP SP2) or if the request queue creation failed .4 (page 1049). Be aware that Microsoft IIS 5 running on Windows XP with SP2 is not able to share port 80 with other HTTP applications running simultaneously. UAC requires administrator rights for adding an URL to http.return 0 (NO_ERROR) on success.18 Page 490 of 1055 .1.sys kernel-mode server .g. The HTTP Server API includes SSL support so that applications can exchange data over secure HTTP connections without IIS.1. receive HTTP requests.default is FALSE. aPort: RawByteString. '*' will accept the request when no other listening hostnames match the request for that port) . aRegisterURI: boolean=false): integer. Release all associated memory and handles function AddUrl(const aRoot. const aDomainName: RawByteString='*'.The HTTP Server API enables applications to communicate over HTTP without using Microsoft Internet Information Server (IIS).g.2. OnlyDelete: boolean=false): string. according to RFC 2068 specifications . WinSock) . in this case. -1 if the corresponding parameters do not match any previous AddUrl) procedure Clone(ChildThreadCount: integer).if the client is also HTTP/1. Will register a compression algorithm .bind to a port and listen to incoming requests . especially under Vista or Seven.this method expect the same parameters as specified to AddUrl() .1. in TSQLHttpServer. this is faster and uses less resources.18 Date: June 16. Https: boolean=false. Will contain the total number of connection to the server .must be called with Administrator rights: this class function is to be used in a Setup program for instance. Will clone this thread into multiple other threads .1.maximum value is 256 . to reserve the Url for the server . will delete but won't add the new authorization. especialy under Windows .1 compatible. 1.a Thread Pool is used internaly to speed up HTTP/1. Un-register the URLs to Listen On . const aDomainName: RawByteString='*'. KeepAlive connection is handled: multiple requests will use the existing connection and thread.if OnlyDelete is true.sys URL reservation store . ServerConnectionCount: cardinal. override. an error code if failed (e.higher should not be worth it procedure RegisterCompress(aFunction: THttpSocketCompress).it implements a HTTP/1.g.Rev. 2013 class function AddUrlAuthorize(const aRoot.return '' on success.0 connections . aPort: RawByteString.overriden method which will handle any cloned instances THttpServer = class(THttpServerGeneric) Main HTTP server Thread using the standard Sockets library (e.will first delete any matching rule for this URL prefix .return 0 (NO_ERROR) on success.18 Page 491 of 1055 . const aDomainName: RawByteString='*'): integer.could speed up the process on multi-core CPU . it will authorize any root for this port . Will authorize a specified URL prefix .it's the global count since the server started SynCrtSock.g.g.it will trigger the Windows firewall popup UAC window at first run .will work only if the OnProcess property was set (this is the case e. aPort: RawByteString.add a new record to the http.Synopse mORMot Framework Software Architecture Design 1.1 compatible server.pas unit .don't forget to use Free procedure when you are finished Used for DI-2.will allow to call AddUrl() later for any user on the computer .assign this requests to THttpServerResp threads . Https: boolean=false.if aRoot is left ''.Create() constructor) . an error message otherwise .4 (page 1049). any error message at deletion will be returned function RemoveUrl(const aRoot.2. aPort: AnsiString.2.in order to make the TCP/IP stream not HTTP compliant. that should not be routed through the proxy function RegisterCompress(aFunction: THttpSocketCompress): boolean.THttpServerSocket are created on the fly for every request.the first registered algorithm will be the prefered one for compression SynCrtSock. TCP/IP prefix to mask HTTP protocol . false if this function or this ACCEPT-ENCODING: header was already registered .this abstract class will be implemented e. to compress on the fly the data. the TCP/IP stream won't be recognized as HTTP. default is 3000 ms Sock: TCrtSocket. you can specify a prefix which will be put before the first header line: in this case. with TWinINet or TWinHttp constructor Create(const aServer.1/1 connections to be kept alive. with standard gzip/deflate or custom (synlzo/synlz) protocols .g.used e.Synopse mORMot Framework Software Architecture Design 1. in milliseconds.has a common behavior as THttpClientSocket() . 2013 ServerKeepAliveTimeOut: cardinal. either WinHTTP API .18 Date: June 16. destructor Destroy.but you won't be able to use an Internet Browser nor AJAX application for remote access any more constructor Create(const aPort: AnsiString . ServerThreadPoolCount: integer=32). will create full HTTP/1.1 request using either WinINet.1 compliant content .returns true on success. const aProxyName: AnsiString=''.0 or HTTP/1.Rev. then a THttpServerResp thread is created for handling this THttpServerSocket TCPPrefix: RawByteString.4 (page 1049). override. and aProxyByPass an optional semicolon delimited list of host names or IP addresses. listening and accept incoming request . and will be ignored by most AntiVirus programs. 1. Create a Server Thread. maximum is 64) Used for DI-2.if not set. const aProxyByPass: AnsiString='').g. binded and listening on a port .it's a raw TCrtSocket. for the HTTP. which only need a socket to be bound.1. and increase security . aHttps: boolean. Will register a compression algorithm .you can specify a number of threads to be initialized to handle incoming connections (default is 32. which may be sufficient for most cases.this constructor will raise a EHttpServer exception if binding failed . Connect to http://aServer:aPort or https://aServer:aPort . or both. Release all memory and handlers TWinHttpAPI = class(TObject) A class to handle HTTP/1. Contains the main server Socket . Time.18 Page 492 of 1055 .optional aProxyName may contain the name of the proxy server to use.pas unit .1. Create a WinINet exception. to use for name resolution .after an Create(server. KeepAlive: cardinal. InData. as specified to the class constructor property Port: cardinal read fPort. Time-out time. The remote server optional proxy. 1. return 200. to use for server connection requests property Https: boolean read fHttps. as stated specified to the class constructor TWinINet = class(TWinHttpAPI) A class to handle HTTP/1.The Microsoft Windows Internet (WinINet) application programming interface (API) enables applications to access standard Internet protocols.Rev.Synopse mORMot Framework Software Architecture Design 1. http status error otherwize property ConnectTimeout: DWORD read fConnectTimeout write fConnectTimeout. with the error message as text SynCrtSock.has a common behavior as THttpClientSocket() .note: WinINet is MUCH slower than THttpClientSocket: do not use this. 2013 function Request(const url.1 request using the WinINet API . the WinINet API should not be used from a service .port). in milliseconds. The remote server optional proxy by-pass list. override. as specified to the class constructor property ProxyName: AnsiString read fProxyName. only if you find some performance improvements on some networks destructor Destroy.not implemented with TWinINet class property SendTimeout: DWORD read fSendTimeout write fSendTimeout. as specified to the class constructor property ProxyByPass: AnsiString read fProxyByPass.204 if OK. Relase the connection EWinINet = class(Exception) WinINet exception type constructor Create. in milliseconds. If the remote server uses HTTPS. . to use for sending requests property Server: AnsiString read fServer. const InHeader. virtual. Time-out time.18 Date: June 16.202. OutData: RawByteString): integer. out OutHeader. in milliseconds. as specified to the class constructor property ReceiveTimeout: DWORD read fReceiveTimeout write fReceiveTimeout. such as FTP and HTTP/HTTPS. Time-out time. method: RawByteString.1 request . The remote server host name. The remote server port number.pas unit . in milliseconds. Low-level HTTP/1. InDataType: RawByteString. to receive a response to a request property ResolveTimeout: DWORD read fResolveTimeout write fResolveTimeout.by design. Time-out time.18 Page 493 of 1055 . 1 request using the WinHTTP API . cslUNIX ). The available available network transport layer . Relase the connection EWinHTTP = class(Exception) WinHTTP exception type Types implemented in the SynCrtSock unit: PPointer = ^Pointer. Compress: boolean): RawByteString. call netsh or proxycfg bits from %SystemRoot%\SysWOW64 folder explicitely) . FPC 64 compatibility pointer type PtrInt = integer. override.pas unit . FPC 64 compatibility integer type RawByteString = AnsiString.exe on Windows Vista and Windows Server 2008 or later. Associated Error Code.Rev.18 Page 494 of 1055 .has a common behavior as THttpClientSocket() but seems to be faster over a network and is able to retrieve the current proxy settings (if available) and handle secure https connection . Not defined in Delphi 5 or older PPtrInt = ^PtrInt.exe on Windows XP and Windows Server 2003 or earlier. as it does exist in Delphi 2009 and up .18 Date: June 16. The WinHTTP proxy configuration is set by either proxycfg.should always return the protocol name for ACCEPT-ENCODING: header e. you can run "proxycfg -u" or "netsh winhttp import proxy source=ie" to use the current user's proxy settings for Internet Explorer (under 64 bit Vista/Seven.type is a generic AnsiString.WinHTTP does not share any proxy settings with Internet Explorer.to be used for byte storage into an AnsiString TCrtSocketLayer = ( cslTCP.g.RegisterCompress method . Define RawByteString. 2013 property ErrorCode: DWORD read fCode.Microsoft Windows HTTP Services (WinHTTP) is targeted at middle-tier and back-end server applications that require access to an HTTP client stack destructor Destroy.so it seems to be the class to use in your client programs .the data is compressed (if Compress=TRUE) or uncompressed (if Compress=FALSE) in the Data variable (i. either netsh. 1.either TCP/IP.Synopse mORMot Framework Software Architecture Design 1. Event used to compress or uncompress some data during HTTP protocol . UDP/IP or Unix sockets THttpSocketCompress = function(var Data: RawByteString. which should be in practice a RawByteString or a RawByteString SynCrtSock. for instance. 'gzip' or 'deflate' for standard HTTP format. it is modified in-place) . but you can add your own (like 'synlzo' or 'synlz') .e. cslUDP. to configure applications using the 32 bit WinHttp settings.to be used with THttpSocket. as retrieved from API TWinHTTP = class(TWinHttpAPI) A class to handle HTTP/1. Rev.pas unit ..) .if OutContentType is HTTP_RESP_STATICFILE (i.g. Used by THttpApiServer.Synopse mORMot Framework Software Architecture Design 1.1 protocol and POST method 496 Open Create a TCrtSocket. using the HTTP/1. by calling GetMimeContentType() function from SynCommons supplyings the file name) SYNOPSE_FRAMEWORK_VERSION = '1.the OutCustomHeader should contain the proper 'Content-type: .18'. 1.1 protocol and GET method 496 HttpPost Send some data to a remote web server. returning nil on error (usefull to easily catch socket error exception ECrtSocket) 496 ResolveName Retrieve the IP adress from a computer name 496 SynCrtSock. Some timeout default values HTTP_RESP_STATICFILE = '!STATICFILE'. e.result of the function is the HTTP error code (200 if OK. by THttpServerGeneric. '!STATICFILE').OnRequest property .. from its IP Address 496 HtmlEncode Escaping of HTML codes like < > & " 496 HttpGet Retrieve the content of a web page.OutCustomHeader will handle Content-Type/Location .sys (much faster than manual buffering/sending) TWinHttpAPIClass = class of TWinHttpAPI. 2013 TNotifyThreadEvent = procedure(Sender: TThread) of object.18 Date: June 16.' corresponding to the file (e. returning nil on error (usefull to easily catch socket error exception ECrtSocket) 496 OpenHttp Create a THttpClientSocket.sys to send a static file . using the HTTP/1.e.Request for http. Event prototype used e. The corresponding version of the freeware Synopse framework Functions or procedures implemented in the SynCrtSock unit: Functions or procedures Description Page Base64Decode Base64 decoding of a string 496 Base64Encode Base64 encoding of a string 496 GetRemoteMacAddress Remotly get the MAC address of a computer. Event handler used by THttpServerGeneric.OnHttpThreadStart TOnHttpServerRequest = function(Ctxt: THttpServerRequest): cardinal of object. then OutContent is the UTF-8 file name of a file which must be sent to the client via http.Ctxt defines both input and output parameters .18 Page 495 of 1055 .g..g. Type of a TWinHttpAPI class Constants implemented in the SynCrtSock unit: HTTP_DEFAULT_RESOLVETIMEOUT = 0. aPort: AnsiString): THttpClientSocket. DataType: RawByteString): boolean. const Port: AnsiString='25'): boolean.g. 2013 Functions or procedures Description Page SendEmail Send an email using the SMTP protocol 496 StatusCodeToReason Retrieve the HTTP reason text from a code 496 function Base64Decode(const s: RawByteString): RawByteString. Text: RawByteString. const User: RawByteString=''. Send some data to a remote web server.18 Date: June 16.Rev. Retrieve the HTTP reason text from a code .g. Base64 decoding of a string function Base64Encode(const s: RawByteString): RawByteString. const Pass: RawByteString=''.return the MAC address as a 12 hexa chars ('0050C204C80A' e. const url.) function HtmlEncode(const s: RawByteString): RawByteString.pas unit . using the HTTP/1. Subject. Retrieve the content of a web page. StatusCodeToReason(200)='OK' SynCrtSock. const Headers: RawByteString=''. const From. using the HTTP/1. Escaping of HTML codes like < > & " function HttpGet(const server.retry true on success function StatusCodeToReason(Code: integer): RawByteString.18 Page 496 of 1055 . port: AnsiString. Create a THttpClientSocket. Base64 encoding of a string function GetRemoteMacAddress(const IP: AnsiString): RawByteString. from its IP Address . Create a TCrtSocket. Remotly get the MAC address of a computer. returning nil on error (usefull to easily catch socket error exception ECrtSocket) function ResolveName(const Name: AnsiString): AnsiString.e.only works under Win2K and later .1 protocol and GET method function HttpPost(const server. returning nil on error (usefull to easily catch socket error exception ECrtSocket) function OpenHttp(const aServer. Send an email using the SMTP protocol . Data.Synopse mORMot Framework Software Architecture Design 1. port: AnsiString. CSVDest.1 protocol and POST method function Open(const aServer. aPort: AnsiString): TCrtSocket. Retrieve the IP adress from a computer name function SendEmail(const Server: AnsiString. 1. const url: RawByteString): RawByteString. version 1. 1. XOR.this unit is a part of the freeware Synopse mORMot framework. ADLER32.optimized for speed (tuned assembler and VIA PADLOCK optional support) .18 Date: June 16.Synopse mORMot Framework Software Architecture Design 1.implements AES. SynCrypto. licensed under a MPL/GPL/LGPL tri-license.this unit is a part of the freeware Synopse mORMot framework. 2013 23.Rev.pas unit Purpose: Fast cryptographic routines (hashing and cypher) . MD5.pas unit .4. licensed under a MPL/GPL/LGPL tri-license.18 Units used in the SynCrypto unit: Unit Name Description Page SynCommons Common functions used by most Synopse projects . version 1. SHA256 algorithms .18 325 TSHA256 TSHA1 TRC4 TMD5 TObject TStream TAESFullHeader TAESOFB TAESFull TAESECB TAESAbstract TAESCTR TAES TAESCFB TAESWriteStream TAESCBC SynCrypto class hierarchy Objects implemented in the SynCrypto unit: Objects Description Page TAES Handle AES cypher/uncypher 498 TAESAbstract Handle AES cypher/uncypher with chaining 499 TAESCBC Handle AES cypher/uncypher with Cipher-block chaining (CBC) 500 SynCrypto.18 Page 497 of 1055 . SHA1. True if the context was initialized function DecryptInit(const Key.Rev. Initialize AES contexts for cypher . Decrypt an AES data block into another data block procedure Decrypt(var B: TAESBlock). Decrypt an AES data block procedure DoBlocks(pIn.18 Date: June 16. KeySize: cardinal): boolean.call either EncryptInit() either DecryptInit() method function EncryptInit(const Key. pOut: PAESBlock. Count: integer. 1.256 procedure Decrypt(const BI: TAESBlock. Initialize AES contexts for uncypher function DoInit(const Key. doEncrypt: boolean): boolean. i. 2013 Objects Description Page TAESCFB Handle AES cypher/uncypher with Cipher feedback (CFB) 500 TAESCTR Handle AES cypher/uncypher with Counter mode (CTR) 500 TAESECB Handle AES cypher/uncypher without chaining (ECB) 500 TAESFull AES and XOR encryption object for easy direct memory or stream access 502 TAESFullHeader Internal header for storing our AES data with salt and CRC 502 TAESOFB Handle AES cypher/uncypher with Output feedback (OFB) 500 TAESWriteStream AES encryption stream 503 TMD5 Handle MD5 hashing 501 TRC4 Handle RC4 encryption/decryption 502 TSHA1 Handle SHA1 hashing 501 TSHA256 Handle SHA256 hashing 501 TAES = object(TObject) Handle AES cypher/uncypher . Generic initialization method for AES contexts .18 Page 498 of 1055 . doEncrypt: boolean). var BO: TAESBlock).call either Encrypt() either Decrypt() method SynCrypto. Perform the AES cypher or uncypher to continuous memory blocks .Synopse mORMot Framework Software Architecture Design 1.pas unit . overload. overload.e. KeySize: cardinal): boolean. overload. 128.KeySize is in bits.192.this is the default Electronic codebook (ECB) mode Initialized: boolean.first method to call before using this class . KeySize: cardinal. Encrypt a memory buffer using a PKCS7 padding pattern . accorsponding to the chaining mode required TAESECB. Perform the AES un-cypher in the corresponding mode . overload. OFB and CTR mode (including PKCS7 padding) constructor Create(const aKey.this special method will use Threads for bigs blocks (>512KB) if multi-CPU .call either Encrypt() either Decrypt() method procedure Done. BufOut: pointer.only used with Padlock procedure Encrypt(const BI: TAESBlock.IV is the Initialization Vector function DecryptPKCS7(const Input: RawByteString): RawByteString.18 Date: June 16.call either Encrypt() either Decrypt() method procedure DoBlocksThread(var bIn. overload. TAESCFB.e.Context. i.PKCS7 is described in RFC 5652 . virtual. Count: integer. var BO: TAESBlock). Encrypt an AES data block into another data block procedure Encrypt(var B: TAESBlock).KeySize is in bits. Perform the AES cypher or uncypher to continuous memory blocks . 128. Decrypt a memory buffer using a PKCS7 padding pattern . BufOut: pointer. and fIn/fOut from BufIn/BufOut procedure Encrypt(BufIn. TAESCBC. out oIn. 1. virtual.this abstract method will set CV from AES.this abstract method will set CV from AES. Count: integer. 2013 procedure DoBlocks(pIn. CBC. overload. doEncrypt: boolean).18 Page 499 of 1055 .192. pOut: PAESBlock.use any of the inherited implementation. Count: cardinal). Perform the AES cypher in the corresponding mode . virtual. TAESOFB and TAESCTR classes to handle in ECB. CFB. Finalize AES contexts for both cypher and uncypher .it will add up to 16 bytes to the input buffer procedure Decrypt(BufIn. Initialize AES contexts for cypher .PKCS7 is described in RFC 5652 .Synopse mORMot Framework Software Architecture Design 1.it will trim up to 16 bytes from the input buffer function EncryptPKCS7(const Input: RawByteString): RawByteString. Perform the AES cypher or uncypher to continuous memory blocks .Rev. oOut: PAESBLock. doEncrypt: boolean). bOut: PAESBlock.Context. Count: cardinal). and fIn/fOut from BufIn/BufOut property Key: TAESKey read fKey. const aIV: TAESBlock).256 .pas unit . Associated Key data SynCrypto. aKeySize: cardinal. Encrypt an AES data block TAESAbstract = class(TObject) Handle AES cypher/uncypher with chaining .first method to call before using this class . in bits (i. Perform the AES cypher in the CFB mode TAESOFB = class(TAESAbstract) Handle AES cypher/uncypher with Output feedback (OFB) procedure Decrypt(BufIn. BufOut: pointer. Perform the AES un-cypher in the OFB mode procedure Encrypt(BufIn. BufOut: pointer. Count: cardinal). Perform the AES cypher in the OFB mode TAESCTR = class(TAESAbstract) Handle AES cypher/uncypher with Counter mode (CTR) procedure Decrypt(BufIn. override. Count: cardinal).IV value set on constructor is used to code the trailing bytes of the buffer (by a simple XOR) procedure Decrypt(BufIn. BufOut: pointer. Perform the AES cypher in the CBC mode TAESCFB = class(TAESAbstract) Handle AES cypher/uncypher with Cipher feedback (CFB) procedure Decrypt(BufIn. Perform the AES un-cypher in the CTR mode SynCrypto. Count: cardinal). Perform the AES un-cypher in the CBC mode procedure Encrypt(BufIn. override. BufOut: pointer.Rev. Perform the AES un-cypher in the CFB mode procedure Encrypt(BufIn. BufOut: pointer. override. override. BufOut: pointer. BufOut: pointer.18 Page 500 of 1055 . override. Count: cardinal).18 Date: June 16. Perform the AES cypher in the ECB mode TAESCBC = class(TAESAbstract) Handle AES cypher/uncypher with Cipher-block chaining (CBC) procedure Decrypt(BufIn.pas unit .192. override. Associated Key Size. 2013 property KeySize: cardinal read fKeySize. Count: cardinal). BufOut: pointer.e. Count: cardinal). 1. Count: cardinal). Perform the AES un-cypher in the ECB mode procedure Encrypt(BufIn. override. Count: cardinal).Synopse mORMot Framework Software Architecture Design 1. override.this mode is known to be less secure than the others . 128.256) TAESECB = class(TAESAbstract) Handle AES cypher/uncypher without chaining (ECB) . override. Count: cardinal). BufOut: pointer. Finalize and compute the resulting SHA1 hash Digest of all data affected to Update() method procedure Full(Buffer: pointer. out Digest: TSHA256Digest). One method to rule them all . then Final() .only Full() is Padlock-implemented . Used by Update and Final initialize SHA256 context for hashing procedure Update(Buffer: pointer. Update the SHA256 context with some data TMD5 = object(TObject) Handle MD5 hashing function Final: TMD5Digest. then Update(). override.18 Date: June 16. then Update().use this rather than Update() procedure Init. Finalize and compute the resulting SHA256 hash Digest of all data affected to Update() method procedure Full(Buffer: pointer. then Update(). Finalize and compute the resulting MD5 hash Digest of all data affected to Update() method procedure Full(Buffer: pointer.Rev.call Init. 2013 procedure Encrypt(BufIn. Used by Update and Final initialize SHA1 context for hashing procedure Update(Buffer: pointer. Len: integer. 1.only Full() is Padlock-implemented . Perform the AES cypher in the CTR mode TSHA1 = object(TObject) Handle SHA1 hashing procedure Final(out Digest: TSHA1Digest). then Final() . Finalize and compute the resulting MD5 hash Digest of all data affected to Update() method procedure Final(out result: TMD5Digest). One method to rule them all .pas unit . out Digest: TMD5Digest). BufOut: pointer. One method to rule them all . Len: integer). overload. Len: integer.call Init. Count: cardinal). then Final() SynCrypto.call Init. Len: integer). Len: integer.Synopse mORMot Framework Software Architecture Design 1. Update the SHA1 context with some data TSHA256 = object(TObject) Handle SHA256 hashing procedure Final(out Digest: TSHA256Digest).18 Page 501 of 1055 . out Digest: TSHA1Digest).use this rather than Update() procedure Init. overload. Len: cardinal).pas unit .RC4 is a symetrical algorithm: use this Encrypt() method for both encryption and decryption of any buffer procedure Init(const aKey.calls internaly TAES objet methods.18 Date: June 16. 2013 procedure Init. Len before compression (if any) SomeSalt: cardinal. aKeyLen: integer). Update the MD5 context with some data TRC4 = object(TObject) Handle RC4 encryption/decryption procedure Encrypt(const BufIn.KeyLen is in bytes. 1.a TAESFullHeader is encrypted at the begining. Initialize the RC4 encryption/decryption . Initialize MD5 context for hashing procedure Update(const buffer. Count: cardinal). allowing fast Key validation. Len before AES encoding TAESFull = object(TObject) AES and XOR encryption object for easy direct memory or stream access . but the resulting stream is not compatible with raw TAES object Head: TAESFullHeader. or a RestoreKey() from a previous SaveKey(). since it will change the internal key[] during its process . Restore the internal key as computed by Init() procedure SaveKey(out Backup: TRC4InternalKey). Perform the RC4 cypher encryption/decryption on a buffer .Synopse mORMot Framework Software Architecture Design 1. and handle memory and streams for best speed . Random Salt for better encryption SourceLen: cardinal. stored at the beginning of struct -> 16-byte aligned SynCrypto.. Header.Rev.each call to this method shall be preceded with an Init() call.255 range procedure RestoreKey(const Backup: TRC4InternalKey).18 Page 502 of 1055 . and should be within 1. var BufOut. Save the internal key computed by Init() TAESFullHeader = object(TObject) Internal header for storing our AES data with salt and CRC HeaderCheck: cardinal. CRC from header OriginalLen: cardinal. -1 if error on decoding (Key not correct) .192. 128. Origin: Word): Longint. This memory stream is used in case of EncodeDecode(outStream=bOut=nil) method call function EncodeDecode(const Key. Write pending data .if outStream is TMemoryStream -> auto-reserve space (no Realloc:) . Finalize the AES encryption stream .last bytes are coded with XOR (not compatible with TAESFull format) . 1. Read some data is not allowed -> this method will raise an exception on call function Seek(Offset: Longint. KeySize.valid KeySize: 0=nothing. bOut: pointer.for Key check constructor Create(outStream: TStream.pas unit . outStream: TStream. Main method of AES or XOR cypher/uncypher . 32=xor.should always be called before closeing the outStream (some data may still be in the internal buffers) Types implemented in the SynCrypto unit: TAESBlock = packed array[0. in a compatible way with AES() . after encryption procedure Finish. 128 bits memory block for AES data cypher/uncypher TAESKey = packed array[0.for normal usage. Count: Longint): Longint. you just have to Assign one In and one Out . 2013 outStreamCreated: TMemoryStream.18 Date: June 16. CRC from uncrypted compressed data . const Key. Count: Longint): Longint. override.Rev.internaly call the Finish method function Read(var Buffer. Encrypt: boolean. an outStream is created via THeapMemoryStream.not optimized for small blocks -> ok if used AFTER TBZCompressor/TZipCompressor .if outStream AND bOut are both nil.Synopse mORMot Framework Software Architecture Design 1.256=AES . SynCrypto.return out size.Create .AESKeySize-1] of byte.18 Page 503 of 1055 .g.. a TMemoryStream or a TFileStream) destructor Destroy.. OriginalLen: cardinal=0): integer.encrypt the Data on the fly.warning: Write() will crypt Buffer memory in place -> use AFTER T*Compressor DestSize: cardinal. If KeySize=0 initialize the AES encryption stream for an output stream (e. Append some data to the outStream.AESBlockSize-1] of byte.if Encrypt -> OriginalLen can be used to store unCompressed Len TAESWriteStream = class(TStream) AES encryption stream .if Padlock is used. override. override. inLen: cardinal. KeySize: cardinal). bIn. Read some data is not allowed -> this method will raise an exception on call function Write(const Buffer. 16-byte alignment is forced (via tmp buffer if necessary) . override. inStream. 15] of Byte. 256 bits memory block for SHA256 hash digest storage Constants implemented in the SynCrypto unit: AESBlockSize = 16...pas unit . 1.Rev. 2013 256 bits memory block for maximum AES key storage TMD5Digest = array[0.Synopse mORMot Framework Software Architecture Design 1. Standard AES block size during cypher/uncypher AESContextSize = 278+sizeof(pointer). as used by TRC4 TSHA1Digest = packed array[0..19] of byte. Internal key permutation buffer. 160 bits memory block for SHA1 hash digest storage TSHA256Digest = packed array[0.18 Page 504 of 1055 .18 Date: June 16. Hide all AES Context complex code AESKeySize = 256 div 8. Hide all SHA Context complex code Functions or procedures implemented in the SynCrypto unit: Functions or procedures Description Page Adler32Asm Fast Adler32 implementation 506 Adler32Pas Simple Adler32 implementation 506 Adler32SelfTest Self test of Adler32 routines 506 AES Direct Encrypt/Decrypt of data using the TAES class 506 AES Direct Encrypt/Decrypt of data using the TAES class 506 AES Direct Encrypt/Decrypt of data using the TAES class 506 AES Direct Encrypt/Decrypt of data using the TAES class 506 AESFull AES and XOR encryption using the TAESFull format 506 AESFull AES and XOR encryption using the TAESFull format 506 AESFullKeyOK AES and XOR decryption check using the TAESFull format 506 AESSelfTest Self test of AES routines 506 SynCrypto. 128 bits memory block for MD5 hash digest storage TRC4InternalKey = array[byte] of byte.31] of byte. Maximum AES key size SHAContextSize = 108. 2013 Functions or procedures Description Page AESSHA256 AES encryption using the TAES format with a supplied SHA256 password 507 AESSHA256 AES encryption using the TAES format with a supplied SHA256 password 507 AESSHA256 AES encryption using the TAES format with a supplied SHA256 password 507 AESSHA256Full AES encryption using the TAESFull format with a supplied SHA256 password 507 bswap160 Little endian fast conversion 507 bswap256 Little endian fast conversion 507 bswap32 Little endian fast conversion 507 htdigest Compute the HTDigest for a user and a realm. 1.18 Page 505 of 1055 .18 Date: June 16. according to a supplied password 507 MD5 Direct MD5 hash calculation of some data (string-encoded) 507 MD5Buf Direct MD5 hash calculation of some data 507 MD5DigestsEqual Compare two supplied MD5 digests 507 MD5DigestToString Compute the hexadecimal representation of a MD5 digest 507 MD5SelfTest Self test of MD5 routines 508 RC4SelfTest Self test of RC4 routines 508 SHA1 Direct SHA1 hash calculation of some data (string-encoded) 508 SHA1DigestToString Compute the hexadecimal representation of a SHA1 digest 508 SHA1SelfTest Self test of SHA1 routines 508 SHA256 Direct SHA256 hash calculation of some data (string-encoded) 508 SHA256DigestToString Compute the hexadecimal representation of a SHA256 digest 508 SHA256SelfTest Self test of SHA256 routines 508 SHA256Weak Direct SHA256 hash calculation of some data (string-encoded) 508 XorBlock 508 XorConst Fast XOR Cypher changing by Count value 508 XorOffset Fast and simple XOR Cypher using Index (=Position in Dest Stream) 508 SynCrypto.Rev.pas unit .Synopse mORMot Framework Software Architecture Design 1. buffer: pointer. Self test of Adler32 routines procedure AES(const Key.last bytes (not part of 16 bytes blocks) are not crypted by AES. Encrypt: boolean. -1 if error function AESFullKeyOK(const Key. Stream: TStream. Encrypt: boolean). p: pointer.outStream will be larger/smaller than Len (full AES encrypted) . const s: RawByteString. KeySize: cardinal.return true if begining of buff contains true AESFull encrypted data with this Key . outStream: TStream. Count: Integer): cardinal. AES and XOR encryption using the TAESFull format .18 Page 506 of 1055 . but shorter code size function Adler32SelfTest: boolean.pas unit . Direct Encrypt/Decrypt of data using the TAES class . buff: pointer): boolean. Encrypt: boolean): boolean. bOut: pointer. Direct Encrypt/Decrypt of data using the TAES class .last bytes (not part of 16 bytes blocks) are not crypted by AES. Encrypt: boolean): RawByteString. but with XOR function AES(const Key. Count: Integer): cardinal. Len: Integer.Synopse mORMot Framework Software Architecture Design 1. but with XOR function AES(const Key. overload. Len: Integer.18 Date: June 16. KeySize: cardinal.a bit slower than Adler32Asm() version below. KeySize: cardinal.bOut must be at least bIn+32/Encrypt bIn-16/Decrypt . KeySize: cardinal. AES and XOR decryption check using the TAESFull format .16-bytes-chunck unrolled asm version function Adler32Pas(Adler: cardinal.returns outLength. Direct Encrypt/Decrypt of data using the TAES class . overload. Len: Integer. buffer: pointer.returns true if OK function AESFull(const Key. Simple Adler32 implementation . but with XOR procedure AES(const Key. Encrypt: boolean). p: pointer.Rev. bIn: pointer. KeySize: cardinal. Direct Encrypt/Decrypt of data using the TAES class . overload. Fast Adler32 implementation . overload. Encrypt: boolean. bOut: pointer. OriginalLen: Cardinal=0): boolean.if not KeySize in [128. 1. Len: Integer. bIn. AES and XOR encryption using the TAESFull format . overload.last bytes (not part of 16 bytes blocks) are not crypted by AES. Len: cardinal. overload. Self test of AES routines SynCrypto. but with XOR function AESFull(const Key. 2013 function Adler32Asm(Adler: cardinal.last bytes (not part of 16 bytes blocks) are not crypted by AES.256] -> use fast and efficient Xor Cypher function AESSelfTest: boolean. KeySize: cardinal. OriginalLen: Cardinal=0): integer.192. KeySize: cardinal. bIn. overload.32 bits = 1 integer . Len: Integer. pass: RawByteString): RawUTF8.apache-compatible: 'agent007:download area:8364d0044ef57b3defcfa141e8f77b65' function MD5(const s: RawByteString): RawUTF8. bOut: pointer.use fast bswap asm in x86/x64 mode function htdigest(const user. according to a supplied password . Encrypt: boolean).last bytes (not part of 16 bytes blocks) are not crypted by AES.d: PIntegerArray). Direct MD5 hash calculation of some data (string-encoded) . Little endian fast conversion . Len: Cardinal): TMD5Digest. Encrypt: boolean).18 Date: June 16. but with XOR procedure AESSHA256Full(bIn: pointer. Little endian fast conversion . 1.pas unit .d: PIntegerArray). Password: RawByteString. 2013 procedure AESSHA256(bIn. AES encryption using the TAES format with a supplied SHA256 password .last bytes (not part of 16 bytes blocks) are not crypted by AES. B: TMD5Digest): Boolean. AES encryption using the TAESFull format with a supplied SHA256 password . Encrypt: boolean): RawByteString. const Password: RawByteString. Direct MD5 hash calculation of some data function MD5DigestsEqual(const A. outStream: TStream.Rev. overload. Len: integer.160 bits = 5 integers . realm. overload.18 Page 507 of 1055 . but with XOR procedure AESSHA256(Buffer: pointer.use fast bswap asm in x86/x64 mode procedure bswap256(s. const Password: RawByteString.result is returned in hexadecimal format function MD5Buf(const Buffer.outStream will be larger/smaller than Len: this is a full AES version with a triming TAESFullHeader at the beginning procedure bswap160(s. AES encryption using the TAES format with a supplied SHA256 password . Compute the hexadecimal representation of a MD5 digest SynCrypto. AES encryption using the TAES format with a supplied SHA256 password .Synopse mORMot Framework Software Architecture Design 1. overload.256 bits = 8 integers . Compute the HTDigest for a user and a realm. but with XOR function AESSHA256(const s. Little endian fast conversion . Encrypt: boolean).use fast bswap asm in x86/x64 mode function bswap32(a: cardinal): cardinal. Len: integer. Compare two supplied MD5 digests function MD5DigestToString(const D: TMD5Digest): RawUTF8. const Password: RawByteString.last bytes (not part of 16 bytes blocks) are not crypted by AES. e. 1. Self test of SHA256 routines procedure SHA256Weak(const s: RawByteString. in order to have at least a 256 bytes long hash: such a feature improve security for small passwords. Fast and simple XOR Cypher using Index (=Position in Dest Stream) . Count: integer). Compute the hexadecimal representation of a SHA256 digest function SHA256SelfTest: boolean.Stream compatible (with updated Index) . overload. Index. the compression rate will not change a lot procedure XorOffset(p: pByte. 2013 function MD5SelfTest: boolean.this procedure has a weak password protection: small incoming data is append to some salt.Synopse mORMot Framework Software Architecture Design 1.result is returned in hexadecimal format function SHA1DigestToString(const D: TSHA1Digest): RawUTF8.very fast XOR according to Cod . Direct SHA256 hash calculation of some data (string-encoded) . procedure XorBlock(p: PIntegerArray.Compression compatible.result is returned in hexadecimal format . Direct SHA1 hash calculation of some data (string-encoded) . as outStream for TAESWriteStream) .result is returned in hexadecimal format function SHA256DigestToString(const D: TSHA256Digest): RawUTF8.Count: integer). since the XOR value is always the same. Self test of SHA1 routines function SHA256(const s: RawByteString): RawUTF8. Compute the hexadecimal representation of a SHA1 digest function SHA1SelfTest: boolean. Direct SHA256 hash calculation of some data (string-encoded) . Self test of RC4 routines function SHA1(const s: RawByteString): RawUTF8.used in AESFull() for KeySize=32 procedure XorConst(p: PIntegerArray.used in AES() and TAESWriteStream SynCrypto. Fast XOR Cypher changing by Count value .Rev.18 Page 508 of 1055 . out Digest: TSHA256Digest).pas unit . . Self test of MD5 routines function RC4SelfTest: boolean.g.g.Compression not compatible with this function: should be applied after compress (e.18 Date: June 16. Cod: integer). Count.not Compression or Stream compatible . 18 Date: June 16. 2013 23. licensed under a MPL/GPL/LGPL tri-license. as used by the SynDB unit 510 ESQLQueryException Generic Exception type raised by the TQuery class 541 ISQLDBRows Generic interface to access a SQL query result rows 513 ISQLDBStatement Generic interface to bind to prepared SQL query 516 TQuery Class mapping VCL DB TQuery for direct database process 543 TQueryValue Pseudo-class handling a TQuery bound parameter or column value 541 TSQLDBColumnDefine Used to define a field/column layout in a table schema 510 TSQLDBColumnProperty Used to define a field/column layout 512 TSQLDBConnection Abstract connection created from TSQLDBConnectionProperties 525 SynDB.18 325 ESQLQueryException Exception ESQLDBException IInterface ISQLDBRows ISQLDBStatement TInterfacedObject TSQLDBStatement TSQLDBStatementWithParams TSQLDBStatementWithParamsAndColumns TSQLDBLib TSQLDBConnectionProperties TSQLDBConnectionPropertiesThreadSafe TSQLDBConnection TSQLDBConnectionThreadSafe TObject TQueryValue TQuery SynDB class hierarchy Objects implemented in the SynDB unit: Objects Description Page ESQLDBException Generic Exception type.5.18 Page 509 of 1055 . version 1. licensed under a MPL/GPL/LGPL tri-license.Synopse mORMot Framework Software Architecture Design 1.this unit is a part of the freeware Synopse mORMot framework.pas unit .pas unit Purpose: Abstract database direct access classes .Rev. SynDB.this unit is a part of the freeware Synopse framework. version 1.18 Units used in the SynDB unit: Unit Name Description Page SynCommons Common functions used by most Synopse projects . 1. e.for TSQLDBConnectionProperties.used e.used e.g. for numerical values ColumnScale: PtrInt. Should be TRUE if the column is indexed ColumnLength: PtrInt. for numerical values SynDB. i. for a value without any maximal length ColumnName: RawUTF8. as used by the SynDB unit TSQLDBColumnDefine = packed record Used to define a field/column layout in a table schema .GetFields to retrieve the table layout ColumnIndexed: boolean. The Column data precision .for TSQLDBConnectionProperties.Rev.18 Date: June 16.g. 1. The Column name ColumnPrecision: PtrInt. The Column default width (in chars or bytes) of ftUTF8 or ftBlob .18 Page 510 of 1055 .pas unit .can be set to value <0 for CLOB or BLOB column type. The Column data scale .Synopse mORMot Framework Software Architecture Design 1.SQLCreate to describe the new table . 2013 Objects Description Page TSQLDBConnectionPrope rties Abstract class used to set Database-related properties 519 TSQLDBConnectionPrope rtiesThreadSafe Connection properties which will implement an internal Thread-Safe connection pool 535 TSQLDBConnectionThrea dSafe Abstract connection created from TSQLDBConnectionProperties 535 TSQLDBIndexDefine Used to describe extended Index definition of a table schema 511 TSQLDBLib Access to a native library 540 TSQLDBParam A structure used to store a standard binding parameter 536 TSQLDBStatement Generic abstract class to implement a prepared SQL query 527 TSQLDBStatementWithPa rams Generic abstract class handling prepared statements with binding 537 TSQLDBStatementWithPa ramsAndColumns Generic abstract class handling prepared statements with binding and column description 540 ESQLDBException = class(Exception) Generic Exception type. 2013 ColumnType: TSQLDBFieldType.only set for MS SQL .com/cd/B19306_01/server.not retrieved for other DB types yet IndexName: RawUTF8. by TSQLDBConnectionProperties.only set for MS SQL . Expression for the subset of rows included in the filtered index . in order of their definition TypeDesc: RawUTF8.oracle.htm SynDB.not retrieved for other DB types yet IncludedColumns: RawUTF8. to be used e.for MS SQL possible values are: HEAP | CLUSTERED | NONCLUSTERED | XML |SPATIAL . If Index is part of a UNIQUE constraint . as retrieved from the database provider . Comma separaded list of a nonkey column added to the index by using the CREATE INDEX INCLUDE clause .Synopse mORMot Framework Software Architecture Design 1.102/b14237/statviews_1069. Description of the index type .pas unit . Comma separated list of indexed column names.not retrieved for other DB types yet KeyColumns: RawUTF8.for Oracle: NORMAL | BITMAP | FUNCTION-BASED NORMAL | FUNCTION-BASED BITMAP | DOMAIN see @http://docs. The Column type.only set for MS SQL .g.GetFieldDefinitions method .18 Page 511 of 1055 .Rev. .returned as plain text by GetFields method.only set for MS SQL .18 Date: June 16.not retrieved for other DB types yet IsUnique: boolean.should not be ftUnknown nor ftNull ColumnTypeNative: RawUTF8.SQLCreate will check for this value to override the default type TSQLDBIndexDefine = packed record Used to describe extended Index definition of a table schema Filter: RawUTF8. If Index is unique IsUniqueConstraint: boolean. 1. The Column type. Name of the index IsPrimaryKey: boolean. If Index is part of a PRIMARY KEY constraint . for SynDBOracle.Execute/Column*() methods to map the IRowSet content ColumnAttr: PtrUInt.pas unit . The Column name ColumnNonNullable: boolean.for TOleDBStatement: should not be ftUnknown ColumnUnique: boolean. if set to 0.SQLCreate to describe the table . 2013 TSQLDBColumnProperty = packed record Used to define a field/column layout .18 Page 512 of 1055 .for SQLCreate: default width (in WideChars or Bytes) of ftUTF8 or ftBlob.for SQLCreate: should not be ftUnknown nor ftNull . 1. Set if the Column shall have unique value (add the corresponding constraint) ColumnValueDBCharSet: integer. For SynDBOracle: used to store the ftUTF8 column encoding.e.for TOleDBStatement. the data.for TSQLDBOracleStatement: contains an offset to this column values inside fRowBuffer[] internal buffer .for TSQLDBConnectionProperties.e. For TSQLDBOracleStatement: used to store one value size (in bytes) SynDB.Rev.Synopse mORMot Framework Software Architecture Design 1.for TSQLDBDatasetStatement: maps TField pointer value ColumnName: RawUTF8. i. The Column type. a CLOB or BLOB column type will be created . equals either to SQLCS_NCHAR or SQLCS_IMPLICIT ColumnValueDBSize: cardinal. For SQLT_STR/SQLT_CLOB: used to store the ftUTF8 column char set encoding . equals to the OCI char set ColumnValueDBForm: byte. used for storage . A general purpose integer value . should not be null) ColumnType: TSQLDBFieldType. for Oracle 1333=4000/3 is used) .note that UTF-8 encoding is expected when calculating the maximum column byte size for the CREATE TABLE statement (e. for SQLT_CLOB. starting with a DBSTATUSENUM.g.18 Date: June 16. Set if the Column must exists (i.for TOleDBStatement: the offset of this column in the IRowSet data. then its length (for inlined sftUTF8 and sftBlob only) . e. overload. first Col is 0 function ColumnBlobBytes(const ColName: RawUTF8): TBytes.for TSQLDBODBCStatement: used to store the DataType as returned by ODBC. from a supplied column name function ColumnCount: integer. Return a Column as a blob value of the current Row.for TSQLDBODBCStatement: FALSE if bigger than 255 WideChar (ftUTF8) or 255 bytes (ftBlob) ColumnValueState: TSQLDBStatementGetCol. overload. 2=TWideStringField ColumnValueInlined: boolean. Internal DB column data type . SQLT_INT.Rev. first Col is 0 function ColumnCurrency(const ColName: RawUTF8): currency. Return a Column as a blob value of the current Row.DescribeColW() use private ODBC_TYPE_TO[ColumnType] to retrieve the marshalled type used during column retrieval .sqltype . 2013 ColumnValueDBType: smallint. Return a Column currency value of the current Row.pas unit .not all TSQLDBStatement methods are available. For TOleDBStatement: set if column was NOT defined as DBTYPE_BYREF . For SynDBODBC: state of the latest SQLGetData() call ISQLDBRows = interface(IInterface) Generic interface to access a SQL query result rows . SQLT_DAT and SQLT_BLOB . 1. first Col is 0 function ColumnBlobBytes(Col: integer): TBytes. from a supplied column name function ColumnBlob(Col: integer): RawByteString. Return a Column currency value of the current Row.for TSQLDBDatasetStatement: indicates the TField class type. overload.for TSQLDBOracleStatement: used to store the DefineByPos() TypeCode. from a supplied column name function ColumnDateTime(const ColName: RawUTF8): TDateTime. when column data < 4 KB .therefore you only have access to the Step() and Column*() methods function ColumnBlob(const ColName: RawUTF8): RawByteString. overload.18 Page 513 of 1055 . overload. overload. Return a Column as a blob value of the current Row.for TSQLDBFirebirdStatement: used to store XSQLVAR. Return a Column as a blob value of the current Row.Synopse mORMot Framework Software Architecture Design 1. but only those to retrieve data from a statement result: the purpose of this interface is to make easy access to result rows. can be SQLT_STR/SQLT_CLOB. 1=TLargeIntField. not provide all available features . The column/field count of the current Row function ColumnCurrency(Col: integer): currency. overload.18 Date: June 16. 0=TField. SQLT_FLT. i. Return a Column floating point value of the current Row. from a supplied column name SynDB.which is the most common case.for TSQLDBOracleStatement: FALSE if column is an array of POCILobLocator . Col value) starts with 0 .ColumnsToJSON .TVarData returned types are varNull. Return a column date and time value of the current Row.Rev. Return a Column text value as generic VCL string of the current Row. overload. varInt64. overload. Col value) starts with 0 . first Col is 0 function ColumnDouble(Col: integer): double. overload.Synopse mORMot Framework Software Architecture Design 1. varDouble. Return a Column integer value of the current Row. var Value: TVarData. overload. var Temp: RawByteString): TSQLDBFieldType. Return a Column floating point value of the current Row.pas unit .e. first Col is 0 function ColumnString(const ColName: RawUTF8): string. from a supplied column name function ColumnTimeStamp(Col: integer): TTimeLog. Return a Column integer value of the current Row.returns -1 if the Column name is not found (via case insensitive search) function ColumnInt(const ColName: RawUTF8): Int64. overload. overload.Columns numeration (i.e. and varAny (BLOB with size = VLongs[0]). overload. overload. Return a Column as a TVarData value.so this Value should not be used typecasted to a Variant . first Col is 0 function ColumnDouble(const ColName: RawUTF8): double. as in TSQLDBStatement. first Col is 0 function ColumnTimeStamp(const ColName: RawUTF8): TTimeLog.18 Page 514 of 1055 . The Column name of the current Row . Return a Column floating point value of the current Row.it's up to the implementation to ensure than all column names are unique function ColumnString(Col: integer): string. varString (mapping a constant PUTF8Char). from a supplied column name function ColumnIndex(const aColumnName: RawUTF8): integer. from a supplied column name function ColumnToVarData(Col: Integer.18 Date: June 16. from a supplied column name function ColumnInt(Col: integer): Int64. Return a Column floating point value of the current Row. first Col is 0 function ColumnName(Col: integer): RawUTF8. overload.Columns numeration (i.the specified Temp variable will be used for temporary storage of varString/varAny values SynDB. 1. ftDate is returned as varString. first Col is 0 . Return a Column text value as generic VCL string of the current Row. 2013 function ColumnDateTime(Col: integer): TDateTime. Return a column date and time value of the current Row. Returns the Column index of a given Column name . Return a Column as a variant .if Expanded is false. Return a Column UTF-8 encoded text value of the current Row.Rev. it will be filled with the number of row data returned (excluding field names) .JSON data is retrieved with UTF-8 encoding .. Return all rows content as a JSON string .if Expanded is true.Synopse mORMot Framework Software Architecture Design 1. from a supplied column name function ColumnVariant(const ColName: RawUTF8): Variant. DoNotFletchBlobs: Boolean=false): RawUTF8. Return a Column UTF-8 encoded text value of the current Row."val12"."col2":"val12"}."Values":["col1". first Col is 0 function ColumnUTF8(const ColName: RawUTF8): RawUTF8. in the '"\uFFF0base64encodedbinary"' format and contains true BLOB data .a ftBlob BLOB content will be mapped into a TBlobData AnsiString variant function ColumnType(Col: integer. overload. and a generic UnicodeString (=string) since Delphi 2009: you may not loose any data during charset conversion . overload.{"col1":val21.similar to corresponding TSQLRequest.val21. from a supplied column name .Execute method in SynSQLite3 unit function GetColumnVariant(const ColName: RawUTF8): Variant. Return a Column as a variant.FieldSize can be set to store the size in chars of a ftUTF8 column (0 means BLOB kind of TEXT column) function ColumnUTF8(Col: integer): RawUTF8. ReturnedRowCount: PPtrInt=nil..a ftBlob BLOB content will be mapped into a TBlobData AnsiString variant function FetchAllAsJSON(Expanded: boolean. overload.val11.BLOB field value is saved as Base64.] } .pas unit . ] . The Column type of the current Row . overload. 1.since a property getter can't be an overloaded method. FieldSize: PInteger=nil): TSQLDBFieldType. Return a Column as a variant.. Return a Column as a variant."col2". 2013 function ColumnToVariant(Col: integer. JSON data is an array of objects.if ReturnedRowCount points to an integer variable.18 Page 515 of 1055 .a ftUTF8 TEXT content will be mapped into a generic WideString variant for pre-Unicode version of Delphi. we define one for the Column[] property function Instance: TSQLDBStatement. for direct use with any Ajax or .NET client: [ {"col1":val11.a ftUTF8 TEXT content will be mapped into a generic WideString variant for pre-Unicode version of Delphi. first Col is 0 . JSON data is serialized (used in TSQLTableJSON) { "FieldCount":1. var Value: Variant): TSQLDBFieldType. Return the associated statement instance SynDB.18 Date: June 16.. from a supplied column name function ColumnVariant(Col: integer): Variant.this default implementation will call Column*() method above . and a generic UnicodeString (=string) since Delphi 2009: you may not loose any data during charset conversion .. overload. otherwise. this method must be called one or more times to evaluate it . to be called within a loop . and varAny (BLOB with size = VLongs[0]) .is used e.g. Return a Column as a variant .you shall call this method before calling any Column*() methods . begin I := MyConnProps.AccountNumber. but resulting code is fast in practice ISQLDBStatement = interface(ISQLDBRows) Generic interface to bind to prepared SQL query . var I: ISQLDBRows. using a variant and a column name will be a bit slower than direct access via the Column*() dedicated methods. property Column[const ColName: RawUTF8]: Variant read GetColumnVariant.should raise an Exception on any error .[aName]). 2013 function Step(SeekFirst: boolean=false): boolean. After a prepared statement has been prepared returning a ISQLDBRows interface. will put the cursor on the first row of results.g.Step do writeln(I['FirstName']. end. so gives access to the result columns data . overload.of course.return TRUE on success.18 Page 516 of 1055 .this default property can be used to write simple code like this: procedure WriteFamily(const aName: RawUTF8).Customer where AccountNumber like ?'.Execute('select * from table where name=?'.Execute( 'select * from Sales.inherits from ISQLDBRows.so this Param should not be used typecasted from a Variant SynDB.access the first or next row of data from the SQL Statement result: if SeekFirst is TRUE.18 Date: June 16.@Customer) do while Step do // loop through all matching data rows assert(Copy(Customer.8)='AW000001'). to function UpdateCount: Integer. . ['AW000001%']. with data ready to be retrieved by Column*() . Bind an array of TVarData values . begin with Props. 1. varDate. IO: TSQLDBParamInOutType=paramIn).Synopse mORMot Framework Software Architecture Design 1.not all TSQLDBStatement methods are available.1.DateToStr(I['BirthDate'])). but only those to bind parameters and retrieve data from a statement result . if the SQL statement is not a SELECT but an UPDATE or INSERT command) .return FALSE if no more row is available (e. while I. varDouble. end.typical use may be: var Customer: Variant. varString (mapping a constant PUTF8Char). it will fetch one row of data.Rev. varInt64.' '.TVarData handled types are varNull. Gets a number of updates made by latest executed statement procedure Bind(const Params: TVarDataDynArray.pas unit . pas unit . const Values: array of TDateTime). when set after encoding via BinToBase64WithMagic() call . const Values: array of currency). const Values: TRawUTF8DynArray. Bind a double value to a parameter .parameters marked as ? should be specified as method parameter in Params[] . Bind an array of RawUTF8 values to a parameter .the leftmost SQL parameter has an index of 1 . 1. const Values: array of RawUTF8). ParamType: TSQLDBFieldType. const Values: array of Int64). overload.the leftmost SQL parameter has an index of 1 procedure Bind(Param: Integer. Bind an array of integer values to a parameter .this default implementation will raise an exception if the engine does not support array binding procedure BindArray(Param: Integer.e.values are stored as in SQL (i. Bind an array of const values .values are stored as in SQL (i.18 Date: June 16. const Values: array of double). overload. 'quoted string') .e. IO: TSQLDBParamInOutType=paramIn).BLOB parameters can be bound with this method. Bind an integer value to a parameter .values are stored as in SQL (i. IO: TSQLDBParamInOutType=paramIn). 'YYYY-MM-DD hh:mm:ss') .TDateTime parameters can be bound with this method. ValuesCount: integer). Bind an array of double values to a parameter .e. overload. overload. Value: Int64.this default implementation will raise an exception if the engine does not support array binding SynDB.this default implementation will raise an exception if the engine does not support array binding procedure BindArrayDateTime(Param: Integer.the leftmost SQL parameter has an index of 1 . when encoded via a DateToSQL() or DateTimeToSQL() call procedure Bind(Param: Integer. Bind an array of TDateTime values to a parameter .the leftmost SQL parameter has an index of 1 . Bind an array of values to a parameter . 'YYYY-MM-DD hh:mm:ss'. number.this default implementation will raise an exception if the engine does not support array binding procedure BindArray(Param: Integer.Synopse mORMot Framework Software Architecture Design 1.the leftmost SQL parameter has an index of 1 procedure BindArray(Param: Integer. IO: TSQLDBParamInOutType=paramIn). overload.this default implementation will raise an exception if the engine does not support array binding procedure BindArrayCurrency(Param: Integer. Value: double.18 Page 517 of 1055 .the leftmost SQL parameter has an index of 1 .the leftmost SQL parameter has an index of 1 . overload. null) . Bind an array of currency values to a parameter . 2013 procedure Bind(const Params: array of const.Rev.the leftmost SQL parameter has an index of 1 . overload.this default implementation will raise an exception if the engine does not support array binding procedure BindArray(Param: Integer. 'quoted string'. the leftmost SQL parameter has an index of 1 procedure BindBlob(Param: Integer. 1. IO: TSQLDBParamInOutType=paramIn). after ColumnsToSQLInsert() method call for fast data conversion between tables procedure BindNull(Param: Integer. Bind a TDateTime value to a parameter . Value: PUTF8Char. IO: TSQLDBParamInOutType=paramIn). Bind an array of fields from an existing SQL statement . IO: TSQLDBParamInOutType=paramIn).Rev. IO: TSQLDBParamInOutType=paramIn). overload. Value: currency. IO: TSQLDBParamInOutType=paramIn).the leftmost SQL parameter has an index of 1 procedure BindTextP(Param: Integer. overload. 2013 procedure BindBlob(Param: Integer. overload. Bind a UTF-8 encoded string to a parameter . overload.g.the leftmost SQL parameter has an index of 1 procedure BindTextS(Param: Integer. Bind a Blob buffer to a parameter . const Value: WideString.the leftmost SQL parameter has an index of 1 procedure BindTextW(Param: Integer. const Value: RawUTF8.the leftmost SQL parameter has an index of 1 procedure BindTextU(Param: Integer. Value: TDateTime. IO: TSQLDBParamInOutType=paramIn). overload.pas unit . IO: TSQLDBParamInOutType=paramIn). Size: integer.the leftmost SQL parameter has an index of 1 procedure BindFromRows(const Fields: TSQLDBColumnPropertyDynArray. Data: pointer.can be used e.the leftmost SQL parameter has an index of 1 SynDB. const Data: RawByteString. Bind a UTF-8 encoded buffer text (#0 ended) to a parameter .the leftmost SQL parameter has an index of 1 procedure BindDateTime(Param: Integer.Synopse mORMot Framework Software Architecture Design 1. IO: TSQLDBParamInOutType=paramIn). const Value: string. overload.18 Page 518 of 1055 . Bind a Blob buffer to a parameter . Bind a NULL value to a parameter . Bind a currency value to a parameter .the leftmost SQL parameter has an index of 1 procedure BindCurrency(Param: Integer. Bind a UTF-8 encoded string to a parameter . IO: TSQLDBParamInOutType=paramIn).18 Date: June 16. overload. overload. Bind a UTF-8 encoded string to a parameter . Rows: TSQLDBStatement). by the mORMot layer constructor Create(const aServerName. 1.used e. as computed from the class name . AfterSelectPos. IO: TSQLDBParamInOutType=paramIn).integer parameters state how the SQL statement has been analysed class function EngineName: RawUTF8.pas unit .g.if DataIsBlob is TRUE. Release related memory.'TSQLDBConnectionProperties' will be trimmed left side of the class name SynDB.URI by-pass virtual table mechanism .e. virtual. LimitPos: integer): boolean.should also provide some Database-specific generic SQL statement creation (e. the Database server location and connection parameters (like UserID and password) .g. override.children may optionaly handle the fact that no UserID or Password is supplied here.AdaptSQLForEngineList() calls this to let TSQLRestServer. will call BindBlob(RawByteString(Data)) instead of BindTextW(WideString(Variant)) . you can access any returned data via ISQLDBRows methods TSQLDBConnectionProperties = class(TObject) Abstract class used to set Database-related properties . Adapt the LIMIT # clause in the SQL SELECT statement to a syntax matching the underlying DBMS . aDatabaseName.should raise an Exception on any error . by displaying a corresponding Dialog box destructor Destroy. aPassWord: RawUTF8).g. Return the database engine name. Execute a prepared SQL statement .g.handle e. const Data: Variant. Bind a Variant value to a parameter . how to create a Table). aUserID.parameters marked as ? should have been already bound with Bind*() functions .18 Page 519 of 1055 . virtual.Synopse mORMot Framework Software Architecture Design 1. DataIsBlob: boolean.will call all virtual Bind*() methods from the Data type . WhereClausePos. LimitRowCount.after execution.the leftmost SQL parameter has an index of 1 .Rev.AsBlob/AsBytes procedure ExecutePrepared. and close MainConnection function AdaptSQLLimitForEngineList(var SQL: RawUTF8. Initialize the properties . TSQLRestServerStaticExternal. to be used e.18 Date: June 16. 2013 procedure BindVariant(Param: Integer. by TQuery.g. const Params: array of const ): ISQLDBRows.overloaded method using FormatUTF8() and inlined parameters function ExecuteNoResult(const aSQL: RawUTF8. end. Execute a SQL query.can be used to launch INSERT. ExpectResults: Boolean): ISQLDBRows.raise an exception on error . e. var R: Variant. then run the corresponding Execute() method . begin I := MyConnProps. overload.pas unit . begin with MyConnProps. ExpectResults: Boolean): ISQLDBRows. var I: ISQLDBRows. Create. 1.18 Page 520 of 1055 .18 Date: June 16.Step do writeln(I['FirstName']. .FirstName.[aName]. then run the corresponding Execute() method .Execute('select * from table where name=?'. end.g. const Params: array of const): integer. . 2013 function Execute(const aSQL: RawUTF8. Execute a SQL query.Rev.return column type as 'Name [Type Length Precision Scale]' SynDB. without returning any rows . you can use it to row column access via late binding.DateToStr(I['BirthDate'])). while I. and provide basic garbage collection.return the number of modified rows (or 0 if the DB driver do not give access to this value) class function GetFieldDefinition(const Column: TSQLDBColumnDefine): RawUTF8. bound inlined parameters and execute a thread-safe statement . prepare.' '.raise an exception on error function ExecuteInlined(SQLFormat: PUTF8Char.returns an ISQLDBRows to access any resulting rows (if ExpectResults is TRUE).[aName]). function ExecuteInlined(const aSQL: RawUTF8. as such: procedure WriteFamily(const aName: RawUTF8). bound inlined parameters and execute a thread-safe statement .if RowsVariant is set. prepare.this implementation will call the NewThreadSafeStatement virtual method. then bound inlined parameters as :(1234): and call its Execute method . as such: procedure WriteFamily(const aName: RawUTF8). const Args: array of const.@R) do while Step do writeln(R.Execute('select * from table where name=?'.will call NewThreadSafeStatement method to retrieve a thread-safe statement instance. returning a statement interface instance to retrieve the result rows .' '. overload. Get one field/column definition as text .DateToStr(R.will call NewThreadSafeStatement method to retrieve a thread-safe statement instance.BirthDate)).Synopse mORMot Framework Software Architecture Design 1. Create. DELETE or UPDATE statement. this method should return a prepared statement instance on success .this method will call ThreadSafeConnection.will call ThreadSafeConnection. otherwise.should return the SQL "ALTER TABLE" statement needed to add a column to an existing table .18 Page 521 of 1055 .on error. depending on the database access (more than 10 seconds waiting is possible) . 2013 function GetForeignKey(const aTableName. RaiseExceptionOnError: Boolean=false): ISQLDBStatement. 1.LastErrorException to retrieve correspnding error information function SQLAddColumn(const aTableName: RawUTF8. Create a new thread-safe statement from an internal cache (if any) .this method will call the overloaded NewThreadSafeStatementPrepared method . so response will be immediate . virtual. but to values to be changed within SQLFormat in place of '%' characters (this method will call FormatUTF8() internaly).used by TSQLDBConnection.the caller is responsible of freeing this instance function NewThreadSafeStatement: TSQLDBStatement. Determine if the SQL statement can be cached . returns nil and you can check Connnection.on error. for multi-thread access) .g. Create a new thread-safe statement from an internal cache (if any) . virtual. Retrieve a foreign key for a specified table and column . ExpectResults: Boolean): ISQLDBStatement.LastErrorMessage / Connection. virtual. aColumnName: RawUTF8): RawUTF8. it will retrieve all foreign keys from the remote database using virtual protected GetForeignKeys method into the protected fForeignKeys list: this may be slow. returns nil and you can check Connnection.NewStatement function NewThreadSafeStatementPrepared(const aSQL: RawUTF8. Create a new thread-safe statement . abstract.the whole foreign key list is shared by all connections function IsCachable(P: PUTF8Char): boolean. const Args: array of const. overload. Used to add a column to a Table . overload.LastErrorMessage / Connection.pas unit .18 Date: June 16. it will raise an exception) function NewThreadSafeStatementPrepared(SQLFormat: PUTF8Char.LastErrorException to retrieve corresponding error information (if RaiseExceptionOnError is left to default FALSE value. which contains by default the ANSI SQL Data Types and maximum 1000 inlined WideChars: inherited classes may change the default fSQLCreateField* content or override this method SynDB.this method should return a prepared statement instance on success .any further call will use this internal list.this default implementation will use internal fSQLCreateField and fSQLCreateFieldMax protected values.NewStatementPrepared() for handling cache function NewConnection: TSQLDBConnection.Synopse mORMot Framework Software Architecture Design 1. Create a new connection .here Args[] array does not refer to bound parameters.first time it is called.NewStatementPrepared .call this method if the shared MainConnection is not enough (e. const aField: TSQLDBColumnProperty): RawUTF8.Rev. ExpectResults: Boolean. parameters will be bound directly on the returned TSQLDBStatement instance . note that 'ID' is used instead of 'RowID' since it fails on Oracle e.a "ID Int64 PRIMARY KEY" column is always added at first position.this default implementation will use internal fSQLCreateField and fSQLCreateFieldMax protected values. 1. if Unique parameter is set to true . virtual.Rev. FROM . virtual." statement to retrieve the specified column names of an existing table .. Used to compute a SELECT statement for the given fields .18 Page 522 of 1055 . 'YYYY-MM-DDTHH:MM:SS' (as expected by Microsoft SQL server e.this default implementation will return the standard SQL statement.this default implementation will return the quoted ISO-8601 value. and will expect the ORM to create an unique RowID value sent at INSERT (could use "select max(ID) from table" to retrieve the last value) . [stBlob] to save time and space) function ThreadSafeConnection: TSQLDBConnection. virtual. . const aFields: TSQLDBColumnDefineDynArray. Used to add an index to a Table . aDefaultPageSize: integer=0): RawUTF8. Convert an ISO-8601 encoded time and date into a date appropriate to be pasted in the SQL request .'. per thread if necessary (e.TSQLDBConnectionPropertiesThreadSafe will implement a per-thread connection pool. 'CREATE [UNIQUE] INDEX index_name ON table_name (column_name[s])' function SQLCreate(const aTableName: RawUTF8.. Get a thread-safe connection .g.this default implementation will only handle dFirebird by now function SQLIso8601ToDate(const Iso8601: RawUTF8): RawUTF8.but if you specify a value in aExcludeTypes. SQL statement to create the corresponding database ..by default.18 Date: June 16.'YYYY-MM-DD HH24:MI:SS') for Oracle function SQLSelectAll(const aTableName: RawUTF8.should return the SQL "CREATE" statement needed to create a table with the specified field/column names and types .e. i.returns to_date('. const aFieldNames: array of RawUTF8.this default implementation will return the MainConnection shared instance.g.) . all columns specified in aFields[] will be available: it will return "SELECT * FROM TableName" .should return the SQL "CREATE INDEX" statement needed to add an index to the specified column names of an existing table . so the provider should be thread-safe by itself .e. aExcludeTypes: TSQLDBFieldTypes): RawUTF8. const aIndexName: RawUTF8=''): RawUTF8. virtual.. which expect one TOleDBConnection instance per thread) SynDB.. for OleDB.g. virtual..Synopse mORMot Framework Software Architecture Design 1. aUnique: boolean. which contains by default the ANSI SQL Data Types and maximum 1000 inlined WideChars: inherited classes may change the default fSQLCreateField* content or override this method function SQLCreateDatabase(const aDatabaseName: RawUTF8. const aFields: TSQLDBColumnPropertyDynArray): RawUTF8.should return the SQL "SELECT .. via an internal TSQLDBConnection pool.g. i.index will expect UNIQUE values in the specified columns. 2013 function SQLAddIndex(const aTableName: RawUTF8. Used to create a Table . it will compute the matching column names to ignore those kind of content (e. virtual.pas unit . Retrieve the advance indexed information of a specified Table .used e.e. WithForeignKeys: boolean). and allow automatic reconnection procedure GetFieldDefinitions(const aTableName: RawUTF8.this default implementation will use protected SQLGetField virtual method to retrieve the field names and properties . Oracle handles array DML operation with iters <= 32767 at best property BatchSendingAbilities: TSQLDBStatementCRUDs read fBatchSendingAbilities. virtual. var Indexes: TSQLDBIndexDefineDynArray).Synopse mORMot Framework Software Architecture Design 1. Retrieve the column/field layout of a specified table . virtual. as specified at creation property DBMS: TSQLDBDefinition read GetDBMS. to purge the connection pool. after a DB connection problem. or MS SQL bulk insert property DatabaseName: RawUTF8 read fDatabaseName. as stated by the inheriting class itself. virtual.18 Page 523 of 1055 .g. or retrieved at connecton time (e.g. var Fields: TSQLDBColumnDefineDynArray).can be called e. by GetFieldDefinitions .g.this default implementation will use protected SQLGetTableNames virtual method to retrieve the table names property BatchMaxSentAtOnce: integer read fBatchMaxSentAtOnce write fBatchMaxSentAtOnce. Release all existing connections .g. The maximum number of rows to be transmitted at once for batch sending . Get all table names . 2013 procedure ClearConnectionPool.if WithForeignKeys is set. for ODBC) property Engine: RawUTF8 read fEngineName. as computed from the class name . Get all field/column definition for a specified Table as text . 1.g.will call ColumnTypeNativeToDB protected virtual method to guess the each mORMot TSQLDBFieldType procedure GetIndexes(const aTableName: RawUTF8. will add external foreign keys as '% tablename' procedure GetFields(const aTableName: RawUTF8. The remote DBMS type.Rev. Return the database engine name. Oracle will handle array binds. The abilities of the database for batch sending . var Fields: TRawUTF8DynArray.call the GetFields method and retrieve the column field name and type as 'Name [Type Length Precision Scale]' .'TSQLDBConnectionProperties' will be trimmed left side of the class name SynDB. virtual.this default implementation will use protected SQLGetIndex virtual method to retrieve the index names and properties . The associated database name.18 Date: June 16.pas unit .currently only MS SQL and Oracle are supported procedure GetTableNames(var Tables: TRawUTF8DynArray).e. you can override this property directly in the TSQLDBConnection property PassWord: RawUTF8 read fPassWord. The associated User Password. 1. This event handler will be called during all process .pas unit . The associated server name.call the ThreadSafeConnection method instead e.since GetForeignKeys is somewhat slow. 'dbo' for MS SQL property ForeignKeysData: RawByteString read GetForeignKeysData write SetForeignKeysData.e.18 Date: June 16. TTestSQLite3ExternalDB regression tests will be two times faster with statement caching) .you can set a custom schema to be used. Can be used to store the fForeignKeys[] data in an external BLOB .g.will cache only statements containing ? parameters or a SELECT with no WHERE clause within property UserID: RawUTF8 read fUserID. e. if none is specified (i.can be used e.g.Synopse mORMot Framework Software Architecture Design 1.default value is TRUE for faster process (e.g. if table name is not set as SCHEMA. as specified at creation SynDB. as specified at creation property ServerName: RawUTF8 read fServerName. The associated User Identifier. An optional Schema name to be used for SQLGetField() instead of UserID .TABLE) . Return a shared connection.cache will be accessed for NewStatementPrepared() method only. as specified at creation property UseCache: boolean read fUseCache. TRUE if an internal cache of SQL statement should be used . for multi-thread access. 2013 property ForcedSchemaName: RawUTF8 read fForcedSchemaName write fForcedSchemaName.g.18 Page 524 of 1055 . corresponding to the given . to change the desktop cursor . could save a lot of time property MainConnection: TSQLDBConnection read GetMainConnection. by returning ISQLDBStatement interface instances .Rev.by default. or NewThreadSafeStatement for direct retrieval of a new statement property OnProcess: TOnSQLDBProcess read fOnProcess write fOnProcess. UserID will be used as schema name. it returns nil and you can check LastErrorMessage and LastErrorException properties to retrieve correspnding error information . an exception is raised SynDB.in this case. avoiding WideString/OleStr content will speed up the process a lot. virtual. and implement handle statement caching is UseCache=true .more than one TSQLDBConnection instance can be run for the same TSQLDBConnectionProperties constructor Create(aProperties: TSQLDBConnectionProperties). virtual.Column[] property or ISQLDBRows. if you are sure that the current charset matches the expected one (which is very likely) . or for the ISQLDBRows.18 Page 525 of 1055 . this won't affect other Column*() methods. or JSON production TSQLDBConnection = class(TObject) Abstract connection created from TSQLDBConnectionProperties . abstract.set this property to TRUE so that the conversion to Variant will create a WideString kind of variant. Initialize a new SQL query statement for the given connection . if RaiseExceptionOnError=false (by default). the conversion to Variant will create an AnsiString kind of variant: for pre-Unicode Delphi.pas unit .this default implementation will call the NewStatement method. 2013 property VariantStringAsWideString: boolean read fVariantWideString write fVariantWideString.the Variant conversion is mostly used for the TQuery wrapper. Release memory and connection function IsConnected: boolean. Initialize a new SQL query statement for the given connection .this method should return a prepared statement instance on success .on error.on error. RaiseExceptionOnError: Boolean=false): ISQLDBStatement. Connect to a specified database engine destructor Destroy. virtual. override. to avoid any character data loss: the access to the property will be slower. virtual.ColumnVariant() method.Reset method shall have been overriden to allow binding and execution of the very same prepared statement . Return TRUE if Connect has been already successfully called function NewStatement: TSQLDBStatement.the caller should free the instance after use function NewStatementPrepared(const aSQL: RawUTF8.starting with Delphi 2009. the TEXT content will be stored as an UnicodeString in the variant. so this property is not necessary .Synopse mORMot Framework Software Architecture Design 1. Set to true to force all variant conversion to WideString instead of the default faster AnsiString. abstract. ExpectResults: Boolean.18 Date: June 16.Rev. the TSQLDBStatement. for pre-Unicode version of Delphi . 1.by default. if RaiseExceptionOnError=true. but you won't have any potential data loss . virtual. TRUE if StartTransaction has been called .18 Page 526 of 1055 .this default implementation will check and set TransactionCount procedure Connect. Some error exception.Rev.18 Date: June 16. Returns TRUE if the connection was set property InTransaction: boolean read GetInTransaction. Commit changes of a Transaction for this connection . virtual.Synopse mORMot Framework Software Architecture Design 1.this default implementation will check and set TransactionCount property Connected: boolean read IsConnected.StartTransaction method must have been called before . during execution of NewStatementPrepared property LastErrorMessage: RawUTF8 read fErrorMessage.should raise an Exception on error . to change the desktop cursor .should raise an Exception on error .OnProcess property property Properties: TSQLDBConnectionProperties read fProperties.g.pas unit .check if TransactionCount>0 property LastErrorException: ExceptClass read fErrorException.g.this default implementation will release all cached statements: so it should be called in overriden methods BEFORE actual disconnection procedure Rollback. 1. Discard changes of a Transaction for this connection . e. Some error message. WithinTransaction: boolean): integer. e.INSERTs will be nested within a transaction if WithinTransaction is TRUE . virtual. if it does not exist . will follow TSQLDBConnectionProperties. This event handler will be called during all process .this default implementation will check and set TransactionCount procedure StartTransaction. The associated database properties SynDB. virtual. Direct export of a DB statement rows into a new table of this database .StartTransaction method must have been called before .will raise an Exception in case of error procedure Commit. Begin a Transaction for this connection . during execution of NewStatementPrepared property OnProcess: TOnSQLDBProcess read fOnProcess write fOnProcess.g. virtual. Stop connection to the specified database .this default implementation will notify OnProgress callback for sucessfull re-connection: it should be called in overriden methods AFTER actual connection process procedure Disconnect.can be used e. Connect to the specified database .by default.the corresponding table will be created within the current connection. 2013 function NewTableFromRows(const TableName: RawUTF8. Rows: TSQLDBStatement. 18 Page 527 of 1055 . overload.can be greater than 1 in case of re-connection via Disconnect/Connect property TransactionCount: integer read fTransactionCount. Return a Column currency value of the current Row. 2013 property ServerTimeStamp: TTimeLog read GetServerTimeStamp. abstract. overload. overload. first Col is 0 function ColumnDateTime(const ColName: RawUTF8): TDateTime.e. i. The current Date and Time. abstract. from a supplied column name function ColumnBlob(Col: integer): RawByteString. as retrieved from the server . virtual. Return a Column date and time value of the current Row. virtual.this default virtual method will call ColumnBlob() function ColumnBlobBytes(const ColName: RawUTF8): TBytes. Create a statement instance function ColumnBlob(const ColName: RawUTF8): RawByteString. Return a Column currency value of the current Row. virtual. overload.Rev.Synopse mORMot Framework Software Architecture Design 1. Step() and Column*() methods constructor Create(aConnection: TSQLDBConnection). Return a Column as a blob value of the current Row.inherited classes should implement the DB-specific connection in its overriden methods.this function will return the BLOB content as a TBytes .18 Date: June 16.default implementation will return the executable time.equals 0 if no transaction is active TSQLDBStatement = class(TInterfacedObject) Generic abstract class to implement a prepared SQL query . abstract. Return a Column as a blob value of the current Row. virtual. overload. virtual. from a supplied column name function ColumnCount: integer. first Col is 0 function ColumnCurrency(const ColName: RawUTF8): currency. Number of nested StartTransaction calls . overload. Number of sucessfull connections for this instance .pas unit .this property will return the timestamp in TTimeLog / Iso8601 / Int64 after correction from the Server returned time-stamp (if any) . first Col is 0 . especially Bind*(). Iso8601Now property TotalConnectionCount: integer read fTotalConnectionCount. first Col is 0 function ColumnBlobBytes(Col: integer): TBytes. overload. ExecutePrepared. Return a Column as a blob value of the current Row. Return a Column date and time value of the current Row. overload. from a supplied column name function ColumnDateTime(Col: integer): TDateTime. Prepare(). The column/field count of the current Row function ColumnCurrency(Col: integer): currency. from a supplied column name SynDB. 1. Return a Column as a blob value of the current Row. Columns numeration (i.and populate the Fields[] array with columns information (type and name) . virtual.this default implementation will call ColumnUTF8 function ColumnString(const ColName: RawUTF8): string.it's up to the implementation to ensure than all column names are unique function ColumnNull(Col: integer): boolean. overload.the SQL statement is prepared with bound parameters. virtual. from a supplied column name . Return a Column floating point value of the current Row.e. abstract. The Column name of the current Row .g. first Col is 0 . 1. to convert some data on the fly from one database to another function ColumnString(Col: integer): string. overload. Returns TRUE if the column contains NULL function ColumnsToSQLInsert(const TableName: RawUTF8. Returns the Column index of a given Column name . first Col is 0 function ColumnDouble(const ColName: RawUTF8): double. Col value) starts with 0 . Return a column date and time value of the current Row. Return a Column text value as generic VCL string of the current Row. Return a Column integer value of the current Row.Rev. e. first Col is 0 . Return a Column floating point value of the current Row. abstract. virtual. Return a Column integer value of the current Row. overload. overload.18 Date: June 16. abstract. 2013 function ColumnDouble(Col: integer): double.pas unit .used e. insert into TableName (Col1. abstract.returns -1 if the Column name is not found (via case insensitive search) function ColumnInt(const ColName: RawUTF8): Int64.e. Compute the SQL INSERT statement corresponding to this columns row . virtual. overload. from a supplied column name function ColumnIndex(const aColumnName: RawUTF8): integer. virtual. from a supplied column name function ColumnTimeStamp(Col: integer): TTimeLog. Return a column date and time value of the current Row.N) .18 Page 528 of 1055 . first Col is 0 function ColumnName(Col: integer): RawUTF8.Columns numeration (i. Col value) starts with 0 .call ColumnDateTime or ColumnUTF8 to convert into Iso8601/Int64 time stamp from a TDateTime or text SynDB. overload.call ColumnDateTime or ColumnUTF8 to convert into Iso8601/Int64 time stamp from a TDateTime or text function ColumnTimeStamp(const ColName: RawUTF8): TTimeLog. overload. var Fields: TSQLDBColumnPropertyDynArray): RawUTF8.Synopse mORMot Framework Software Architecture Design 1.g. from a supplied column name function ColumnInt(Col: integer): Int64. Return a Column text value as generic VCL string of the current Row. overload. virtual. abstract. virtual.Col2) values (?. Return a Column UTF-8 encoded text value of the current Row.a ftUTF8 TEXT content will be mapped into a generic WideString variant for pre-Unicode version of Delphi.18 Page 529 of 1055 . FieldSize: PInteger=nil): TSQLDBFieldType. first Col is 0 . overload. virtual. virtual. 2013 function ColumnToVarData(Col: Integer. virtual. varString (mapping a constant PUTF8Char). virtual. first Col is 0 function ColumnUTF8(const ColName: RawUTF8): RawUTF8. overload. Return a Column as a variant.TVarData returned types are varNull.so this Value should not be used typecasted to a Variant . overload. 1.this default implementation will call corresponding Column*() method function ColumnToVariant(Col: integer.FieldSize can be set to store the size in chars of a ftUTF8 column (0 means BLOB kind of TEXT column) function ColumnUTF8(Col: integer): RawUTF8. Return a Column as a variant. Return a Column as a variant. varInt64. and a generic UnicodeString (=string) since Delphi 2009: you may not loose any data during charset conversion .the specified Temp variable will be used for temporary storage of varString/varAny values .a ftBlob BLOB content will be mapped into a TBlobData AnsiString variant function ColumnVariant(const ColName: RawUTF8): Variant. ftDate is returned as varString. The Column type of the current Row .Rev. Return a Column UTF-8 encoded text value of the current Row. as in TSQLDBStatement. from a supplied column name function ColumnVariant(Col: integer): Variant. from a supplied column name SynDB.Synopse mORMot Framework Software Architecture Design 1. abstract.18 Date: June 16.pas unit .this default implementation will call Column*() method above .a ftBlob BLOB content will be mapped into a TBlobData AnsiString variant function ColumnType(Col: integer. first Col is 0 . Return a Column as a TVarData value. varDouble. overload. var Value: Variant): TSQLDBFieldType.a ftUTF8 TEXT content will be mapped into a generic WideString variant for pre-Unicode version of Delphi.ColumnsToJSON . and a generic UnicodeString (=string) since Delphi 2009: you may not loose any data during charset conversion . var Value: TVarData.this default implementation will call ColumnToVariant() method . first Col is 0 . abstract. var Temp: RawByteString): TSQLDBFieldType. and varAny (BLOB with size = VLongs[0]). "col2":"val12"}.."Values":["col1".val21.pas unit .if Expanded is false. Retrieve the parameter content. ...18 Date: June 16. virtual. for instance our "douce France") .warning: TSQLRestServerStaticExternal.if Tab=TRUE.."val12".. in the '"\uFFF0base64encodedbinary"' format and contains true BLOB data .Execute method in SynSQLite3 unit function FetchAllToCSVValues(Dest: TStream.JSON data is retrieved with UTF-8 encoding .returns the number of row data returned (excluding field names) ."col2":"val12"}. JSON data is an array of objects..if Expanded is false.}]'#10 function ParamToVariant(Param: Integer. with UTF-8 encoding . Tab: boolean.val21.NET client: [ {"col1":val11.BLOB field value is saved as Base64. ] .similar to corresponding TSQLRequest.use e. var Value: Variant. will use TAB instead of '. JSON data is an array of objects. CheckIsOutParameter: boolean=true): TSQLDBFieldType.if Expanded is true.val11. AddBOM: boolean=true): PtrInt.g. JSON data is serialized (used in TSQLTableJSON) { "FieldCount":1.' between columns .BLOB fields will be appended as "blob" with no data .. 1."val12". ] .Synopse mORMot Framework Software Architecture Design 1."col2"."col2"."Values":["col1".] } . Expanded: boolean. the global ListSeparator variable (from SysUtils) to reflect the current system definition (some country use '. with stored procedures .{"col1":val21. DoNotFletchBlobs: Boolean=false): PtrInt. after SQL execution .the parameter should have been bound with IO=paramOut or IO=paramInOut if CheckIsOutParameter is TRUE .to be used e..BLOB field value is saved as Base64.AddBOM will add a UTF-8 Byte Order Mark at the beginning of the content ..'.18 Page 530 of 1055 . JSON data is serialized (used in TSQLTableJSON) { "FieldCount":1.{"col1":val21.if Expanded is true. 2013 function FetchAllAsJSON(Expanded: boolean.] } . CommaSep: AnsiChar='.returns the number of row data returned function FetchAllToJSON(JSON: TStream.NET client: [ {"col1":val11.. DoNotFletchBlobs: Boolean=false): RawUTF8.if ReturnedRowCount points to an integer variable.g. for direct use with any Ajax or . Return all rows content as a JSON string .CSV data is added to the supplied TStream.' separator ..the leftmost SQL parameter has an index of 1 .EngineRetrieve in mORMotDB unit expects the Expanded=true format to return '[{.this implementation just check that Param is correct: overriden method should fill Value content SynDB. it will be filled with the number of row data returned (excluding field names) .val11.' as decimal separator.similar to corresponding TSQLRequest. Append all rows content as a CSV stream .. ReturnedRowCount: PPtrInt=nil. in the '"\uFFF0base64encodedbinary"' format and contains true BLOB data .Execute method in SynSQLite3 unit . for direct use with any Ajax or .you can customize the '.Rev. pas unit . and varAny (BLOB with size = VLongs[0]) .access the first or next row of data from the SQL Statement result: if SeekFirst is TRUE. end. varDate. virtual.1.ColumnName(0).return TRUE on success.ColumnUTF8(0).g.Rev. this method must be called one or more times to evaluate it . 2013 function Step(SeekFirst: boolean=false): boolean.Synopse mORMot Framework Software Architecture Design 1.18 Page 531 of 1055 . varDouble. end. function UpdateCount: integer.NewThreadSafeStatementPrepared('select AccountNumber from Sales. otherwise. virtual. abstract.8)='AW000001'). Bind an array of const values . varInt64.parameters marked as ? should be specified as method parameter in Params[] . it will fetch one row of data. ['AW000001%']. begin Query := Props.g.18 Date: June 16. IO: TSQLDBParamInOutType=paramIn).BLOB parameters can be bound with this method. to be called within a loop . when set after encoding via BinToBase64WithMagic() call .should raise an Exception on any error .the leftmost SQL parameter has an index of 1 procedure Bind(const Params: array of const. virtual. IO: TSQLDBParamInOutType=paramIn).so this Param should not be used typecasted from a Variant . Value: Int64.TDateTime parameters can be bound with this method. IO: TSQLDBParamInOutType=paramIn). with data ready to be retrieved by Column*() . if Query<>nil then begin assert(SameTextU(Query.this default implementation will call corresponding Bind*() method SynDB. the mORMotDB unit): var Query: ISQLDBStatement.true).return FALSE if no more row is available (e. Bind an integer value to a parameter . 1. will put the cursor on the first row of results.typical use may be (see also e. when encoded via a DateToSQL() or DateTimeToSQL() call .Customer where AccountNumber like ?'. abstract.you shall call this method before calling any Column*() methods . After a statement has been prepared via Prepare() + ExecutePrepared() or Execute(). Gets a number of updates made by latest executed statement . if the SQL statement is not a SELECT but an UPDATE or INSERT command) .this default implementation will call corresponding Bind*() method procedure Bind(const Params: TVarDataDynArray.'AccountNumber')). while Query.default implementation returns 0 procedure Bind(Param: Integer. overload. Bind an array of TVarData values .TVarData handled types are varNull. overload.Step do // loop through all matching data rows assert(Copy(Query. overload. virtual. varString (mapping a constant PUTF8Char). virtual. number. Bind an array of values to a parameter .this default implementation will raise an exception if the engine does not support array binding procedure BindArray(Param: Integer.the leftmost SQL parameter has an index of 1 . const Values: TRawUTF8DynArray. overload. Bind an array of double values to a parameter . const Values: array of RawUTF8). Bind a Blob buffer to a parameter . const Values: array of double).18 Page 532 of 1055 . abstract. 'quoted string') . ValuesCount: integer).Synopse mORMot Framework Software Architecture Design 1. overload.the leftmost SQL parameter has an index of 1 procedure BindBlob(Param: Integer. Bind an array of RawUTF8 values to a parameter . overload.e. const Values: array of Int64).e. overload. 'YYYY-MM-DD hh:mm:ss') . const Data: RawByteString.the leftmost SQL parameter has an index of 1 . 1. virtual.this default implementation will raise an exception if the engine does not support array binding procedure BindArray(Param: Integer. overload. virtual.the leftmost SQL parameter has an index of 1 . Data: pointer.18 Date: June 16.pas unit . virtual. Size: integer. virtual.the leftmost SQL parameter has an index of 1 . virtual. Bind an array of integer values to a parameter .values are stored as in SQL (i.e. Bind a double value to a parameter . IO: TSQLDBParamInOutType=paramIn).values are stored as in SQL (i.the leftmost SQL parameter has an index of 1 procedure BindArray(Param: Integer.this default implementation will raise an exception if the engine does not support array binding procedure BindArray(Param: Integer.the leftmost SQL parameter has an index of 1 SynDB. abstract.this default implementation will raise an exception if the engine does not support array binding procedure BindArrayDateTime(Param: Integer. null) . const Values: array of TDateTime). overload. virtual.values are stored as in SQL (i.the leftmost SQL parameter has an index of 1 . virtual. virtual. Bind an array of TDateTime values to a parameter . 'YYYY-MM-DD hh:mm:ss'. overload. abstract. virtual.the leftmost SQL parameter has an index of 1 . const Values: array of currency).this default implementation will raise an exception if the engine does not support array binding procedure BindBlob(Param: Integer. 'quoted string'.this default implementation will raise an exception if the engine does not support array binding procedure BindArrayCurrency(Param: Integer. ParamType: TSQLDBFieldType. Value: double. IO: TSQLDBParamInOutType=paramIn). 2013 procedure Bind(Param: Integer. IO: TSQLDBParamInOutType=paramIn).Rev. Bind a Blob buffer to a parameter . Bind an array of currency values to a parameter . AsBlob/AsBytes SynDB. virtual. IO: TSQLDBParamInOutType=paramIn). after ColumnsToSQLInsert() method call for fast data conversion between tables procedure BindNull(Param: Integer. abstract. virtual.the leftmost SQL parameter has an index of 1 procedure BindVariant(Param: Integer. const Value: WideString. virtual. overload. by TQuery. 1. Bind an array of fields from an existing SQL statement .the leftmost SQL parameter has an index of 1 procedure BindDateTime(Param: Integer.18 Date: June 16. virtual. IO: TSQLDBParamInOutType=paramIn). IO: TSQLDBParamInOutType=paramIn). IO: TSQLDBParamInOutType=paramIn).used e. virtual. overload. Bind a NULL value to a parameter . Bind a UTF-8 encoded buffer text (#0 ended) to a parameter . abstract. 2013 procedure BindCurrency(Param: Integer.the leftmost SQL parameter has an index of 1 .if DataIsBlob is TRUE.the leftmost SQL parameter has an index of 1 procedure BindTextS(Param: Integer.the leftmost SQL parameter has an index of 1 procedure BindTextU(Param: Integer.18 Page 533 of 1055 .the leftmost SQL parameter has an index of 1 procedure BindTextP(Param: Integer.Rev.Synopse mORMot Framework Software Architecture Design 1. abstract. will call BindBlob(RawByteString(Data)) instead of BindTextW(WideString(Variant)) .g.the leftmost SQL parameter has an index of 1 procedure BindTextW(Param: Integer. abstract. const Value: string. abstract.the leftmost SQL parameter has an index of 1 procedure BindFromRows(const Fields: TSQLDBColumnPropertyDynArray. Rows: TSQLDBStatement). virtual. Value: currency. overload. const Data: Variant. Bind a currency value to a parameter . virtual. Value: TDateTime. IO: TSQLDBParamInOutType=paramIn). Bind a UTF-8 encoded string to a parameter . IO: TSQLDBParamInOutType=paramIn). abstract.pas unit .g. IO: TSQLDBParamInOutType=paramIn). Bind a UTF-8 encoded string to a parameter . overload. virtual.can be used e. const Value: RawUTF8. abstract. IO: TSQLDBParamInOutType=paramIn). overload. Bind a UTF-8 encoded string to a parameter . Bind a TDateTime value to a parameter . DataIsBlob: boolean. overload.will call all virtual Bind*() methods from the Data type . Bind a Variant value to a parameter . Value: PUTF8Char. 18 Date: June 16.true.Expand to guess the expected output format .if ExpectResults is TRUE.Synopse mORMot Framework Software Architecture Design 1.parameters marked as ? should be specified as method parameter in Params[] .should raise an Exception on any error .if ExpectResults is TRUE. 2013 procedure ColumnsToJSON(WR: TJSONWriter. ExpectResults: Boolean.18 Page 534 of 1055 .this method will bind parameters. const Args. const Params: array of const).parameters marked as ? should have been already bound with Bind*() functions .this method will bind parameters.this default implementation will call Column*() methods above.should raise an Exception on any error .so could be used as such. then call Excecute() virtual method procedure ExecutePrepared.parameters marked as % will be replaced by Args[] value in the SQL text .pas unit . abstract. Append all columns values of the current Row to a JSON stream . then Step() and Column*() methods are available to retrieve the data rows . 1. Prepare and Execute an UTF-8 encoded SQL statement .parameters marked as ? should have been already bound with Bind*() functions above . Params: array of const). Execute a prepared SQL statement .if ExpectResults is TRUE. overload.TableName]. but need an explicit call to BindBlob() method . but need an explicit call to BindBlob() method . overload.should raise an Exception on any error SynDB.[FieldName. then Step() and Column*() methods are available to retrieve the data rows .BLOB field value is saved as Base64.should raise an Exception on any error .will use WR.parameters marked as ? should be specified as method parameter in Params[] .this method will call Prepare then ExecutePrepared methods procedure Execute(const aSQL: RawUTF8. ExpectResults: Boolean. in the '"\uFFF0base64encodedbinary" format and contains true BLOB data procedure Execute(const aSQL: RawUTF8. then Step() and Column*() methods are available to retrieve the data rows . virtual. overload. Prepare and Execute an UTF-8 encoded SQL statement .BLOB parameters could not be bound with this method. virtual.BLOB parameters could not be bound with this method.[ID]) . ExpectResults: Boolean). DoNotFletchBlobs: boolean). then call Excecute() virtual method procedure Execute(SQLFormat: PUTF8Char. but you should also implement a custom version with no temporary variable .Execute('SELECT % FROM % WHERE RowID=?'. Prepare and Execute an UTF-8 encoded SQL statement . mixing both % and ? parameters: Statement.Rev. corresponding to Column*() methods .parameters marked as ? will be bound later. The prepared SQL statement. Reset the previous prepared statement . override. 2013 procedure Prepare(const aSQL: RawUTF8.should raise an Exception on any error .this default implementation will just store aSQL content and the ExpectResults parameter. The current row after Execute call. Prepare an UTF-8 encoded SQL statement .g.is not reset when there is no more row of available data (Step returns false).e.pas unit . aDatabaseName. overload. virtual. and connect to the remote server is was not already connected procedure Reset. virtual. then Step() and Column*() methods are available to retrieve the data rows . aUserID.some drivers expect an explicit reset before binding parameters and executing the statement another time . Release related memory. override. OleDB. The prepared SQL statement.18 Date: June 16. or a number >=1 property SQL: RawUTF8 read fSQL.Synopse mORMot Framework Software Architecture Design 1.this overriden class will defined an hidden thread ID. as supplied to Prepare() method property SQLWithInlinedParams: RawUTF8 read GetSQLWithInlinedParams. and all per-thread connections SynDB. with all '?' changed into the supplied parameter values property TotalRowsRetrieved: Integer read fTotalRowsRetrieved. or when Step() is called with SeekFirst=true TSQLDBConnectionThreadSafe = class(TSQLDBConnection) Abstract connection created from TSQLDBConnectionProperties . ODBC and Oracle connections will inherit from this class TSQLDBConnectionPropertiesThreadSafe = class(TSQLDBConnectionProperties) Connection properties which will implement an internal Thread-Safe connection pool constructor Create(const aServerName. The total number of data rows retrieved by this instance . Initialize the properties . The associated database connection property CurrentRow: Integer read fCurrentRow. aPassWord: RawUTF8).Rev.this default implementation will just do nothing property Connection: TSQLDBConnection read fConnection.18 Page 535 of 1055 . ExpectResults: Boolean).this overriden method will initialize the internal per-thread connection pool destructor Destroy. 1.contains 0 in case of no (more) available data. to ensure that one connection will be create per thread .if ExpectResults is TRUE. before ExecutePrepared call . but this type can be used to implement a generic parameter ..warning: no connection shall be still be used on the background.number of items in array is stored in VInt64 . override. by TSQLDBStatementWithParams as a dynamic array (and its inherited TSQLDBOracleStatement) VArray: TRawUTF8DynArray.g.18 Date: June 16. 'YYYY-MM-DD hh:mm:ss'. end. 'quoted string'.18 Page 536 of 1055 . You can call this method just before a thread is finished to ensure that the associated Connection will be released .e.values are stored as in SQL (i.OnHttpThreadTerminate(Sender: TObject). in database embedded mode (SQLite3/FireBird).g.Execute overriden method . null) SynDB.finally block inside a TThread.could be used e..Synopse mORMot Framework Software Architecture Design 1. if you call it from the main thread. for instance via a method defined as such: procedure TMyServer. override. begin fMyConnectionProps. Release all existing connections . or some unexpected border effects may occur procedure EndCurrentThread. via an internal pool procedure ClearConnectionPool.could be used e.this overriden implementation will release all per-thread TSQLDBConnection internal connection pool . 2013 function ThreadSafeConnection: TSQLDBConnection. Get a thread-safe connection .to be used e.pas unit . to call CoUnInitialize from thread in which CoInitialize was made.this overriden implementation will define a per-thread TSQLDBConnection connection pool.you can use your own internal representation of parameters (TOleDBStatement use its own TOleDBStatementParam type).g.Rev. Storage used for array bind values . in a try. Set this property if you want to disable the per-thread connection pool .EndCurrentThread.used e.g.g.this method shall be called from the thread about to be terminated: e. it may fail to release resources . 1. when multiple connections may break stability and decrease performance TSQLDBParam = packed record A structure used to store a standard binding parameter . mORMotDB unit will call this method for every terminating thread created for TSQLRestServerNamedPipeResponse or TSQLHttpServer multi-thread process property ForceOnlyOneSharedConnection: boolean read fForceOneConnection write fForceOneConnection. number. virtual.within the mORMot server. . Value: double.pas unit . override.raise an Exception on any error procedure Bind(Param: Integer. Storage used for ftInt64.raise an Exception on any error SynDB. Create a statement instance .Rev. overload. 2013 VData: RawByteString.this overriden function will retrieve the value stored in the protected fParams[] array: the ExecutePrepared method should have updated its content as exepcted procedure Bind(Param: Integer.18 Page 537 of 1055 .ftUTF8 are stored as RawUTF8 . or ftDate value converted to SQLT_TIMESTAMP VDBType: word. overload.the leftmost SQL parameter has an index of 1 . var Value: Variant. Value: Int64. Used e.to be used e.g.g.this overriden version will initialize the internal fParam* fields function ParamToVariant(Param: Integer. Bind an integer value to a parameter .18 Date: June 16.sometimes.Synopse mORMot Framework Software Architecture Design 1.ftBlob are stored as RawByteString . ftDate and ftCurrency value VType: TSQLDBFieldType. IO: TSQLDBParamInOutType=paramIn). ftDouble. by TSQLDBOracleStatement VInOut: TSQLDBParamInOutType. override. The column/parameter Value type TSQLDBStatementWithParams = class(TSQLDBStatement) Generic abstract class handling prepared statements with binding . Retrieve the parameter content. Define if parameter can be retrieved after a stored procedure execution VInt64: Int64. Bind a double value to a parameter .the leftmost SQL parameter has an index of 1 .will provide protected fields and methods for handling standard TSQLDBParam parameters constructor Create(aConnection: TSQLDBConnection). override. Storage used for TEXT (ftUTF8) and BLOB (ftBlob) values . IO: TSQLDBParamInOutType=paramIn). 1. after SQL execution . override. may be ftInt64 or ftCurrency provided as SQLT_AVC text. with stored procedures . CheckIsOutParameter: boolean=true): TSQLDBFieldType.the leftmost SQL parameter has an index of 1 . VArray procedure BindArrayDateTime(Param: Integer. stored in TSQLDBParam.this default implementation will call BindArray() after conversion into RawUTF8 items. 'quoted string'.e. stored in TSQLDBParam.this default implementation will raise an exception if the engine does not support array binding procedure BindArray(Param: Integer.values are stored as in SQL (i. RawUTF8.Synopse mORMot Framework Software Architecture Design 1. 'YYYY-MM-DD hh:mm:ss') procedure BindArrayCurrency(Param: Integer. Integer/Int64.values are stored as in SQL (i.e. ValuesCount: integer).the leftmost SQL parameter has an index of 1 . override. stored in TSQLDBParam. number.VArray procedure BindArrayRow(const aValues: array of const). Bind a set of parameters for further array binding .this default implementation will call BindArray() after conversion into RawUTF8 items. 'YYYY-MM-DD hh:mm:ss'. overload.this default implementation will call BindArray() after conversion into RawUTF8 items. double).the leftmost SQL parameter has an index of 1 .18 Page 538 of 1055 . const Values: array of RawUTF8). overload. const Values: array of Int64).e.this default implementation will raise an exception if the engine does not support array binding . Bind an array of integer values to a parameter .the leftmost SQL parameter has an index of 1 . you can also bind directly a TDateTime value if the corresponding binding has been defined as ftDate by BindArrayRowPrepare() SynDB.this default implementation will call BindArray() after conversion into RawUTF8 items. override. const Values: TRawUTF8DynArray. const Values: array of double).supplied parameters shall follow the BindArrayRowPrepare() supplied types (i. 2013 procedure BindArray(Param: Integer. 1. Bind an array of RawUTF8 values to a parameter . ParamType: TSQLDBFieldType.pas unit . const Values: array of TDateTime).VArray procedure BindArray(Param: Integer. Bind an array of values to a parameter using OCI bind array feature . overload. override. Bind an array of TDateTime values to a parameter .the leftmost SQL parameter has an index of 1 .this default implementation will raise an exception if the engine does not support array binding . const Values: array of currency).Rev. stored in TSQLDBParam.the leftmost SQL parameter has an index of 1 . override.this default implementation will raise an exception if the engine does not support array binding . override. override.18 Date: June 16. 'YYYY-MM-DD hh:mm:ss') .VArray procedure BindArray(Param: Integer. Bind an array of currency values to a parameter .the leftmost SQL parameter has an index of 1 . overload. Bind an array of double values to a parameter .e.values are stored as 'quoted string' .values are stored as in SQL (i. null) . override. Bind a currency value to a parameter . const Value: string. Bind a UTF-8 encoded buffer text (#0 ended) to a parameter .call this method.Synopse mORMot Framework Software Architecture Design 1.the leftmost SQL parameter has an index of 1 .the leftmost SQL parameter has an index of 1 .BindArray*() methods expect the data to be supplied "verticaly": this method allow-per row binding .raise an Exception on any error procedure BindCurrency(Param: Integer. Bind a VCL string to a parameter . then BindArrayRow() with the corresponding values for one statement row. IO: TSQLDBParamInOutType=paramIn). const Value: RawUTF8.raise an Exception on any error SynDB.18 Date: June 16. overload. Bind a TDateTime value to a parameter . IO: TSQLDBParamInOutType=paramIn). override. Size: integer. Data: pointer.the leftmost SQL parameter has an index of 1 . Bind a Blob buffer to a parameter . IO: TSQLDBParamInOutType=paramIn).Rev. overload. const Data: RawByteString. overload.the leftmost SQL parameter has an index of 1 procedure BindTextS(Param: Integer.raise an Exception on any error procedure BindBlob(Param: Integer. Bind a Blob buffer to a parameter . override. IO: TSQLDBParamInOutType=paramIn).raise an Exception on any error procedure BindNull(Param: Integer.the leftmost SQL parameter has an index of 1 . then Execute to send the query procedure BindBlob(Param: Integer. overload. Value: currency.the leftmost SQL parameter has an index of 1 . Bind a NULL value to a parameter .18 Page 539 of 1055 .raise an Exception on any error procedure BindTextU(Param: Integer.raise an Exception on any error procedure BindTextP(Param: Integer. overload. Value: PUTF8Char. override. Bind a UTF-8 encoded string to a parameter . IO: TSQLDBParamInOutType=paramIn). Value: TDateTime. overload. IO: TSQLDBParamInOutType=paramIn). aExpectedMinimalRowCount: integer=0).raise an Exception on any error procedure BindDateTime(Param: Integer. 2013 procedure BindArrayRowPrepare(const aParamTypes: array of TSQLDBFieldType. IO: TSQLDBParamInOutType=paramIn). override. 1.the leftmost SQL parameter has an index of 1 . IO: TSQLDBParamInOutType=paramIn). Start parameter array binding per-row process . overload. override. override. override.pas unit .the leftmost SQL parameter has an index of 1 . ftCurrency type should be handled specificaly. override.e.Columns numeration (i. Col value) starts with 0 .it's up to the implementation to ensure than all column names are unique function ColumnType(Col: integer. const Value: WideString. Retrieve a column name of the current Row . 1. overload.this implementation will store fColumns[Col].ColumnValueDBSize if ColumnValueInlined=true property Columns: TSQLDBColumnPropertyDynArray read fColumns. override.g.e.Rev. override. Reset the previous prepared statement .Columns numeration (i. Col value) starts with 0 . Direct access to the columns description .18 Date: June 16. override. Returns the Column index of a given Column name .is used e.gives more details than the default ColumnType() function TSQLDBLib = class(TObject) Access to a native library . since currency is a standard OleDB type . IO: TSQLDBParamInOutType=paramIn).this overriden version will initialize the internal fColumn* fields function ColumnIndex(const aColumnName: RawUTF8): integer. in SynDBOracle by TSQLDBOracleLib to access the OCI library. for faster process and avoid any rounding issue. Bind an OLE WideString to a parameter .will provide protected fields and methods for handling both TSQLDBParam parameters and standard TSQLDBColumnProperty column description constructor Create(aConnection: TSQLDBConnection).Synopse mORMot Framework Software Architecture Design 1.returns -1 if the Column name is not found (via case insensitive search) function ColumnName(Col: integer): RawUTF8. The Column type of the current Row . or by SynDBODBC to access the ODBC library SynDB.18 Page 540 of 1055 . override.the leftmost SQL parameter has an index of 1 .raise an Exception on any error procedure Reset. override. Create a statement instance .this overriden implementation will just do reset the internal fParams[] TSQLDBStatementWithParamsAndColumns = class(TSQLDBStatementWithParams) Generic abstract class handling prepared statements with binding and column description .pas unit . FieldSize: PInteger=nil): TSQLDBFieldType.this generic class is to be used for any native connection using an external library .FieldSize can be set to store the size in chars of a ftUTF8 column (0 means BLOB kind of TEXT column) . 2013 procedure BindTextW(Param: Integer. 2013 destructor Destroy.will mimic both TField and TParam classes as defined in standard DB unit.pas unit . by pointing both classes types to PQueryValue .18 Page 541 of 1055 . Access the Value as TDate property AsDateTime: TDateTime read GetDateTime write SetDateTime.Rev.e. Release associated memory and linked library property Handle: HMODULE read fHandle write fHandle. Set the column value to null property AsBlob: TBlobData read GetBlob write SetBlob. Access the Value as Currency .avoid any rounding conversion. The associated library handle ESQLQueryException = class(Exception) Generic Exception type raised by the TQuery class TQueryValue = object(TObject) Pseudo-class handling a TQuery bound parameter or column value . Access the BLOB Value as array of byte (TBytes) .18 Date: June 16. since Delphi 2009) . Access the Value as double SynDB.it is based on an internal Variant to store the parameter or column value procedure Clear. as with AsFloat property AsDate: TDateTime read GetDateTime write SetDateTime. Access the Value as boolean property AsBytes: TBytes read GetAsBytes write SetAsBytes.usage of an object instead of a class allow faster access via a dynamic array (and our TDynArrayHashed wrapper) for fast property name handling (via name hashing) and pre-allocation . override.for a BLOB parameter or column.e. 1. Access the Value as TDateTime property AsFloat: double read GetDouble write SetDouble. Access the BLOB Value as an AnsiString .will work for all Delphi versions. including Unicode versions (i.for a BLOB parameter or column. including Unicode versions (i.Synopse mORMot Framework Software Architecture Design 1. since Delphi 2009) . you should use AsBlob or AsBlob properties instead of AsString (this later won't work after Delphi 2007) property AsCurrency: Currency read GetCurrency write SetCurrency. you should use AsBlob or AsBlob properties instead of AsString (this later won't work after Delphi 2007) property AsBoolean: Boolean read GetBoolean write SetBoolean.will work for all Delphi versions. Synopse mORMot Framework Software Architecture Design 1. 1. The associated (parameter) name property ParamType: TParamType read fParamType write fParamType. Int64 is not handled: the Variant type only handle integer types. Just do nothing .Rev. before Delphi 2009) property AsTime: TDateTime read GetDateTime write SetDateTime. The associated (field) name property IsNull: Boolean read GetIsNull.e. in this Delphi version :( property AsInteger: integer read GetInteger write SetInteger.note that under Delphi 5. How to use this parameter on queries or stored procedures SynDB. Access the Value as an unicode String . our SynUnicode type) property Bound: Boolean write SetBound.note that under Delphi 5. Access the Value as String .here for compatibility reasons with Clear + Bound := true property FieldName: string read fName. Int64 is not handled: the Variant type only handle integer types. 2013 property AsInt64: Int64 read GetInt64 write SetInt64. Returns TRUE if the stored Value is null property Name: string read fName. in this Delphi version :( property AsString: string read GetString write SetString.will return a WideString before Delphi 2009. and an UnicodeString for Unicode versions of the compiler (i. Access the Value as Int64 .e. Access the Value as Int64 . Access the Value as Variant property AsWideString: SynUnicode read GetAsWideString write SetAsWideString. Access the Value as Integer property AsLargeInt: Int64 read GetInt64 write SetInt64. Access the Value as TTime property AsVariant: Variant read GetVariant write SetVariant.used in the VCL world for both TEXT and BLOB content (BLOB content will only work in pre-Unicode Delphi version. i.18 Date: June 16.pas unit .18 Page 542 of 1055 . SQL.Synopse mORMot Framework Software Architecture Design 1.Create(aSQLDBConnection). Lookup methods do not exist within this class) . end. but having such code-compatible TQuery replacement could make easier some existing code upgrade (e. // optional Q. Locate.g.TABLE').').you should better use TSQLDBStatement instead of this wrapper. Retrieve a column value from the current opened SQL query row . Q. 1.since there is no underlying TDataSet.Eof do begin assert(Q.will raise an ESQLQueryException error in case of error. Retrieve a column value from the current opened SQL query row .g. try Q. and will be faster for field and parameters access than the standard TDataSet based implementation. . will natively handle Int64/TBytes field or parameter data..this class is Unicode-ready even before Delphi 2009 (via the TQueryValue AsWideString method). override. generate smaller executable.Add('select * from DOMAIN.ParamByName('DETAIL'). // optional finally Q.Next.FieldByName('id_detail'). Append.Free. Cancel. avoid rewriting a lot of existing code lines of a big application.pas unit .use QueryToDataSet() function from SynDBVCL. if no column name matchs the supplied name function FindField(const aFieldName: string): TField.it is able to run basic queries as such: Q := TQuery.AsString := '123420020100000430015'.First.Open. OleDB replaces the BDE or the DBExpress layer.Clear. and will have less overhead than the standard DB components of the VCL . if no column name matchs the supplied name SynDB. // optional while not Q. or use the visual DB components of the VCL: it's limited to direct emulation of low-level SQL as in the above code.pas to create a TDataSet from such a TQuery instance.dll) . Initialize a query for the associated database connection destructor Destroy. 2013 TQuery = class(TObject) Class mapping VCL DB TQuery for direct database process . Q.g. and link this request to visual DB components . or access directly to the client library (e. for TSQLDBOracleConnectionProperties which calls oci..) constructor Create(aConnection: TSQLDBConnection). but won't need any BDE installed. in fact.Rev. e. access any database without paying a big fee. e. Post. end.SQL. Q.this class can mimic basic TQuery VCL methods. you can't have read and write access.Close. to avoid deploying the deprecated BDE. Q. Q.g. with one-direction retrieval (e.will return nil in case of error.g.Add(' WHERE ID_DETAIL=:detail.18 Page 543 of 1055 . Prior. Q.18 Date: June 16.AsString='123420020100000430015'). Release internal memory and statements function FieldByName(const aFieldName: string): TField. the Edit.SQL. Equals true if there is no row returned SynDB.Synopse mORMot Framework Software Architecture Design 1.18 Page 544 of 1055 . End the SQL query . out of range index property IsEmpty: Boolean read GetIsEmpty. Access a SQL statement parameter.if the requested parameter do not exist yet in the internal fParams list. the returned rows being available via FieldByName methods procedure Prepare.18 Date: June 16. for a non SELECT statement . Equals true if on first row property Connection: TSQLDBConnection read fConnection. Begin the SQL query. go the the next row of results procedure Open. Equals true if the query is opened property Bof: Boolean read GetBof. Begin the SQL query.will parse the entered SQL statement. entered as :aParamName in the SQL . results and bound parameters .g. The number of columns in the current opened SQL query row property Fields[aIndex: integer]: TField read GetField.the query will be released with a call to Close within this method procedure First.the query should be released with a call to Close before reopen procedure ExecSQL.will return nil in case of error. ready to use First/Eof/Next methods. After a successfull Open. 2013 function ParamByName(const aParamName: string.will release the SQL statement. 1. just available for compatibility purpose property Active: Boolean read GetActive. CreateIfNotExisting: boolean=true): TParam. for a SELECT statement . After successfull Open and First. Retrieve a column value from the current opened SQL query row . e.will then execute the SELECT statement. AND if CreateIfNotExisting=true.pas unit . Equals true if there is some rows pending property FieldCount: integer read GetFieldCount. and bind parameters . and bind parameters . a new TQueryValue instance will be created and registered procedure Close.will parse the entered SQL statement. will get the first row of results procedure Next. The associated database connection property Eof: Boolean read GetEof. A do-nothing method.Rev. Pointer mapping the VCL DB TField class . The number of bound parameters in the current SQL statement property Params[aIndex: integer]: TParam read GetParam.pas unit .statement will be prepared and executed via Open or ExecSQL methods .speNonActive / speActive will be used to notify external DB blocking access. speActive. so can be used e. it will be executed only once in case of nested calls) .speReconnected will be called if TSQLDBConnection did successfully recover its database connection (on error. if property SQL: TStringList read fSQL. i.will return nil in case of error. The SQL statement to be executed .g. Returns 0 if no record was retrievd.is nil if the TQuery is not prepared (e..speConnectionLost will be called by TQuery in case of broken connection. speReconnected ).OnProcess properties .not the exact count: just here for compatibility purpose with code like aQuery.OnProperties properties TSQLDBConnectionProperties.Clear will force a call to the Close method (i. just as with the default VCL implementation) property SQLAsText: string read GetSQLAsText.OnProcess or TSQLDBConnection. reset the query.g.Synopse mORMot Framework Software Architecture Design 1. after Close) property RecordCount: integer read GetRecordCount. Non VCL property to access the internal SynDB prepared statement . out of range index property PreparedSQLDBStatement: ISQLDBStatement read fPrepared.Rev.e. TQuery will call speConnectionLost) . Pointer to TQuery bound parameter or column value TBlobData = RawByteString. Possible events notified to TOnSQLDBProcess callback method event handler is specified by TSQLDBConnectionProperties. 1.to be used e. speConnectionLost. 1 if there was some records .. and if SynDB.18 Page 545 of 1055 .e. 2013 property ParamCount: integer read GetParamCount.g.g.18 Date: June 16. Event handler called during all external DB process event handler is specified by TSQLDBConnection.SQL. with code using local TField instances in a loop TOnSQLDBProcess = procedure(Sender: TSQLDBConnection. Retrieve a bound parameters in the current SQL statement . Event: TOnSQLDBProcessEvent) of object.OnProcess or TOnSQLDBProcessEvent = ( speNonActive. The SQL statement with inlined bound parameters Types implemented in the SynDB unit: PQueryValue = ^TQueryValue. e.RecordCount>0 then . Generic type used by TQuery / TQueryValue for BLOBs fields TField = PQueryValue. to change the mouse cursor shape (this trigger is re-entrant. 2013 Disconnect/Reconnect did not restore it as expected (i. Pointer mapping the VCL DB TParam class . TEXT.g.g. for cross-Delphi true Unicode process TSQLDBFieldTypeDefinition = array[TSQLDBFieldType] of RawUTF8.dk/db/rdbms SynDB. ftNull maps RawUTF8 index # field.arvin. ptInputOutput. ptInput.g. ftCurrency. An array of RawUTF8. The handled field/parameter/column types by this unit .TQuery will use TDynArrayHashed for fast search TSQLDBColumnDefineDynArray = array of TSQLDBColumnDefine. REAL.Synopse mORMot Framework Software Architecture Design 1. like Oracle. dNexusDB ).e. INTEGER.to be used e. other types map their default kind . NULL. Represent the use of parameters on queries or stored procedures . ftUTF8 will define the BLOB field.pas unit .the RowID definition will expect the ORM to create an unique identifier. Used to define the column layout of a table schema . for each existing column type . Specify the class of TSQLDBConnectionProperties . 1. dSQLite.for UTF-8 text.18 Date: June 16. The known database definitions . speReconnected) TParam = PQueryValue.ftUnknown maps ID field (as integer). whereas ftNull will expect to be formated with an expected field length in ColumnAttr . dMSSQL. dDefault. do not support standard's IDENTITY attribute) . SynDBExplorer or sample 16) TSQLDBDefinition = ( dUnknown. i.18 Page 546 of 1055 . with code using local TParam instances TParamType = ( ptUnknown. for TSQLDBConnectionProperties. ftDate. dMySQL.GetFields TSQLDBColumnPropertyDynArray = array of TSQLDBColumnProperty. dJet. from a set of available classes (see e.sometimes used to create connection properties instances.pas . dFirebird.this will map low-level database-level access types. ftBlob ). and will use the ftUnknown type definition for this (may be not the same as ftInt64.will be used e. for TSQLDBConnectionProperties. Used to define a table/field column layout TSQLDBConnectionPropertiesClass = class of TSQLDBConnectionProperties. dOracle. ftDouble.sqlite.g. e. ptOutput. ftUTF8 maps RawUTF8 blob field. it can be mapped to standard SQLite3 generic types.g.same enumeration as with the standard DB unit from VCL TQueryValueDynArray = array of TQueryValue.org/datatype3.e. not high-level Delphi types as TSQLFieldType defined in mORMot.Rev. or for ODBC definition TSQLDBFieldType = ( ftUnknown. by SQLCreate method .html .used e. BLOB (with the addition of a ftCurrency and ftDate type.see http://troels.e.for instance. for better support of most DB engines) see @http://www. for SQLite3 it should be INTEGER and not BIGINT) and send it with the INSERT statement (some databases. ftNull. ftInt64. ftUTF8. A dynamic array of TQuery bound parameters or column values .SQLFieldCreate().the only string type handled here uses UTF-8 encoding (implemented using our RawUTF8 type).g. ptResult ). paramInOut ). for batch send abilities of a DB engine TSQLDBStatementGetCol = ( colNone. 2013 TSQLDBFieldTypeDynArray = array of TSQLDBFieldType. Used to describe extended Index definition of a table schema . ftCurrency.used by TSQLDBColumnProperty. Function helper logging some column truncation information text SynDB. for TSQLDBConnectionProperties. by TSQLDBStatementWithParams (and its inherited TSQLDBOracleStatement) TSQLDBParamInOutType = ( paramIn.used e. colTmpUsed. Used to specify an array of field/parameter/column types TSQLDBFieldTypes = set of TSQLDBFieldType. 1. Possible column retrieval patterns . 548 TrimLeftSchema Retrieve a table name without any left schema 548 procedure LogTruncatedColumn(const Col: TSQLDBColumnProperty).will be paramIn by default.could be set to paramOut or paramInOut if must be refereshed after execution (for calling a stored procedure expecting such parameters) TSQLDBStatementCRUD = ( cCreate.g.18 Date: June 16.18 Page 547 of 1055 . The diverse type of bound parameters during a statement execution . Dynamic array used to store standard binding parameters . ftDouble.g.used e. which is the case 90% of time .Rev.Synopse mORMot Framework Software Architecture Design 1. TSQLDBFieldType kind of columns which have a fixed width Functions or procedures implemented in the SynDB unit: Functions or procedures Description Page LogTruncatedColumn Function helper logging some column truncation information text 547 ReplaceParamsByNames Replace all '?' in the SQL statement with named parameters like :AA :AB.ColumnValueState Constants implemented in the SynDB unit: FIXEDLENGTH_SQLDBFIELDTYPE = [ftInt64. colNull. cUpdate.e. colWrongType. Used to specify a set of field/parameter/column types TSQLDBIndexDefineDynArray = array of TSQLDBIndexDefine.GetIndexes TSQLDBParamDynArray = array of TSQLDBParam. colTmpUsedTruncated ). ftDate]. paramOut. Identify a CRUD mode of a statement TSQLDBStatementCRUDs = set of TSQLDBStatementCRUD.g.. cDelete ). cRead. Identify the CRUD modes of a statement .pas unit . 18 Page 548 of 1055 .since not all exceptions are handled specificaly by this unit. .Rev.18 Date: June 16.returns the number of ? parameters found within aSQL function TrimLeftSchema(const TableName: RawUTF8): RawUTF8.you may override it with TSQLLog.pas unit . Replace all '?' in the SQL statement with named parameters like :AA :AB.g. if available from mORMot. you may better use a common TSynLog class for the whole application or module SynDB. 2013 function ReplaceParamsByNames(const aSQL: RawUTF8. var aNewSQL: RawUTF8): integer.pas .Synopse mORMot Framework Software Architecture Design 1. 1. TrimLeftSchema('SCHEMA.. Retrieve a table name without any left schema .TABLENAME')='TABLENAME' Variables implemented in the SynDB unit: SynDBLog: TSynLogClass=TSynLog. The TSynLog class used for logging for all our SynDB related units .e. pas unit Purpose: DB.this unit is a part of the freeware Synopse framework.pas unit Dataset connection TSQLDBDatasetConnectionProperties = class(TSQLDBConnectionPropertiesThreadSafe) implement properties shared by via the DB.this unit is a part of the freeware Synopse framework. 2013 23.pas unit Dataset connection 549 TSQLDBDatasetConnecti onProperties implement properties shared by via the DB.pas TDataset-based direct access classes (abstract TQuery-like) .18 Page 549 of 1055 . 1.18 509 Exception ESQLDBDataset TSQLDBConnectionPropertiesThreadSafe TSQLDBDatasetConnectionProperties TSQLDBStatementWithParamsAndColumns TSQLDBDatasetStatementAbstract TSQLDBDatasetStatement SynDBDataset class hierarchy Objects implemented in the SynDBDataset unit: Objects Description Page ESQLDBDataset Exception type associated to generic TDataSet / DB.pas TDataSet/TQuery-like connection 550 ESQLDBDataset = class(Exception) Exception type associated to generic TDataSet / DB.18 Date: June 16.18 325 SynDB Abstract database direct access classes . version 1.Synopse mORMot Framework Software Architecture Design 1.18 Units used in the SynDBDataset unit: Unit Name Description Page SynCommons Common functions used by most Synopse projects . licensed under a MPL/GPL/LGPL tri-license.6.pas TQuery-like connections 549 TSQLDBDatasetStatemen t implements a statement via the DB. version 1.pas TDataSet/TQuery-like connection 551 TSQLDBDatasetStatemen tAbstract implements an abstract statement via the DB.pas unit . licensed under a MPL/GPL/LGPL tri-license.Rev. SynDBDataset.this unit is a part of the freeware Synopse mORMot framework. licensed under a MPL/GPL/LGPL tri-license.pas TQuery-like connections SynDBDataset. version 1. but you won't have any potential data loss . Return a Column currency value of the current Row. override. override.pas unit .on some versions of Delphi.Rev.18 Page 550 of 1055 . aPassWord: RawUTF8). either as Int64 variant .dedicated abstract class. 1. you may have to use a conversion to double to avoid a runtime error property ForceUseWideString: boolean read fForceUseWideString write fForceUseWideString. the TEXT content will be processed as an UnicodeString.g. Return a Column as a blob value of the current Row. Set to true to force all Int64 content to be processed as a truncated float . UTF-8 text parameter or column will use an AnsiString value: for pre-Unicode Delphi.g. override. override.starting with Delphi 2009. 2013 constructor Create(const aServerName. if you are sure that the current charset matches the expected one (which is very likely) . override. and some version of TDataSet (e. it won't be converted to WideString (since it is not necessary) .set this property to TRUE so that WideString will be used when working with the internal TDataSet. Release the prepared statement function ColumnBlob(Col: Integer): RawByteString. BDE).pas corresponding engine . as implemented in TSQLDBDatasetStatement. Return a Column date and time value of the current Row. first Col is 0 function ColumnDateTime(Col: Integer): TDateTime.pas TDataSet/TQuery-like connection .by default.Synopse mORMot Framework Software Architecture Design 1. override. for pre-Unicode version of Delphi .if the text value contains only ASCII 7 bit characters. Return a Column floating point value of the current Row. override. Set to true to force all text content to be processed as WideString instead of the default faster AnsiString. so this property is not necessary TSQLDBDatasetStatementAbstract = class(TSQLDBStatementWithParamsAndColumns) implements an abstract statement via the DB. to avoid any character data loss: the access to the property will be slower. first Col is 0 function ColumnDouble(Col: Integer): double. first Col is 0 function ColumnCurrency(Col: Integer): currency. Initialize the properties to connect to the DB. FireDAC/AnyDAC do have its own parameters type) constructor Create(aConnection: TSQLDBConnection). Int64 values will be bound either as an integer (if the value is within expected range). aUserID. able to use any TDataSet with any kind of parameter linking (e.this overriden method will set the BATCH mode properties. aDatabaseName. first Col is 0 SynDBDataset. Create a statement instance destructor Destroy.by default.18 Date: June 16. avoiding WideString/OleStr content will speed up the process a lot.ExecutePrepared() property ForceInt64AsFloat: boolean read fForceInt64AsFloat write fForceInt64AsFloat. return true on success.will use WR. ExpectResults: boolean = false). first Col is 0 function Step(SeekFirst: boolean = false): boolean. override. Returns TRUE if the column contains NULL function ColumnUTF8(Col: Integer): RawUTF8. 1. 2013 function ColumnInt(Col: Integer): Int64.raise an ESQLDBDataset on any error procedure ColumnsToJSON(WR: TJSONWriter. override. override.parameters marked as ? will be bound later. Return a Column integer value of the current Row. Prepare an UTF-8 encoded SQL statement .18 Page 551 of 1055 .parameters marked as ? should have been already bound with Bind*() functions . with data ready to be retrieved by Column*() methods . Return a Column UTF-8 encoded text value of the current Row. Execute a prepared SQL statement . first Col is 0 function ColumnNull(Col: Integer): boolean. override.pas unit . to implement BATCH mode .raise an ESQLDBDataset on any error TSQLDBDatasetStatement = class(TSQLDBDatasetStatementAbstract) implements a statement via the DB.Expand to guess the expected output format . override. if the SQL statement is not a SELECT but an UPDATE or INSERT command) . in the '"\uFFF0base64encodedbinary" format and contains true BLOB data procedure ExecutePrepared.pas TDataSet/TQuery-like connection .raise an ESQLDBDataset on any error procedure Reset.g.Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16.this overriden implementation will reset all bindings and the cursor state .if SeekFirst is TRUE. Append all columns values of the current Row to a JSON stream .Rev. DoNotFletchBlobs: boolean). Access the next or first row of data from the SQL Statement result . override. before ExecutePrepared call . will put the cursor on the first row of results . override.raise an ESQLDBDataset on any error procedure Prepare(const aSQL: RawUTF8. override. then Step() and Column*() methods are available to retrieve the data rows .this implementation will also loop through all internal bound array of values (if any).return false if no more row is available (e. but one inherited implementation with overriden Dataset*() protected methods to handle the internal fQuery: TDataSet property SynDBDataset.you should not use this abstract class directly.BLOB field value is saved as Base64. Reset the previous prepared statement .if ExpectResults is TRUE. overload. const AValue: TBcd). 1. ExpectResults: boolean = false).if ExpectResults is TRUE. then Step() and Column*() methods are available to retrieve the data rows . before ExecutePrepared call . overload. Append a TBcd value as text to the output buffer .very optimized for speed SynDBDataset.raise an ESQLDBDataset on any error Functions or procedures implemented in the SynDBDataset unit: Functions or procedures Description Page AddBcd Append a TBcd value as text to the output buffer 552 procedure AddBcd(WR: TTextWriter.Rev.18 Date: June 16.Synopse mORMot Framework Software Architecture Design 1. 2013 procedure Prepare(const aSQL: RawUTF8.pas unit . override.parameters marked as ? will be bound later. Prepare an UTF-8 encoded SQL statement .18 Page 552 of 1055 . licensed under a MPL/GPL/LGPL tri-license. 1.this unit is a part of the freeware Synopse mORMot framework.x library direct access classes to be used with our SynDB architecture .7. generated for ODBC connection TODBCConnectionProperties = class(TSQLDBConnectionPropertiesThreadSafe) Will implement properties shared by the ODBC library SynDBODBC. 2013 23. SynDBODBC.18 509 ESQLDBException EODBCException TSQLDBConnectionPropertiesThreadSafe TODBCConnectionProperties TSQLDBConnectionThreadSafe TODBCConnection TSQLDBStatementWithParamsAndColumns TODBCStatement SynDBODBC class hierarchy Objects implemented in the SynDBODBC unit: Objects Description Page EODBCException Generic Exception type.18 Units used in the SynDBODBC unit: Unit Name Description Page SynCommons Common functions used by most Synopse projects . licensed under a MPL/GPL/LGPL tri-license. version 1.18 325 SynDB Abstract database direct access classes .18 Date: June 16. generated for ODBC connection 553 TODBCConnection Implements a direct connection to the ODBC library 554 TODBCConnectionProper ties Will implement properties shared by the ODBC library 553 TODBCStatement Implements a statement using a ODBC connection 555 EODBCException = class(ESQLDBException) Generic Exception type.18 Page 553 of 1055 .pas unit Purpose: ODBC 3. version 1.this unit is a part of the freeware Synopse framework.Rev. version 1.this unit is a part of the freeware Synopse mORMot framework.Synopse mORMot Framework Software Architecture Design 1. licensed under a MPL/GPL/LGPL tri-license.pas unit . override. override. override.18 Page 554 of 1055 . aPassWord: RawUTF8).will retrieve the corresponding metadata from ODBC library if SQL direct access was not defined procedure GetForeignKeys. Commit changes of a Transaction for this connection .will raise an exception if the ODBC library is not available function NewConnection: TSQLDBConnection. Connect to the ODBC library.the caller should free the instance after use procedure Commit. 2013 constructor Create(const aServerName. Create a new connection .call this method if the shared MainConnection is not enough (e. for multi-thread access) . override. override. aUserID.used by GetForeignKey method procedure GetTableNames(var Tables: TRawUTF8DynArray).e. aDatabaseName. Initialize the connection properties .the caller is responsible of freeing this instance . override. Initialize fForeignKeys content with all foreign keys of this DB .Rev.pas unit . Connect to a specified ODBC database destructor Destroy.g. override. Release memory and connection function IsConnected: boolean.this overriden method will create an TODBCConnection instance procedure GetFields(const aTableName: RawUTF8. Retrieve the column/field layout of a specified table .18 Date: June 16. override. override. create the DB instance .StartTransaction method must have been called before procedure Connect.will retrieve the corresponding metadata from ODBC library if SQL direct access was not defined TODBCConnection = class(TSQLDBConnectionThreadSafe) Implements a direct connection to the ODBC library constructor Create(aProperties: TSQLDBConnectionProperties). Initialize a new SQL query statement for the given connection . Get all table names . 1. override. i. var Fields: TSQLDBColumnDefineDynArray).should raise an Exception on error SynDBODBC. override.Synopse mORMot Framework Software Architecture Design 1. Return TRUE if Connect has been already successfully called function NewStatement: TSQLDBStatement. e. The remote DBMS name. to avoid any rounding/conversion error from floating-point types function ColumnDateTime(Col: integer): TDateTime.should raise an Exception on error procedure Rollback. but you can use the Prepare once followed by several ExecutePrepared methods .ColumnBlob() will return the binary content of the field is was not ftBlob. override. override. Return a Column floating point value of the current Row.Rev. or a direct mapping of the RawUnicode function ColumnCurrency(Col: integer): currency. override.current implementation do not support nested transaction with those methods: exception will be raised in such case property DBMS: TSQLDBDefinition read fDBMS.if the supplied connection is not of TOleDBConnection type.g. override. first Col is 0 SynDBODBC. e. The remote DBMS version. override.StartTransaction method must have been called before procedure StartTransaction. Return a Column floating point value of the current Row.the Execute method can be called once per TODBCStatement instance. a 8 bytes RawByteString for a vtInt64/vtDouble/vtDate/vtCurrency. Return a Column as a blob value of the current Row. as retrieved at ODBC connection opening TODBCStatement = class(TSQLDBStatementWithParamsAndColumns) Implements a statement using a ODBC connection constructor Create(aConnection: TSQLDBConnection). as retrieved at ODBC connection opening property DBMSVersion: RawUTF8 read fDBMSVersion.18 Date: June 16. Return a Column currency value of the current Row. The remote DBMS type. first Col is 0 . Stop connection to the ODBC library. override. release the DB instance . Release all associated memory and ODBC handles function ColumnBlob(Col: integer): RawByteString. 1.Synopse mORMot Framework Software Architecture Design 1. will raise an exception destructor Destroy. Discard changes of a Transaction for this connection . i. Begin a Transaction for this connection . first Col is 0 function ColumnDouble(Col: integer): double. first Col is 0 . override.pas unit .should retrieve directly the 64 bit Currency content. override. as retrieved at ODBC connection opening property DBMSName: RawUTF8 read fDBMSName. 2013 procedure Disconnect. Create a ODBC statement instance. override.18 Page 555 of 1055 . from an existing ODBC connection . Expand to guess the expected output format .return TRUE on success. if the SQL statement is not a SELECT but an UPDATE or INSERT command) . override. before ExecutePrepared call . otherwise. DoNotFletchBlobs: boolean).raise an EODBCException or ESQLDBException exception on any error function UpdateCount: integer.fast overriden implementation with no temporary variable . Return a Column integer value of the current Row. Return a Column UTF-8 encoded text value of the current Row. with data ready to be retrieved by Column*() . override. then Step() and Column*() methods are available to retrieve the data rows .g.Synopse mORMot Framework Software Architecture Design 1. to be called within a loop .BLOB field value is saved as Base64. 1. this method must be called one or more times to evaluate it .will use WR.if ExpectResults is TRUE.raise an EODBCException or ESQLDBException on any error procedure Prepare(const aSQL: RawUTF8. override.parameters marked as ? should have been already bound with Bind*() functions . will put the cursor on the first row of results.you shall call this method before calling any Column*() methods .raise an EODBCException or ESQLDBException on any error procedure Reset. override. Returns the number of rows updated by the execution of this statement procedure ColumnsToJSON(WR: TJSONWriter. it will fetch one row of data. override. override. Reset the previous prepared statement . Returns TRUE if the column contains NULL function ColumnUTF8(Col: integer): RawUTF8.pas unit . override.18 Date: June 16. override.Rev. Append all columns values of the current Row to a JSON stream . After a statement has been prepared via Prepare() + ExecutePrepared() or Execute(). overload.18 Page 556 of 1055 .this overriden implementation will reset all bindings and the cursor state . 2013 function ColumnInt(Col: integer): Int64. first Col is 0 function ColumnNull(Col: integer): boolean. Prepare an UTF-8 encoded SQL statement .access the first or next row of data from the SQL Statement result: if SeekFirst is TRUE. ExpectResults: Boolean=false).return FALSE if no more row is available (e.raise an EODBCException on any error SynDBODBC. override.parameters marked as ? will be bound later. Execute a prepared SQL statement . in the '"\uFFF0base64encodedbinary" format and contains true BLOB data procedure ExecutePrepared. first Col is 0 function Step(SeekFirst: boolean=false): boolean. 18 Units used in the SynDBOracle unit: Unit Name Description Page SynCommons Common functions used by most Synopse projects .18 Date: June 16.8. version 1. licensed under a MPL/GPL/LGPL tri-license.this unit is a part of the freeware Synopse framework. 2013 23.pas unit Purpose: Oracle DB direct access classes (via OCI) . licensed under a MPL/GPL/LGPL tri-license. version 1.this unit is a part of the freeware Synopse framework.Synopse mORMot Framework Software Architecture Design 1.18 Page 557 of 1055 . SynDBOracle. 1.18 509 Exception ESQLDBOracle TObject TOracleDate TSQLDBConnectionPropertiesThreadSafe TSQLDBOracleConnectionProperties TSQLDBConnectionThreadSafe TSQLDBOracleConnection TSQLDBStatementWithParamsAndColumns TSQLDBOracleStatement SynDBOracle class hierarchy Objects implemented in the SynDBOracle unit: Objects Description Page ESQLDBOracle Execption type associated to the native Oracle Client Interface (OCI) 558 TOracleDate Memory structure used to store a date and time in native Oracle format 558 TSQLDBOracleConnectio n Implements a direct connection to the native Oracle Client Interface (OCI) 560 TSQLDBOracleConnectio nProperties Will implement properties shared by native Oracle Client Interface connections 558 TSQLDBOracleStatement Implements a statement via the native Oracle Client Interface (OCI) 561 SynDBOracle.pas unit .18 325 SynDB Abstract database direct access classes . licensed under a MPL/GPL/LGPL tri-license. version 1.this unit is a part of the freeware Synopse mORMot framework.Rev. overload. wrong DecodeTime() computation from retrieved value: if you need to retrieve dates before 1899.this overriden method will force the code page to be zero: you shall better call the CreateWithCodePage constructor instead of this generic method SynDBOracle. overload.g. override.pas unit . overload. you should better retrieve the content using ISO-8601 text encoding function ToIso8601(Dest: PUTF8Char): integer. aPassWord: RawUTF8). aDatabaseName. 2013 ESQLDBOracle = class(Exception) Execption type associated to the native Oracle Client Interface (OCI) TOracleDate = object(TObject) Memory structure used to store a date and time in native Oracle format .will fill up to 21 characters.Synopse mORMot Framework Software Architecture Design 1. Convert textual ISO-8601 into native Oracle date and time format procedure ToIso8601(var aIso8601: RawByteString). including double quotes procedure From(const aIso8601: RawUTF8). Length: integer). overload.dll library is not initialized with OCI_THREADED: this could make the process faster on multi-core CPU and a multi-threaded server application constructor Create(const aServerName. aUserID. overload. Convert an Oracle date and time into its textual expanded ISO-8601 .18 Date: June 16. 1. to avoid e. Convert an Oracle date and time into its textual expanded ISO-8601 .inherited from TSQLDBConnectionPropertiesThreadSafe so that the oci.e. without double quotes TSQLDBOracleConnectionProperties = class(TSQLDBConnectionPropertiesThreadSafe) Will implement properties shared by native Oracle Client Interface connections .this method will ignore any date before 30 Dec 1899 (i. any TDateTime result < 0). Convert an Oracle date and time into Delphi TDateTime .aDatabaseName is not used for Oracle: only aServerName is to be set .return the ISO-8601 text. Convert textual ISO-8601 into native Oracle date and time format procedure From(const aValue: TDateTime). Convert Delphi TDateTime into native Oracle date and time format procedure From(aIso8601: PUTF8Char.18 Page 558 of 1055 .Rev. Initialize the connection properties .follow the SQLT_DAT column type layout function ToDateTime: TDateTime. Returns the Client version e.since the OCI client will make conversion when returning column data. Extract the TNS listener name from a Oracle full connection string . 1252 for default CODEPAGE_US . '//sales-server:1523/sales' .call this method if the shared MainConnection is not enough (e. 2013 constructor CreateWithCodePage(const aServerName. The code page used for the connection .0.e. either the global NLS_LANG environnement variable is used. since will likely be used in a multi-threaded context.g. aPassWord: RawUTF8.e. Initialize the OCI connection properties .dll' property CodePage: cardinal read fCodePage.is set to 4096 (4 KB) by default.2.if aCodePage is set to 0. ExtractTnsName('1.1 at oci.g. or a connection string like '//host[:port]/[service_name]'.the caller is responsible of freeing this instance . Create a new connection . 1. The size (in bytes) of the internal buffer used to retrieve rows in statements .equals OCI_EVENTS or OCI_THREADED by default. which gives very good results SynDBOracle. override. but CHAR / NVARCHAR2 fields will use this code page encoding to avoid any column truncation when retrieved from the server property EnvironmentInitializationMode: integer read fEnvironmentInitializationMode write fEnvironmentInitializationMode.pas unit . The size (in bytes) of LOB prefecth . virtual.Rev. but may be changed for tuned performance property ClientVersion: RawUTF8 read GetClientVersion.g.g.g. either the thread setting (GetACP) class function ExtractTnsName(const aServerName: RawUTF8): RawUTF8.g.2. The OCI initialization mode used for the connection .connection is opened globaly as UTF-8. for multi-thread access) . CODEPAGE_US=1252 for default WinAnsi western encoding) .default is 128 KB. as existing on the server (e.Synopse mORMot Framework Software Architecture Design 1. '11. aUserID.can be tuned depending on the configuration or the Oracle version property InternalBufferSize: integer read fInternalBufferSize write fInternalBufferSize.4:1521/dbname') returns 'dbname' function NewConnection: TSQLDBConnection.3.this overriden method will create an TSQLDBOracleConnection instance property BlobPrefetchSize: integer read fBlobPrefetchSize write fBlobPrefetchSize. aCodePage: integer).you may specify the TNSName in aServerName. to avoid any truncate when retrieving VARCHAR2 or CHAR fields into the internal fixed-sized buffer. to match the internal encoding of our units. you may specify here the exact database code page.18 Page 559 of 1055 . e.18 Date: June 16.we don't need a database name parameter for Oracle connection . and OCI_EVENTS is needed to support Oracle RAC Connection Load Balancing . override. override. the TSQLDBOracleConnectionProperties. override.BlobPrefetchSize and StatementCacheSize field values of the associated properties will be used to tune the opened connection procedure Disconnect. this overriden implementation will use server-side Oracle statement cache in this case.if UseCache=true. to avoid any truncation during data retrieval .pas unit .18 Date: June 16. Discard changes of a Transaction for this connection . override. StatementCacheSize will define how many statements are to be cached . override. 2013 property StatementCacheSize: integer read fStatementCacheSize write fStatementCacheSize. override.Rev.is set to 30 by default . override. or a prepared statement instance in case of success (with default RaiseExceptionOnError=false) procedure Commit.should raise an Exception on error procedure Rollback.StartTransaction method must have been called before procedure Connect. override. 1.the caller should free the instance after use function NewStatementPrepared(const aSQL: RawUTF8.this method should return nil in case of error. for CHAR / NVARCHAR2 fields. Return TRUE if Connect has been already successfully called function NewStatement: TSQLDBStatement.should raise an Exception on error .the connection will be globaly opened with UTF-8 encoding. ExpectResults: Boolean.18 Page 560 of 1055 . Initialize a new SQL query statement for the given connection . Initialize a new SQL query statement for the given connection .only used if UseCache=true TSQLDBOracleConnection = class(TSQLDBConnectionThreadSafe) Implements a direct connection to the native Oracle Client Interface (OCI) constructor Create(aProperties: TSQLDBConnectionProperties).StartTransaction method must have been called before SynDBOracle. Prepare a connection to a specified Oracle database server destructor Destroy. Stop connection to the specified Oracle database server . Release memory and connection function IsConnected: boolean. Commit changes of a Transaction for this connection . Connect to the specified Oracle database server . RaiseExceptionOnError: Boolean=false): ISQLDBStatement.CodePage encoding will be used instead. override.Synopse mORMot Framework Software Architecture Design 1. The number of prepared statements cached by OCI on the Client side . g. Return a Column as a blob value of the current Row. Begin a Transaction for this connection . first Col is 0 function ColumnNull(Col: integer): boolean. via BindTextU(StringOfChar(3000).ColumnBlob() will return the binary content of the field is was not ftBlob.Rev.this function will return the BLOB content as a TBytes . will raise an exception destructor Destroy. Return a Column date and time value of the current Row. a 8 bytes RawByteString for a vtInt64/vtDouble/vtDate/vtCurrency.paramOut) constructor Create(aConnection: TSQLDBConnection).pas unit . not to reinvent the wheel this time . Return a Column currency value of the current Row. override. override. from an existing OCI connection . override. first Col is 0 . unless StartTransaction is called TSQLDBOracleStatement = class(TSQLDBStatementWithParamsAndColumns) Implements a statement via the native Oracle Client Interface (OCI) .e. TSQLDBOracleStatement works in AutoCommit mode. override. override. override. first Col is 0 . first Col is 0 function ColumnInt(Col: integer): Int64.this default virtual method will call ColumnBlob() function ColumnCurrency(Col: integer): currency.Synopse mORMot Framework Software Architecture Design 1. Return a Column as a blob value of the current Row. but by default we enabled the OCI-side statement cache. first Col is 0 function ColumnDouble(Col: integer): double. Create an OCI statement instance. override.should retrieve directly the 64 bit Currency content.the Execute method can be called once per TSQLDBOracleStatement instance.current implementation do not support nested transaction with those methods: exception will be raised in such case . Release all associated memory and OCI handles function ColumnBlob(Col: integer): RawByteString.those statements can be prepared on the Delphi side. 1.18 Date: June 16. Returns TRUE if the column contains NULL SynDBOracle. 2013 procedure StartTransaction.by default. override. but you can use the Prepare once followed by several ExecutePrepared methods . Return a Column integer value of the current Row.if the supplied connection is not of TOleDBConnection type. to avoid any rounding/conversion error from floating-point types function ColumnDateTime(Col: integer): TDateTime. Return a Column floating point value of the current Row. or a direct mapping of the RawUnicode function ColumnBlobBytes(Col: integer): TBytes.18 Page 561 of 1055 . override. first Col is 0 .note that bound OUT ftUTF8 parameters will need to be pre-allocated before calling .g. e. override. and handling ftCurrency/NUMBER(22. override.g. Append all columns values of the current Row to a JSON stream .pas unit . var Temp: RawByteString): TSQLDBFieldType. we tried to optimize it) .ColumnsToJSON . override. var Value: Variant): TSQLDBFieldType.return TRUE on success.raise an ESQLDBOracle on any error function UpdateCount: integer. DoNotFletchBlobs: boolean).Expand to guess the expected output format .return FALSE if no more row is available (e. and a generic UnicodeString (=string) since Delphi 2009: you may not loose any data during charset conversion . and varAny (BLOB with size = VLongs[0]). it will fetch one row of data.will use WR. 2013 function ColumnToVarData(Col: Integer.Column method as defined in mORMotDB unit (i. this method must be called one or more times to evaluate it .a ftUTF8 content will be mapped into a generic WideString variant for pre-Unicode version of Delphi. var Value: TVarData.18 Date: June 16. 1. directly from the memory buffers returned by OCI: it will ensure best performance possible when called from TSQLVirtualTableCursorExternal. Return a Column as a variant . varDouble. mORMot external DB access) function ColumnToVariant(Col: integer.a ftBlob content will be mapped into a TBlobData AnsiString variant function ColumnUTF8(Col: integer): RawUTF8. Return a Column as a TVarData value.access the first or next row of data from the SQL Statement result: if SeekFirst is TRUE. Return a Column UTF-8 encoded text value of the current Row.TVarData returned types are varNull.Synopse mORMot Framework Software Architecture Design 1.the specified Temp variable will be used for temporary storage of varString/varAny values . ftDate is returned as varString. if the SQL statement is not a SELECT but an UPDATE or INSERT command) . override. Returns the number of rows updated by the execution of this statement procedure ColumnsToJSON(WR: TJSONWriter.Rev. as in TSQLDBStatement.0) as fast as possible. override. otherwise. override.you shall call this method before calling any Column*() methods . varString (mapping a constant PUTF8Char).this implementation will retrieve the data with no temporary variable.BLOB field value is saved as Base64.18 Page 562 of 1055 . first Col is 0 function Step(SeekFirst: boolean=false): boolean. first Col is 0 . in the '"\uFFF0base64encodedbinary" format and contains true BLOB data SynDBOracle.this implementation will retrieve the data with no temporary variable (since TQuery calls this method a lot. After a statement has been prepared via Prepare() + ExecutePrepared() or Execute().e. varInt64. to be called within a loop . with data ready to be retrieved by Column*() .fast overriden implementation with no temporary variable (about 20% faster when run over high number of data rows) . will put the cursor on the first row of results.so this Value should not be used typecasted to a Variant . override. by default.(maxInt div sizeof(TOracleDate))-1] of TOracleDate.dll is to be found SynDBOracle.18 Date: June 16.pas unit .Rev. Wrapper to an array of TOracleDate items Variables implemented in the SynDBOracle unit: SynDBOracleOCIpath: TFileName.raise an ESQLDBOracle on any error Types implemented in the SynDBOracle unit: TOracleDateArray = array[0.parameters marked as ? will be bound later.you can specify here a folder name in which the oci. 2013 procedure ExecutePrepared. 1.Synopse mORMot Framework Software Architecture Design 1. then Step() and Column*() methods are available to retrieve the data rows . Execute a prepared SQL statement .. override. then in %ORACLE_HOME%\bin .if ExpectResults is TRUE. override. overload.18 Page 563 of 1055 .raise an ESQLDBOracle on any error procedure Prepare(const aSQL: RawUTF8. ExpectResults: Boolean=false). before ExecutePrepared call . Optional folder where the Oracle Client Library is to be searched . Prepare an UTF-8 encoded SQL statement .parameters marked as ? should have been already bound with Bind*() functions .dll library is searched in the system PATH. the oci. licensed under a MPL/GPL/LGPL tri-license.this unit is a part of the freeware Synopse mORMot framework. version 1.18 Page 564 of 1055 .this unit is a part of the freeware Synopse framework. version 1. version 1.pas unit . licensed under a MPL/GPL/LGPL tri-license.18 Date: June 16. 1.9.1 The SQLite3 engine shall be embedded to the framework 1052 Units used in the SynDBSQLite3 unit: Unit Name Description Page SynCommons Common functions used by most Synopse projects .18 509 SynSQLite3 SQLite3 Database engine direct access .pas unit Purpose: SQLite3 direct access classes to be used with our SynDB architecture . licensed under a MPL/GPL/LGPL tri-license.Rev. 2013 23.this unit is a part of the freeware Synopse mORMot framework.this unit is a part of the freeware Synopse framework. SynDBSQLite3.Synopse mORMot Framework Software Architecture Design 1. version 1.18 647 TSQLDBConnection TSQLDBSQLite3Connection TSQLDBConnectionProperties TSQLDBSQLite3ConnectionProperties TSQLDBStatement TSQLDBSQLite3Statement SynDBSQLite3 class hierarchy Objects implemented in the SynDBSQLite3 unit: Objects Description Page TSQLDBSQLite3Connecti on Implements a direct connection to the SQLite3 engine 565 TSQLDBSQLite3Connecti onProperties Will implement properties shared by the static SQLite3 engine 565 TSQLDBSQLite3Statemen t Implements a statement using the SQLite3 engine 566 SynDBSQLite3.2.18 325 SynDB Abstract database direct access classes .18 The SynDBSQLite3 unit is quoted in the following items: SWRS # Description Page DI-2. licensed under a MPL/GPL/LGPL tri-license. better not to be used on production . override. Initialize a new SQL query statement for the given connection . override. override.not compatible with the official SQLite Encryption Extension module . Stop connection to the SQLite3 engine.html (beta feature .the caller should free the instance after use procedure Commit. TRUE if you want the SQL creation fields to use mORMot collation .com/sw/sqlite/see. UserID) are ignored function NewConnection: TSQLDBConnection.2. which will be used to access the database via some custom kind of encryption .g.e.pas unit . and Iso8601 handling .see @http://www. override. for multi-thread access) .in which the default encryption level is very low) .StartTransaction method must have been called before procedure Connect.default value is TRUE for use within the mORMot framework. i. function IsConnected: boolean. override. Initialize the properties .only used parameter is aServerName. override.1 (page 1052). 1. Connect to the SQLite3 engine. create the DB instance .1 (page 1052).Synopse mORMot Framework Software Architecture Design 1. aPassWord: RawUTF8).18 Page 565 of 1055 .you can specify an optional password.the caller is responsible of freeing this instance property UseMormotCollations: boolean read fUseMormotCollations write SetUseMormotCollations.Rev.2. aDatabaseName. to use dedicated UTF-8 collation and full Unicode support. release the DB instance .e.call this method if the shared MainConnection is not enough (e.18 Date: June 16.should raise an Exception on error SynDBSQLite3. i.hwaci.when set to FALSE. override. aUserID. 2013 TSQLDBSQLite3ConnectionProperties = class(TSQLDBConnectionProperties) Will implement properties shared by the static SQLite3 engine Used for DI-2.should raise an Exception on error procedure Disconnect. at database file level TSQLDBSQLite3Connection = class(TSQLDBConnection) Implements a direct connection to the SQLite3 engine Used for DI-2. constructor Create(const aServerName. Commit changes of a Transaction for this connection . SQLCreate() method will return standard ASCII SQLite collations for TEXT: it will make interaction with other programs more compatible. Create a new connection .other parameters (DataBaseName. Return TRUE if Connect has been already successfully called function NewStatement: TSQLDBStatement. which should point to the SQLite3 database file to be opened (one will be created if none exists) . from an existing SQLite3 connection .default lmNormal is ACID and safe .assigned to not nil after successfull connection property LockingMode: TSQLLockingMode read GetLockingMode write SetLockingMode. Release all associated memory and SQLite3 handles function ColumnBlob(Col: integer): RawByteString.smOff is the fastest. override. i.ColumnBlob() will return the binary content of the field is was not ftBlob. the way it waits for the data to be flushed on hard drive .if the supplied connection is not of TOleDBConnection type. Create a SQLite3 statement instance. Begin a Transaction for this connection . first Col is 0 . the way it locks the file . i.18 Page 566 of 1055 . Query or change the SQlite3 file-based syncrhonization mode. Discard changes of a Transaction for this connection .Synopse mORMot Framework Software Architecture Design 1.default smFull is very slow. Query or change the SQlite3 file-based locking mode. constructor Create(aConnection: TSQLDBConnection).2.lmExclusive gives better performance in case of a number of write transactions. override. 2013 procedure Rollback. so can be used to release a mORMot server power: but you won't be able to access the database file from outside the process (like a "normal" database engine) property Synchronous: TSQLSynchronousMode read GetSynchronous write SetSynchronous.g. but you can use the Prepare once followed by several ExecutePrepared methods . but achieve 100% ACID behavior .current implementation do not support nested transaction with those methods: exception will be raised in such case property DB: TSQLDataBase read fDB. a 8 bytes RawByteString for a vtInt64/vtDouble/vtDate/vtCurrency. 1.StartTransaction method must have been called before procedure StartTransaction.Rev.1 (page 1052).the Execute method can be called once per TSQLDBSQLite3Statement instance.18 Date: June 16. will raise an exception destructor Destroy. override. The associated SQLite3 DB instance . and safe until a catastrophic hardware failure occurs .e. e. but database file may be corrupted in case of failure at the wrong time TSQLDBSQLite3Statement = class(TSQLDBStatement) Implements a statement using the SQLite3 engine Used for DI-2.e. or a direct mapping of the RawUnicode SynDBSQLite3. data should be safe if the application crashes. override.smNormal is faster. override. Return a Column as a blob value of the current Row.pas unit . 18 Page 567 of 1055 .return TRUE on success. first Col is 0 function ColumnName(Col: integer): RawUTF8. override.access the first or next row of data from the SQL Statement result: if SeekFirst is TRUE.you shall call this method before calling any Column*() methods .ftCurrency type should be handled specificaly. first Col is 0 function ColumnDouble(Col: integer): double. override. The Column type of the current Row . override. override. 1. first Col is 0 function Step(SeekFirst: boolean=false): boolean. FieldSize: PInteger=nil): TSQLDBFieldType. since currency is a standard OleDB type function ColumnUTF8(Col: integer): RawUTF8. to avoid any rounding/conversion error from floating-point types function ColumnDateTime(Col: integer): TDateTime. overload. Bind a double value to a parameter . will put the cursor on the first row of results. Return a Column integer value of the current Row.the leftmost SQL parameter has an index of 1 SynDBSQLite3. Col value) starts with 0 .18 Date: June 16.pas unit . After a statement has been prepared via Prepare() + ExecutePrepared() or Execute(). Value: double. to be called within a loop .Columns numeration (i.return FALSE if no more row is available (e. override.e. Return a Column floating point value of the current Row. it will fetch one row of data.g. Returns TRUE if the column contains NULL function ColumnType(Col: integer.Synopse mORMot Framework Software Architecture Design 1. override.it's up to the implementation to ensure than all column names are unique function ColumnNull(Col: integer): boolean. override. Col value) starts with 0 . Returns the Column index of a given Column name . IO: TSQLDBParamInOutType=paramIn). override. this method must be called one or more times to evaluate it .Columns numeration (i.Rev. override.should retrieve directly the 64 bit Currency content. 2013 function ColumnCurrency(Col: integer): currency.e. Return a Column currency value of the current Row. first Col is 0 . override. Return a Column UTF-8 encoded text value of the current Row. for faster process and avoid any rounding issue. if the SQL statement is not a SELECT but an UPDATE or INSERT command) . override. first Col is 0 function ColumnIndex(const aColumnName: RawUTF8): integer.raise an ESQLite3Exception exception on any error procedure Bind(Param: Integer.returns -1 if the Column name is not found (via case insensitive search) function ColumnInt(Col: integer): Int64. otherwise. with data ready to be retrieved by Column*() . Return a Column floating point value of the current Row. Retrieve a column name of the current Row . the leftmost SQL parameter has an index of 1 procedure BindBlob(Param: Integer. IO: TSQLDBParamInOutType=paramIn). override.the leftmost SQL parameter has an index of 1 procedure BindNull(Param: Integer. IO: TSQLDBParamInOutType=paramIn). override. override. IO: TSQLDBParamInOutType=paramIn). override. IO: TSQLDBParamInOutType=paramIn). Bind a UTF-8 encoded buffer text (#0 ended) to a parameter .Synopse mORMot Framework Software Architecture Design 1. Bind a Blob buffer to a parameter .the leftmost SQL parameter has an index of 1 procedure BindTextW(Param: Integer. Bind a UTF-8 encoded string to a parameter . override.the leftmost SQL parameter has an index of 1 procedure BindTextP(Param: Integer. overload.the leftmost SQL parameter has an index of 1 procedure BindCurrency(Param: Integer. override. Value: TDateTime. overload. IO: TSQLDBParamInOutType=paramIn). const Data: RawByteString.the leftmost SQL parameter has an index of 1 procedure BindTextU(Param: Integer. Bind a NULL value to a parameter . overload. overload. IO: TSQLDBParamInOutType=paramIn). const Value: WideString. const Value: RawUTF8. IO: TSQLDBParamInOutType=paramIn). Bind a currency value to a parameter . 1. overload. override.pas unit . overload.the leftmost SQL parameter has an index of 1 procedure BindBlob(Param: Integer. IO: TSQLDBParamInOutType=paramIn). Value: Int64. Bind a UTF-8 encoded string to a parameter . override. const Value: string.the leftmost SQL parameter has an index of 1 procedure BindTextS(Param: Integer. Value: currency. overload.18 Date: June 16. overload. override. IO: TSQLDBParamInOutType=paramIn). Bind a Blob buffer to a parameter .the leftmost SQL parameter has an index of 1 procedure BindDateTime(Param: Integer. override.the leftmost SQL parameter has an index of 1 SynDBSQLite3. 2013 procedure Bind(Param: Integer. Value: PUTF8Char. Data: pointer.Rev.18 Page 568 of 1055 . Bind a TDateTime value to a parameter . Size: integer. Bind an integer value to a parameter . Bind a UTF-8 encoded string to a parameter . overload. IO: TSQLDBParamInOutType=paramIn). Rows: TSQLDBStatement.raise an ESQLDBException on any error procedure Prepare(const aSQL: RawUTF8. Direct export of a DB statement rows into a SQLite3 database . DoNotFletchBlobs: boolean). Reset the previous prepared statement Functions or procedures implemented in the SynDBSQLite3 unit: Functions or procedures Description Page RowsToSQLite3 Direct export of a DB statement rows into a SQLite3 database 569 function RowsToSQLite3(const Dest: TFileName. override.pas unit .will use WR. 1.raise an ESQLDBException on any error procedure Reset.BLOB field value is saved as Base64.parameters marked as ? should have been already bound with Bind*() functions . before ExecutePrepared call .the corresponding table will be created within the specified DB file SynDBSQLite3. then Step() and Column*() methods are available to retrieve the data rows .18 Page 569 of 1055 .Expand to guess the expected output format . overload. const TableName: RawUTF8. override.fast overriden implementation with no temporary variable .Rev.18 Date: June 16.Synopse mORMot Framework Software Architecture Design 1. override. 2013 procedure ColumnsToJSON(WR: TJSONWriter. in the '"\uFFF0base64encodedbinary" format and contains true BLOB data procedure ExecutePrepared. UseMormotCollations: boolean): integer. Execute a prepared SQL statement .parameters marked as ? will be bound later. Prepare an UTF-8 encoded SQL statement .if ExpectResults is TRUE. Append all columns values of the current Row to a JSON stream . ExpectResults: Boolean=false). override. created from the supplied TSQLTable content (a more optimized version may appear later) .Rev. Fetch a SynDB TQuery result into a VCL DataSet . it is recommended to use http://andy. created from the supplied TSQLTable content (a more optimized version may appear later) .Synopse mORMot Framework Software Architecture Design 1. will return up to the specified number of rows .de/blog/bugfix-units/midas-speed-fix-12 function StatementToDataSet(aOwner: TComponent.if aMaxRowCount>0.if aMaxRowCount>0.TQuery. aStatement: TSQLDBStatement. aMaxRowCount: integer=0): TDataSet.current implementation will return a TClientDataSet instance.for better speed with Delphi older than Delphi 2009 Update 3.jgknet.18 Date: June 16. 2013 23. licensed under a MPL/GPL/LGPL tri-license. aMaxRowCount: integer=0): TDataSet.18 325 SynDB Abstract database direct access classes .18 Page 570 of 1055 .pas unit .this unit is a part of the freeware Synopse framework. SynDBVCL. it is recommended to use http://andy. version 1.pas unit Purpose: DB VCL dataset using SynDB data access . 1.this unit is a part of the freeware Synopse mORMot framework. Fetch a SynDB TSQLDBStatement result into a VCL DataSet .de/blog/bugfix-units/midas-speed-fix-12 SynDBVCL. version 1.10.18 509 Functions or procedures implemented in the SynDBVCL unit: Functions or procedures Description Page QueryToDataSet Fetch a SynDB TQuery result into a VCL DataSet 570 StatementToDataSet Fetch a SynDB TSQLDBStatement result into a VCL DataSet 570 function QueryToDataSet(aOwner: TComponent. version 1. aStatement: SynDB.for better speed with Delphi older than Delphi 2009 Update 3.jgknet.current implementation will return a TClientDataSet instance. licensed under a MPL/GPL/LGPL tri-license. will return up to the specified number of rows .18 Units used in the SynDBVCL unit: Unit Name Description Page SynCommons Common functions used by most Synopse projects .this unit is a part of the freeware Synopse framework. licensed under a MPL/GPL/LGPL tri-license. 18 Page 571 of 1055 .x direct access classes for SynDB units (not DB.11.this unit is a part of the freeware Synopse mORMot framework. SynDBZEOS.18 Date: June 16.18 325 SynDB Abstract database direct access classes .pas based) .this unit is a part of the freeware Synopse framework.Synopse mORMot Framework Software Architecture Design 1.this unit is a part of the freeware Synopse framework. licensed under a MPL/GPL/LGPL tri-license. version 1. licensed under a MPL/GPL/LGPL tri-license.Rev. licensed under a MPL/GPL/LGPL tri-license. 2013 23.pas unit . version 1.pas unit Purpose: ZEOS 7. 1. version 1.18 Units used in the SynDBZEOS unit: Unit Name Description Page SynCommons Common functions used by most Synopse projects .18 509 ESQLDBException ESQLDBZEOS TSQLDBConnectionPropertiesThreadSafe TSQLDBZEOSConnectionProperties TSQLDBConnectionThreadSafe TSQLDBZEOSConnection TSQLDBStatementWithParamsAndColumns TSQLDBZEOSStatement SynDBZEOS class hierarchy Objects implemented in the SynDBZEOS unit: Objects Description Page ESQLDBZEOS Exception type associated to the ZEOS database components 571 TSQLDBZEOSConnection Implements a connection via the ZEOS access layer 573 TSQLDBZEOSConnectionP roperties Implement properties shared by ZEOS connections 571 TSQLDBZEOSStatement Implements a statement via a ZEOS database connection 573 ESQLDBZEOS = class(ESQLDBException) Exception type associated to the ZEOS database components TSQLDBZEOSConnectionProperties = class(TSQLDBConnectionPropertiesThreadSafe) Implement properties shared by ZEOS connections SynDBZEOS. var Fields: TSQLDBColumnDefineDynArray).0.URI(dFirebird.0://127. to be completed on the left side with the executable path . as retrieved by ZEOS .''. procedure GetFields(const aTableName: RawUTF8.dll'). aPassWord: RawUTF8). PropsFirebird := TSQLDBZEOSConnectionProperties.URI() class method .you can use Protocols property to retrieve all available protocol names destructor Destroy.e. aLibraryLocationAppendExePath: boolean=true): RawUTF8.'oci64\oci.Create( TSQLDBZEOSConnectionProperties. Initialize the properties to connect to the ZEOS engine .'user'. 2013 constructor Create(const aServerName.this overriden method will use ZDBC metadata to retrieve the information procedure GetTableNames(var Tables: TRawUTF8DynArray). aPassword are used if not already set as URI in aServerName value . override. 'databasefilename'.g: zdbc:firebird-2. Access to the database metadata.aDatabaseName.0.. Retrieve the column/field layout of a specified table . aUserID.you can set an optional full path to the client library name.'Firebird\fbembed. override. Get all table names .Rev.caller is responsible of freeing this instance . const aLibraryLocation: TFileName=''. Create a new connection . Compute the ZEOS URI from a given database engine . The remote DBMS name. ZEOS URL SynDBZEOS. aDatabaseName.18 Date: June 16.you can define the TZConnection.this overriden method will create an TSQLDBZEOSConnection instance class function URI(aServer: TSQLDBDefinition.URI(dOracle.possible use may be: PropsOracle := TSQLDBZEOSConnectionProperties.pas unit . i.or simple use TSQLDBZEOSConnectionProperties.Synopse mORMot Framework Software Architecture Design 1.1:3050/model?username=sysdba.aServerName shall contain the ZEOS URI. override.Create( TSQLDBZEOSConnectionProperties.returns TRUE if metadata interface has been retrieved function NewConnection: TSQLDBConnection. 1. as retrieved from ServerName.LibraryLocation property by setting a '?LibLocation=.18 Page 572 of 1055 . '[zdbc:]PROTOCOL://HOST:PORT[/DATABASE][?paramname=value]' .e.pass'). aUserID.this overriden method will use ZDBC metadata to retrieve the information property DBMSName: RawUTF8 read fDBMSName.dll').'). 'tnsname'.. override.' parameter within the aServerName URL value . override. e. Finalize properties internal structures function GetDatabaseMetadata(out meta: IZDatabaseMetadata): boolean.password=masterkey sqlite i. Return a Column as a blob value of the current Row. Discard changes of a Transaction for this connection .StartTransaction method must have been called before procedure Connect.should raise an ESQLDBZEOS on error procedure Rollback. Create a new statement instance procedure Commit. override. Connect to the specified ZEOS server . override. Access to the associated ZEOS connection instance TSQLDBZEOSStatement = class(TSQLDBStatementWithParamsAndColumns) Implements a statement via a ZEOS database connection function ColumnBlob(Col: Integer): RawByteString. override.Rev. Return a Column currency value of the current Row. Return a Column floating point value of the current Row. override. first Col is 0 function ColumnDateTime(Col: Integer): TDateTime. first Col is 0 SynDBZEOS. override. Begin a Transaction for this connection property Database: IZConnection read fDatabase. first Col is 0 function ColumnCurrency(Col: Integer): currency. Stop connection to the specified ZEOS database server .18 Date: June 16. override.Synopse mORMot Framework Software Architecture Design 1. Commit changes of a Transaction for this connection . override. first Col is 0 function ColumnInt(Col: Integer): Int64. first Col is 0 function ColumnDouble(Col: Integer): double. override.18 Page 573 of 1055 . Return a Column integer value of the current Row. 1. override. 2013 TSQLDBZEOSConnection = class(TSQLDBConnectionThreadSafe) Implements a connection via the ZEOS access layer constructor Create(aProperties: TSQLDBConnectionProperties). override.should raise an ESQLDBZEOS on error procedure Disconnect. Return a Column date and time value of the current Row.pas unit . Prepare a connection to a specified ZEOS database server function IsConnected: boolean.StartTransaction method must have been called before procedure StartTransaction. override. override. override. Return TRUE if Connect has been already successfully called function NewStatement: TSQLDBStatement. 18 Page 574 of 1055 . then Step() and Column*() methods are available to retrieve the data rows .18 Date: June 16. override.return true on success. overload.pas unit . Access the next or first row of data from the SQL Statement result . override. override.raise an ESQLDBZeos on any error procedure Prepare(const aSQL: RawUTF8. if the SQL statement is not a SELECT but an UPDATE or INSERT command) . with data ready to be retrieved by Column*() methods .Synopse mORMot Framework Software Architecture Design 1. before ExecutePrepared call .parameters marked as ? should have been already bound with Bind*() functions .this implementation will also loop through all internal bound array of values (if any).return false if no more row is available (e.raise an ESQLDBZeos on any error procedure ExecutePrepared. Returns TRUE if the column contains NULL function ColumnUTF8(Col: Integer): RawUTF8.if ExpectResults is TRUE. Execute a prepared SQL statement . 2013 function ColumnNull(Col: Integer): boolean.parameters marked as ? will be bound later. 1. To be called in order to populate the global ZEOSProtocols list Variables implemented in the SynDBZEOS unit: SynDBZEOS. override.raise an ESQLDBZeos on any error Functions or procedures implemented in the SynDBZEOS unit: Functions or procedures Description Page SetZEOSProtocols To be called in order to populate the global ZEOSProtocols list 574 procedure SetZEOSProtocols. override. to implement BATCH mode .Rev. first Col is 0 function Step(SeekFirst: boolean = false): boolean. ExpectResults: boolean = false).g. will put the cursor on the first row of results . override.raise an ESQLDBZeos on any error procedure Reset.this overriden implementation will reset all bindings and the cursor state . Return a Column UTF-8 encoded text value of the current Row. Prepare an UTF-8 encoded SQL statement . Reset the previous prepared statement .if SeekFirst is TRUE. as TSQLDBZEOSConnectionProperties.Synopse mORMot Framework Software Architecture Design 1.18 Page 575 of 1055 .to be used e. 1. to update this global list with all initialized ZPlain*Driver units .g. List of all available ZEOS protocols .pas unit . within ZEOS URI.ServerName SynDBZEOS.18 Date: June 16.Rev. 2013 ZEOSProtocols: TRawUTF8DynArray.you have to call SetZEOSProtocols before using it. 2013 23. licensed under a MPL/GPL/LGPL tri-license.GIF file extension 579 TJpegImage Sub class to handle .pas unit .PNG file extension 579 SynGdiPlus. PNG and JPG pictures read/write support as standard TGraphic .allows Antialiased rending of any EMF file using GDI+ .2 A reporting feature.3. with full preview and export as PDF or TXT files.pas unit Purpose: GDI+ library API access .18 Page 576 of 1055 .18 Date: June 16.12. version 1.make available most useful GDI+ drawing methods .this unit is a part of the freeware Synopse framework.JPG file extension 579 TPngImage Sub class to handle . shall be integrated 1054 TTiffImage TPngImage TGraphic TSynPicture TJpegImage TGifImage TObject TSynLibrary TGDIPlus TGDIPlusFull SynGdiPlus class hierarchy Objects implemented in the SynGdiPlus unit: Objects Description Page TGdipBitmapData Data as retrieved by GdipFull.Rev. SynGdiPlus.BitmapLockBits 577 TGDIPlus Handle picture related GDI+ library calls 577 TGDIPlusFull Handle most GDI+ library calls 579 TGdipPointF GDI+ floating point coordinates for a point 577 TGdipRect GDI+ integer coordinates rectangles 577 TGdipRectF GDI+ floating point coordinates rectangles 577 TGifImage Sub class to handle .adds GIF. 1.18 The SynGdiPlus unit is quoted in the following items: SWRS # Description Page DI-2. TIF.Synopse mORMot Framework Software Architecture Design 1. 18 Page 577 of 1055 . Unload the GDI+ library SynGdiPlus.pas unit .Rev.BitmapLockBits TSynLibrary = class(TObject) An object wrapper to load dynamically a library function Exists: boolean. TIFF and JPG pictures support using GDI+ library 578 TTiffImage Sub class to handle . reintroduce.returns TRUE on success .2 (page 1054). override. but GDI + functions (e.3. therefore the executable is able to launch before Windows XP. 2013 Objects Description Page TSynLibrary An object wrapper to load dynamically a library 577 TSynPicture GIF. GIF. PNG.use width and height instead of right and bottom TGdipPointF = packed record GDI+ floating point coordinates for a point TGdipBitmapData = packed record Data as retrieved by GdipFull.Synopse mORMot Framework Software Architecture Design 1. Return TRUE if the library and all procedures were found TGDIPlus = class(TSynLibrary) Handle picture related GDI+ library calls Used for DI-2. PNG.TIF file extension 579 TGdipRect = packed record GDI+ integer coordinates rectangles . TIFF and JPG pictures support) won't be available in such case destructor Destroy.library is loaded dynamically.g. 1.use width and height instead of right and bottom TGdipRectF = packed record GDI+ floating point coordinates rectangles . constructor Create(const aDllFileName: TFileName). Load the GDI+ library and all needed procedures .18 Date: June 16. microsoft.85).g.jpeg . 100 means 100%. CompressionQuality: integer=80. will use ord(evCompressionLZW) to save the TIFF picture with LZW . only valid values are ord(evCompressionLZW). ord(evCompressionCCITT4).cf @http://msdn.you can specify a zoom factor by the ScaleX and ScaleY parameters in percent: e.return gptBMP if no format is found class function IsPicture(const FileName: TFileName): TGraphicClass.18 Date: June 16. aTextRendering: TTextRenderingHint=trhClearTypeGridFit): TBitmap. ord(evCompressionCCITT3). procedure RegisterPictures.tif .e.aspx for all available image formats function GetImageFormat: TGDIPPictureType. for gptTIF format.18 Page 578 of 1055 . ScaleX: integer=100. R: TRect.3.CompressionQuality is used for gptJPG format saving and is expected to be from 0 to 100. TIFF and JPG pictures support using GDI+ library .3.use a TGDIPlusFull instance for true GDI+ AntiAliaised drawing . aSmoothing: TSmoothingMode=smAntiAlias.com/en-us/library/ms536393(VS.png . Draw the corresponding EMF metafile into a given device context .if any side of the picture is bigger than the specified pixel number. Save the picture into any GIF/PNG/JPG/TIFF format . overload. PNG.jpg . 2013 function DrawAntiAliased(Source: TMetafile. Calculate a TRect which fit the specified maximum pixel number .2 (page 1054).Rev. Guess the picture type from its internal format . ScaleY: integer=100. by default. overload. Registers the . 1. no scaling Used for DI-2.you can just launch Gdip.TPicture can now load such files . ord(evCompressionRle) and ord(evCompressionNone) SynGdiPlus. the TRect is sized down in order than the biggest size if this value function SaveAs(Stream: TStream. i. use ord(TGDIPPEncoderValue) to define the parameter.gif . Return TRUE if the supplied filename is a picture handled by TSynPicture function RectNotBiggerThan(MaxPixelsForBiggestSide: Integer): TRect. Format: TGDIPPictureType.this default implementation uses GDI drawing only .2 (page 1054). procedure DrawAntiAliased(Source: TMetafile.for gptTIF. IfBitmapSetResolution: single=0): TGdipStatus.RegisterPictures to initialize the GDI+ library TSynPicture = class(TGraphic) GIF. Dest: HDC. Draw the corresponding EMF metafile into a bitmap created by the method .Synopse mORMot Framework Software Architecture Design 1.tiff file extensions to the program . aTextRendering: TTextRenderingHint=trhClearTypeGridFit).use TGDIPlusFull overriden method for true GDI+ AntiAliaised drawing Used for DI-2. aSmoothing: TSmoothingMode=smAntiAlias. virtual.this default TGDIPlus implementation uses GDI drawing only .pas unit . set to 80 by default TGifImage = class(TSynPicture) Sub class to handle .Synopse mORMot Framework Software Architecture Design 1.an instance of this object is initialized by this unit: you don't have to create a new instance SynGdiPlus. Implements the saving feature property CompressionQuality: integer read fCompressionQuality write fCompressionQuality. 1. Return the GDI+ native image handle TPngImage = class(TSynPicture) Sub class to handle .18 Page 579 of 1055 .GDI+ seems not able to load all Tiff file formats.GIF file extension TTiffImage = class(TSynPicture) Sub class to handle . 2013 function ToBitmap: TBitmap. wBMP: TBitmap).pas unit . Multi-page . Extract a page from the TIFF and assign it to a bitmap property ActivePageIndex: integer read fActivePage write SelectPage. Retrieve the number of pages in the TIFF file procedure ExtractPage(index: integer.18 Date: June 16. depending on the Windows version and third-party libraries installed .TIF file extension . The associated encoding quality (from 0 to 100) . override.Rev.this overriden class implements multiple pages function GetPageCount:integer.PNG file extension TJpegImage = class(TSynPicture) Sub class to handle .JPG file extension procedure SaveToStream(Stream: TStream). Create a bitmap from the corresponding picture property NativeImage: THandle read fImage.default Frame/Page Index is 0 TGDIPlusFull = class(TGDIPlus) Handle most GDI+ library calls . GDI+ metafile) . Return true if DrawAntiAliased() method will use native GDI+ conversion. with DrawImageRect) by DisposeImage() function MetaFileToStream(Source: TMetafile. aTextRendering: TTextRenderingHint=trhClearTypeGridFit). GIF. it will search the system for the most recent version of GDI+ (either GDIPLUS. 1.Synopse mORMot Framework Software Architecture Design 1.returns TRUE on success .1 is available only since Vista and Seven.18 Date: June 16. but will handle UniScribe positioning and associated font fallback . but GDI + functions (e. aSmoothing: TSmoothingMode=smAntiAlias.g. R: TRect.if no GdiPlus.i. and enabled only for chars >= $600 .less accurate for individual character positioning (e.pas unit .g. either the OS version . out hGlobal: THandle): IStream. Dest: HDC. aTextRendering: TTextRenderingHint=trhClearTypeGridFit): THandle. 2013 constructor Create(aDllFileName: TFileName='').1 conversion. for underlined fonts or font fallback .e. either the Office 2003 version. override.1 method does not handle font fallback.1) function ConvertToEmfPlus(Source: TMetafile. Dest: HDC.return a metafile handle.this overriden implementation handles GDI+ AntiAliased drawing . TIFF and JPG pictures support or AntiAliased drawing) won't be available . return 0 . Can be set to true if to force DrawAntiAliased() method NOT to use native GDI+ 1.programs can set this property to true to avoid using GDI+ 1. so our internal conversion is more accurate thanks to this parameter property NativeConvertToEmfPlus: boolean read getNativeConvertToEmfPlus. Load the GDI+ library and all needed procedures .library is loaded dynamically. therefore the executable is able to launch before Windows XP. PNG. text will be rendered using DrawString and not DrawDriverString if the content has some chars non within 0000-05ff Unicode BMP range . it will use default GDI32 function property ForceInternalConvertToEmfPlus: boolean read fForceInternalConvertToEmfPlus write fForceInternalConvertToEmfPlus.e. justification). if GDI+ installed version is 1.1 Types implemented in the SynGdiPlus unit: TEmfType = SynGdiPlus.g. e. XP only shipped with version 1.we found out that GDI+ 1.if GDI+ is not available.Rev. i.1 property ForceUseDrawString: boolean read fUseDrawString write fUseDrawString. Draw the corresponding EMF metafile into a given device context .18 Page 580 of 1055 .dll file name is available.DLL in the current directory. Internal method used for GDI32 metafile loading procedure DrawAntiAliased(Source: TMetafile. to be released after use (e.e.1. even if available .g.1 was not as good as our internal conversion function written in Delphi.note that the GdipConvertToEmfPlus() GDI+ 1.if GDI+ is not available or conversion failed. Convert a supplied EMF metafile into a EMF+ (i. aSmoothing: TSmoothingMode=smAntiAlias. allows antialiased drawing of the EMF metafile . If TRUE.is disable by default. GDI+ text rendering smoothing types TUnit = ( uWorld. evCompressionCCITT4. The corresponding file extension for every saving format type SynGdiPlus. evTransformFlipVertical. smNone.use e. stUnknownImageFormat. trhAntiAlias. evCompressionRle.Rev. uGdi ). GDI+ available coordinates units Constants implemented in the SynGdiPlus unit: GDIPPictureExt: array [TGDIPPictureType] of TFileName = ('. etEmfPlusDual ). stPropertyNotSupported ). GDI+ types of conversion from EMF to EMF+ TFillMode = ( fmAlternate. stWrongState. gptTIF ). evRenderProgressive. stOutOfMemory. smHighQuality.bmp'. evCompressionLZW. evTransformRotate180.tif'). lmUserInputBuf ). etEmfOnly. stNotImplemented.'.18 Page 581 of 1055 . gptPNG. GDI+ lock mode settings for GdipFull. GDI+ floating point coordinates for an array of points TGdipStatus = ( stOk. evFrameDimensionResolution. Allowed types for image saving TGdipPointFArray = array[0. evVersionGif89. 2013 ( etEmf0. stUnsupportedGdiplusVersion. GDI+ line drawing smoothing types TTextRenderingHint = ( trhDefault. evLastFrame. stGenericError. evRenderNonProgressive. trhSingleBitPerPixel. stGdiplusNotInitialized. ord(evCompressionCCITT4) to save a TIFF picture as CCITT4 TGDIPPictureType = ( gptGIF. evScanMethodNonInterlaced. evVersionGif87. lmWrite. uInch. stFontStyleNotFound. evColorTypeYCCK.BitmapLockBits TSmoothingMode = ( smDefault. The optional TIFF compression levels . uDisplay. etEmf1. gptBMP. fmWinding ).gif'. GDI+ available filling modes TGDIPPEncoderValue = ( evColorTypeCMYK. 1. stInsufficientBuffer. evTransformFlipHorizontal.1000] of TGdipPointF. evFlush. stAborted. uDocument. evMultiFrame. evTransformRotate270.Synopse mORMot Framework Software Architecture Design 1. stWin32Error. smHighSpeed. trhClearTypeGridFit ). trhSingleBitPerPixelGridFit.png'.BitmapLockBits TLockModeOptions = set of TLockModeOption. stNotTrueTypeFont. uPixel.pas unit . smAntiAlias ). stAccessDenied. evFrameDimensionTime. stObjectBusy. uPoint.g. stInvalidParameter. stFileNotFound. evScanMethodInterlaced.18 Date: June 16. stPropertyNotFound. gptJPG. GDI+ error codes TLockModeOption = ( lmRead. evCompressionCCITT3. etEmfPlusOnly. evCompressionNone. uMillimeter. evFrameDimensionPage ).'. etEmf2.jpg'.. evTransformRotate90. stValueOverflow. GDI+ lock mode for GdipFull.'. stFontFamilyNotFound. trhAntiAliasGridFit.'. ForceInternalAntiAliasedFontFallBack: boolean=false). 1.by default.the file is drawn with a special antialiased GDI+ drawing method (if the global Gdip var is a TGDIPlusFull instance) function LoadFromRawByteString(const Picture: AnsiString): TBitmap.pas unit .if file extension if . no font fall-back is implemented (for characters not included within the font glyphs).ForceUseDrawString property) procedure GdipTest(const JpegFile: TFileName).EMF. Draw the specified GDI TMetaFile (emf) using the GDI-plus antialiaised engine . overload. the file is drawn with a special antialiased GDI+ drawing method (if the global Gdip var is a TGDIPlusFull instance) function LoadFrom(const MetaFile: TMetaFile): TBitmap.Rev. Helper function to create a bitmap from any EMF content . Test function function LoadFrom(const FileName: TFileName): TBitmap. overload. Source: TMetaFile. 2013 Functions or procedures implemented in the SynGdiPlus unit: Functions or procedures Description Page DrawEmfGdip Draw the specified GDI TMetaFile (emf) using the GDI-plus antialiaised engine 582 GdipTest Test function 582 LoadFrom Helper function to create a bitmap from any EMF content 582 LoadFrom Helper function to create a bitmap from any GIF/PNG/JPG/TIFF/EMF/WMF file 582 LoadFromRawByteString Helper to load a specified graphic from GIF/PNG/JPG/TIFF format content 582 PictureName Retrieve a ready to be displayed name of the supplied Graphic Class 582 SaveAs Helper to save a specified graphic into GIF/PNG/JPG/TIFF format 583 SaveAs Helper to save a specified graphic into GIF/PNG/JPG/TIFF format 583 SaveAsRawByteString Helper to save a specified graphic into GIF/PNG/JPG/TIFF format 583 procedure DrawEmfGdip(aHDC: HDC.18 Date: June 16.18 Page 582 of 1055 . Retrieve a ready to be displayed name of the supplied Graphic Class SynGdiPlus. Helper function to create a bitmap from any GIF/PNG/JPG/TIFF/EMF/WMF file .Synopse mORMot Framework Software Architecture Design 1. Helper to load a specified graphic from GIF/PNG/JPG/TIFF format content function PictureName(Pic: TGraphicClass): string. var R: TRect. ForceInternalAntiAliased: boolean. but you may force it via the corresponding parameter (used to set the TGDIPlusFull. MaxPixelsForBiggestSide: cardinal=0.if MaxPixelsForBiggestSide is set to something else than 0. Helper to save a specified graphic into GIF/PNG/JPG/TIFF format .if MaxPixelsForBiggestSide is set to something else than 0.g.CompressionQuality is only used for gptJPG format saving and is expected to be from 0 to 100 . overload. on Windows 2000) nor the current executable folder SynGdiPlus.Gdip. BitmapSetResolution: single=0). the resulting picture biggest side won't exceed this pixel number procedure SaveAsRawByteString(Graphic: TPersistent. const FileName: TFileName. the resulting picture biggest side won't exceed this pixel number procedure SaveAs(Graphic: TPersistent. out Data: AnsiString. 1. 2013 procedure SaveAs(Graphic: TPersistent. Helper to save a specified graphic into GIF/PNG/JPG/TIFF format . Format: TGDIPPictureType.if MaxPixelsForBiggestSide is set to something else than 0. GDI+ library instance . MaxPixelsForBiggestSide: cardinal=0.Exists return FALSE if the GDI+ library is not available in this operating system (e. CompressionQuality: integer=80.pas unit .Synopse mORMot Framework Software Architecture Design 1.CompressionQuality is only used for gptJPG format saving and is expected to be from 0 to 100 .18 Page 583 of 1055 .Rev.only initialized at program startup if the NOTSYNPICTUREREGISTER is NOT defined (which is not the default) . Stream: TStream. Format: TGDIPPictureType. the resulting picture biggest side won't exceed this pixel number Variables implemented in the SynGdiPlus unit: Gdip: TGDIPlus = nil. overload.CompressionQuality is only used for gptJPG format saving and is expected to be from 0 to 100 . BitmapSetResolution: single=0). CompressionQuality: integer=80. CompressionQuality: integer=80.18 Date: June 16. Helper to save a specified graphic into GIF/PNG/JPG/TIFF format . Format: TGDIPPictureType. BitmapSetResolution: single=0). MaxPixelsForBiggestSide: cardinal=0. ) 585 function CompressSynLZ(var Data: RawByteString. but slower 585 SynLZdecompressdestle n Get uncompressed size from lz-compressed buffer (to reserve memory.Rev. will instantly return '' function SynLZcompress1asm(src: PAnsiChar.pas unit Purpose: SynLZ Compression routines .18 Types implemented in the SynLZ unit: RawByteString = AnsiString. Define RawByteString.will store a hash of both compressed and uncompressed stream: if the data is corrupted during transmission. 1. but slower 585 SynLZcompressdestlen Get maximum possible (worse) compressed size for out_p 585 SynLZdecompress1asm Optimized asm version of the 1st compression method 585 SynLZdecompress1parti al 1st compression method uses hashing with a 32bits control word 585 SynLZdecompress1pas 1st compression method uses hashing with a 32bits control word 585 SynLZdecompress2 2nd compression method optimizes pattern copy -> a bit smaller. dst: PAnsiChar): integer. version 1.licensed under a MPL/GPL/LGPL tri-license. dst: PAnsiChar): integer. 2013 23. Optimized asm version of the 1st compression method function SynLZcompress1pas(src: PAnsiChar. as it does exist in Delphi 2009 and up .pas unit .will return 'synlz' as ACCEPT-ENCODING: header parameter .Synopse mORMot Framework Software Architecture Design 1. e.18 Date: June 16. SynLZ.13. 1st compression method uses hashing with a 32bits control word SynLZ. size: integer.as expected by THttpSocket.to be used for byte storage into an AnsiString Functions or procedures implemented in the SynLZ unit: Functions or procedures Description Page CompressSynLZ Compress a data content using the SynLZ algorithm 584 SynLZcompress1asm Optimized asm version of the 1st compression method 584 SynLZcompress1pas 1st compression method uses hashing with a 32bits control word 584 SynLZcompress2 2nd compression method optimizes pattern copy -> a bit smaller.RegisterCompress .18 Page 584 of 1055 . size: integer. Compress a data content using the SynLZ algorithm .g. Compress: boolean): RawByteString. Synopse mORMot Framework Software Architecture Design 1. so will be more secure than other functions.this is the fastest pure pascal method function SynLZdecompress2(src: PAnsiChar. which expect the content to be verified (e. Optimized asm version of the 1st compression method function SynLZdecompress1partial(src: PAnsiChar.) SynLZ.this overload function is slower. size: integer. 2013 function SynLZcompress2(src: PAnsiChar. size: integer. 1. size: integer. dst: PAnsiChar): integer.g. dst: PAnsiChar. 2nd compression method optimizes pattern copy -> a bit smaller. e. dst: PAnsiChar): Integer. size: integer.18 Date: June 16. via CRC) function SynLZdecompress1pas(src: PAnsiChar. but slower function SynLZdecompressdestlen(in_p: PAnsiChar): integer. 2nd compression method optimizes pattern copy -> a bit smaller. dst: PAnsiChar): Integer. dst: PAnsiChar): Integer.g. Get uncompressed size from lz-compressed buffer (to reserve memory. size: integer. Get maximum possible (worse) compressed size for out_p function SynLZdecompress1asm(src: PAnsiChar.18 Page 585 of 1055 .Rev. but will allow to uncompress only the start of the content (e. maxDst: Integer): Integer. 1st compression method uses hashing with a 32bits control word . to read some metadata header) .g. 1st compression method uses hashing with a 32bits control word .pas unit .it will also check for dst buffer overflow. but slower function SynLZcompressdestlen(in_len: integer): integer. will instantly return '' function lzopas_compress(in_p: PAnsiChar.18 Page 586 of 1055 . returns out_len 586 lzopas_decompressdest len Get uncompressed size from lzo-compressed buffer (to reserve memory.g. version 1.) 586 function CompressSynLZO(var Data: AnsiString.will store a hash of both compressed and uncompressed stream: if the data is corrupted during transmission. 1. (de)compress a data content using the SynLZO algorithm .14. e.Synopse mORMot Framework Software Architecture Design 1.Rev.g.returns compressed size in out_p function lzopas_compressdestlen(in_len: integer): integer. Compress: boolean): AnsiString.pas unit Purpose: Fast LZO Compression routines .will return 'synlzo' as ACCEPT-ENCODING: header parameter . out_p: PAnsiChar): integer. Compress in_p(in_len) into out_p .may write up to out_len+3 bytes in out_p . SynLZO.licensed under a MPL/GPL/LGPL tri-license. 2013 23.pas unit .the decompression mode is "fast-unsafe" -> CRC/Adler32 in_p data before call function lzopas_decompressdestlen(in_p: PAnsiChar): integer. in_len: integer. out_p: PAnsiChar): Integer.as expected by THttpSocket. e.out_p must be at least lzopas_compressdestlen(in_len) bytes long . Get maximum possible (worse) compressed size for out_p function lzopas_decompress(in_p: PAnsiChar.) SynLZO.RegisterCompress . Get uncompressed size from lzo-compressed buffer (to reserve memory.13 Functions or procedures implemented in the SynLZO unit: Functions or procedures Description Page CompressSynLZO (de)compress a data content using the SynLZO algorithm 586 lzopas_compress Compress in_p(in_len) into out_p 586 lzopas_compressdestle n Get maximum possible (worse) compressed size for out_p 586 lzopas_decompress Uncompress in_p(in_len) into out_p (must be allocated before call). in_len: integer. Uncompress in_p(in_len) into out_p (must be allocated before call).18 Date: June 16. returns out_len . licensed under a MPL/GPL/LGPL tri-license.18 Page Page 587 of 1055 . SynOleDB.15.18 509 ESQLDBException EOleDBException ITransactionOptions ITransaction ITransactionLocal IRowset IErrorRecords IDBSchemaRowset IDBPromptInitialize IUnknown IDBInitialize IDBCreateSession IDBCreateCommand IDataInitialize ICommand ICommandText IColumnsInfo TOleDBOracleConnectionProperties IAccessor TOleDBODBCSQLConnectionProperties TOleDBMSOracleConnectionProperties TOleDBMySQLConnectionProperties TSQLDBConnectionPropertiesThreadSafe TOleDBConnectionProperties TOleDBMSSQL2012ConnectionProperties TOleDBMSSQLConnectionProperties TSQLDBConnectionThreadSafe TOleDBConnection TOleDBMSSQL2005ConnectionProperties TOleDBJetConnectionProperties TSQLDBStatement TOleDBStatement TOleDBAS400ConnectionProperties SynOleDB class hierarchy Objects implemented in the SynOleDB unit: Objects Description SynOleDB.18 Units used in the SynOleDB unit: Unit Name Description Page SynCommons Common functions used by most Synopse projects . version 1.pas unit Purpose: Fast OleDB direct access classes .pas unit .this unit is a part of the freeware Synopse mORMot framework.18 325 SynDB Abstract database direct access classes .this unit is a part of the freeware Synopse framework. version 1. licensed under a MPL/GPL/LGPL tri-license.this unit is a part of the freeware Synopse framework.Synopse mORMot Framework Software Architecture Design 1. 2013 23.18 Date: June 16. 1. licensed under a MPL/GPL/LGPL tri-license.Rev. version 1. commit. and abort transactions on the session 589 ITransactionOptions Gets and sets a suite of options associated with an OleDB transaction 589 TOleDBAS400Connection Properties OleDB connection properties to IBM AS/400 592 TOleDBConnection Implements an OleDB connection 593 TOleDBConnectionPrope rties Will implement properties shared by OleDB connections 590 TOleDBJetConnectionPr operties OleDB connection properties to Jet/MSAccess . generated for OleDB connection 590 IAccessor Provides methods for accessor management. via SQL Server Native Client 11. via SQL Server Native Client (SQL Server 2005) 592 TOleDBMSSQL2012Connec tionProperties OleDB connection properties to Microsoft SQL Server 2012.18 Date: June 16.pas unit . tables and fields layout) 590 IErrorRecords Interface used to retrieve enhanced custom error information 590 IRowset Provides methods for fetching rows sequentially.mdb files 592 TOleDBMSOracleConnect ionProperties OleDB connection properties to an Oracle database using Microsoft's Provider 591 TOleDBMSSQL2005Connec tionProperties OleDB connection properties to Microsoft SQL Server 2005.18 Page 588 of 1055 . via SQL Server Native Client 10. getting the data from those rows. and managing rows 589 ITransaction Commit.0 (SQL Server 2012) 592 TOleDBMSSQLConnection Properties OleDB connection properties to Microsoft SQL Server 2008-2012. to access OleDB data 590 IColumnsInfo Expose information about columns of an OleDB rowset or prepared command 590 ICommand Provide methods to execute commands 589 ICommandText Methods to access the ICommand text to be executed 589 IDataInitialize Create an OleDB data source object using a connection string 589 IDBCreateCommand Used on an OleDB session to obtain a new command 590 IDBCreateSession Obtain a new session to a given OleDB data source 589 IDBInitialize Initialize and uninitialize OleDB data source objects and enumerators 589 IDBPromptInitialize Allows the display of the data link dialog boxes programmatically 590 IDBSchemaRowset Used to retrieve the database metadata (e. used to start.g. and obtain status information about OleDB transactions 589 ITransactionLocal Optional interface on OleDB sessions. 2013 Objects Description Page EOleDBException Generic Exception type.Rev. abort.0 (SQL Server 2008) 592 SynOleDB.Synopse mORMot Framework Software Architecture Design 1. 1. and obtain status information about OleDB transactions ITransactionOptions = interface(IUnknown) Gets and sets a suite of options associated with an OleDB transaction ITransactionLocal = interface(ITransaction) Optional interface on OleDB sessions. 2013 Objects Description Page TOleDBMySQLConnection Properties OleDB connection properties to MySQL Server 592 TOleDBODBCSQLConnecti onProperties OleDB connection properties via Microsoft Provider for ODBC 592 TOleDBOracleConnectio nProperties OleDB connection properties to an Oracle database using Oracle's Provider 591 TOleDBStatement Implements an OleDB SQL query statement 594 TOleDBStatementParam Used to store properties and value about one TOleDBStatement Param 594 IDBInitialize = interface(IUnknown) Initialize and uninitialize OleDB data source objects and enumerators IDataInitialize = interface(IUnknown) Create an OleDB data source object using a connection string IDBCreateSession = interface(IUnknown) Obtain a new session to a given OleDB data source ITransaction = interface(IUnknown) Commit. stdcall.18 Date: June 16.pas unit . 1. Adds a reference count to an existing row handle function GetData(HROW: HROW. rgRefCounts: PCardinalArray. commit.18 Page 589 of 1055 . HACCESSOR: HACCESSOR. and managing rows function AddRefRows(cRows: UINT. pData: Pointer): HResult. used to start. getting the data from those rows. rgRowStatus: PCardinalArray): HResult. stdcall. Retrieves data from the rowset's copy of the row SynOleDB. rghRows: PCardinalArray.Rev. and abort transactions on the session ICommand = interface(IUnknown) Provide methods to execute commands ICommandText = interface(ICommand) Methods to access the ICommand text to be executed IRowset = interface(IUnknown) Provides methods for fetching rows sequentially. abort.Synopse mORMot Framework Software Architecture Design 1. 2013 function GetNextRows(hReserved: HCHAPTER.Rev.Parent is an optional GDI Window Handle for modal display SynOleDB. .For each column in a row (or parameter in a set of parameters). stdcall.18 Date: June 16. lRowsOffset: Integer. IColumnsInfo = interface(IUnknown) Expose information about columns of an OleDB rowset or prepared command IDBPromptInitialize = interface(IUnknown) Allows the display of the data link dialog boxes programmatically IDBSchemaRowset = interface(IUnknown) Used to retrieve the database metadata (e. Releases rows function RestartPosition(hReserved: HCHAPTER): HResult. Display the OleDB/ADO Connection Settings dialog to customize the OleDB connection string .An accessor is a data structure created by the consumer that describes how row or parameter data from the data store is to be laid out in the consumer's data buffer.pas unit . var prghRows: pointer): HResult.g. the accessor contains a binding.this method has been modified from original OleDB. A binding is a DBBinding data structure that holds information about a column or parameter value. stdcall. data type. such as its ordinal value. generated for OleDB connection TOleDBConnectionProperties = class(TSQLDBConnectionPropertiesThreadSafe) Will implement properties shared by OleDB connections function ConnectionStringDialogExecute(Parent: HWND=0): boolean.pas to allow direct typecast of prghRows parameter to pointer(fRowStepHandles) function ReleaseRows(cRows: UINT.returns TRUE if the connection string has been modified . to access OleDB data . rgRefCounts. rgRowOptions. Repositions the next fetch position to its initial position . out pcRowsObtained: UINT. Fetches rows sequentially. stdcall. remembering the previous position . and destination in the consumer's buffer. cRows: Integer. tables and fields layout) EOleDBException = class(ESQLDBException) Generic Exception type. its position when the rowset was first created IErrorRecords = interface(IUnknown) Interface used to retrieve enhanced custom error information IDBCreateCommand = interface(IUnknown) Used on an OleDB session to obtain a new command IAccessor = interface(IUnknown) Provides methods for accessor management. rgRowStatus: PCardinalArray): HResult.18 Page 590 of 1055 .that is. 1. rghRows: PCardinalArray.Synopse mORMot Framework Software Architecture Design 1. Get all table names . Retrieve the column/field layout of a specified table . var Fields: TSQLDBColumnDefineDynArray).is set by the Create() constructor most of the time from the supplied server name.oracle.will retrieve the corresponding metadata from OleDB interfaces if SQL direct access was not defined procedure GetTableNames(var Tables: TRawUTF8DynArray).pas unit . 1.this will use the native OleDB provider supplied by Oracle see @http://download. Custom Error handler for OleDB COM objects .call this method if the shared MainConnection is not enough (e.default implementation just returns false property ProviderName: RawUTF8 read fProviderName. The associated OleDB provider name.this will use the generic (older) OleDB provider supplied by Microsoft which would not be used any more: "This feature will be removed in a future version of Windows. user id and password.you may want to customize it via the ConnectionStringDialogExecute method. override. Create a new connection .aspx SynOleDB. according to the database provider corresponding to the class .18 Page 591 of 1055 . and plan to modify applications that currently use this feature.this overriden method will create an TOleDBConnection instance procedure GetFields(const aTableName: RawUTF8. use Oracle’s OLE DB provider. Instead. Avoid using this feature in new development work.18 Date: June 16.will retrieve the corresponding metadata from OleDB interfaces if SQL direct access was not defined property ConnectionString: SynUnicode read fConnectionString write fConnectionString.microsoft.Synopse mORMot Framework Software Architecture Design 1.returns TRUE if specific error was retrieved and has updated ErrorMessage and InfoMessage .the caller is responsible of freeing this instance ." see http://msdn.htm TOleDBMSOracleConnectionProperties = class(TOleDBOracleConnectionProperties) OleDB connection properties to an Oracle database using Microsoft's Provider . or to provide some additional parameters property OnCustomError: TOleDBOnCustomError read fOnCustomError write fOnCustomError. as set for each class TOleDBOracleConnectionProperties = class(TOleDBConnectionProperties) OleDB connection properties to an Oracle database using Oracle's Provider .com/en-us/library/ms675851(v=VS.g.Rev. override. The associated OleDB connection string . override. 2013 function NewConnection: TSQLDBConnection. for multi-thread access) .com/docs/cd/E11882_01/win.85).112/e17726/toc. will fall back to SQLNCLI10 . 1. use the inherited class TOleDBMSSQL2012ConnectionProperties.85).18 Page 592 of 1055 .85).you should better use direct connection classes.mdb files . via SQL Server Native Client 11.this will use the ODBC provider supplied by Microsoft see http://msdn. e.microsoft. or set your own provider string TOleDBMSSQL2005ConnectionProperties = class(TOleDBMSSQLConnectionProperties) OleDB connection properties to Microsoft SQL Server 2005. if you want all features.0 (SQL Server 2012) . via SQL Server Native Client 10.aspx . Initialize the properties . you need to connect to a old MS SQL Server 2005. aPassWord: RawUTF8).0 (SQL Server 2008) . aDatabaseName. aServerName.an ODBC Driver should be specified at creation .com/en-us/library/ms677227(v=VS.pas unit .com/en-us/library/ms131291.will use the SQLNCLI10 provider.g. it will use Windows Integrated Security for the connection TOleDBMSSQL2012ConnectionProperties = class(TOleDBMSSQLConnectionProperties) OleDB connection properties to Microsoft SQL Server 2012.Rev.this overriden version will use newer SQLNCLI11 provider.18 Date: June 16. it will use Windows Integrated Security for the connection .is aUserID='' at Create.is aUserID='' at Create.aspx .in this case. 2013 TOleDBMSSQLConnectionProperties = class(TOleDBConnectionProperties) OleDB connection properties to Microsoft SQL Server 2008-2012. adding '{ DSN=name | FileDSN=filename }. like TOleDBMSSQLConnectionProperties or TOleDBOracleConnectionProperties constructor Create(const aDriver.is aUserID='' at Create.see http://msdn.an additional parameter is available to set the ODBC driver to use .aspx .this overriden version will use deprecated SQLNCLI provider.microsoft.Synopse mORMot Framework Software Architecture Design 1. but won't work under Windows XP . it will use Windows Integrated Security for the connection TOleDBMySQLConnectionProperties = class(TOleDBConnectionProperties) OleDB connection properties to MySQL Server TOleDBJetConnectionProperties = class(TOleDBConnectionProperties) OleDB connection properties to Jet/MSAccess .note that the Jet OleDB driver is not available under Win64 platform TOleDBAS400ConnectionProperties = class(TOleDBConnectionProperties) OleDB connection properties to IBM AS/400 TOleDBODBCSQLConnectionProperties = class(TOleDBConnectionProperties) OleDB connection properties via Microsoft Provider for ODBC .com/en-us/library/ms675326(v=VS.' SynOleDB. on the other hand. use TOleDBMSSQL2005ConnectionProperties. especially under MS SQL 2012. via SQL Server Native Client (SQL Server 2005) .mdb file name .this will use the native OleDB provider supplied by Microsoft see http://msdn. if. reintroduce.you may also set aDriver='' and modify the connection string directly.the server name should be the .microsoft. but will with MS SQL Server 2005 . which will work on Windows XP. aUserID. override. override. Commit changes of a Transaction for this connection . override.com/en-us/library/ms716985(v=vs.should raise an EOleDBException on error procedure Disconnect. override. Internal information message.18 Page 593 of 1055 . as retrieved from the OleDB provider property OleDBProperties: TOleDBConnectionProperties read fOleDBProperties. 1.aspx property OleDBErrorMessage: string read fOleDBErrorMessage.18 Date: June 16.StartTransaction method must have been called before procedure StartTransaction. Initialize a new SQL query statement for the given connection . as retrieved from the OleDB provider property OleDBInfoMessage: string read fOleDBInfoMessage. override.be aware that not all OleDB provider support nested transactions see http://msdn. Discard changes of a Transaction for this connection . shared among connections constructor Create(aProperties: TSQLDBConnectionProperties).will retrieve the remote DataBase behavior from a supplied TSQLDBConnectionProperties class. Return TRUE if Connect has been already successfully called function NewStatement: TSQLDBStatement. 2013 property Driver: RawUTF8 read fDriver.the caller should free the instance after use procedure Commit.Rev.pas unit . Stop connection to the specified database .StartTransaction method must have been called before procedure Connect. override. override. Connect to a specified OleDB database destructor Destroy. Connect to the specified database . The associated ODBC Driver name. Internal error message. Release all associated memory and OleDB COM objects function IsConnected: boolean.should raise an EOleDBException on error procedure Rollback. The associated OleDB database properties SynOleDB. Begin a Transaction for this connection .Synopse mORMot Framework Software Architecture Design 1. override. override.85). as specified at creation TOleDBConnection = class(TSQLDBConnectionThreadSafe) Implements an OleDB connection .microsoft. 2013 TOleDBStatementParam = packed record Used to store properties and value about one TOleDBStatement Param .SizeOf(Int64)-1] of byte.e. override. Storage used for ftInt64. using DBTYPE_WSTR value (i.pas unit . 'Requested conversion is not supported'): we found out that only DBTYPE_BSTR type (i.e.whole memory block of a TOleDBStatementParamDynArray will be used as the source Data for the OleDB parameters . Storage used for BLOB (ftBlob) values . will raise an exception destructor Destroy.if the supplied connection is not of TOleDBConnection type.we don't use a Variant.18 Page 594 of 1055 .Rev.e..so let it be VType: TSQLDBFieldType.the Execute method can be called only once per TOleDBStatement instance .Synopse mORMot Framework Software Architecture Design 1. AFAIK). paramInOut] . but manual storage for better performance .18 Date: June 16.we store TEXT here as WideString.. OLE WideString) does work. what the doc. Storage used for TEXT (ftUTF8) values . 1. The column/parameter Value type TOleDBStatement = class(TSQLDBStatement) Implements an OleDB SQL query statement .will be refered as DBTYPE_BYREF when sent as OleDB parameters. override. so we'll use it here! Shame on Microsoft! . says) will raise an OLEDB Error 80040E1D (DB_E_UNSUPPORTEDCONVERSION. ftDate and ftCurrency value VText: WideString.so we should align data carefully VBlob: RawByteString. i. to avoid unnecessary memory copy VFill: array[sizeof(TSQLDBFieldType)+sizeof(TSQLDBParamInOutType).. and not RawUTF8. since OleDB expects the text to be provided with Unicode encoding . not the standard TSQLDBParam record type. Define if parameter can be retrieved after a stored procedure execution VInt64: Int64. Create an OleDB statement instance. ftDouble. from an OleDB connection . but will allow direct per-row access using the Step() and Column*() methods constructor Create(aConnection: TSQLDBConnection).this statement won't retrieve all rows of data.what's fine with DBTYPE_BSTR is that it can be resized by the provider in case of VInOut in [paramOut. So that VInt64 will be 8 bytes aligned VInOut: TSQLDBParamInOutType. Release all associated memory and COM objects SynOleDB.for some providers (like Microsoft SQL Server 2008 R2. 18 Date: June 16. Return a Column as a variant .this implementation will retrieve the data with no temporary variable (since TQuery calls this method a lot.g.pas unit . to avoid any rounding/conversion error from floating-point types function ColumnDateTime(Col: integer): TDateTime. The Column type of the current Row .a ftBlob content will be mapped into a TBlobData AnsiString variant function ColumnType(Col: integer. first Col is 0 . override. first Col is 0 . 2013 function ColumnBlob(Col: integer): RawByteString.should retrieve directly the 64 bit Currency content. a 8 bytes RawByteString for a vtInt64/vtDouble/vtDate/vtCurrency. Return a Column integer value of the current Row. Return a Column currency value of the current Row. Return a Column as a blob value of the current Row. e. override. first Col is 0 function ColumnIndex(const aColumnName: RawUTF8): integer. and a generic UnicodeString (=string) since Delphi 2009: you may not loose any data during charset conversion . override. override. Return a Column date and time value of the current Row.Synopse mORMot Framework Software Architecture Design 1. var Value: Variant): TSQLDBFieldType.returns -1 if the Column name is not found (via case insensitive search) function ColumnInt(Col: integer): Int64. Col value) starts with 0 .it's up to the implementation to ensure than all column names are unique function ColumnNull(Col: integer): boolean.18 Page 595 of 1055 . override. override. override. Returns TRUE if the column contains NULL function ColumnString(Col: integer): string. for faster process and avoid any rounding issue. or a direct mapping of the RawUnicode function ColumnCurrency(Col: integer): currency. we tried to optimize it) . override. Returns the Column index of a given Column name . first Col is 0 function ColumnDouble(Col: integer): double. first Col is 0 function ColumnToVariant(Col: integer.e. override.Columns numeration (i. 1.Rev.ColumnBlob() will return the binary content of the field is was not ftBlob.FieldSize can be set to store the size in chars of a ftUTF8 column (0 means BLOB kind of TEXT column) SynOleDB. FieldSize: PInteger=nil): TSQLDBFieldType. Return a Column floating point value of the current Row.ftCurrency type should be handled specificaly.e. Retrieve a column name of the current Row . override. since currency is a standard OleDB type . override. Col value) starts with 0 .a ftUTF8 content will be mapped into a generic WideString variant for pre-Unicode version of Delphi. Return a Column text generic VCL string value of the current Row.Columns numeration (i. first Col is 0 function ColumnName(Col: integer): RawUTF8. After a statement has been prepared via Prepare() + ExecutePrepared() or Execute().g. with stored procedures .raise an EOleDBException on any error procedure BindBlob(Param: Integer. will put the cursor on the first row of results.raise an EOleDBException on any error procedure BindBlob(Param: Integer.18 Date: June 16.Rev. with data ready to be retrieved by Column*() . var Value: Variant. Value: Int64. if the SQL statement is not a SELECT but an UPDATE or INSERT command) . 2013 function ColumnUTF8(Col: integer): RawUTF8.access the first or next row of data from the SQL Statement result: if SeekFirst is TRUE.raise an EOleDBException on any error procedure Bind(Param: Integer. IO: TSQLDBParamInOutType=paramIn).e. IO: TSQLDBParamInOutType=paramIn).return FALSE if no more row is available (e.raise an ESQLEOleDBException on any error function UpdateCount: integer. Retrieve the parameter content. IO: TSQLDBParamInOutType=paramIn). first Col is 0 function ParamToVariant(Param: Integer.raise an EOleDBException on any error SynOleDB. Gets a number of updates made by latest executed statement procedure Bind(Param: Integer. Value: double. override. override. override. it will fetch one row of data. Data: pointer.the leftmost SQL parameter has an index of 1 . Bind a Blob buffer to a parameter . Return a Column UTF-8 encoded text value of the current Row. overload.any TEXT parameter will be retrieved as WideString Variant (i. const Data: RawByteString. CheckIsOutParameter: boolean=true): TSQLDBFieldType. override.the leftmost SQL parameter has an index of 1 .to be used e.the leftmost SQL parameter has an index of 1 . override. overload. this method must be called one or more times to evaluate it . to be called within a loop . override. Bind a double value to a parameter . Bind an integer value to a parameter .pas unit . overload.the leftmost SQL parameter has an index of 1 .g.you shall call this method before calling any Column*() methods . IO: TSQLDBParamInOutType=paramIn). as stored in TOleDBStatementParam) function Step(SeekFirst: boolean=false): boolean. overload. override. Size: integer. after SQL execution .Synopse mORMot Framework Software Architecture Design 1. Bind a Blob buffer to a parameter . otherwise. override.18 Page 596 of 1055 .return TRUE on success. 1.the leftmost SQL parameter has an index of 1 . raise an EOleDBException on any error procedure BindTextW(Param: Integer.raise an EOleDBException on any error procedure BindTextU(Param: Integer.Synopse mORMot Framework Software Architecture Design 1. Bind a UTF-8 encoded buffer text (#0 ended) to a parameter . IO: TSQLDBParamInOutType=paramIn). override.Rev. Value: currency. IO: TSQLDBParamInOutType=paramIn).raise an EOleDBException on any error procedure BindTextS(Param: Integer. Append all columns values of the current Row to a JSON stream . override. Bind a currency value to a parameter . in the '"\uFFF0base64encodedbinary" format and contains true BLOB data procedure ExecutePrepared. IO: TSQLDBParamInOutType=paramIn). Bind an OLE WideString to a parameter .the leftmost SQL parameter has an index of 1 .the leftmost SQL parameter has an index of 1 . overload. const Value: RawUTF8.will use WR. Bind a UTF-8 encoded string to a parameter . DoNotFletchBlobs: boolean). const Value: WideString.the leftmost SQL parameter has an index of 1 . override.raise an EOleDBException on any error SynOleDB.18 Date: June 16.Expand to guess the expected output format . overload.BLOB field value is saved as Base64.the leftmost SQL parameter has an index of 1 . IO: TSQLDBParamInOutType=paramIn).raise an EOleDBException on any error procedure ColumnsToJSON(WR: TJSONWriter.raise an EOleDBException on any error procedure BindTextP(Param: Integer. IO: TSQLDBParamInOutType=paramIn). Value: TDateTime. overload. override.the leftmost SQL parameter has an index of 1 . overload.parameters marked as ? should have been already bound with Bind*() functions above .fast overriden implementation with no temporary variable .pas unit . IO: TSQLDBParamInOutType=paramIn).18 Page 597 of 1055 . override. Bind a NULL value to a parameter . IO: TSQLDBParamInOutType=paramIn). override. Value: PUTF8Char. 1.raise an EOleDBException on any error procedure BindDateTime(Param: Integer. 2013 procedure BindCurrency(Param: Integer. overload. override. override.the leftmost SQL parameter has an index of 1 . Execute an UTF-8 encoded SQL statement . Bind a TDateTime value to a parameter .the leftmost SQL parameter has an index of 1 . overload. Bind a VCL string to a parameter . override. const Value: string.raise an EOleDBException on any error procedure BindNull(Param: Integer. stTruncated.see http://msdn. via SQL Server Native Client 10. OleDB connection properties to Microsoft SQL Server 2008.0 (SQL Server 2008) . SynOleDB. by TOleDBStatement.several rows are retrieved at once into the internal buffer . bsNoInterface.Execute or to retrieve metadata columns . stIsNull. stBadStatus. stBadAccessor. If TRUE. Size in bytes of the internal OleDB buffer used to fetch rows . stSignMismatch.is used e. bsMultipleStorage ).is enabled by default. Binding status of a given column . stCanNotConvertValue.default value is 16384 bytes.parameters marked as ? will be bound later. stPermissionDenied. stCanNotCreateValue. before ExecutePrepared call . stDefault ). Used to store properties about TOleDBStatement Parameters . and should not be modified in most cases property OleDBConnection: TOleDBConnection read fOleDBConnection.pas unit . Prepare an UTF-8 encoded SQL statement . stDataoverFlow. bsUnsupportedConversion. override.com/en-us/library/windows/desktop/ms720969 TOleDBMSSQL2008ConnectionProperties = TOleDBMSSQLConnectionProperties.this overriden implementation will reset all bindings and the cursor state . bsBadBindInfo. override. the data will be 8 bytes aligned in OleDB internal buffers .if ExpectResults is TRUE. then Step() and Column*() methods are available to retrieve the data rows .18 Page 598 of 1055 .raise an exception on error procedure Prepare(const aSQL: RawUTF8.Rev.18 Date: June 16. stUnavailable.whole memory block of a TOleDBStatementParamDynArray will be used as the source Data for the OleDB parameters TOleDBStatus = ( stOK. minimal allowed size is 8192 Types implemented in the SynOleDB unit: TOleDBBindStatus = ( bsOK. Reset the previous prepared statement .microsoft. ExpectResults: Boolean=false). overload.raise an EOleDBException on any error procedure Reset. bsBadOrdinal. bsBadStorageFlags. 2013 procedure FromRowSet(RowSet: IRowSet). stIntegrityViolation. Retrieve column information from a supplied IRowSet .raise an EOleDBException on any error property AlignDataInternalBuffer: boolean read fAlignBuffer write fAlignBuffer.g.just maps default TOleDBMSSQLConnectionProperties type TOleDBStatementParamDynArray = array of TOleDBStatementParam. Just map the original Collection into a TOleDBConnection class property RowBufferSize: integer read fRowBufferSize write SetRowBufferSize. 1.it's recommended by official OleDB documentation for faster process .Synopse mORMot Framework Software Architecture Design 1. 85).Destroy.only made public for user convenience. when thread associated to an OleDb connection is terminated . e. when using custom COM objects function IsJetFile(const FileName: TFileName): boolean.Create when an OleDb connection is instantiated for a new thread .Synopse mORMot Framework Software Architecture Design 1. Check from the file beginning if sounds like a valid Jet / MSAccess file SynOleDB.g. 2013 Indicates whether the data value or some other value.see http://msdn.only made public for user convenience. to call the CoInitialize API only once per thread .g. when using custom COM objects procedure CoUninit. 1. e. This global procedure should be called at thread termination .every call of CoInit shall be followed by a call to CoUninit . such as a NULL. e.implementation will maintain some global counting.pas unit .g. is to be used as the value of the column or parameter .it is already called by TOleDBConnection.18 Page 599 of 1055 .Rev.18 Date: June 16.every call of CoInit shall be followed by a call to CoUninit .aspx Functions or procedures implemented in the SynOleDB unit: Functions or procedures Description Page CoInit This global procedure should be called for each thread needing to use OLE 599 CoUninit This global procedure should be called at thread termination 599 IsJetFile Check from the file beginning if sounds like a valid Jet / MSAccess file 599 procedure CoInit. This global procedure should be called for each thread needing to use OLE .com/en-us/library/ms722617(VS.it is already called by TOleDBConnection.microsoft. 18 Page 600 of 1055 .this unit is a part of the freeware Synopse framework. shall be integrated 1054 Units used in the SynPdf unit: Unit Name Description Page SynCommons Common functions used by most Synopse projects . 1. 2013 23. licensed under a MPL/GPL/LGPL tri-license.16.pas unit Purpose: PDF file generation .Synopse mORMot Framework Software Architecture Design 1. version 1.adds GIF.pas unit .Rev. TIF. version 1.this unit is a part of the freeware Synopse mORMot framework.18 584 SynZip Low-level access to ZLib compression (1.5 engine version) . licensed under a MPL/GPL/LGPL tri-license.2.allows Antialiased rending of any EMF file using GDI+ . version 1.18 325 SynGdiPlus GDI+ library API access .make available most useful GDI+ drawing methods .this unit is a part of the freeware Synopse framework. PNG and JPG pictures read/write support as standard TGraphic .18 707 SynPdf.licensed under a MPL/GPL/LGPL tri-license. licensed under a MPL/GPL/LGPL tri-license. licensed under a MPL/GPL/LGPL tri-license.2 A reporting feature.3. version 1. with full preview and export as PDF or TXT files. version 1. SynPdf.18 576 SynLZ SynLZ Compression routines .18 The SynPdf unit is quoted in the following items: SWRS # Description Page DI-2.18 Date: June 16.this unit is a part of the freeware Synopse framework. Rev. 1. 2013 EPdfInvalidValue Exception EPdfInvalidOperation TPdfXref TPdfXrefEntry TPdfVirtualObject TPdfWrite TPdfTextUTF8 TPdfTTF TPdfText TPdfTrailer TPdfStream TPdfTextString TPdfRawText TPdfName TPdfImage TPdfXObject TPdfObjectMgr TPdfReal TPdfObject TPdfNumber TPdfDocument TPdfNull TPdfDictionaryElement TPdfDictionary TPdfDestination TPdfBoolean TPdfCanvas TPdfBinary TPdfForm TObject TPdfPage TPdfPageGDI TPdfOutlines TPdfArray TPdfDocumentGDI TPdfOutlineEntry TPdfOutlineRoot TPdfInfo TPersistent TPdfDictionaryWrapper TPdfFontType1 TPdfFontWinAnsi TPdfFont TPdfFontTrueType TPdfFontCIDFontType2 TPdfCatalog SynPdf class hierarchy Objects implemented in the SynPdf unit: Objects Description Page EPdfInvalidOperation PDF exception.18 Page 601 of 1055 .Synopse mORMot Framework Software Architecture Design 1. raised when an invalid value is given to a constructor 604 TCmapFmt4 Header for the 'cmap' Format 4 table 604 TCmapHEAD The 'head' table contains global information about the font 604 SynPdf.18 Date: June 16.pas unit . raised when an invalid operation is trigerred 604 EPdfInvalidValue PDF exception. 604 TCmapHHEA Platform identifier Platform-specific encoding identifier Offset of the mapping table The 'hhea' table contains information needed to layout fonts whose characters are written horizontally. storing a numerical (integer) value 607 TPdfObject Master class for most PDF objects declaration 606 SynPdf.18 Date: June 16. that is. either left to right or right to left 604 TPdfArray Used to store an array of PDF objects 608 TPdfBinary Used to handle object which are not defined in this library 611 TPdfBoolean A PDF object. storing a PDF name 608 TPdfNull A PDF object.18 Page 602 of 1055 .Synopse mORMot Framework Software Architecture Design 1. storing a boolean value 607 TPdfBox A PDF coordinates box 604 TPdfCanvas Access to the PDF Canvas. used to draw on the page 619 TPdfDestination A destination defines a particular view of a document. 1. consisting of the following: 630 TPdfDictionary A PDF Dictionay is used to manage Key / Value pairs 609 TPdfDictionaryElement PDF dictionary element definition 609 TPdfDictionaryWrapper Common ancestor to all dictionary wrapper classes 626 TPdfDocument The main class of the PDF engine. 2013 Objects Description Page TCmapHeader The 'cmap' table begins with an index containing the table version number followed by the number of encoding tables.pas unit . storing a NULL value 607 TPdfNumber A PDF object.Rev. handling at least WinAnsi encoding 627 TPdfForm Handle any form XObject 634 TPdfImage Generic image object 633 TPdfInfo A dictionary wrapper class for the PDF document information fields 626 TPdfName A PDF object. processing the whole PDF document 613 TPdfDocumentGDI Class handling PDF document creation using GDI commands 632 TPdfFont A generic PDF font object 627 TPdfFontCIDFontType2 An embedded Composite CIDFontType2 628 TPdfFontTrueType Handle TrueType Font 629 TPdfFontType1 An embedded WinAnsi-Encoded standard Type 1 font 628 TPdfFontWinAnsi A generic PDF font object. The encoding subtables follow. 18 Page 603 of 1055 . storing a raw PDF content 608 TPdfReal A PDF object.pas unit . storing a textual value 608 TPdfTextUTF8 A PDF object.Rev. after analysis of a unicode text 634 TScriptProperties Contains information about Uniscribe special processing for each script 634 TScriptState An UniScribe script state 634 TScriptVisAttr Contains the visual (glyph) attributes that identify clusters and justification points. as generated by ScriptShape 634 SynPdf. storing a numerical (floating point) value 607 TPdfRect A PDF coordinates rectangle 604 TPdfStream A temporary memory stream.Synopse mORMot Framework Software Architecture Design 1. 1.18 Date: June 16. storing a textual value 607 TPdfTrailer The Trailer of the PDF File 612 TPdfTTF Handle Unicode glyph description for a True Type Font 628 TPdfVirtualObject A virtual PDF object. with an associated PDF Object Number 607 TPdfWrite Buffered writer class. with its corresponding Meta File and Canvas 632 TPdfRawText A PDF object. stored as a PDF dictionary 613 TPdfPage A PDF page 618 TPdfPageGDI A PDF page. specialized for PDF encoding 604 TPdfXObject Any object stored to the PDF file 613 TPdfXref Store the XRef list of the PDF file 612 TPdfXrefEntry Store one entry in the XRef list of the PDF file 612 TScriptAnalysis An Uniscribe script analysis 634 TScriptItem A Uniscribe script item. 2013 Objects Description Page TPdfObjectMgr Object manager is a virtual class to manage instance of indirect PDF objects 606 TPdfOutlineEntry An Outline entry in the PDF document 631 TPdfOutlineRoot Root entry for all Outlines of the PDF document 632 TPdfOutlines Generic PDF Outlines entries. to be stored into the PDF content 611 TPdfText A PDF object. storing a textual value 607 TPdfTextString A PDF object. raised when an invalid value is given to a constructor EPdfInvalidOperation = class(Exception) PDF exception. overload. specialized for PDF encoding constructor Create(DestStream: TStream.18 Page 604 of 1055 .no conversion is made SynPdf.Rev. overload. Direct raw write of some data . 1. overload.up to 2 decimals are written function Add(const Text: RawByteString): TPdfWrite. Number of encoding subtables version: word. for a specified destination stream function Add(Value: Extended): TPdfWrite. Create the buffered writer.pas unit .Synopse mORMot Framework Software Architecture Design 1. 2013 TCmapHeader = packed record The 'cmap' table begins with an index containing the table version number followed by the number of encoding tables. either left to right or right to left TCmapHEAD = packed record The 'head' table contains global information about the font TCmapFmt4 = packed record Header for the 'cmap' Format 4 table . Direct raw write of some data . raised when an invalid operation is trigerred TPdfRect = record A PDF coordinates rectangle TPdfBox = record A PDF coordinates box TPdfWrite = class(TObject) Buffered writer class. Len: integer): TPdfWrite. numberSubtables: word. Version number (Set to zero) TCmapHHEA = packed record Platform identifier Platform-specific encoding identifier Offset of the mapping table The 'hhea' table contains information needed to layout fonts whose characters are written horizontally.18 Date: June 16. that is.this is a two-byte encoding format EPdfInvalidValue = class(Exception) PDF exception. The encoding subtables follow. Add a floating point numerical value to the buffer . CodePage: integer).no conversion is made function Add(Text: PAnsiChar. > for Unicode characters . 2013 function Add(Value. 1.use (.g.if NextLine is TRUE.used by TPdfText object function AddEscapeName(Text: PAnsiChar): TPdfWrite. indicate used glyphs for further Font properties writting to the PDF file content.18 Page 605 of 1055 . Add a character to the buffer function AddColorStr(Color: TColorRef): TPdfWrite.. then write it as PDF Text . overload. Font: TPdfFont): TPdfWrite.) for all WinAnsi characters.18 Date: June 16. one by one function AddHex4(aWordValue: cardinal): TPdfWrite.. GlyphsCount: integer. encoded as Glyphs indexes. overload.. Write some Unicode text.ShowText method for WinAnsi text function AddGlyphs(Glyphs: PWord. or <. Add an integer numerical value to the buffer . Add some WinAnsi text as PDF text .. Add an integer numerical value to the buffer function Add(c: AnsiChar): TPdfWrite. NextLine: boolean. Add an ISO 8601 encoded date time (e. Canvas: TPdfCanvas): TPdfWrite.Synopse mORMot Framework Software Architecture Design 1.used by TPdfCanvas.during the text process. Add a word value.Ansi to Unicode conversion uses the CodePage set by Create() constructor .pas unit .if the current font is not True Type. corresponding TPdfTrueTypeFont properties are updated (Unicode version created if necessary. corresponding to the current font function AddHex(const Bin: PDFString): TPdfWrite.Ansi to Unicode conversion uses the CodePage set by Create() constructor function AddToUnicodeHexText(const Text: PDFString. Convert some text into unicode characters. '2010-06-16T15:06:59-07:00') function AddToUnicodeHex(const Text: PDFString): TPdfWrite.) .hexa.Rev. Hexadecimal write of some row data . as Big-Endian 4 hexadecimal characters function AddIso8601(DateTime: TDateTime): TPdfWrite. then write it as as Big-Endian 4 hexadecimal characters . all Unicode characters are drawn as '?' SynPdf.. Add some WinAnsi text as PDF text .. Add a PDF color. overload. the first written PDF Text command is not Tj but ' .with a specified fixed number of digits (left filled by '0') function Add(Value: Integer): TPdfWrite. Add some PDF /property value function AddEscapeText(Text: PAnsiChar. Canvas: TPdfCanvas): TPdfWrite. Convert some text into unicode characters.row data is written as hexadecimal byte values. DigitCount: Integer): TPdfWrite. from its TColorRef RGB value function AddEscape(Text: PAnsiChar): TPdfWrite. ) for all WinAnsi characters..this is used by ConcatToCTM e. Decimals: cardinal): TPdfWrite.up to 2 decimals are written. 1. Flush the internal buffer to the destination stream TPdfObjectMgr = class(TObject) Object manager is a virtual class to manage instance of indirect PDF objects TPdfObject = class(TObject) Master class for most PDF objects declaration constructor Create.Rev.during the text process. Count: integer).add a trailing space function AddWithSpace(Value: Extended): TPdfWrite. together with a trailing space .this version handles a variable number of decimals. overload. Add a TBitmap. or enhanced precision function Position: Integer. the first written PDF Text command is not Tj but ' .. Write some Unicode text.18 Page 606 of 1055 . Add a floating point numerical value to the buffer .incoming unicode text must end with a #0 . Create the PDF object instance SynPdf.) ..this method could not use Save to flush the data.if NextLine is TRUE.pas unit . PInc. NextLine: boolean..18 Date: June 16. Canvas: TPdfCanvas): TPdfWrite. virtual. together with a trailing space function AddWithSpace(Value: Extended. corresponding TPdfTrueTypeFont properties are updated (Unicode version created if necessary.. 2013 function AddUnicodeHex(PW: PWideChar.use (. or <. as PDF text .Scanline[] content into the stream procedure Save. Write some unicode text as as Big-Endian 4 hexadecimal characters function AddUnicodeHexText(PW: PWideChar.hexa.> for Unicode characters . if all input was inside the internal buffer (save some CPU and memory): so don't intend the destination stream to be flushed after having called this method procedure AddRGB(P: PAnsiChar.Synopse mORMot Framework Software Architecture Design 1. Add a floating point numerical value to the buffer . indicate used glyphs for further Font properties writting to the PDF file content. Get the data written to the Writer as a PDFString . overload. all Unicode characters are drawn as '?' function AddWithSpace(Value: Integer): TPdfWrite..g. overload. Add an integer numerical value to the buffer . Return the current position .add the current internal buffer stream position to the destination stream position function ToPDFString: PDFString. WideCharCount: integer): TPdfWrite.if the current font is not True Type. 18 Date: June 16. storing a numerical (integer) value TPdfReal = class(TPdfObject) A PDF object. storing a numerical (floating point) value TPdfText = class(TPdfObject) A PDF object. Write object to specified stream . and stored as '<FEFFHexUnicodeEncodedValue>' TPdfTextUTF8 = class(TPdfObject) A PDF object. The associated PDF Object Number . 1. conversion is made into Unicode before writing. The corresponding type of this PDF object TPdfVirtualObject = class(TPdfObject) A virtual PDF object. 2013 procedure WriteTo(var W: TPdfWrite). storing a textual value . with an associated PDF Object Number TPdfBoolean = class(TPdfObject) A PDF object.pas unit . storing a NULL value TPdfNumber = class(TPdfObject) A PDF object.the value is specified as a PDFString . The associated PDF Generation Number property ObjectNumber: integer read FObjectNumber write SetObjectNumber. conversion is made into Unicode before writing. storing a textual value .If object is indirect object then write references to stream procedure WriteValueTo(var W: TPdfWrite).in case of MBCS. Otherwise. storing a boolean value TPdfNull = class(TPdfObject) A PDF object.the value is specified as an UTF-8 encoded string .this method called by parent object property GenerationNumber: integer read FGenerationNumber.If you set an object number higher than zero.this object is stored as '(escapedValue)' . the object is considered as indirect.this object is stored as '(escapedValue)' . Write indirect object to specified stream . the object is considered as direct object. property ObjectType: TPdfObjectType read FObjectType.in case characters with ANSI code higher than 8 Bits. and '<FEFFHexUnicodeEncodedValue>' SynPdf.Synopse mORMot Framework Software Architecture Design 1.Rev.18 Page 607 of 1055 . reintroduce. do nothing function FindName(const AName: PDFString): TPdfName. Create an array of PDF objects. reintroduce. Simple creator.this object is stored as '(escapedValue)' .this object is stored as '/Value' TPdfArray = class(TPdfObject) Used to store an array of PDF objects constructor Create(AObjectMgr: TPdfObjectMgr. Create an array of PDF objects constructor CreateNames(AObjectMgr: TPdfObjectMgr. and all embedded objects instances function AddItem(AItem: TPdfObject): integer. overload. const AArray: array of double). reintroduce. reintroduce. overload.this object is stored into the PDF stream as the defined Value constructor CreateFmt(Fmt: PAnsiChar. Create an array of PDF objects. const AArray: array of Integer). overload. Create an array of PDF objects. AArray: PWordArray. 1. 2013 TPdfTextString = class(TPdfTextUTF8) A PDF object. storing a PDF name . overload.pas unit . overload.Synopse mORMot Framework Software Architecture Design 1. and '<FEFFHexUnicodeEncodedValue>' TPdfRawText = class(TPdfText) A PDF object. const AArray: array of PDFString).the value is specified as a generic VCL string .18 Date: June 16. override. with some specified TPdfName values constructor CreateReals(AObjectMgr: TPdfObjectMgr. Create an array of PDF objects. const Args: array of Integer). storing a textual value . conversion is made into Unicode before writing. reintroduce. replacing every % in Fmt by the corresponding Args[] TPdfName = class(TPdfText) A PDF object.if AItem already exists. with some specified TPdfNumber values constructor Create(AObjectMgr: TPdfObjectMgr). Release the instance memory. Add a PDF object to the array .Rev. with some specified TPdfNumber values constructor Create(AObjectMgr: TPdfObjectMgr.18 Page 608 of 1055 . AArrayCount: integer). Retrieve a TPDFName object stored in the array SynPdf. storing a raw PDF content .in case characters with ANSI code higher than 8 Bits. with some specified TPdfReal values destructor Destroy. 1.pas unit . Release the element instance. The associated Key Name property Value: TPdfObject read FValue. and all associated elements function PdfArrayByName(const AKey: PDFString): TPdfArray. Direct access to the internal TList instance . The associated PDF Object Manager TPdfDictionaryElement = class(TObject) PDF dictionary element definition constructor Create(const AKey: PDFString. If this element was created as internal.Synopse mORMot Framework Software Architecture Design 1. not to be saved to the PDF content property Key: PDFString read GetKey. override. reintroduce.18 Date: June 16. Create the corresponding Key / Value pair destructor Destroy. Retrieve the array size property Items[Index: integer]: TPdfObject read GetItems.18 Page 609 of 1055 . Remove a specified TPDFName object stored in the array property ItemCount: integer read GetItemCount.Rev. Fast find an array value by its name function PdfBooleanByName(const AKey: PDFString): TPdfBoolean. i. override. Fast find a boolean value by its name function PdfDictionaryByName(const AKey: PDFString): TPdfDictionary. The associated Value stored in this element TPdfDictionary = class(TPdfObject) A PDF Dictionay is used to manage Key / Value pairs constructor Create(AObjectMgr: TPdfObjectMgr). Fast find a dictionary value by its name SynPdf.e. AValue: TPdfObject. stored in the array property List: TList read FArray. Create the PDF dictionary destructor Destroy. AInternal: Boolean=false). Retrieve an object instance. Release the dictionay instance. and both associated Key and Value property IsInternal: boolean read FIsInternal.not to be used normaly property ObjectMgr: TPdfObjectMgr read FObjectMgr. 2013 function RemoveName(const AName: PDFString): boolean. AInternal: Boolean=false). the TPdfTextString. AValue: PDFString). Add a specified Key / Value pair (of type TPdfName) to the dictionary procedure AddItem(const AKey: PDFString. Fast find a numerical (floating-point) value by its name function PdfTextByName(const AKey: PDFString): TPdfText. 1. and add it to list .Value otherwize function PdfTextValueByName(const AKey: PDFString): PDFString.create PdfDictionaryElement with given key and value. AValue: PDFString). Add a specified Key / Value pair (of type TPdfNumber) to the dictionary procedure AddItem(const AKey. Fast find a textual value by its name function PdfTextStringValueByName(const AKey: PDFString): string. the TPdfText. Add a specified Key / Value pair (of type TPdfTextUTF8) to the dictionary . if necessary SynPdf.if the element exists.return '' if not found.return '' if not found.Value otherwize function PdfTextUTF8ValueByName(const AKey: PDFString): RawUTF8. Fast find a textual value by its name . Add a specified Key / Value pair (of type TPdfTextUTF8) to the dictionary . AValue: integer). and not to be saved to the PDF content procedure AddItemText(const AKey. Fast find a textual value by its name . overload. Fast find a numerical (integer) value by its name function PdfRealByName(const AKey: PDFString): TPdfReal. const AValue: RawUTF8).the value is a generic VCL string: it will be written as Unicode hexadecimal to the PDF stream. overload.Synopse mORMot Framework Software Architecture Design 1. overload.pas unit . overload. AValue: TPdfObject. const AValue: string).Value otherwize function ValueByName(const AKey: PDFString): TPdfObject. overload. Fast find a value by its name procedure AddItem(const AKey: PDFString.the value can be any UTF-8 encoded text: it will be written as Unicode hexadecimal to the PDF stream.return '' if not found. Add a specified Key / Value pair to the dictionary .internal items are local to the framework. overload. the TPdfTextUTF8. if necessary procedure AddItemTextUTF8(const AKey: PDFString. replace value of element by given value .18 Page 610 of 1055 . Fast find a textual value by its name . 2013 function PdfNameByName(const AKey: PDFString): TPdfName.18 Date: June 16. Fast find a name value by its name function PdfNumberByName(const AKey: PDFString): TPdfNumber.Rev. Add a specified Key / Value pair (of type TPdfText) to the dictionary procedure AddItemTextString(const AKey: PDFString. if the FlateDecode filter is set constructor Create(ADoc: TPdfDocument.not to be used normaly property ObjectMgr: TPdfObjectMgr read FObjectMgr. 1. e. Create the temporary memory stream . Retrieve the associated buffered writer .if the element does not exist. Direct access to the internal TList instance .typicaly used for the page content .an optional DontAddToFXref is available. i.18 Page 611 of 1055 . Retrieve the associated Object Manager property TypeOf: PDFString read getTypeOf. reintroduce. Remove the element specified by its Key from the dictionary .g.e. Retrieve the type of the pdfdictionary object. the stream Length property Filter: TPdfArray read FFilter. 2013 procedure RemoveItem(const AKey: PDFString). Create the instance.Rev. DontAddToFXref: boolean=false).pas unit . Retrieve the associated attributes. Retrieve the associated filter property Writer: TPdfWrite read FWriter. i.use this TPdfWrite instance to write some data into the stream TPdfBinary = class(TPdfObject) Used to handle object which are not defined in this library constructor Create.18 Date: June 16. do nothing property ItemCount: integer read GetItemCount. the 'Type' property name TPdfStream = class(TPdfObject) A temporary memory stream. Retrieve the dictionary element count property Items[Index: integer]: TPdfDictionaryElement read GetItems. override. override. to be stored into the PDF content .can be compressed.Synopse mORMot Framework Software Architecture Design 1.e. if you don't want to add this object to the main XRef list of the PDF file destructor Destroy. Release the memory stream property Attributes: TPdfDictionary read FAttributes. Retrieve any dictionary element property List: TList read FArray. its associated stream SynPdf. if the value is nil (e. the type is 'f' (PDF_FREE_ENTRY). The associated PDF object TPdfXref = class(TPdfObjectMgr) Store the XRef list of the PDF file constructor Create. override. override. otherwize the entry type is 'n' (PDF_IN_USE_ENTRY) destructor Destroy. Release the instance property Stream: TMemoryStream read FStream. override.mostly 0. Create the entry. Release the memory. The associated Generation Number . The associated memory stream.g.create first a void 'f' (PDF_FREE_ENTRY) as root destructor Destroy.pas unit . The position (in bytes) in the PDF file content stream property EntryType: PDFString read FEntryType write FEntryType. used to store the corresponding data . 1. 2013 destructor Destroy.Rev. with the specified value . if any procedure SaveToPdfWrite(var W: TPdfWrite). override. or 65535 (PDF_MAX_GENERATION_NUM) for the root 'f' entry property Value: TPdfObject read FValue.18 Date: June 16. either 'n' (PDF_IN_USE_ENTRY) property GenerationNumber: integer read FGenerationNumber write FGenerationNumber. Release instance memory and all associated XRef objects function GetObject(ObjectID: integer): TPdfObject.the content of this stream will be written to the resulting TPdfTrailer = class(TObject) The Trailer of the PDF File TPdfXrefEntry = class(TObject) Store one entry in the XRef list of the PDF file constructor Create(AValue: TPdfObject). Write the XRef list entry property ByteOffset: integer read FByteOffSet. root entry).18 Page 612 of 1055 . Return either 'f' (PDF_FREE_ENTRY). Retrieve an object from its object ID SynPdf.Synopse mORMot Framework Software Architecture Design 1. Initialize the XRef object list . and the associated value. Wrapper to create an annotation . the current system code page is used .the current PDF Canvas page is associated with this destination object SynPdf.you can specify a Code Page to be used for the PDFString encoding.the current charset and code page are retrieved from the SysLocale value.note that only Win-Ansi encoding allows use of embedded standard fonts .these objects are written in the PDF file. followed by a "xref" table TPdfOutlines = class(TPdfDictionary) Generic PDF Outlines entries.you can set an encryption instance. by using TPdfEncryption.18 Date: June 16. Create a Destination . APDFA1: boolean=false ). Retrieve the XRef object count property Items[ObjectID: integer]: TPdfXrefEntry read GetItem.these objects are the main unit of the PDF file content . 2013 procedure AddObject(AObject: TPdfObject). by default (ACodePage left to 0). virtual.Rev.pas unit . from its object ID TPdfXObject = class(TPdfStream) Any object stored to the PDF file . processing the whole PDF document Used for DI-2. reintroduce. constructor Create(AUseOutlines: Boolean=false.you can create a PDF/A-1 compliant document by setting APDFA1 to true . ACodePage: integer=0. so the PDF engine is MBCS ready . overload. Add then register an object (typicaly a TPdfImage) to the PDF document . Add a Page to the current PDF document function AddXObject(const AName: PDFString. stored as a PDF dictionary TPdfDocument = class(TObject) The main class of the PDF engine. Register object to the xref table.New() destructor Destroy. override. Retrieve a XRef object instance. AXObject: TPdfXObject): integer.2 (page 1054). const ARect: TPdfRect): TPdfDictionary.returns the internal index as added in FXObjectList[] function CreateAnnotation(AType: TPdfAnnotationSubType.18 Page 613 of 1055 .the annotation is set to a specified position of the current page function CreateDestination: TPdfDestination. Release the PDF document instance function AddPage: TPdfPage. with a Canvas and a default A4 paper size . 1. override. and set corresponding object ID property ItemCount: integer read GetItemCount. Create the PDF document instance.Synopse mORMot Framework Software Architecture Design 1.3. returns '' if this image is not already there . in order to avoid false positives function GetXObjectIndex(const AName: PDFString): integer. Create an Outline entry at a specified position of the current page .the outline tree is created from the specified numerical level (0=root).NewDoc.Synopse mORMot Framework Software Architecture Design 1. Height: Integer): PDFString.return FALSE on any writing error (e.pas unit . Create a Pages object . just after the item added via the previous CreateOutline call . DrawAt: PPdfBox=nil. TopPosition: Single): TPdfOutlineEntry.if the ForceNoBitmapReuse is FALSE . Retrieve a XObject from its name .the title is a generic VCL string. Save the PDF file content into a specified file .this method will handle also the Virtual Objects function GetXObjectImageName(const Hash: TPdfImageHash.Pages objects can be nested.e.returns the internal index as added in FXObjectList[] function SaveToFile(const aFileName: TFileName): boolean.returns the internal XObject name of the resulting TPDFImage . Create an image from a supplied bitmap .Rev.18 Page 614 of 1055 . to handle fully Unicode support function CreatePages(Parent: TPdfDictionary): TPdfDictionary. const AName: PDFString): integer.the link is set to a specified rectangular position of the current page . 2013 function CreateLink(const ARect: TPdfRect.18 Date: June 16.if you specify a PPdfBox to draw the image at the given position/size . if the file is opened in the Acrobar Reader) SynPdf. created with 4 diverse algorithms. the TPDFImage will be reused (it will therefore spare resulting pdf file space) .if the same bitmap content is sent more than once.you can specify a clipping rectangle region as ClipRc parameter function CreateOutline(const Title: string. if it no such name has been defined yet via the CreateBookMark method). and will be linked at CreateBookMark method call function CreateOrGetImage(B: TBitmap.only necessary if you have more than 8000 pages (this method is called by TPdfDocument. to save memory used by the Viewer .g.uses 4 hash codes. it's added to the internal fMissingBookmarks list. the picture will be stored as a JPEG . ClipRc: PPdfBox=nil): PDFString. Register an object (typicaly a TPdfImage) to the PDF document . Level: integer.if the bookmark name is not existing (i. Retrieve a XObject TPdfImage index from its picture attributes . specified by a bookmark . Retrieve a XObject index from its name . Width. 1. so you shouldn't have to use it) function GetXObject(const AName: PDFString): TPdfXObject. const aBookmarkName: RawUTF8): TPdfDictionary.this method won't handle the Virtual Objects function RegisterXObject(AObject: TPdfXObject.if ForceCompression property is set. Wrapper to create a Link annotation. by the Create constructor . 2013 procedure CreateBookMark(TopPosition: Single. The compression method used for page content storage .shall be made once after a SaveToStreamDirectBegin() call . Retrieve the current PDF Canvas.Rev. AddPage method call) SynPdf.the current PDF Canvas page is associated with the destination object . ForceModDate: TDateTime=0). associated to the current page property CharSet: integer read FCharSet.shall be finished by a SaveToStreamDirectEnd call procedure SaveToStreamDirectEnd.shall be made one or several times after a SaveToStreamDirectBegin() call and before a final SaveToStreamDirectEnd call .see TPdfDocumentGDI.g.the associated bookmark name must be unique. The default page height.a dtXYZ destination with the corresponding TopPosition Y value is defined .you can call it multiple time if you want to reset the whole document content procedure SaveToStream(AStream: TStream. Save the PDF file content into a specified Stream procedure SaveToStreamDirectBegin(AStream: TStream.this method is called first. The current Code Page encoding used for this PDF Document property CompressionMethod: TPdfCompressionMethod read FCompressionMethod write FCompressionMethod. Prepare to save the PDF file content into a specified Stream .ExportPDFStream() in mORMotReport. Create a new document .is called by SaveToStream() method procedure SaveToStreamDirectPageFlush.Synopse mORMot Framework Software Architecture Design 1. and TGDIPages. virtual. used for new every page creation (i. Prepare to save the PDF file content into a specified Stream . Create an internal bookmark entry at a specified position of the current page . Save the current page content to the PDF file . The current CharSet used for this PDF Document property CodePage: cardinal read FCodePage. otherwise an exception is raised procedure NewDoc.SaveToStream() in this unit. const aBookmarkName: RawUTF8). for report creation) .pas for real use cases property Canvas: TPdfCanvas read fCanvas.you can then append other individual pages with SaveToStreamCurrentPage to avoid most resource usage (e.is set by default to cmFlateDecode when the class instance is created property DefaultPageHeight: cardinal read FDefaultPageHeight write SetDefaultPageHeight.18 Date: June 16. ForceModDate: TDateTime=0).e.18 Page 615 of 1055 .pas unit . 1.is called by SaveToStream() method . Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 property DefaultPageLandscape: boolean read GetDefaultPageLandscape write SetDefaultPageLandscape; The default page orientation - a call to this property will swap default page width and height if the orientation is not correct property DefaultPageWidth: cardinal read FDefaultPageWidth write SetDefaultPageWidth; The default page width, used for new every page creation (i.e. AddPage method call) property DefaultPaperSize: TPDFPaperSize read FDefaultPaperSize write SetDefaultPaperSize; The default page size, used for every new page creation (i.e. AddPage method call) - a write to this property this will reset the default paper orientation to Portrait: you must explicitely set DefaultPageLandscape to true, if needed property EmbeddedTTF: boolean read fEmbeddedTTF write fEmbeddedTTF; If set to TRUE, the used True Type fonts will be embedded to the PDF content - not set by default, to save disk space and produce tiny PDF property EmbeddedTTFIgnore: TRawUTF8List read GetEmbeddedTTFIgnore; You can add some font names to this list, if you want these fonts NEVER to be embedded to the PDF file, even if the EmbeddedTTF property is set - if you want to ignore all standard windows fonts, use: EmbeddedTTFIgnore.Text := MSWINDOWS_DEFAULT_FONTS; property EmbeddedWholeTTF: boolean read fEmbeddedWholeTTF write fEmbeddedWholeTTF; If set to TRUE, the embedded True Type fonts will be totaly Embeddeded - by default, is set to FALSE, meaning that a subset of the TTF font is stored into the PDF file, i.e. only the used glyphs are stored - this option is only available if running on Windows XP or later property FontFallBackName: string read GetFontFallBackName write SetFontFallBackName; Set the font name to be used for missing characters - used only if UseFontFallBack is TRUE - default value is 'Arial Unicode MS', if existing property ForceJPEGCompression: integer read fForceJPEGCompression write fForceJPEGCompression; This property can force saving all canvas bitmaps images as JPEG - handle bitmaps added by VCLCanvas/TMetaFile and bitmaps added as TPdfImage - by default, this property is set to 0 by the constructor of this class, meaning that the JPEG compression is not forced, and the engine will use the native resolution of the bitmap - in this case, the resulting PDF file content will be bigger in size (e.g. use this for printing) - 60 is the prefered way e.g. for publishing PDF over the internet - 80/90 is a good ration if you want to have a nice PDF to see on screen - of course, this doesn't affect vectorial (i.e. emf) pictures SynPdf.pas unit - Rev. 1.18 Page 616 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 property ForceNoBitmapReuse: boolean read fForceNoBitmapReuse write fForceNoBitmapReuse; This property can force all canvas bitmaps to be stored directly - by default, the library will try to match an existing same bitmap content, and reuse the existing pdf object - you can set this property for a faster process, if you do not want to use this feature property Info: TPdfInfo read GetInfo; Retrieve the PDF information, associated to the PDF document property OutlineRoot: TPdfOutlineRoot read GetOutlineRoot; Retrieve the PDF Outline, associated to the PDF document - UseOutlines must be set to TRUE before any use of the OutlineRoot property property PDFA1: boolean read fPDFA1 write SetPDFA1; Is TRUE if the file was created in order to be PDF/A-1 compliant - set APDFA1 parameter to true for Create constructor in order to use it - warning: setting a value to this propery after creation will call the NewDoc method, therefore will erase all previous content and pages (including Info properties) property RawPages: TList read fRawPages; Direct read-only access to all corresponding TPdfPage - can be useful in inherited classe property Root: TPdfCatalog read fRoot; Retrieve the PDF Document Catalog, as root of the document's object hierarchy property ScreenLogPixels: Integer read FScreenLogPixels write FScreenLogPixels; The resolution used for pixel to PDF coordinates conversion - by default, contains the Number of pixels per logical inch along the screen width - you can override this value if you really need additional resolution for your bitmaps and such this is useful only with TPdfDocumentGDI and its associated TCanvas: all TPdfDocument native TPdfCanvas methods use the native resolution of the PDF, i.e. more than 7200 DPI (since we write coordinates with 2 decimals per point - which is 1/72 inch) property StandardFontsReplace: boolean read FStandardFontsReplace write SetStandardFontsReplace; Set if the PDF engine must use standard fonts substitution - if TRUE, 'Arial', 'Times New Roman' and 'Courier New' will be replaced by the corresponding internal Type 1 fonts, defined in the Reader - only works with current ANSI_CHARSET, i.e. if you want to display some other unicode characters, don't enable this property: all non WinAnsi glyphs would be replaced by a '?' sign - default value is false (i.e. not embedded standard font) property UseFontFallBack: boolean read fUseFontFallBack write fUseFontFallBack; Used to define if the PDF document will handle "font fallback" for characters not existing in the current font: it will avoid rendering block/square symbols instead of the correct characters (e.g. for Chinese text) - will use the font specified by FontFallBackName property to add any Unicode glyph not existing in the currently selected font - default value is TRUE SynPdf.pas unit - Rev. 1.18 Page 617 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 property UseOutlines: boolean read FUseoutlines write FUseoutlines; Used to define if the PDF document will use outlines - must be set to TRUE before any use of the OutlineRoot property property UseUniscribe: boolean read fUseUniscribe write fUseUniscribe; Set if the PDF engine must use the Windows Uniscribe API to render Ordering and/or Shaping of the text - usefull for Hebrew, Arabic and some Asiatic languages handling - set to FALSE by default, for faster content generation - you can set this property temporary to TRUE, when using the Canvas property, but this property must be set appropriately before the content generation if you use any TPdfDocumentGdi.VCLCanvas text output with such scripting (since the PDF rendering is done once just before the saving, e.g. before SaveToFile() or SaveToStream() methods calls) - the PDF engine don't handle Font Fallback yet: the font you use must contain ALL glyphs necessary for the supplied unicode text - squares or blanks will be drawn for any missing glyph/character TPdfPage = class(TPdfDictionary) A PDF page constructor Create(ADoc: TPdfDocument); reintroduce; virtual; Create the page with its internal VCL Canvas function MeasureText(const Text: PDFString; Width: Single): integer; Calculate the number of chars which can be displayed in the specified width, according to current attributes - this function is compatible with MBCS strings, and returns the index in Text, not the glyphs index function TextWidth(const Text: PDFString): Single; Calculate width of specified text according to current attributes - this function is compatible with MBCS strings property CharSpace: Single read FCharSpace write SetCharSpace; Retrieve or set the Char Space attribute property Font: TPdfFont read FFont write FFont; Retrieve the current used font - for TPdfFontTrueType, this points not always to the WinAnsi version of the Font, but can also point to the Unicode Version, if the last drawn character by ShowText() was unicode - see TPdfWrite.AddUnicodeHexText property FontSize: Single read FFontSize write SetFontSize; Retrieve or set the font Size attribute property HorizontalScaling: Single read FHorizontalScaling write SetHorizontalScaling; Retrieve or set the Horizontal Scaling attribute property Leading: Single read FLeading write SetLeading; Retrieve or set the text Leading attribute SynPdf.pas unit - Rev. 1.18 Page 618 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 property PageHeight: integer read GetPageHeight write SetPageHeight; Retrieve or set the current page height property PageLandscape: Boolean read GetPageLandscape write SetPageLandscape; Retrieve or set the paper orientation property PageWidth: integer read GetPageWidth write SetPageWidth; Retrieve or set the current page width property WordSpace: Single read FWordSpace write SetWordSpace; Retrieve or set the word Space attribute TPdfCanvas = class(TObject) Access to the PDF Canvas, used to draw on the page Used for DI-2.3.2 (page 1054). constructor Create(APdfDoc: TPdfDocument); Create the PDF canvas instance function GetNextWord(const S: PDFString; var Index: integer): PDFString; Get the index of the next word in the supplied text - this function is compatible with MBCS strings, and returns the index in Text, not the glyphs index function MeasureText(const Text: PDFString; AWidth: Single): integer; Calculate the number of chars which can be displayed in the specified width, according to current attributes - this function is compatible with MBCS strings, and returns the index in Text, not the glyphs index - note: this method only work with embedded fonts by now, not true type fonts (because text width measuring is not yet implemented for them) function SetFont(ADC: HDC; const ALogFont: TLogFontW; ASize: single): TPdfFont; overload; Set the current font for the PDF Canvas - this method use the Win32 structure that defines the characteristics of the logical font function SetFont(const AName: RawUTF8; ASize: Single; AStyle: TFontStyles; ACharSet: integer=-1; AForceTTF: integer=-1; AIsFixedWidth: boolean=false): TPdfFont; overload; Set the current font for the PDF Canvas - expect the font name to be either a standard embedded font ('Helvetica','Courier','Times') or its Windows equivalency (i.e. 'Arial','Courier New','Times New Roman'), either a UTF-8 encoded True Type font name available on the system - if no CharSet is specified (i.e. if it remains -1), the current document CharSet parameter is used function TextWidth(const Text: PDFString): Single; Calculate width of specified text according to current Canvas attributes - works with MBCS strings SynPdf.pas unit - Rev. 1.18 Page 619 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 function UnicodeTextWidth(PW: PWideChar): Single; Calculate width of specified text according to current Canvas attributes - this function compute the raw width of the specified text, and won't use HorizontalScaling, CharSpace nor WordSpace in its calculation procedure BeginText; Begin a text object - Text objects cannot be nested procedure Clip; Nonzero winding clipping path set - Modify the current clipping path by intersecting it with the current path, using the nonzero winding number rule to determine which regions lie inside the clipping path - The graphics state contains a clipping path that limits the regions of the page affected by painting operators. The closed subpaths of this path define the area that can be painted. Marks falling inside this area will be applied to the page; those falling outside it will not. (Precisely what is considered to be “inside” a path is discussed under “Filling,” above.) - The initial clipping path includes the entire page. Both clipping path methods (Clip and EoClip) may appear after the last path construction operator and before the path-painting operator that terminates a path object. Although the clipping path operator appears before the painting operator, it does not alter the clipping path at the point where it appears. Rather, it modifies the effect of the succeeding painting operator. After the path has been painted, the clipping path in the graphics state is set to the intersection of the current clipping path and the newly constructed path. procedure Closepath; Close the current subpath by appending a straight line segment from the current point to the starting point of the subpath - This operator terminates the current subpath; appending another segment to the current path will begin a new subpath, even if the new segment begins at the endpoint reached by the h operation - If the current subpath is already closed or the current path is empty, it does nothing procedure ClosepathEofillStroke; Close, fill, and then stroke the path, using the even-odd rule to determine the region to fill - This operator has the same effect as the sequence Closepath; EofillStroke; procedure ClosepathFillStroke; Close, fill, and then stroke the path, using the nonzero winding number rule to determine the region to fill - This operator has the same effect as the sequence ClosePath; FillStroke; procedure ClosePathStroke; Close and stroke the path - This operator has the same effect as the sequence ClosePath; Stroke; SynPdf.pas unit - Rev. 1.18 Page 620 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 procedure ConcatToCTM(a, b, c, d, e, f: Single; Decimals: Cardinal=6); Modify the CTM by concatenating the specified matrix - The current transformation matrix (CTM) maps positions from user coordinates to device coordinates - This matrix is modified by each application of the ConcatToCTM method - CTM Initial value is a matrix that transforms default user coordinates to device coordinates - since floating-point precision does make sense for a transformation matrix, we added a custom decimal number parameter here procedure CurveToC(x1, y1, x2, y2, x3, y3: Single); Append a cubic Bezier curve to the current path - The curve extends from the current point to the point (x3, y3), using (x1, y1) and (x2, y2) as the Bezier control points - The new current point is (x3, y3) procedure CurveToV(x2, y2, x3, y3: Single); Append a cubic Bezier curve to the current path - The curve extends from the current point to the point (x3, y3), using the current point and (x2, y2) as the Bezier control points - The new current point is (x3, y3) procedure CurveToY(x1, y1, x3, y3: Single); Append a cubic Bezier curve to the current path - The curve extends from the current point to the point (x3, y3), using (x1, y1) and (x3, y3) as the Bezier control points - The new current point is (x3, y3) procedure DrawXObject(X, Y, AWidth, AHeight: Single; const AXObjectName: PDFString); Draw the specified object (typicaly an image) with stretching procedure DrawXObjectEx(X, Y, AWidth, AHeight: Single; ClipX, ClipY, ClipWidth, ClipHeight: Single; const AXObjectName: PDFString); Draw the specified object (typicaly an image) with stretching and clipping procedure Ellipse(x, y, width, height: Single); Draw an ellipse - use Bezier curves internaly to draw the ellipse procedure EndText; End a text object, discarding the text matrix procedure EoClip; Even-Odd winding clipping path set - Modify the current clipping path by intersecting it with the current path, using the even-odd rule to determine which regions lie inside the clipping path procedure EoFill; Fill the path, using the even-odd rule to determine the region to fill SynPdf.pas unit - Rev. 1.18 Page 621 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 procedure EofillStroke; Fill and then stroke the path, using the even-odd rule to determine the region to fill - This operator produces the same result as FillStroke, except that the path is filled as if with Eofill instead of Fill procedure ExecuteXObject(const xObject: PDFString); Paint the specified XObject procedure Fill; Fill the path, using the nonzero winding number rule to determine the region to fill procedure FillStroke; Fill and then stroke the path, using the nonzero winding number rule to determine the region to fill - This produces the same result as constructing two identical path objects, painting the first with Fill and the second with Stroke. Note, however, that the filling and stroking portions of the operation consult different values of several graphics state parameters, such as the color procedure GRestore; Restores the entire graphics state to its former value by popping it from the stack procedure GSave; Pushes a copy of the entire graphics state onto the stack procedure LineTo(x, y: Single); Append a straight line segment from the current point to the point (x, y). - The new current point is (x, y) procedure MoveTextPoint(tx, ty: Single); Move to the start of the next line, offset from the start of the current line by (tx ,ty) - tx and ty are numbers expressed in unscaled text space units procedure MoveTo(x, y: Single); Change the current coordinates position - Begin a new subpath by moving the current point to coordinates (x, y), omitting any connecting line segment. If the previous path construction operator in the current path was also MoveTo(), the new MoveTo() overrides it; no vestige of the previous MoveTo() call remains in the path. procedure MoveToNextLine; Move to the start of the next line procedure MultilineTextRect(ARect: TPdfRect; const Text: PDFString; WordWrap: boolean); Show the text in the specified rectangle and alignment - text can be multiline, separated by CR + LF (i.e. #13#10) - text can optionaly word wrap - note: this method only work with embedded fonts by now, not true type fonts (because it use text width measuring) procedure NewPath; End the path object without filling or stroking it - This operator is a “path-painting no-op,” used primarily for the side effect of changing the clipping path SynPdf.pas unit - Rev. 1.18 Page 622 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 procedure Rectangle(x, y, width, height: Single); Append a rectangle to the current path as a complete subpath, with lower-left corner (x, y) and dimensions width and height in user space procedure RenderMetaFile(MF: TMetaFile; Scale: Single=1.0; XOff: single=0.0; YOff: single=0.0; TextPositioning: TPdfCanvasRenderMetaFileTextPositioning=tpSetTextJustification; KerningHScaleBottom: single=99.0; KerningHScaleTop: single=101.0); Draw a metafile content into the PDF page - not 100% of content is handled yet, but most common are (even metafiles embedded inside metafiles) - UseSetTextJustification is to be set to true to ensure better rendering if the EMF content used SetTextJustification() API call to justify text - KerningHScaleBottom/KerningHScaleTop are limits below which and over which Font Kerning is transformed into PDF Horizontal Scaling commands Used for DI-2.3.2 (page 1054). procedure RoundRect(x1,y1,x2,y2,cx,cy: Single); Draw a rounded rectangle - use Bezier curves internaly to draw the rounded rectangle procedure SetCharSpace(charSpace: Single); Set the character spacing - CharSpace is a number expressed in unscaled text space units. - Character spacing is used by the ShowText and ShowTextNextLine methods - Default value is 0 procedure SetCMYKFillColor(C, M, Y, K: integer); Set the color space to a CMYK percent value - this method set the color to use for nonstroking operations procedure SetCMYKStrokeColor(C, M, Y, K: integer); Set the color space to a CMYK value - this method set the color to use for stroking operations procedure SetDash(const aarray: array of integer; phase: integer=0); Set the line dash pattern in the graphics state - The line dash pattern controls the pattern of dashes and gaps used to stroke paths. It is specified by a dash array and a dash phase. The dash array’s elements are numbers that specify the lengths of alternating dashes and gaps; the dash phase specifies the distance into the dash pattern at which to start the dash. The elements of both the dash array and the dash phase are expressed in user space units. Before beginning to stroke a path, the dash array is cycled through, adding up the lengths of dashes and gaps. When the accumulated length equals the value specified by the dash phase, stroking of the path begins, using the dash array cyclically from that point onward. SynPdf.pas unit - Rev. 1.18 Page 623 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 procedure SetFlat(flatness: Byte); Set the flatness tolerance in the graphics state - see Section 6.5.1, “Flatness Tolerance” of the PDF 1.3 reference: The flatness tolerance controls the maximum permitted distance in device pixels between the mathematically correct path and an approximation constructed from straight line segments - Flatness is a number in the range 0 to 100; a value of 0 specifies the output device’s default flatness tolerance procedure SetFontAndSize(const fontshortcut: PDFString; size: Single); Set the font, Tf, to font and the font size, Tfs , to size. - font is the name of a font resource in the Font subdictionary of the current resource dictionary (e.g. 'F0') - size is a number representing a scale factor - There is no default value for either font or size; they must be specified using this method before any text is shown procedure SetHorizontalScaling(hScaling: Single); Set the horizontal scaling to (scale ÷ 100) - hScaling is a number specifying the percentage of the normal width - Default value is 100 (e.g. normal width) procedure SetLeading(leading: Single); Set the text leading, Tl, to the specified leading value - leading which is a number expressed in unscaled text space units; it specifies the vertical distance between the baselines of adjacent lines of text - Text leading is used only by the MoveToNextLine and ShowTextNextLine methods - you can force the next line to be just below the current one by calling: SetLeading(Attributes.FontSize); - Default value is 0 procedure SetLineCap(linecap: TLineCapStyle); Set the line cap style in the graphics state - The line cap style specifies the shape to be used at the ends of open subpaths (and dashes, if any) when they are stroked procedure SetLineJoin(linejoin: TLineJoinStyle); Set the line join style in the graphics state - The line join style specifies the shape to be used at the corners of paths that are stroked procedure SetLineWidth(linewidth: Single); Set the line width in the graphics state - The line width parameter specifies the thickness of the line used to stroke a path. It is a nonnegative number expressed in user space units; stroking a path entails painting all points whose perpendicular distance from the path in user space is less than or equal to half the line width. The effect produced in device space depends on the current transformation matrix (CTM) in effect at the time the path is stroked. If the CTM specifies scaling by different factors in the x and y dimensions, the thickness of stroked lines in device space will vary according to their orientation. The actual line width achieved can differ from the requested width by as much as 2 device pixels, depending on the positions of lines with respect to the pixel grid. SynPdf.pas unit - Rev. 1.18 Page 624 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 procedure SetMiterLimit(miterlimit: Single); Set the miter limit in the graphics state - When two line segments meet at a sharp angle and mitered joins have been specified as the line join style, it is possible for the miter to extend far beyond the thickness of the line stroking the path. The miter limit imposes a maximum on the ratio of the miter length to the line width. When the limit is exceeded, the join is converted from a miter to a bevel procedure SetPage(APage: TPdfPage); virtual; Assign the canvas to the specified page procedure SetPDFFont(AFont: TPdfFont; ASize: Single); Set the current font for the PDF Canvas procedure SetRGBFillColor(Value: TPdfColor); Set the color space to a Device-dependent RGB value - this method set the color to use for nonstroking operations procedure SetRGBStrokeColor(Value: TPdfColor); Set the color space to a Device-dependent RGB value - this method set the color to use for stroking operations procedure SetTextMatrix(a, b, c, d, x, y: Single); Set the Text Matrix to a,b,c,d and the text line Matrix x,y procedure SetTextRenderingMode(mode: TTextRenderingMode); Set the text rendering mode - the text rendering mode determines whether text is stroked, filled, or used as a clipping path procedure SetTextRise(rise: word); Set the text rise, Trise, to the specified value - rise is a number expressed in unscaled text space units, which specifies the distance, in unscaled text space units, to move the baseline up or down from its default location. Positive values of text rise move the baseline up. Adjustments to the baseline are useful for drawing superscripts or subscripts. The default location of the baseline can be restored by setting the text rise to 0. - Default value is 0 procedure SetWordSpace(wordSpace: Single); Set the word spacing - WordSpace is a number expressed in unscaled text space units - word spacing is used by the ShowText and ShowTextNextLine methods - Default value is 0 procedure ShowGlyph(PW: PWord; Count: integer); Show an Unicode Text string, encoded as Glyphs or the current font - PW must follow the ETO_GLYPH_INDEX layout, i.e. refers to an array as returned from the GetCharacterPlacement: all glyph indexes are 16-bit values procedure ShowText(PW: PWideChar; NextLine: boolean=false); overload; Show an Unicode Text string - if NextLine is TRUE, moves to the next line and show a text string; in this case, method as the same effect as MoveToNextLine; ShowText(s); SynPdf.pas unit - Rev. 1.18 Page 625 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 procedure ShowText(const text: PDFString; NextLine: boolean=false); overload; Show a text string - text is expected to be Ansi-Encoded, in the current CharSet; if some Unicode or MBCS conversion is necessary, it will be notified to the corresponding - if NextLine is TRUE, moves to the next line and show a text string; in this case, method as the same effect as MoveToNextLine; ShowText(s); procedure Stroke; Stroke the path procedure TextOut(X, Y: Single; const Text: PDFString); Show some text at a specified page position procedure TextOutW(X, Y: Single; PW: PWideChar); Show some unicode text at a specified page position procedure TextRect(ARect: TPdfRect; const Text: PDFString; Alignment: TPdfAlignment; Clipping: boolean); Show the text in the specified rectangle and alignment - optional clipping can be applied property Contents: TPdfStream read FContents; Retrieve the current Canvas content stream, i.e. where the PDF commands are to be written to property Doc: TPdfDocument read GetDoc; Retrieve the associated PDF document instance which created this Canvas property Page: TPdfPage read GetPage; Retrieve the current Canvas Page property RightToLeftText: Boolean read fRightToLeftText write fRightToLeftText; If Uniscribe-related methods must handle the text from right to left TPdfDictionaryWrapper = class(TPersistent) Common ancestor to all dictionary wrapper classes property Data: TPdfDictionary read FData write SetData; The associated dictionary, containing all data property HasData: boolean read GetHasData; Return TRUE if has any data stored within TPdfInfo = class(TPdfDictionaryWrapper) A dictionary wrapper class for the PDF document information fields - all values use the generic VCL string type, and will be encoded as Unicode if necessary property Author: string read GetAuthor write SetAuthor; The PDF document Author property CreationDate: TDateTime read GetCreationDate write SetCreationDate; The PDF document Creation Date SynPdf.pas unit - Rev. 1.18 Page 626 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 property Creator: string read GetCreator write SetCreator; The Software or Library name which created this PDF document property Keywords: string read GetKeywords write SetKeywords; The PDF document associated key words property ModDate: TDateTime read GetModDate write SetModDate; The PDF document modification date property Subject: string read GetSubject write SetSubject; The PDF document subject property Title: string read GetTitle write SetTitle; The PDF document title TPdfFont = class(TPdfDictionaryWrapper) A generic PDF font object constructor Create(AXref: TPdfXref; const AName: PDFString); Create the PDF font object instance function GetAnsiCharWidth(const AText: PDFString; APos: integer): integer; virtual; Retrieve the width of a specified character - implementation of this method is either WinAnsi (by TPdfFontWinAnsi), either compatible with MBCS strings (TPdfFontCIDFontType2) - return 0 by default (descendant must handle the Ansi charset) procedure AddUsedWinAnsiChar(aChar: AnsiChar); Mark some WinAnsi char as used property Name: PDFString read FName; The internal PDF font name (e.g. 'Helvetica-Bold') - postscript font names are inside the unit: these postscript names could not match the "official" True Type font name, stored as UTF-8 in FTrueTypeFonts property ShortCut: PDFString read FShortCut; The internal PDF shortcut (e.g. 'F3') property Unicode: boolean read fUnicode; Is set to TRUE if the font is dedicated to Unicode Chars TPdfFontWinAnsi = class(TPdfFont) A generic PDF font object, handling at least WinAnsi encoding - TPdfFontTrueType descendent will handle also Unicode chars, for all WideChar which are outside the WinAnsi selection destructor Destroy; override; Release the used memory SynPdf.pas unit - Rev. 1.18 Page 627 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 function GetAnsiCharWidth(const AText: PDFString; APos: integer): integer; override; Retrieve the width of a specified character - implementation of this method expect WinAnsi encoding - return the value contained in fWinAnsiWidth[] by default TPdfFontType1 = class(TPdfFontWinAnsi) An embedded WinAnsi-Encoded standard Type 1 font - handle Helvetica, Courier and Times font by now constructor Create(AXref: TPdfXref; const AName: PDFString; WidthArray: PSmallIntArray); reintroduce; Create a standard font instance, with a given name and char widths - if WidthArray is nil, it will create a fixed-width font of 600 units - WidthArray[0]=Ascent, WidthArray[1]=Descent, WidthArray[2..]=Width(#32..) TPdfFontCIDFontType2 = class(TPdfFont) An embedded Composite CIDFontType2 - i.e. a CIDFont whose glyph descriptions are based on TrueType font technology - typicaly handle Japan or Chinese standard fonts - used with MBCS encoding, not WinAnsi TPdfTTF = class(TObject) Handle Unicode glyph description for a True Type Font - cf http://www.microsoft.com/typography/OTSPEC/otff.htm#otttables - handle Microsoft cmap format 4 encoding (i.e. most used true type fonts on Windows) endCode: PWordArray; End characterCode for each cmap format 4 segment fmt4: ^TCmapFmt4; Character to glyph mapping (cmap) table, in format 4 glyphIndexArray: PWordArray; Glyph index array (arbitrary length) head: ^TCmapHEAD; These are pointers to the usefull data of the True Type Font: Font header hhea: ^TCmapHHEA; Horizontal header idDelta: PSmallIntArray; Delta for all character codes in each cmap format 4 segment idRangeOffset: PWordArray; Offsets into glyphIndexArray or 0 startCode: PWordArray; Start character code for each cmap format 4 segment SynPdf.pas unit - Rev. 1.18 Page 628 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 constructor Create(aUnicodeTTF: TPdfFontTrueType); reintroduce; Create Unicode glyph description for a supplied True Type Font - the HDC of its corresponding document must have selected the font first - this constructor will fill fUsedWide[] and fUsedWideChar of aUnicodeTTF with every available unicode value, and its corresponding glyph and width TPdfFontTrueType = class(TPdfFontWinAnsi) Handle TrueType Font - handle both WinAnsi text and Unicode characters in two separate TPdfFontTrueType instances (since PDF need two separate fonts with diverse encoding) constructor Create(ADoc: TPdfDocument; AFontIndex: integer; AStyle: TFontStyles; const ALogFont: TLogFontW; AWinAnsiFont: TPdfFontTrueType); reintroduce; Create the TrueType font object instance destructor Destroy; override; Release the associated memory and handles function FindOrAddUsedWideChar(aWideChar: WideChar): integer; Mark some unicode char as used - return the index in fUsedWideChar[] and fUsedWide[] - this index is the one just added, or the existing one if the value was found to be already in the fUserWideChar[] array function GetWideCharWidth(aWideChar: WideChar): Integer; Retrieve the width of an unicode character - WinAnsi characters are taken from fWinAnsiWidth[], unicode chars from fUsedWide[].Width property FixedWidth: boolean read fFixedWidth; Is set to TRUE if the font has a fixed width property Style: TFontStyles read fStyle; The associated Font Styles property UnicodeFont: TPdfFontTrueType read fUnicodeFont; Points to the corresponding Unicode font - returns NIL if the Unicode font has not yet been created by the CreateUnicodeFont method - may return SELF if the font is itself the Unicode version property WideCharUsed: Boolean read GetWideCharUsed; Is set to TRUE if the PDF used any true type encoding property WinAnsiFont: TPdfFontTrueType read fWinAnsiFont; Points to the corresponding WinAnsi font - always return a value, whatever it is self SynPdf.pas unit - Rev. 1.18 Page 629 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 TPdfDestination = class(TObject) A destination defines a particular view of a document, consisting of the following: - The page of the document to be displayed - The location of the display window on that page - The zoom factor to use when displaying the page constructor Create(APdfDoc: TPdfDocument); Create the PDF destination object - the current document page is associated with this destination destructor Destroy; override; Release the object function GetValue: TPdfArray; Retrieve the array containing the location of the display window - the properties values which are not used are ignored property Bottom: Integer index 3 read GetElement write SetElement; Retrieve the bottom coordinate of the location of the display window property DestinationType: TPdfDestinationType read FType write FType; Destination Type determines default user space coordinate system of Explicit destinations property Doc: TPdfDocument read FDoc; The associated PDF document which created this Destination object property Left: Integer index 0 read GetElement write SetElement; Retrieve the left coordinate of the location of the display window property Page: TPdfPage read FPage; The associated Page property PageHeight: Integer read GetPageHeight; The page height of the current page - return the corresponding MediaBox value property PageWidth: Integer read GetPageWidth; The page width of the current page - return the corresponding MediaBox value property Reference: TObject read FReference write FReference; An object associated to this destination, to be used for conveniance property Right: Integer index 2 read GetElement write SetElement; Retrieve the righ tcoordinate of the location of the display window property Top: Integer index 1 read GetElement write SetElement; Retrieve the top coordinate of the location of the display window property Zoom: Single read FZoom write SetZoom; The associated Zoom factor - by default, the Zoom factor is 1 SynPdf.pas unit - Rev. 1.18 Page 630 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 TPdfOutlineEntry = class(TPdfDictionaryWrapper) An Outline entry in the PDF document constructor Create(AParent: TPdfOutlineEntry; TopPosition: integer=-1); reintroduce; Create the Outline entry instance - if TopPosition is set, a corresponding destination is created on the current PDF Canvas page, at this Y position destructor Destroy; override; Release the associated memory and reference object function AddChild(TopPosition: integer=-1): TPdfOutlineEntry; Create a new entry in the outline tree - this is the main method to create a new entry property Dest: TPdfDestination read FDest write FDest; The associated destination property Doc: TPdfDocument read FDoc; The associated PDF document which created this Destination object property First: TPdfOutlineEntry read FFirst; The first outline entry of this entry list property Last: TPdfOutlineEntry read FLast; The last outline entry of this entry list property Level: integer read FLevel write FLevel; An internal property (not exported to PDF content) property Next: TPdfOutlineEntry read FNext; The next outline entry of this entry property Opened: boolean read FOpened write FOpened; If the outline must be opened property Parent: TPdfOutlineEntry read FParent; The parent outline entry of this entry property Prev: TPdfOutlineEntry read FPrev; The previous outline entry of this entry property Reference: TObject read FReference write FReference; An object associated to this destination, to be used for conveniance property Title: string read FTitle write FTitle; The associated title - is a generic VCL string, so is Unicode ready SynPdf.pas unit - Rev. 1.18 Page 631 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 TPdfOutlineRoot = class(TPdfOutlineEntry) Root entry for all Outlines of the PDF document - this is a "fake" entry which must be used as parent for all true TPdfOutlineEntry instances, but must not be used as a true outline entry constructor Create(ADoc: TPdfDocument); reintroduce; Create the Root entry for all Outlines of the PDF document procedure Save; override; Update internal parameters (like outline entries count) before saving TPdfPageGDI = class(TPdfPage) A PDF page, with its corresponding Meta File and Canvas destructor Destroy; override; Release associated memory TPdfDocumentGDI = class(TPdfDocument) Class handling PDF document creation using GDI commands - this class allows using a VCL standard Canvas class - handles also PDF creation directly from TMetaFile content constructor Create(AUseOutlines: Boolean=false; ACodePage: integer=0; APDFA1: boolean=false ); Create the PDF document instance, with a VCL Canvas property - see TPdfDocument.Create connstructor for the arguments expectations function AddPage: TPdfPage; override; Add a Page to the current PDF document procedure SaveToStream(AStream: TStream; ForceModDate: TDateTime=0); override; Save the PDF file content into a specified Stream - this overriden method draw first the all VCLCanvas content into the PDF property KerningHScaleBottom: Single read fKerningHScaleBottom write fKerningHScaleBottom; The % limit below which Font Kerning is transformed into PDF Horizontal Scaling commands (when text positioning is tpKerningFromAveragePosition) - set to 99.0 by default property KerningHScaleTop: Single read fKerningHScaleTop write fKerningHScaleTop; The % limit over which Font Kerning is transformed into PDF Horizontal Scaling commands (when text positioning is tpKerningFromAveragePosition) - set to 101.0 by default SynPdf.pas unit - Rev. 1.18 Page 632 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 property UseMetaFileTextPositioning: TPdfCanvasRenderMetaFileTextPositioning read fUseMetaFileTextPositioning write fUseMetaFileTextPositioning; Defines how TMetaFile text positioning is rendered - default is tpSetTextJustification - tpSetTextJustification if content used SetTextJustification() API calls - tpExactTextCharacterPositining for exact font kerning, but resulting in bigger pdf size - tpKerningFromAveragePosition will compute average pdf Horizontal Scaling in association with KerningHScaleBottom/KerningHScaleTop properties - replace deprecated property UseSetTextJustification property VCLCanvas: TCanvas read GetVCLCanvas; The VCL Canvas of the current page property VCLCanvasSize: TSize read GetVCLCanvasSize; The VCL Canvas size of the current page - usefull to calculate coordinates for the current page - filled with (0,0) before first call to VCLCanvas property TPdfImage = class(TPdfXObject) Generic image object - is either bitmap encoded or jpeg encoded constructor Create(aDoc: TPdfDocument; aImage: TGraphic; DontAddToFXref: boolean); reintroduce; Create the image from a supplied VCL TGraphic instance - handle TBitmap and SynGdiPlus picture types, i.e. TJpegImage (stored as jpeg), and TGifImage/TPngImage (stored as bitmap) - use TPdfForm to handle TMetafile in vectorial format - an optional DontAddToFXref is available, if you don't want to add this object to the main XRef list of the PDF file constructor CreateJpegDirect(aDoc: TPdfDocument; aJpegFile: TMemoryStream; DontAddToFXref: boolean=true); reintroduce; overload; Create an image from a supplied JPEG content - an optional DontAddToFXref is available, if you don't want to add this object to the main XRef list of the PDF file constructor CreateJpegDirect(aDoc: TPdfDocument; const aJpegFileName: TFileName; DontAddToFXref: boolean=true); reintroduce; overload; Create an image from a supplied JPEG file name - will raise an EFOpenError exception if the file doesn't exist - an optional DontAddToFXref is available, if you don't want to add this object to the main XRef list of the PDF file property PixelHeight: Integer read fPixelHeight; Height of the image, in pixels units property PixelWidth: Integer read fPixelWidth; Width of the image, in pixels units SynPdf.pas unit - Rev. 1.18 Page 633 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 TPdfForm = class(TPdfXObject) Handle any form XObject - A form XObject (see Section 4.9, of PDF reference 1.3) is a self-contained description of an arbitrary sequence of graphics objects, defined as a PDF content stream constructor Create(aDoc: TPdfDocumentGDI; aMetaFile: TMetafile); reintroduce; Create a form XObject from a supplied TMetaFile TScriptState = packed record An UniScribe script state - uBidiLevel: Unicode Bidi algorithm embedding level (0..16) - fFlags: Script state flags TScriptAnalysis = packed record An Uniscribe script analysis - eScript: Shaping engine - fFlags: Script analysis flags - s: Script state TScriptItem = packed record A Uniscribe script item, after analysis of a unicode text a: TScriptAnalysis; Corresponding Uniscribe script analysis iCharPos: Integer; Logical offset to first character in this item TScriptProperties = packed record Contains information about Uniscribe special processing for each script fFlags: TScriptProperties_set; Set of possible Uniscribe processing properties for a given language langid: Word; Primary and sublanguage associated with script TScriptVisAttr = packed record Contains the visual (glyph) attributes that identify clusters and justification points, as generated by ScriptShape - uJustification: Justification class - fFlags: Uniscribe visual (glyph) attributes - fShapeReserved: Reserved for use by shaping engines Types implemented in the SynPdf unit: PDFString = AnsiString; The PDF library use internaly AnsiString text encoding SynPdf.pas unit - Rev. 1.18 Page 634 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 - the corresponding charset is the current system charset, or the one supplied as a parameter to TPdfDocument.Create TCmapSubTableArray = packed array[byte] of packed record platformID: word; platformSpecificID: word; offset: Cardinal; end; Points to every 'cmap' encoding subtables TGradientDirection = ( gdHorizontal, gdVertical ); PDF gradient direction TLineCapStyle = ( lcButt_End, lcRound_End, lcProjectingSquareEnd ); Line cap style specifies the shape to be used at the ends of open subpaths when they are stroked TLineJoinStyle = ( ljMiterJoin, ljRoundJoin, ljBevelJoin ); The line join style specifies the shape to be used at the corners of paths that are stroked TPdfAlignment = ( paLeftJustify, paRightJustify, paCenter ); PDF text paragraph alignment TPdfAnnotationSubType = ( asTextNotes, asLink ); The annotation types determines the valid annotation subtype of TPdfDoc TPdfCanvasRenderMetaFileTextPositioning = ( tpKerningFromAveragePosition, tpSetTextJustification, tpExactTextCharacterPositining ); Is used to define how TMetaFile text positioning is rendered - tpSetTextJustification will handle efficiently the fact that TMetaFileCanvas used SetTextJustification() API calls to justify text: it will converted to SetWordSpace() pdf rendering - tpExactTextCharacterPositining will use the individual glyph positioning information as specified within the TMetaFile content: resulting pdf size will be bigger, but font kerning will be rendered as expected - tpKerningFromAveragePosition will use global font kerning via SetHorizontalScaling() pdf rendering TPdfColor = -$7FFFFFFF-1..$7FFFFFFF; The available PDF color range TPdfCompressionMethod = ( cmNone, cmFlateDecode ); Define if streams must be compressed TPdfDate = PDFString; A PDF date, encoded as 'D:20100414113241' TPdfDestinationType = ( dtXYZ, dtFit, dtFitH, dtFitV, dtFitR, dtFitB, dtFitBH, dtFitBV ); Destination Type determines default user space coordinate system of Explicit destinations TPdfGDIComment = ( pgcOutline, pgcBookmark, pgcLink ); Defines the data stored inside a EMR_GDICOMMENT message - pgcOutline can be used to add an outline at the current position (i.e. the last Y parameter of a Move): the text is the associated title, UTF-8 encoded and the outline tree is created from the number of leading spaces in the title - pgcBookmark will create a destination at the current position (i.e. the last Y parameter of a Move), with some text supplied as bookmark name - pgcLink will create a asLink annotation, expecting the data to be filled with TRect inclusive-inclusive bounding rectangle coordinates, followed by the corresponding bookmark name SynPdf.pas unit - Rev. 1.18 Page 635 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 - use the GDIComment*() functions to append the corresponding EMR_GDICOMMENT message to a metafile content TPdfImageHash = array[0..3] of cardinal; Array used to store a TPdfImage hash - uses 4 hash codes, created with 4 diverse algorithms, in order to avoid false positives TPdfObjectType = ( otDirectObject, otIndirectObject, otVirtualObject ); Allowed types for PDF objects (i.e. TPdfObject) TPdfPageLayout = ( plSinglePage, plOneColumn, plTwoColumnLeft, plTwoColumnRight ); The page layout to be used when the document is opened TPdfPageMode = ( pmUseNone, pmUseOutlines, pmUseThumbs, pmFullScreen ); Page mode determines how the document should appear when opened TPDFPaperSize = ( psA4, psA5, psA3, psLetter, psLegal, psUserDefined ); Available known paper size (psA4 is the default on TPdfDocument creation) TPdfViewerPreference = ( vpHideToolbar, vpHideMenubar, vpHideWindowUI, vpFitWindow, vpCenterWindow ); Viewer preferences specifying how the reader User Interface must start TPdfViewerPreferences = set of TPdfViewerPreference; Set of Viewer preferences TPScriptPropertiesArray = array[byte] of PScriptProperties; An array of Uniscribe processing information TScriptAnalysis_enum = ( s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, fRTL, fLayoutRTL, fLinkBefore, fLinkAfter, fLogicalOrder, fNoGlyphIndex ); Uniscribe script analysis flag elements - s0,s1,s2,s3,s4,s5,s6,s7,s8,s9: map TScriptAnalysis.eScript - fRTL: Rendering direction - fLayoutRTL: Set for GCP classes ARABIC/HEBREW and LOCALNUMBER - fLinkBefore: Implies there was a ZWJ before this item - fLinkAfter: Implies there is a ZWJ following this item. - fLogicalOrder: Set by client as input to ScriptShape/Place - fNoGlyphIndex: Generated by ScriptShape/Place - this item does not use glyph indices TScriptAnalysis_set = set of TScriptAnalysis_enum; A set of Uniscribe script analysis flags TScriptProperties_enum = ( fNumeric, fComplex, fNeedsWordBreaking, fNeedsCaretInfo, bCharSet0, bCharSet1, bCharSet2, bCharSet3, bCharSet4, bCharSet5, bCharSet6, bCharSet7, fControl, fPrivateUseArea, fNeedsCharacterJustify, fInvalidGlyph, fInvalidLogAttr, fCDM, fAmbiguousCharSet, fClusterSizeVaries, fRejectInvalid ); All possible Uniscribe processing properties of a given language - fNumeric: if a script contains only digits - fComplex: Script requires special shaping or layout - fNeedsWordBreaking: Requires ScriptBreak for word breaking information SynPdf.pas unit - Rev. 1.18 Page 636 of 1055 fInhibitSymSwap. cleared by U+206C (IAFS) .r1.. The text rendering mode determines whether text is stroked. end.fNeedsCaretInfo: Requires caret restriction to cluster boundaries .fClusterSizeVaries: Measured cluster width depends on adjacent clusters . trFillClipping. a2.fDigitSubstitute: Set by U+206E (NADS).uBidiLevel . r4. 1.fCDM: Contains Combining Diacritical Marks . trClipping ). bCharSet7: Charset to use when creating font .18 Page 637 of 1055 .fControl: Contains only control characters .fGcpClusters: For Generating Backward Compatible GCP Clusters (legacy Apps) TScriptState_set = set of TScriptState_enum. fClusterStart. ZWJ. fDisplayZWG.fZeroWidth: Blank.fRejectInvalid: Invalid combinations should be rejected TScriptProperties_set = set of TScriptProperties_enum. Set of Uniscribe visual (glyph) attributes TTextRenderingMode = ( trFill. fGcpClusters ). a3.fInvalidGlyph: Invalid combinations generate glyph wgInvalid in the glyph buffer . no Unicode control characters yet . 1: ( Int: integer.fArabicNumContext: For EN->AN Unicode rule . ZWNJ etc. UniScribe script state flag elements .pas unit . r3.Synopse mORMot Framework Software Architecture Design 1.r4: map TScriptState.fNeedsCharacterJustify: Requires inter-character justification . fOverrideDirection.fInhibitLigate: Equiv !GCP_Ligate.fCharShape: Set by U+206D (AAFS). or used as a clipping path TUsedWide = array of packed record case byte of 0: ( Width: word. fCharShape.Rev. with no width .fAmbiguousCharSet: Script does not correspond 1//:1 with a charset .18 Date: June 16.r2. trFillStrokeClipping.. r2.fInhibitSymSwap: Set by U+206A (ISS).fDiacritic: Diacritic . ). fDiacritic.r3. trInvisible. 2013 .r0. fInhibitLigate. Glyph: word. fZeroWidth.fInvalidLogAttr: Invalid combinations are marked by fInvalid in the logical attributes . fReserved ). filled. r1.fReserved: General reserved bit TScriptVisAttr_set = set of TScriptVisAttr_enum. cleared by U+206F (NODS) . trStrokeClipping. trFillThenStroke. Uniscribe visual (glyph) attributes .fPrivateUseArea: This item is from the Unicode range U+E000 through U+F8FF . trStroke. A set of UniScribe script state flags TScriptVisAttr_enum = ( a0.bCharSet0 . This dynamic array stores details about used unicode characters SynPdf.a0 . no Unicode control chars yet . Set of possible Uniscribe processing properties of a given language TScriptState_enum = ( r0. cleared by U+206B (ASS) . a3: map the Justification class number . fArabicNumContext.fClusterStart: First glyph of representation of cluster .fOverrideDirection: Set when in LRO/RLO embedding . ). fDigitSubstitute.fDisplayZWG: Equiv GCP_DisplayZWG. a1. pas unit .Text := MSWINDOWS_DEFAULT_FONTS. Error returned by Uniscribe when the current selected font does not contain sufficient glyphs or shaping tables Functions or procedures implemented in the SynPdf unit: Functions or procedures Description Page CurrentPrinterPaperSi ze Retrieve the paper size used by the current selected printer 639 CurrentPrinterRes Retrieve the current printer resolution 639 GDICommentBookmark Append a EMR_GDICOMMENT message for handling PDF bookmarks 639 GDICommentLink Append a EMR_GDICOMMENT message for creating a Link into a specified bookmark 639 GDICommentOutline Append a EMR_GDICOMMENT message for handling PDF outline 640 SynPdf.every used unicode character has its own width and glyph index in the true type font content TXObjectID = integer.Rev. and save some KB.g. 2013 . The Carriage Return and Line Feed values used in the PDF file generation .g. the root entry PDF_IN_USE_ENTRY = 'n'. List of common fonts available by default since Windows 2000 .note that this is usefull only if the EmbeddedTTF property was set to TRUE PDF_FREE_ENTRY = 'f'. 1. Used for an unused (free) xref entry. just use the EmbeddedTTFIgnore property of TPdfDocument/TPdfDocumentGDI: PdfDocument.g. . e. Numerical ID for every XObject Constants implemented in the SynPdf unit: CRLF = #10.18 Page 638 of 1055 .EmbeddedTTFIgnore. for the root xref entry USP_E_SCRIPT_NOT_IN_FONT = HRESULT((SEVERITY_ERROR shl 31) or (FACILITY_ITF shl 16)) or $200. only Line Feed) is enough for the PDF standard.18 Date: June 16. Used e.Synopse mORMot Framework Software Architecture Design 1. and will create somewhat smaller PDF files LF = #10. but #10 (e.to not embedd these fonts in the PDF document. Used for an used xref entry PDF_MAX_GENERATION_NUM = 65535.expect #13 and #10 under Windows. The Line Feed value MSWINDOWS_DEFAULT_FONTS: RawUTF8 = 'Arial'#13#10'Courier New'#13#10'Georgia'#13#10+ 'Impact'#13#10'Lucida Console'#13#10'Roman'#13#10'Symbol'#13#10+ 'Tahoma'#13#10'Times New Roman'#13#10'Trebuchet'#13#10+ 'Verdana'#13#10'WingDings'. 2013 Functions or procedures Description Page L2R Reverse char orders for every hebrew and arabic words 640 PdfBox Wrapper to create a temporary PDF box 640 PdfCoord Convert some milli meters dimension to internal PDF twips value 640 PdfRect Wrapper to create a temporary PDF coordinates rectangle 640 PdfRect Wrapper to create a temporary PDF coordinates rectangle 640 RawUTF8ToPDFString Convert a specified UTF-8 content into a PDFString value 640 ScriptGetProperties Uniscribe function to retrieve information about the current scripts 640 ScriptItemize Uniscribe function to break a Unicode string into individually shapeable items 640 ScriptLayout Uniscribe function to convert an array of run embedding levels to a map of visual-to-logical position and/or logical-to-visual position 641 ScriptShape Uniscribe function to generate glyphs and visual attributes for an Unicode run 641 _DateTimeToPdfDate Convert a date. with some text supplied as bookmark name procedure GDICommentLink(MetaHandle: HDC. into PDF string format.will create a PDF destination at the current position (i. Retrieve the current printer resolution procedure GDICommentBookmark(MetaHandle: HDC. i. Retrieve the paper size used by the current selected printer function CurrentPrinterRes: TPoint. const aBookmarkName: RawUTF8).e. Append a EMR_GDICOMMENT message for handling PDF bookmarks .Synopse mORMot Framework Software Architecture Design 1. 1. encoded as 'D:20100414113241' 641 function CurrentPrinterPaperSize: TPDFPaperSize.pas unit . const aBookmarkName: RawUTF8. the last Y parameter of a Move). Append a EMR_GDICOMMENT message for creating a Link into a specified bookmark SynPdf.e.18 Page 639 of 1055 .18 Date: June 16. const aRect: TRect). as 'D:20100414113241' 641 _GetCharCount Return the number of glyphs in the supplied text 641 _HasMultiByteString This function returns TRUE if the supplied text contain any MBCS character 641 _PdfDateToDateTime Decode PDF date.Rev. pwcInChars: Pointer to a Unicode string to itemize. . Uniscribe function to break a Unicode string into individually shapeable items . Alternatively. L: integer).iCharPos. Append a EMR_GDICOMMENT message for handling PDF outline . cInChars: Integer. Wrapper to create a temporary PDF coordinates rectangle function RawUTF8ToPDFString(const Value: RawUTF8): PDFString.pItems: Pointer to a buffer in which the function retrieves SCRIPT_ITEM structures representing the items that have been processed. . out piNumScripts: Integer): HRESULT.pItems[i]. const psState: pointer. Top.iCharPos . Convert some milli meters dimension to internal PDF twips value function PdfRect(Left.cMaxItems: Maximum number of SCRIPT_ITEM structures defining items to process. the last Y parameter of a Move): the text is the associated title. Pointer to a SCRIPT_STATE structure indicating the initial bidirectional algorithm state.psState: Optional. The valid range for this value is 0 through piNumScripts-1.Rev. overload.pas unit . Alternatively. Convert a specified UTF-8 content into a PDFString value function ScriptGetProperties(out ppSp: PScriptPropertiesArray. external Usp10. Wrapper to create a temporary PDF box function PdfCoord(MM: single): integer. Height: Single): TPdfBox.piNumScripts: Pointer to the number of scripts. const psControl: pointer. Width. Wrapper to create a temporary PDF coordinates rectangle function PdfRect(const Box: TPdfBox): TPdfRect. The function always adds a terminal item to the item analysis array so that the length of the item with zero-based index "i" is always available as: pItems[i+1].psControl: Optional.e. Reverse char orders for every hebrew and arabic words . 2013 procedure GDICommentOutline(MetaHandle: HDC. pItems: PScriptItem. .Synopse mORMot Framework Software Architecture Design 1. stdcall. .ppSp: Pointer to an array of pointers to SCRIPT_PROPERTIES structures indexed by script. UTF-8 encoded and the outline tree is created from the specified numerical level (0=root) procedure L2R(W: PWideChar.used to add an outline at the current position (i.cInChars: Number of characters in pwcInChars to itemize. Pointer to a SCRIPT_CONTROL structure indicating the type of itemization to perform. The buffer should be cMaxItems*sizeof(SCRIPT_ITEM) + 1 bytes in length. var pcItems: Integer): HRESULT.18 Page 640 of 1055 . . 1. Right. . overload. Uniscribe function to retrieve information about the current scripts . aLevel: Integer). Top. const aTitle: RawUTF8. cMaxItems: Integer. external Usp10.just reverse all the chars in the supplied buffer function PdfBox(Left. function ScriptItemize( const pwcInChars: PWideChar. the application can set this parameter to NULL if no SCRIPT_CONTROL properties are needed. Bottom: Single): TPdfRect. the application can set this parameter to NULL if the script state is not needed. It is invalid to call this function with a buffer to hold less than two SCRIPT_ITEM structures.pcItems: Pointer to the number of SCRIPT_ITEM structures processed SynPdf. stdcall.18 Date: June 16. . Decode PDF date. encoded as 'D:20100414113241' SynPdf. var pcGlyphs: Integer): HRESULT. stdcall. into PDF string format.. psva: PScriptVisAttr.e.work with MBCS strings function _HasMultiByteString(Value: PAnsiChar): boolean. external Usp10. function _PdfDateToDateTime(const AText: TPdfDate): TDateTime. cMaxGlyphs: Integer.typical call must check first if MBCS is currently enabled if SysLocale.piVisualToLogical: List of run indices in visual order . pwOutGlyphs: PWord.18 Page 641 of 1055 ..cChars: Length of unicode run .pas unit . This function returns TRUE if the supplied text contain any MBCS character .FarEast and _HasMultiByteString(pointer(Text)) then .piLogicalToVisual: List of visual run positions function ScriptShape(hdc: HDC.Rev.psa: Result of ScriptItemize (may have fNoGlyphIndex set) . const pbLevel: PByte.hdc: Optional (see under caching) .pwLogClust: Logical clusters . const pwcChars: PWideChar.cRuns: Number of runs to process . piLogicalToVisual: PInteger): HRESULT. 2013 function ScriptLayout(cRuns: Integer.pbLevel: Array of run embedding levels . external Usp10.pwOutGlyphs: Output glyph buffer .pcGlyphs: Count of glyphs generated function _DateTimeToPdfDate(ADate: TDateTime): TPdfDate. pwLogClust: PWord. piVisualToLogical: PInteger.cMaxGlyphs: Max glyphs to generate .18 Date: June 16. cChars: Integer.pwcChars: Logical unicode run . Uniscribe function to convert an array of run embedding levels to a map of visual-to-logical position and/or logical-to-visual position . i. 1.psc: Uniscribe font metric cache handle . Return the number of glyphs in the supplied text . stdcall.Synopse mORMot Framework Software Architecture Design 1.psva: Visual glyph attributes . psa: PScriptAnalysis. Uniscribe function to generate glyphs and visual attributes for an Unicode run . Convert a date. var psc: pointer. as 'D:20100414113241' function _GetCharCount(Text: PAnsiChar): integer. version 1.this unit is a part of the freeware Synopse mORMot framework.this unit is a part of the freeware Synopse framework.this unit is a part of the freeware Synopse mORMot framework.licensed under a MPL/GPL/LGPL tri-license.18 The SynSelfTests unit is quoted in the following items: SWRS # Description Page DI-2. shall be tested using Unitary testing 1053 Units used in the SynSelfTests unit: Unit Name Description Page SynCommons Common functions used by most Synopse projects .2.optimized for speed (tuned assembler and VIA PADLOCK optional support) .this unit is a part of the freeware Synopse mORMot framework. SynSelfTests. MD5.18 600 SynSQLite3 SQLite3 Database engine direct access . version 1. licensed under a MPL/GPL/LGPL tri-license.18 Page 642 of 1055 .this unit is a part of the freeware Synopse framework. version 1.pas unit . version 1.this unit is a part of the freeware Synopse mORMot framework. SHA256 algorithms . 1.licensed under a MPL/GPL/LGPL tri-license.Synopse mORMot Framework Software Architecture Design 1.2 The framework libraries. licensed under a MPL/GPL/LGPL tri-license. version 1. licensed under a MPL/GPL/LGPL tri-license. version 1. version 1.18 584 SynLZO Fast LZO Compression routines .18 497 SynDB Abstract database direct access classes .this unit is a part of the freeware Synopse mORMot framework. version 1. version 1.18 509 SynDBSQLite3 SQLite3 direct access classes to be used with our SynDB architecture . 2013 23. licensed under a MPL/GPL/LGPL tri-license. licensed under a MPL/GPL/LGPL tri-license. licensed under a MPL/GPL/LGPL tri-license. licensed under a MPL/GPL/LGPL tri-license.18 325 SynCrtSock Classes implementing HTTP/1.this unit is a part of the freeware Synopse framework. SHA1.1 client and server protocol . ADLER32. version 1.18 479 SynCrypto Fast cryptographic routines (hashing and cypher) . including all its SQLite3 related features.17.18 647 SynSelfTests.18 564 SynLZ SynLZ Compression routines . licensed under a MPL/GPL/LGPL tri-license. XOR.implements AES.Rev.13 586 SynPdf PDF file generation .18 Date: June 16.pas unit Purpose: Automated tests for common units of the Synopse mORMot Framework . this unit is a part of the freeware Synopse framework.18 707 TTestSynopsePDF TTestLowLevelTypes TSynTestCase TTestLowLevelCommon TTestCryptographicRoutines TTestCompression SynSelfTests class hierarchy Objects implemented in the SynSelfTests unit: Objects Description Page TTestCompression This test case will test most functions.18 Page 643 of 1055 . 2013 Unit Name Description Page SynSQLite3Static SQLite3 Database engine . classes and types defined and implemented in the SynCommons unit Used for DI-2. 1.this unit is a part of the freeware Synopse mORMot framework. classes and types defined and implemented in the mORMot. licensed under a MPL/GPL/LGPL tri-license.18 Date: June 16.pas unit 645 TTestSynopsePDF This test case will test most functions.Synopse mORMot Framework Software Architecture Design 1.18 696 SynZip Low-level access to ZLib compression (1. version 1. The low-level bit management functions SynSelfTests.pas unit .2. classes and types defined and implemented in the SynCrypto unit 645 TTestLowLevelCommon This test case will test most functions. procedure Bits. classes and types defined and implemented in the SynPDF unit 646 TTestLowLevelCommon = class(TSynTestCase) This test case will test most functions. classes and types defined and implemented in the SynZip unit 645 TTestCryptographicRou tines This test case will test most functions. licensed under a MPL/GPL/LGPL tri-license.obj for Windows 32 bit .2 (page 1053).statically linked .Rev. version 1.5 engine version) .2. classes and types defined and implemented in the SynCommons unit 643 TTestLowLevelTypes This test case will test most low-level functions. e. Low level fast Integer or Floating-Point to/from string conversion .000 items to test speed procedure _TSynCache. Test the TSynCache class SynSelfTests. 1. The camel-case / camel-uncase features.especially the RawUTF8 or PUTF8Char relative versions procedure Soundex.pas unit . The new fast Currency to/from string conversion procedure FastStringCompare. Test IsMatch() function procedure _TDynArray. The faster CopyRecord function.18 Date: June 16.pas unit procedure Unicode_UTF8. The ISO-8601 date and time encoding . through RawUnicode) procedure UrlDecoding. used for i18n from Delphi RTII procedure _IdemPropName.test especially the conversion to/from text procedure MimeTypes. Test StrIComp() and AnsiIComp() functions procedure IniFiles.18 Page 644 of 1055 . enhancing the system. Test mime types recognition procedure NumericalConversions. Test UrlEncode() and UrlDecode() functions .Rev.Synopse mORMot Framework Software Architecture Design 1. The Soundex search feature (i. TSynSoundex and all related functions) procedure SystemCopyRecord. Test UrlEncode() and UrlDecode() functions procedure _CamelCase. Test the TDynArray object and methods procedure _TDynArrayHashed. Test the TDynArrayHashed object and methods (dictionary features) . 2013 procedure Curr64. The fast . Test UTF-8 and Win-Ansi conversion (from or to.this test will create an array of 200. Test IdemPropName() and IdemPropNameU() functions procedure _IsMatch.ini file content direct access procedure Iso8601DateAndTime.this method use some ISO-8601 encoded dates and times for the testing procedure UrlEncoding. zip archive handling procedure _SynLZ.18 Page 645 of 1055 . 2013 procedure _TSynFilter. procedure EncodeDecodeJSON.2 (page 1053). . Low-level TSynValidate classes TTestLowLevelTypes = class(TSynTestCase) This test case will test most low-level functions. classes and types defined and implemented in the SynZip unit procedure GZipFormat. Test TSynTable class and TSynTableVariantType new variant type procedure _TSynValidate.2. SynLZ internal format procedure _SynLZO.pas unit .18 Date: June 16.gzip archive handling procedure InMemoryCompression. Adler32 hashing functions SynSelfTests. Direct LZ77 deflate/inflate functions procedure ZipFormat. 1.Synopse mORMot Framework Software Architecture Design 1. .pas unit Used for DI-2. Some low-level Url encoding from parameters TTestCompression = class(TSynTestCase) This test case will test most functions. Some low-level JSON encoding/decoding procedure UrlEncoding.Rev. classes and types defined and implemented in the SynCrypto unit procedure Adler32. SynLZO internal format TTestCryptographicRoutines = class(TSynTestCase) This test case will test most functions. Low-level TSynFilter classes procedure _TSynLogFile. classes and types defined and implemented in the mORMot. Low-level TSynLogFile class procedure _TSynTable. 18 Date: June 16.pas unit . AES encryption/decryption functions procedure _MD5. 2013 procedure Base64. with data from NIST) SynSelfTests. Base-64 encoding/decoding functions procedure _AES256.validates the EMF/TMetaFile enumeration. Create a PDF document. if you want to check out the result (it's simply a curve drawing. MD5 hashing functions procedure _RC4. using the PDF Canvas property . SHA-256 hashing functions TTestSynopsePDF = class(TSynTestCase) This test case will test most functions.this method will produce a . especially standard font substitution procedure _TPdfDocumentGDI. classes and types defined and implemented in the SynPDF unit procedure _TPdfDocument.18 Page 646 of 1055 . 1. using a EMF content .Synopse mORMot Framework Software Architecture Design 1.pdf file in the executable directory. Create a PDF document. RC4 encryption function procedure _SHA1.Rev.test font handling. and its conversion into the PDF content . SHA-1 hashing functions procedure _SHA256. Rev.pas unit Purpose: SQLite3 Database engine direct access . version 1. licensed under a MPL/GPL/LGPL tri-license.18 Date: June 16.18 Page 647 of 1055 .18 325 ESynException ESQLite3Exception TSQLStatementCached TSQLRequest TObject TSQLite3Library TSQLite3LibraryDynamic TSQLDataBaseSQLFunction TSQLDataBaseSQLFunctionDynArray TSQLDataBase TStream TSQLBlobStream SynSQLite3 class hierarchy Objects implemented in the SynSQLite3 unit: Objects Description Page ESQLite3Exception Custom SQLite3 dedicated Exception type 672 TFTSMatchInfo Map the matchinfo function returned BLOB value 648 TSQLBlobStream Used to read or write a BLOB Incrementaly 685 TSQLDataBase Simple wrapper for direct SQLite3 database manipulation 679 SynSQLite3.18.this unit is a part of the freeware Synopse mORMot framework. 2013 23. version 1.18 The SynSQLite3 unit is quoted in the following items: SWRS # Description Page DI-2.Synopse mORMot Framework Software Architecture Design 1.1 The SQLite3 engine shall be embedded to the framework 1052 Units used in the SynSQLite3 unit: Unit Name Description Page SynCommons Common functions used by most Synopse projects .pas unit . licensed under a MPL/GPL/LGPL tri-license. 1.2.this unit is a part of the freeware Synopse mORMot framework. SynSQLite3. 652 TSQLite3VTab Virtual Table Instance Object 651 TSQLite3VTabCursor Virtual Table Cursor Object 652 TSQLRequest Wrapper to a SQLite3 request 672 TSQLStatementCache Used to retrieve a prepared statement 677 TSQLStatementCached Handle a cache of prepared statements 678 TFTSMatchInfo = record Map the matchinfo function returned BLOB value .Rev.e.i.used for the FTS3/FTS4 ranking of results by TSQLRest. the default 'pcx' layout. one item per column 649 TSQLite3Library Wrapper around all SQLite3 library API calls 659 TSQLite3LibraryDynami c Allow access to an exernal SQLite3 library engine 671 TSQLite3Module Defines a module object used to implement a virtual table.18 Page 648 of 1055 .see http://www.html#matchinfo .sqlite. 1. for both FTS3 and FTS4 .org/fts3.org/fts3.pas unit .Synopse mORMot Framework Software Architecture Design 1.FTSMatch method and the internal RANK() function as proposed in http://www. 2013 Objects Description Page TSQLDataBaseSQLFuncti on Those classes can be used to define custom SQL functions inside a TSQLDataBase 678 TSQLDataBaseSQLFuncti onDynArray To be used to define custom SQL functions for dynamic arrays BLOB search 679 TSQLite3IndexConstrai nt Records WHERE clause constraints of the form "column OP expr" 649 TSQLite3IndexConstrai ntUsage Define what information is to be passed to xFilter() for a given WHERE clause constraint of the form "column OP expr" 650 TSQLite3IndexInfo Structure used as part of the virtual table interface to pass information into and receive the reply from the xBestIndex() method of a virtual table module 650 TSQLite3IndexOrderBy ORDER BY clause.html#appendix_a SynSQLite3.sqlite.18 Date: June 16. pas unit . iTermOffset: Integer.Synopse mORMot Framework Software Architecture Design 1.Rev. <. Column on left-hand side of constraint . True if this constraint is usable .18 Date: June 16. if the WHERE clause contained a term like this: a = 5 Then one of the constraints would be on the "a" column with operator "=" and an expression of "5" . >. and just ignore contraints with usable set to false TSQLite3IndexOrderBy = record ORDER BY clause. Column number .Hidden columns are counted when determining the column index. 2013 TSQLite3IndexConstraint = record Records WHERE clause constraints of the form "column OP expr" .OP is =. for example. OP is an operator like "=" or "<". or >= using one of the SQLITE_INDEX_CONSTRAINT_* values usable: boolean. SynSQLite3. if the WHERE clause contained something like this: x BETWEEN 10 AND 100 AND 999>y The query optimizer might translate this into three separate constraints: x >= 10 x <= 100 y < 999 iColumn: Integer. True for DESC. The xBestIndex method must therefore only consider constraints that have a usable flag which is true.xBestIndex() should ignore this field op: byte. Used internally . Constraint operator . iColumn: Integer.The ROWID of the virtual table is column -1 . 1.The first column of the virtual table is column 0 .18 Page 649 of 1055 .The aConstraint[] array contains information about all constraints that apply to the virtual table.For example.So.The first column of the virtual table is column 0 . <=. But some of the constraints might not be usable because of the way tables are ordered in a join.Where "column" is a column in the virtual table.The ROWID of the virtual table is column -1 . False for ASC. and EXPR is an arbitrary expression . one item per column desc: boolean.Hidden columns are counted when determining the column index. . 2013 TSQLite3IndexConstraintUsage = record Define what information is to be passed to xFilter() for a given WHERE clause constraint of the form "column OP expr" argvIndex: Integer. then when xFilter() is called. if the aConstraint[3].Synopse mORMot Framework Software Architecture Design 1. and so forth up to as many or as few as the xBestIndex() method wants. If omit is true. The information in idxNum and idxStr is arbitrary as far as the SQLite core is concerned.Outputs fields will be passed as parameter to the xFilter() method. xBestIndex() method fills the idxNum and idxStr fields with information that communicates an indexing strategy to the xFilter method. then the constraint is assumed to be fully handled by the virtual table and is not checked again by SQLite .has the same number of items than the aConstraint[] array .Rev.pas unit . another to 3.argvIndex to have the corresponding argument in xFilter() argc/argv[] expression list aOrderBy: PSQLite3IndexOrderByArray. The SQLite core just copies the information through to the xFilter() method.For example. Input: List of ORDER BY clause. xBestFilter() method can suppress that double-check by setting this field TSQLite3IndexInfo = record Structure used as part of the virtual table interface to pass information into and receive the reply from the xBestIndex() method of a virtual table module . and will be initialized to zero by SQLite . the argv[0] passed to xFilter will have the EXPR value of the aConstraint[3] constraint. another to 2. 1.18 Date: June 16.argvIndex is set to 1.18 Page 650 of 1055 .Exactly one entry should be set to 1. Output: filled by xBestIndex() method with information about what parameters to pass to xFilter() method .For instance. the SQLite core double checks all constraints on each row of the virtual table that it receives. aConstraint: PSQLite3IndexConstraintArray. Input: List of WHERE clause constraints of the form "column OP expr" aConstraintUsage: PSQLite3IndexConstraintUsageArray.By default. Use the SetInfo() method of this object in order to make a temporary copy of any needed data. omit: boolean. Any desired meaning can be assigned to idxNum and idxStr as long as xBestIndex() and xFilter() agree on what that meaning is.should set the aConstraintUsage[]. If argvIndex>0 then the right-hand side of the corresponding aConstraint[] is evaluated and becomes the argvIndex-th entry in argv . If such a check is redundant. one per column SynSQLite3.The EXPR of the corresponding constraints will then be passed in as the argv[] parameters to xFilter() . 18 Page 651 of 1055 . This structure therefore contains a pInstance field.Synopse mORMot Framework Software Architecture Design 1.may contain any variable-length data or class/record content. then choose the query plan that gives the lowest estimate idxNum: Integer. 1.pas unit . which will be used to store a class instance handling the virtual table as a pure Delphi class: the TSQLVirtualTableModule class will use it internaly nRef: Integer. as necessary nConstraint: Integer.malloc() . will indicate to the SQLite core that it will need to do a separate sorting pass over the data after it comes out of the virtual table TSQLite3VTab = record Virtual Table Instance Object . The purpose of this superclass is to define certain fields that are common to all module implementations. Input: Number of entries in aConstraint array needToFreeIdxStr: Integer.The SQLite core will often call xBestIndex() multiple times with different constraints. Output: Estimated cost of using this index . if the virtual table will output rows in the order specified by the ORDER BY clause .Each subclass will be tailored to the specific needs of the module implementation.e.Rev.Should be set to the estimated number of disk access operations required to execute this query against the virtual table .Every virtual table module implementation uses a subclass of this object to describe a particular instance of the virtual table. The module for this virtual table SynSQLite3. Input: Number of terms in the aOrderBy array orderByConsumed: Integer. This will be used to store a Delphi class instance handling the Virtual Table pModule: PSQLite3Module. 2013 estimatedCost: Double. obtain multiple cost estimates.free() if true (=1) nOrderBy: Integer. possibly obtained from sqlite3. No longer used pInstance: TObject. Output: True (=1) if output is already ordered . .i.if False (=0). Output: Number used to identify the index idxStr: PAnsiChar. Output: String.18 Date: June 16. Output: Free idxStr using sqlite3. TSQLite3VTabCursor = record Virtual Table Cursor Object . or inserting rows.Every virtual table module implementation uses a subclass of the following structure to describe cursors that point into the virtual table and are used to loop through the virtual table.Synopse mORMot Framework Software Architecture Design 1.free() prior to assigning a new string to zErrMsg. but in future releases of SQLite the module structure definition might be extended with additional methods and in that case the iVersion value will be increased SynSQLite3. Virtual table of this cursor TSQLite3Module = record Defines a module object used to implement a virtual table. xColumn. updating.Cursors are created using the xOpen method of the module and are destroyed by the xClose method.18 Page 652 of 1055 . one might have a module that provides read-only access to comma-separated-value (CSV) files on disk. handled iVersion is 2.Each module implementation will define the content of a cursor structure to suit its own needs.The method should take care that any prior string is freed by a call to sqlite3. This will be used to store a Delphi class instance handling the cursor pVtab: PSQLite3VTab.Currently. iVersion: Integer.After the error message is delivered up to the client application.Think of a module as a class from which one can construct multiple virtual tables having similar properties. . reading and writing data. the string will be automatically freed by sqlite3. . Defines the particular edition of the module table structure . . .Virtual tables methods can set an error message by assigning a string obtained from sqlite3.pas unit .The module structure contains methods that are invoked by SQLite to perform various actions on the virtual table such as creating new instances of a virtual table or destroying old ones.This superclass exists in order to define fields of the cursor that are common to all implementationsThis structure therefore contains a pInstance field. and xRowid methods of the module. xEof. For example. 2013 zErrMsg: PUTF8Char.Rev. xNext.mprintf() to zErrMsg.18 Date: June 16. which will be used to store a class instance handling the virtual table as a pure Delphi class: the TSQLVirtualTableModule class will use it internaly pInstance: TObject. 1. Error message from sqlite3. Cursors are used by the xFilter.free() and the zErrMsg field will be zeroed. . .mprintf() . searching for and deleting. That one module can then be used to create several virtual tables where each virtual table refers to a different CSV file. . For nested transactions. Care must be taken to store the copy in a place where it will be deallocated. cdecl. .While compiling a single SQL query. . the SQLite core is saying to the virtual table that it needs to access some subset of the rows in the virtual table and it wants to know the most efficient way to do that access. via the xFilter() method. In other words. .prepare() or the equivalent. xClose: function(pVtabCursor: PSQLite3VTabCursor): Integer. Closes a cursor previously opened by xOpen .pas unit . .Rev.Multiple calls to other methods can and likely will occur in between the xBegin and the corresponding xCommit or xRollback. then the value of the column defaults to an SQL NULL.Virtual table transactions do not nest. such as in the idxStr field with needToFreeIdxStr set to 1.To raise an error. var pInfo: TSQLite3IndexInfo): Integer.The pInfo parameter is used for input and output parameters .result_*() functions with the specified sContext .The SQLite core calls the xBestIndex() method when it is compiling a query that involves a virtual table. use xSavepoint. xRelease and xRollBackTo methods. . it should make a copy. . cdecl.result_*() functions. The SQLite core invokes this method in order to find the value for the N-th column of the current row . The xBestIndex method replies with information that the SQLite core can then use to conduct an efficient search of the virtual table. 1. so the xBegin method will not be invoked more than once on a single virtual table without an intervening call to either xCommit or xRollback. then return an appropriate error code. xBestIndex: function(var pVTab: TSQLite3VTab.The information in the pInfo structure is ephemeral and may be overwritten or deallocated as soon as the xBestIndex() method returns. Begins a transaction on a virtual table . xCommit: function(var pVTab: TSQLite3VTab): Integer. 2013 xBegin: function(var pVTab: TSQLite3VTab): Integer. . sContext: TSQLite3FunctionContext.If the xColumn method implementation calls none of the sqlite3.The routine will not be called again even if it returns an error. N: Integer): Integer.18 Page 653 of 1055 .18 Date: June 16. . cdecl.Synopse mORMot Framework Software Architecture Design 1.This method is always followed by one call to either the xCommit or xRollback method. . cdecl. Used to determine the best way to access the virtual table . SQLite calls this method when it is running sqlite3. .The xColumn method may return its result back to SQLite using one of the standard sqlite3. The SQLite core will not use the pVtabCursor again after it has been closed. The SQLite core will then select the combination that appears to give the best performance.N is zero-based so the first column is numbered 0. the xColumn method should use one of the result_text() methods to set the error message text. Causes a virtual table transaction to commit SynSQLite3.By calling this method.This method must release all resources allocated by the corresponding xOpen call. xColumn: function(var pVtabCursor: TSQLite3VTabCursor. cdecl.The xColumn method must return SQLITE_OK on success. the SQLite core might call xBestIndex multiple times with different settings in pInfo.The SQLite core will always call xClose once for each cursor opened using xOpen. If the xBestIndex() method needs to remember any part of the pInfo structure. The xConnect method just connects to an existing backing store.create_module_v2() call that registered the virtual table module . is the name of the module being invoked. const argv: PPUTF8CharArray.Only the pVTab object is destroyed. var pzErr: PUTF8Char): Integer. as specified following the TABLE keyword in the CREATE VIRTUAL TABLE statement . The xDestroy method is only called when a DROP TABLE statement is executed against the virtual table. 1. XConnect is called to establish a new connection to an existing virtual table. the fourth and subsequent strings in the argv[] array report the arguments to the module name in the CREATE VIRTUAL TABLE statement . just like the xDisconnect method. or "temp" for TEMP database. xDisconnect: function(pVTab: PSQLite3VTab): Integer.create_module() and as the argument to the USING clause of the CREATE VIRTUAL TABLE statement that is running. Releases a connection to a virtual table .The third element of the array. cdecl.Rev. SynSQLite3. whereas xCreate is called to create a new virtual table from scratch . var pzErr: PUTF8Char): Integer. . The virtual table is not destroyed and any backing store associated with the virtual table persists. 2013 xConnect: function(DB: TSQLite3DB. xCreate: function(DB: TSQLite3DB.The second. .It has the same parameters and constructs a new PSQLite3VTab structure . argv[2].18 Page 654 of 1055 . and it also destroys the underlying table implementation.This method undoes the work of xCreate .pas unit .Synopse mORMot Framework Software Architecture Design 1.As part of the task of creating a new PSQLite3VTab structure.declare_vtab() to tell the SQLite core about the columns and datatypes in the virtual table xDestroy: function(pVTab: PSQLite3VTab): Integer.The DB parameter is a pointer to the SQLite database connection that is executing the CREATE VIRTUAL TABLE statement . cdecl. var ppVTab: PSQLite3VTab. is the name of the new virtual table.If present. argv[1].The first string.The pAux argument is the copy of the client data pointer that was the fourth argument to the sqlite3. or the name given at the end of the ATTACH statement for attached databases. The database name is "main" for the primary database. var ppVTab: PSQLite3VTab. The module name is the name provided as the second argument to sqlite3.The job of this method is to construct the new virtual table object (an PSQLite3VTab object) and return a pointer to it in ppVTab . this method must invoke sqlite3. const argv: PPUTF8CharArray.xCreate and xConnect methods are only different when the virtual table has some kind of backing store that must be initialized the first time the virtual table is created. argc: Integer.The argv parameter is an array of argc pointers to null terminated strings . . pAux: Pointer. cdecl.The xDisconnect method is called whenever a database connection that uses a virtual table is closed. is the name of the database in which the new virtual table is being created. argv[0]. Releases a connection to a virtual table. Called to create a new instance of a virtual table in response to a CREATE VIRTUAL TABLE statement . This method undoes the work of xConnect.18 Date: June 16. cdecl. The xCreate method creates and initializes the backing store. argc: Integer. pAux: Pointer. The next two arguments define a particular search index previously chosen by xBestIndex(). idxNum: Integer.If the cursor is successfully advanced to another row of content. The SQLite engine will use the xColumn and xRowid methods to access that row content. this method is called to see if the virtual table would like to overload the function. Advances a virtual table cursor to the next row of a result set initiated by xFilter . If no overloading is desired. But for "like(A. var pxFunc: TSQLFunctionFunc. and MATCH) reverse the order of their arguments. cdecl. . .This method must return SQLITE_OK if successful. then the cursor must be left in a state that will cause the xEof to return true (non-zero). . .pas unit . and the name of the function. the number of arguments to the function.B)" is equivalent to "B like A". . Those values are passed to xFilter() using the argc and argv parameters. then subsequent calls to xEof must return false (zero).Must return false (zero) if the specified cursor currently points to a valid row of data. REGEXP. argc: Integer. To overload the function. 1. var argv: TSQLite3ValueArray): Integer. .argvIndex values of its pInfo structure. const idxStr: PAnsiChar.18 Page 655 of 1055 . or an sqlite error code if an error occurs. cdecl. var ppArg: Pointer): Integer. this method returns 0.The xBestIndex() function may have requested the values of certain expressions using the aConstraintUsage[]. So "like(A. 2013 xEof: function(var pVtabCursor: TSQLite3VTabCursor): Integer. this method writes the new function implementation into pxFunc and writes user data into ppArg and returns 1. or an sqlite error code if an error occurs.B)" the A term is considered the first argument. The specific meanings of idxNum and idxStr are unimportant as long as xFilter() and xBestIndex() agree on what that meaning is.Note that infix functions (LIKE. cdecl. Called during sqlite3.Synopse mORMot Framework Software Architecture Design 1. nArg: Integer. xNext: function(var pVtabCursor: TSQLite3VTabCursor): Integer. or true (non-zero) otherwise xFilter: function(var pVtabCursor: TSQLite3VTabCursor. GLOB. For the form "B like A" the B term is considered the first argument to the function.18 Date: June 16. Subsequent calls to xEof must return false (zero).When a function uses a column from a virtual table as its first argument. then the cursor no longer points to valid data and a subsequent call to the xEof method must return true (non-zero). If there are no rows match.If the virtual table contains one or more rows that match the search criteria. The xNext method will be used to advance to the next row. .This method must return SQLITE_OK if successful. xFindFunction: function(var pVTab: TSQLite3VTab.prepare() to give the virtual table implementation an opportunity to overload SQL functions . The first three parameters are inputs: the virtual table. Checks if cursor reached end of rows . SynSQLite3. then the cursor must be left point at the first row. cdecl.Rev.The first argument is a cursor opened by xOpen.The function pointer returned by this routine must be valid for the lifetime of the pVTab object given in the first parameter. Begins a search of a virtual table . const zName: PAnsiChar.If the cursor is already pointing at the last row when this routine is called. . iSavepoint parameter indicates the unique name of the SAVEPOINT xRename: function(var pVTab: TSQLite3VTab. except that the SAVEPOINT and RELEASE commands are named and may be nested. Merges a transaction into its parent transaction. so that the specified transaction and its parent become the same transaction . Should fill pRowid with the rowid of row that the virtual table cursor pVtabCursor is currently pointing at xSavepoint: function(var pVTab: TSQLite3VTab.iSavepoint parameter indicates the unique name of the SAVEPOINT xRowid: function(var pVtabCursor: TSQLite3VTabCursor. 1.Synopse mORMot Framework Software Architecture Design 1. iSavepoint: integer): Integer. cdecl. initialize the new object. xRollback: function(var pVTab: TSQLite3VTab): Integer.pas unit .sqlite.A successful invocation of this method will allocate the memory for the TPSQLite3VTabCursor (or a subclass).18 Page 656 of 1055 .When initially opened.Causes all savepoints back to and including the most recent savepoint with a matching identifier to be removed from the transaction stack . The SQLite core will invoke the xFilter method on the cursor prior to any attempt to position or read from the cursor. cdecl. . . var ppCursor: PSQLite3VTabCursor): Integer. var pRowid: Int64): Integer.org/lang_savepoint. cdecl.If this method returns an error code then the renaming is prevented. The SQLite core will take care of that chore automatically. the cursor is in an undefined state. cdecl. and make ppCursor point to the new object.For every successful call to this method. See @http://www. similar to BEGIN and COMMIT. 2013 xOpen: function(var pVTab: TSQLite3VTab. .18 Date: June 16. This is an acceptable point of view as long as one remembers that the changes committed by an inner transaction might later be undone by a rollback in an outer transaction.If this method returns SQLITE_OK then SQLite renames the table. . Creates a new cursor used for accessing (read and/or writing) a virtual table . Provides notification that the virtual table implementation that the virtual table will be given a new name .A virtual table implementation must be able to support an arbitrary number of simultaneously open cursors.SAVEPOINTs are a method of creating transactions.The xOpen method need not initialize the pVtab field of the ppCursor structure. the SQLite core will later invoke the xClose method to destroy the allocated cursor.Some people view RELEASE as the equivalent of COMMIT for a SAVEPOINT. iSavepoint: integer): Integer. cdecl. const zNew: PAnsiChar): Integer. cdecl. Reverts the state of the virtual table content back to what it was just after the corresponding SAVEPOINT .iSavepoint parameter indicates the unique name of the SAVEPOINT SynSQLite3.html .Rev. cdecl. xRelease: function(var pVTab: TSQLite3VTab. The successful call then returns SQLITE_OK. . Causes a virtual table transaction to rollback xRollbackTo: function(var pVTab: TSQLite3VTab. Starts a new transaction with the virtual table . iSavepoint: integer): Integer. . Synopse mORMot Framework Software Architecture Design 1. 2013 xSync: function(var pVTab: TSQLite3VTab): Integer. the entire transaction is rolled back. .If any of the xSync methods fail. the xSync method on all virtual tables is invoked prior to invoking the xCommit method on any virtual table. SynSQLite3. Signals the start of a two-phase commit on a virtual table .Rev.18 Page 657 of 1055 .pas unit . 1.18 Date: June 16.In order to implement two-phase commit.This method is only invoked after call to the xBegin method and prior to an xCommit or xRollback. cdecl. . attempting to store a value of the wrong datatype.. SynSQLite3. nArg > 1 ppArg[0] = NULL A new row is inserted with a rowid ppArg[1] and column values in ppArg[2] and following.last_insert_rowid() function. No insert occurs.The ppArg[0] parameter is the rowid of a row in the virtual table to be deleted. the implementation must set pRowid to the rowid of the newly inserted row. as in the statement: UPDATE table SET rowid=rowid+1 WHERE . var pRowid: Int64): Integer. the pVTab. not the ppArg[i] object itself: nArg = 1 The single row with rowid equal to ppArg[0] is deleted.The value of nArg will be 1 for a pure delete operation or N+2 for an insert or replace or update where N is the number of columns in the table (including any hidden columns) . If a failure occurs. but not limited to. . 1. in the order that the columns were declared.The ppArg[1] parameter is the rowid of a new row to be inserted into the virtual table. then no deletion occurs .pas unit . the a new unique rowid is generated automatically. .There might be one or more TSQLite3VTabCursor objects open and in use on the virtual table instance and perhaps even on the row of the virtual table when the xUpdate() method is invoked.When doing an insert without a rowid (nArg>1. The implementation of xUpdate() must be prepared for attempts to delete or modify rows of the table out from other existing cursors.18 Date: June 16. ppArg[1] is an SQL NULL). If the virtual table cannot accommodate such changes.The nArg parameter specifies the number of entries in the ppArg[] array .18 Page 658 of 1055 .. If ppArg[1] is an SQL NULL. this will become the value returned by the sqlite3.. nArg > 1 ppArg[0] <> NULL ppArg[0] <> ppArg[1] The row with rowid ppArg[0] is updated with rowid ppArg[1] and new values in ppArg[2] and following parameters.zErrMsg element may optionally be replaced with a custom error message text. 2013 xUpdate: function(var pVTab: TSQLite3VTab. If ppArg[0] is an SQL NULL. .declare_vtab() call. then the implementation must choose a rowid for the newly inserted row.Rev. Makes a change to a virtual table content (insert/delete/update) . nArg > 1 ppArg[0] <> NULL ppArg[0] = ppArg[1] The row with rowid ppArg[0] is updated with new values in ppArg[2] and following parameters. All hidden columns are included. attempting to store a value that is too large or too small. or attempting to change a read-only value) then the xUpdate() must fail with an appropriate error code. Note that references to ppArg[i] mean the SQL value held within the ppArg[i] object. the SQLite engine ignores the pRowid return value if nArg=1 or ppArg[1] is not an SQL NULL. .The xUpdate() method must return SQLITE_OK if and only if it is successful. If ppArg[1] is an SQL NULL. the xUpdate() method must return an error code. The number of columns will match the table declaration that the xConnect or xCreate method made using the sqlite3. On a failure. var ppArg: TSQLite3ValueArray. nArg: Integer.If the xUpdate() method violates some constraint of the virtual table (including.Synopse mORMot Framework Software Architecture Design 1. This will occur when an SQL statement updates a rowid.Each call to xUpdate() will fall into one of cases shown below. Subsequent ppArg[] entries contain values of the columns of the virtual table. . the xUpdate() must return an appropriate error code. Setting this value in all the other cases is a harmless no-op. cdecl. S is a statement prepared by a previous call to sqlite3.return SQLITE_OK on success or an error code . Bind a Blob Value to a parameter of a prepared statement . SQLite allocates N of memory.aggregate_context() within the same aggregate function instance will not resize the memory allocation. so you should call sqlite3. Changing the value of N in subsequent call to sqlite3.1 (page 1052). .2. cdecl.prepare_v2() . Buf: pointer. On second and subsequent calls to sqlite3.a global sqlite3: TSQLite3Library will be defined in this unit. cdecl. sqlite3.abstract class allowing direct binding of static sqlite3. zeroes out that memory. .The first time the sqlite3.Param is the index of the SQL parameter to be set (leftmost=1) .set DestroyPtr as SQLITE_STATIC (nil) for static binding . Implementations of aggregate SQL functions use this routine to allocate memory for storing their state.SQLite automatically frees the memory allocated by sqlite3. When no rows match an aggregate query.Rev. bind_blob: function(S: TSQLite3Statement.18 Page 659 of 1055 .open() for instance . . 1. it will initialize a TSQLite3LibrayStatic instance Used for DI-2. sqlite3.aggregate_context(C.Synopse mORMot Framework Software Architecture Design 1.errmsg() .aggregate_context() for the same aggregate function instance.set DestroyPtr to SQLITE_TRANSIENT (-1) for SQLite to make its own private copy of the data (this is the prefered way in our Framework) .18 Date: June 16. 2013 TSQLite3Library = class(TObject) Wrapper around all SQLite3 library API calls .see SQLITE_* and sqlite3.aggregate_context() might be called for the first time from within xFinal().N) is determined by the N parameter on first successful call.aggregate_context(C.N) routine is called for a particular aggregate function. aggregate_context: function(Context: TSQLite3FunctionContext.Buf_bytes contains the number of bytes in Buf . In those cases. the same buffer is returned. Buf_bytes: integer. and returns a pointer to the new memory.aggregate_context(C.Buf must point to a memory buffer of Buf_bytes bytes .pas unit . Param: integer. DestroyPtr: TSQLDestroyPtr=SQLITE_TRANSIENT): integer.N) routine returns a NULL pointer if N is less than or equal to zero or if a memory allocate error occurs.set DestroyPtr to sqlite3InternalFree if Value must be released via Freemem() SynSQLite3. the xStep() callback of the aggregate function implementation is never called and xFinal() is called exactly once.The sqlite3. nBytes: integer): pointer.The amount of space allocated by sqlite3.if your project refers to SynSQLite3Static unit.open() instead of sqlite3.aggregate_context() is normally called once for each invocation of the xStep callback and then one last time when the xFinal callback is invoked.aggregate_context() when the aggregate query concludes.obj (TSQLite3LibrayStatic) or with an external library (TSQLite3LibraryDynamic) . . see SQLITE_* and sqlite3. cdecl.return SQLITE_OK on success or an error code .Rev. this will correspond to the number of unique parameters.set DestroyPtr as SQLITE_STATIC (nil) for static binding .errmsg() . Text: PUTF8Char.Param is the index of the SQL parameter to be set (leftmost=1) .return SQLITE_OK on success or an error code .Value is the 32 bits Integer to bind bind_int64: function(S: TSQLite3Statement.returns the index of the largest (rightmost) parameter.return SQLITE_OK on success or an error code . Bind a NULL Value to a parameter of a prepared statement .return SQLITE_OK on success or an error code .set DestroyPtr to SQLITE_TRANSIENT (-1) for SQLite to make its own private copy of the data (this is the prefered way in our Framework) .pas unit .prepare_v2() .18 Date: June 16. cdecl. Bind a Text Value to a parameter of a prepared statement . If parameters of the ?NNN are used. Bind a 32 bits Integer Value to a parameter of a prepared statement .errmsg() .Text must contains an UTF8-encoded null-terminated string query .S is a statement prepared by a previous call to sqlite3. .set DestroyPtr to sqlite3InternalFree if Value must be released via Freemem() SynSQLite3.errmsg() . bind_text: function(S: TSQLite3Statement.prepare_v2() .prepare_v2() .see SQLITE_* and sqlite3. cdecl. For all forms except ?NNN.errmsg() .Param is the index of the SQL parameter to be set (leftmost=1) . Value: Int64): integer. cdecl. excluding the null terminator .Param is the index of the SQL parameter to be set (leftmost=1) .see SQLITE_* and sqlite3. Bind a 64 bits Integer Value to a parameter of a prepared statement .Value is the floating point number to bind bind_int: function(S: TSQLite3Statement. DestroyPtr: TSQLDestroyPtr=SQLITE_TRANSIENT): integer. Value: double): integer.errmsg() .prepare_v2() .Text_bytes contains -1 (to stop at the null char) or the number of chars in the input string. cdecl.return SQLITE_OK on success or an error code .see SQLITE_* and sqlite3. 1.S is a statement prepared by a previous call to sqlite3.S is a statement prepared by a previous call to sqlite3.Synopse mORMot Framework Software Architecture Design 1. Param: integer.S is a statement prepared by a previous call to sqlite3. 2013 bind_double: function(S: TSQLite3Statement. Param: integer. Value: integer): integer.18 Page 660 of 1055 .Param is the index of the SQL parameter to be set (leftmost=1) bind_parameter_count: function(S: TSQLite3Statement): integer.S is a statement prepared by a previous call to sqlite3. cdecl.prepare_v2() .Value is the 64 bits Integer to bind bind_null: function(S: TSQLite3Statement. Bind a floating point Value to a parameter of a prepared statement . Number Of SQL Parameters for a prepared statement . Param: integer): integer. there may be gaps in the list. Param: integer. The leftmost SQL parameter has an index of 1.Param is the index of the SQL parameter to be set. Text_bytes: integer=-1.see SQLITE_* and sqlite3. Param: integer. cdecl. column ColumnName. cdecl.returns a BLOB handle for row RowID. const Data. then SQLITE_BUSY or SQLITE_IOERR_BLOCKED is returned immediately upon encountering the lock. Offset: Integer): Integer. cdecl. After at least "ms" milliseconds of sleeping.uses a fixed amount of memory (just an integer to hold its size) while it is being processed. Register A Callback To Handle SQLITE_BUSY Errors . cdecl. the handler returns 0 which causes sqlite3. the same BLOB that would be selected by: SELECT ColumnName FROM DBName. table TableName in database DBName. var Blob: TSQLite3Blob): Integer.This routine sets a callback function that might be invoked whenever an attempt is made to open a database table that another thread or process has locked. in other words.a negative value for the Size parameter results in a zero-length BLOB .18 Date: June 16.step() to return SQLITE_BUSY or SQLITE_IOERR_BLOCKED. Return The Size Of An Open BLOB blob_close: function(Blob: TSQLite3Blob): Integer.If the busy callback is NULL.18 Page 661 of 1055 . Milliseconds: integer): integer. Param: integer. but ?NNN may override it blob_bytes: function(Blob: TSQLite3Blob): Integer. busy_timeout: function(DB: TSQLite3DB. If the busy callback is not NULL. .There can only be a single busy handler for a particular database connection any given moment. .the leftmost SQL parameter has an index of 1. 2013 bind_zeroblob: function(S: TSQLite3Statement. Flags: Integer. 1. Count. CallbackPtr: TSQLBusyHandler. cdecl. DBName. cdecl. then the callback might be invoked with two arguments. cdecl. . ColumnName: PUTF8Char.TableName WHERE rowid = RowID. const Data.Synopse mORMot Framework Software Architecture Design 1. . . user: Pointer): integer.Rev. SynSQLite3.This routine sets a busy handler that sleeps for a specified amount of time when a table is locked.The default busy callback is NULL. Open a BLOB For Incremental I/O . Set A Busy Timeout . Close A BLOB Handle blob_open: function(DB: TSQLite3DB. TableName. Count. RowID: Int64. Write Data To a BLOB Incrementally busy_handler: function(DB: TSQLite3DB. blob_read: function(Blob: TSQLite3Blob. Bind a ZeroBlob buffer to a parameter . Offset: Integer): Integer.Calling this routine with an argument less than or equal to zero turns off all busy handlers. that other busy handler is cleared. The handler will sleep multiple times until at least "ms" milliseconds of sleeping have accumulated. cdecl.busy_handler()) prior to calling this routine. Zeroblobs are intended to serve as placeholders for BLOBs whose content is later written using incremental BLOB I/O routines.pas unit . Read Data From a BLOB Incrementally blob_write: function(Blob: TSQLite3Blob. If another busy handler was defined (using sqlite3. Size: integer): integer. clear_bindings: function(S: TSQLite3Statement): integer. 1. Number of bytes for a BLOB or UTF-8 string result .column_text() or sqlite3.NULL is converted into nil . indexed from 0 to sqlite3.TEXT and BLOB are returned directly column_bytes: function(S: TSQLite3Statement.This function returns the number of database rows that were changed or inserted or deleted by the most recently completed SQL statement on the database connection specified by the first parameter.S is the SQL statement.Rev. after sqlite3. Destructor for the sqlite3 object.Col is the column number.TEXT or BLOB is converted from all correct ASCII numbers with 0.next_stmt() interface can be used for this task) .total_changes() function to find the total number of changes including changes caused by triggers and foreign key actions. Use the sqlite3.if invoked while a transaction is open. cdecl.18 Page 662 of 1055 .0 . Number of columns in the result set for the statement column_decltype: function(S: TSQLite3Statement. cdecl.an implicit conversion into UTF-8 text is made for a numeric value or UTF-16 column: you must call sqlite3.column_blob() before calling sqlite3. or DELETE statement are counted. cdecl. Col: integer): PAnsiChar.INTEGER or FLOAT are converted into ASCII rendering of the numerical value . Auxiliary changes caused by triggers or foreign key actions are not counted.SynSQLite3Static will use its own internal function for handling properly its own encryption format column_blob: function(S: TSQLite3Statement.Synopse mORMot Framework Software Architecture Design 1.Applications should finalize all prepared statements and close all BLOB handles associated with the sqlite3 object prior to attempting to close the object (sqlite3. cdecl.column_bytes() to perform the conversion itself column_count: function(S: TSQLite3Statement): integer.NULL is converted into 0. cdecl.INTEGER is converted into corresponding floating point value . Col: integer): PAnsiChar. Col: integer): integer.If a separate thread makes changes on the same database connection while sqlite3. Reset All Bindings On A Prepared Statement close: function(DB: TSQLite3DB): integer.column_count(S)-1 .pas unit . Returns a zero-terminated UTF-8 string containing the declared datatype of a result column column_double: function(S: TSQLite3Statement. cdecl.18 Date: June 16. which handle is DB . 2013 changes: function(DB: TSQLite3DB): Integer.0 as default SynSQLite3. Count The Number Of Rows Modified . UPDATE. Col: integer): double.step(S) returned SQLITE_ROW . Converts the Col column in the current row of prepared statement S into a BLOB and then returns a pointer to the converted value . Converts the Col column in the current row prepared statement S into a floating point value and returns a copy of that value . Only changes that are directly specified by the INSERT.changes() is running then the value returned is unpredictable and not meaningful. the transaction is automatically rolled back . cdecl. cdecl. . pArg: Pointer): Pointer. Col: integer): integer.18 Date: June 16. SQLITE_TEXT.FLOAT is truncated into corresponding integer value .NULL is converted into 0 . Register Commit Notification Callbacks . value is undefined column_value: function(S: TSQLite3Statement. Col: integer): TSQLite3Value. SynSQLite3.Col is the column number. cdecl. Col: integer): int64.The sqlite3.TEXT is returned directly (with UTF-16 -> UTF-8 encoding if necessary) .18 Page 663 of 1055 .must be called before any sqlite3.value_*() function below commit_hook: function(DB: TSQLite3DB.NULL is converted into nil .C.TEXT or BLOB is converted from all correct ASCII numbers with 0 as default column_name: function(S: TSQLite3Statement.Any callback set by a previous call to sqlite3.commit_hook(D. Returns the name of a result column as a zero-terminated UTF-8 string column_text: function(S: TSQLite3Statement. SQLITE_BLOB or SQLITE_NULL . cdecl.P) function returns the P argument from the previous call of the same function on the same database connection D. . cdecl.NULL is converted into 0 . xCallback: TSQLCommitCallback.BLOB add a zero terminator if needed column_type: function(S: TSQLite3Statement.value object .column_count(S)-1 . . Datatype code for the initial data type of a result column .TEXT or BLOB is converted from all correct ASCII numbers with 0 as default column_int64: function(S: TSQLite3Statement. 1.Rev. Converts the Col column in the current row prepared statement S into a 32 bit integer value and returns a copy of that value . or nil for the first call for each function on D.step(S) returned SQLITE_ROW . which may result in an implicit type conversion: in this case.column_*() statement.The sqlite3. Get the value handle of the Col column in the current row of prepared statement S .INTEGER or FLOAT are converted into ASCII rendering of the numerical value . cdecl.S is the SQL statement. 2013 column_int: function(S: TSQLite3Statement.this handle can then be accessed with any sqlite3. cdecl. cdecl.Registering a nil function disables the Commit callback.FLOAT is truncated into corresponding integer value . Converts the Col column in the current row prepared statement S into a 64 bit integer value and returns a copy of that value . . cdecl.returned value is one of SQLITE_INTEGER.commit_hook() for the same database connection is overridden. indexed from 0 to sqlite3. after sqlite3. Col: integer): integer.commit_hook() interface registers a callback function to be invoked whenever a transaction is committed. Col: integer): PUTF8Char.this handle represent a sqlite3.pas unit .Synopse mORMot Framework Software Architecture Design 1. Converts the Col column in the current row prepared statement S into a zero-terminated UTF-8 string and returns a pointer to that string . Col: integer): PUTF8Char. SQLITE_FLOAT. Create add WIN32CASE. pass nil pointers for all three function callbacks. nil pointers must be passed as the xStep and xFinal parameters. . pApp. xFinal: TSQLFunctionFinal. .It is permitted to register multiple implementations of the same functions with the same name but with either differing numbers of arguments or differing preferred text encodings.The seventh. But some implementations may be more efficient with one encoding than another. xStep: TSQLFunctionFunc. Function creation routine used to add SQL functions or aggregates or to redefine the behavior of existing SQL functions or aggregates . xStep and xFinal.18 Date: June 16. . The length of the name is limited to 255 bytes in a UTF-8 representation. Define New Collating Sequences . WIN32NOCASE and ISO8601 collations create_function_v2: function(DB: TSQLite3DB. If the third parameter is less than -1 or greater than 127 then the behavior is undefined.Synopse mORMot Framework Software Architecture Design 1. StringEncoding: integer. A scalar SQL function requires an implementation of the xFunc callback only. UTF-16le. . specifies what text encoding this SQL function prefers for its parameters. An aggregate SQL function requires an implementation of xStep and xFinal and nil pointer must be passed for xFunc. If an application uses more than one database connection then application-defined SQL functions must be added to each database connection separately. is an arbitrary pointer. it is passed a single argument which is a copy of the pointer which was the fifth parameter to sqlite3. When the destructure callback of the tenth parameter is invoked.create_function_v2(). or UTF-16be. To delete an existing SQL function or aggregate.pas unit . exclusive of the zero-terminator.The fifth parameter.create_function_v2() routine that originally registered the application defined function create_collation: function(DB: TSQLite3DB. cmp: TSQLCollateFunc): integer.Rev. Any attempt to create a function with a longer name will result in SQLITE_MISUSE being returned.The third parameter (nArg) is the number of arguments that the SQL function or aggregate takes.user_data(). nArg. SynSQLite3. eighth and ninth parameters.The second parameter is the name of the SQL function to be created or redefined. CollateParam: pointer. then it is invoked when the function is deleted. are pointers to C-language functions that implement the SQL function or aggregate. Every SQL function implementation must be able to work with UTF-8. The implementation of the function can gain access to this pointer using sqlite3. SQLite will pick the one that involves the least amount of data conversion. xFunc. 1. . .add new collation sequences to the database connection specified . 2013 context_db_handle: function(Context: TSQLite3FunctionContext): TSQLite3DB. then the fourth argument should be SQLITE_ANY. Note that the name length limit is in UTF-8 bytes.The first parameter is the database connection to which the SQL function is to be added. . SQLite will use the implementation that most closely matches the way in which the SQL function is used. either by being overloaded or when the database connection closes. cdecl.The fourth parameter. FunctionName: PUTF8Char. cdecl.If the tenth parameter is not NULL. If there is only a single implementation which does not care what text encoding is used. cdecl. not characters nor UTF-16 bytes.18 Page 664 of 1055 . or in SELECT * FROM t1 ORDER BY c COLLATE CollationName. pApp: pointer.collation name is to be used in CREATE TABLE t1 (a COLLATE CollationName). When multiple implementations of the same function are available. eTextRep.StringEncoding is either SQLITE_UTF8 either SQLITE_UTF16 . xDestroy: TSQLDestroyPtr): Integer. xFunc. eTextRep: integer.TSQLDataBase. Returns a copy of the pointer to the database connection (the 1st parameter) of the sqlite3. . CollationName: PUTF8Char. 2. var p: TSQLite3Module.Memory to hold the error message string is managed internally. SQLite will invoke the destructor function (if it is not nil) when SQLite no longer needs the pClientData pointer.malloc() or sqlite3. and 3. and the error code returned will be SQLITE_ABORT free_: procedure(p: Pointer).Free method SynSQLite3. Hidden columns are not included in the implicit column-list used by an INSERT statement that lacks an explicit column-list. finalize: function(S: TSQLite3Statement): integer. depending on the circumstances. pClientData: Pointer. .pas unit .If a column datatype contains the special keyword "HIDDEN" (in any combination of upper and lower case letters) then that keyword it is omitted from the column datatype name and the column is marked as a hidden column internally. Releases memory previously returned by sqlite3.The module name is registered on the database connection specified by the first DB parameter.The fourth parameter is an arbitrary client data pointer that is passed through into the xCreate and xConnect methods of the virtual table module when a new virtual table is be being created or reinitialized. . cdecl. that is like encountering an error or an interrupt. The destructor will also be invoked if call to sqlite3. The application does not need to worry about freeing the result. the error string might be overwritten or deallocated by subsequent calls to other SQLite interface functions.renamed free_ in order not to override TObject.this routine can be called at any point during the execution of the prepared statement.realloc() . Declare the Schema of a virtual table .Synopse mORMot Framework Software Architecture Design 1. Returns English-language text that describes an error. . const zName: PAnsiChar. cdecl.e. using UTF-8 encoding (which. Used to register a new virtual table module name .The third parameter is a pointer to the implementation of the virtual table module. declare_vtab: function(DB: TSQLite3DB.should call native free() function. cdecl.declare_vtab() routine returns. 2013 create_module_v2: function(DB: TSQLite3DB. . i.18 Date: June 16. .return SQLITE_OK on success or an error code . Incomplete updates may be rolled back and transactions canceled. FreeMem() in this unit .see SQLITE_* and sqlite3.errmsg() . const zSQL: PAnsiChar): Integer. The string can be deallocated and/or reused as soon as the sqlite3. cdecl. If the virtual machine has not completed execution when this routine is called.18 Page 665 of 1055 . 1. A hidden column differs from a normal column in three respects: 1. Hidden columns are not included in the expansion of a "*" expression in the result set of a SELECT. Hidden columns are not listed in the dataset returned by "PRAGMA table_info". with English text. errmsg: function(DB: TSQLite3DB): PAnsiChar.Rev. is the same as Ansi). cdecl.The xCreate() and xConnect() methods of a virtual table module call this interface to declare the format (the names and datatypes of the columns) of the virtual tables they implement. xDestroy: TSQLDestroyPtr): Integer. .create_module_v2() fails.The fifth parameter can be used to specify a custom destructor for the pClientData buffer. However.The name of the module is given by the second parameter. Delete a previously prepared statement . 18 Date: June 16. Open a SQLite3 database filename. var DB: TSQLite3DB): integer.18 Page 666 of 1055 . 1.an error code (see SQLITE_* const) is returned otherwize . cdecl.SynSQlite3Static will use its own internal encryption format last_insert_rowid: function(DB: TSQLite3DB): Int64.c is compiled with SQLITE_OMIT_AUTOINIT defined key: function(DB: TSQLite3DB.close() when it is no longer required SynSQLite3.allocate a sqlite3 object. creating a DB handle . .return SQLITE_OK on success .filename must be UTF-8 encoded (filenames containing international characters must be converted to UTF-8 prior to passing them) . cdecl.pas unit .errmsg() can be used to obtain an English language description of the error .memory_used() since the high-water mark was last reset memory_used: function: Int64.Assigned(key)=false if encryption is not available for this . Returns the number of bytes of memory currently outstanding (malloced but not freed) next_stmt: function(DB: TSQLite3DB. Returns a pointer to a block of memory at least N bytes in length . resources associated with the database connection handle should be released by passing it to sqlite3.Synopse mORMot Framework Software Architecture Design 1.currently returns '3. keyLen: Integer): integer. Returns the maximum value of sqlite3. Return the version of the SQLite database engine. cdecl. Specify the encryption key on a newly opened database connection . associated with the database connection DB. . Returns the rowid of the most recent successful INSERT into the database libversion: function: PUTF8Char. GetMem() in this unit memory_highwater: function(resetFlag: Integer): Int64.if an external SQLite3 library is used. when used with our SynSQLite3Static unit . 2013 initialize: function: integer.if S is 0 then this interface returns a pointer to the first prepared statement associated with the database connection DB. i. and return its handle in DB . cdecl. S: TSQLite3Statement): TSQLite3Statement.this interface returns a handle to the next prepared statement after S. Initialize the SQLite3 database code .e.7.dll .Whatever or not an error occurs when it is opened. cdecl.so sqlite3.Rev. version may vary malloc: function(n: Integer): Pointer.17'.automaticaly called by the initialization block of this unit . cdecl.if no prepared statement satisfies the conditions of this routine. cdecl. key: pointer. in ascii format .should call native malloc() function. Find the next prepared statement . cdecl. cdecl.sqlite3. it returns 0 open: function(filename: PUTF8Char. . the prepared statement that is returned contains a copy of the original SQL text . cdecl.set DestroyPtr as SQLITE_STATIC (nil) for static binding .step(S) returned SQLITE_ROW or SQLITE_DONE.if the most recent call to sqlite3. or if sqlite3.S will contain an handle of the resulting statement (an opaque sqlite3. or will 0 on error . Sets the result from an application-defined function to be the BLOB .return an appropriate error code if the most recent call to sqlite3.errmsg() . DestroyPtr: TSQLDestroyPtr=SQLITE_TRANSIENT).SQL must contains an UTF8-encoded null-terminated string query . cdecl.pas unit .Assigned(key)=false if encryption is not available for this .step(S) has never before been called with S.should call native realloc() function. SQL_bytes: integer.reset(S) returns SQLITE_OK.content is pointed to by the Value and which is Value_bytes bytes long .this routine only compiles the first statement in SQL. cdecl. key: pointer.set DestroyPtr to SQLITE_TRANSIENT (-1) for SQLite to make its own private copy of the data (this is the prefered way in our Framework) .set DestroyPtr to sqlite3InternalFree if Value must be released via Freemem() or to sqlite3InternalFreeObject if Value must be released via a Free method result_double: procedure(Context: TSQLite3FunctionContext. cdecl. keyLen: Integer): integer.18 Date: June 16. cdecl. var S: TSQLite3Statement.step(S) failed . ready to be re-Prepared . 2013 prepare_v2: function(DB: TSQLite3DB. n: Integer): Pointer. cdecl. Attempts to resize a prior memory allocation . Reset a prepared statement object back to its initial state. Change the encryption key on a database connection that is already opened .Rev. Compile a SQL query into byte-code . Value_bytes: Integer=0.clear_bindings() to reset the bindings. 1. Value: double).SynSQlite3Static will throw an exception if you try to use this API: you shall call ChangeSQLEncryptTablePassWord() procedure instead reset: function(S: TSQLite3Statement): integer.see SQLITE_* and sqlite3. Value: Pointer. then sqlite3.dll .stmt object) on success.any SQL statement variables that had values bound to them using the sqlite3.SQL_bytes contains -1 (to stop at the null char) or the number of bytes in the input string. result_blob: procedure(Context: TSQLite3FunctionContext.the calling procedure is responsible for deleting the compiled SQL statement using sqlite3.can also decrypt a previously encrypted database (so that it is accessible from any version of SQLite) by specifying a nil key .bind_*() API retain their values.finalize() after it has finished with it . i.e. Use sqlite3.18 Page 667 of 1055 .Synopse mORMot Framework Software Architecture Design 1.return SQLITE_OK on success or an error code . ReallocMem() in this unit rekey: function(DB: TSQLite3DB. including the null terminator . var SQLtail: PUTF8Char): integer. SQL: PUTF8Char. so SQLtail is left pointing to what remains uncompiled realloc: function(pOld: Pointer. Sets the result from an application-defined function to be a floating point value specified by its 2nd argument SynSQLite3.in this "v2" interface. set DestroyPtr to sqlite3InternalFree if Value must be released via Freemem() or to sqlite3InternalFreeObject if Value must be released via a Free method result_value: procedure(Context: TSQLite3FunctionContext. Sets the return value of the application-defined function to be NULL result_text: procedure(Context: TSQLite3FunctionContext. then as many bytes (NOT characters: this parameter must include the #0 terminator) of the text pointed to by the Value parameter are taken as the application-defined function result .set DestroyPtr as SQLITE_STATIC (nil) for static binding .value so that the sqlite3. Register Rollback Notification Callbacks .if MsgLen is negative. cdecl.SQLite interprets the error message string from sqlite3. Msg must be #0 ended.18 Page 668 of 1055 . cdecl. Value: PUTF8Char. Cause the implemented SQL function to throw an exception .result_value() interface makes a copy of the sqlite3.rollback_hook() interface registers a callback function to be invoked whenever a transaction is rolled back. Sets the result of the application-defined function to be a copy the unprotected sqlite3. pArg: Pointer): Pointer. or nil for the first call for each function on D.The sqlite3. cdecl.Rev. or MsgLen must tell the numnber of characters in the Msg UTF-8 buffer result_int64: procedure(Context: TSQLite3FunctionContext.18 Date: June 16. Msg: PUTF8Char.value specified in the parameter may change or be deallocated after sqlite3.value object specified by the 2nd parameter .if Value_bytes is negative. 1. 2013 result_error: procedure(Context: TSQLite3FunctionContext.result_value() returns without harm rollback_hook: function(DB: TSQLite3DB.C. cdecl. Sets the return value of the application-defined function to be a text string which is represented as UTF-8 . Sets the return value of the application-defined function to be the 64-bit signed integer value given in the 2nd argument result_null: procedure(Context: TSQLite3FunctionContext).Synopse mORMot Framework Software Architecture Design 1.if Value_bytes is non-negative.pas unit . Value_bytes: Integer=-1. then SQLite takes result text from the Value parameter through the first zero character . DestroyPtr: TSQLDestroyPtr=SQLITE_TRANSIENT).The sqlite3. Value: TSQLite3Value).Any callback set by a previous call to sqlite3.The sqlite3. cdecl. .rollback_hook() for the same database connection is overridden.rollback_hook(D. . MsgLen: integer=-1).P) function returns the P argument from the previous call of the same function on the same database connection D. SynSQLite3. Value: Int64). .result_error() as UTF-8 .set DestroyPtr to SQLITE_TRANSIENT (-1) for SQLite to make its own private copy of the data (this is the prefered way in our Framework) .Registering a nil function disables the Rollback callback. xCallback: TSQLCommitCallback. cdecl. Disable the authorizer by installing a nil callback . COMMIT.SQLITE_MISUSE means that the this routine was called inappropriately. If the statement is not a COMMIT and occurs within a explicit transaction then you should rollback the transaction before continuing. and RELEASE cause sqlite3.Transaction control statements such as BEGIN. Shutdown the SQLite3 database core .SQLITE_SCHEMA means that the database schema changes.step() has to be called again to retrieve the next row of data. ROLLBACK.SQLITE_DONE means that the statement has finished executing successfully.Only a single authorizer can be in place on a database connection at a time . 2013 set_authorizer: function(DB: TSQLite3DB.The authorizer is disabled by default shutdown: function: integer.18 Date: June 16. .set_authorizer overrides the previous call .SQLITE_ROW is returned each time a new row of data is ready for processing by the caller. The values may be accessed using the column access functions below.another specific error code is returned on fatal error stmt_readonly: function(S: TSQLite3Statement): boolean. as a fatal error. returning a result status: . Perhaps it was called on a prepared statement that has already been finalized or on one that had previously returned SQLITE_ERROR or SQLITE_DONE. SynSQLite3. Registers an authorizer callback to a specified DB connection . but the schame changed in a way that makes the statement no longer valid. Evaluate An SQL Statement. cdecl. xAuth: TSQLAuthorizerCallback. The ATTACH and DETACH statements also cause sqlite3. Or it could be the case that the same database connection is being used by two or more threads at the same moment in time. they do not make changes to the content of the database files on disk. If the statement is a COMMIT or occurs outside of an explicit transaction.Each call to sqlite3. 1.reset() to reset the virtual machine state back. sqlite3.Synopse mORMot Framework Software Architecture Design 1. sqlite3.SQLITE_BUSY means that the database engine was unable to acquire the database locks it needs to do its job.automaticaly called by the finalization block of this unit step: function(S: TSQLite3Statement): integer. then you can retry the statement. and the SQL statement has been recompiled and run again. pUserData: Pointer): Integer.pas unit . while those statements change the configuration of a database connection. since the statements themselves do not actually modify the database but rather they control the timing of when other statements modify the database.stmt_readonly() to return true. cdecl. cdecl. .step() should not be called again on this virtual machine without first calling sqlite3. Returns true (non-zero) if and only if the prepared statement X makes no direct changes to the content of the database file .Rev. .18 Page 669 of 1055 . . . cdecl.stmt_readonly() to return true since. SAVEPOINT. though if the INSTEAD OF trigger makes changes of its own. update_hook: function(DB: TSQLite3DB. aUserData: Pointer): Pointer.The update hook is not invoked when internal system tables are modified (i.total_changes() is running then the value returned is unpredictable and not meaningful.pas unit . sqlite_master and sqlite_sequence).sqlite3. the update hook is not invoked when duplication rows are deleted because of an ON CONFLICT REPLACE clause. or nil for the first call on database connection D. The callbacks for triggers contain a UTF-8 SQL comment that identifies the trigger. Total Number Of Rows Modified .This function returns the number of row changes caused by INSERT. trace: function(DB: TSQLite3DB.The sqlite3. cdecl. 1.Note that you should also trace COMMIT and ROLLBACK commands (calling sqlite3.This routine must be called from the same thread in which the application-defined function is running SynSQLite3.Rev.The callback function registered by sqlite3. cdecl. Register Data Change Notification Callbacks .reset() or sqlite3. inserted or deleted.In the current implementation.step().finalize()).total_changes() function counts the changes as soon as the statement that makes them is completed (when the statement handle is passed to sqlite3.C.commit_hook() and sqlite3.create_function_v2() routine that originally registered the application defined function .trace() callback is invoked with a UTF-8 rendering of the SQL statement text as the statement first begins executing. The sqlite3. or DROP TABLE processing.If a separate thread makes changes on the same database connection while sqlite3. 2013 total_changes: function(DB: TSQLite3DB): Integer. Returns a copy of the pointer that was the pUserData parameter (the 5th parameter) of the sqlite3. UPDATE or DELETE statements since the database connection was opened. Additional sqlite3. cdecl. pArg: pointer): pointer. those changes are counted.update_hook() interface registers a callback function with the database connection identified by the first argument to be invoked whenever a row is updated.trace() is invoked at various times when an SQL statement is being run by sqlite3.total_changes() includes all changes from all trigger contexts and changes made by foreign key actions.Synopse mORMot Framework Software Architecture Design 1. do rollbacks or ABORT processing. tCallback: TSQLTraceCallback. The count does not include rows of views that fire an INSTEAD OF trigger. . Nor is the update hook invoked when rows are deleted using the truncate optimization.e.18 Page 670 of 1055 . cdecl. . . The exceptions defined in this paragraph might change in a future release of SQLite. The sqlite3.Any callback set by a previous call to this function for the same database connection is overridden. xCallback: TSQLUpdateCallback.P) function returns the P argument from the previous call on the same database connection D.18 Date: June 16.trace() callbacks might occur as each triggered subprogram is entered. However. Register callback function that can be used for tracing the execution of SQL statements . .update_hook(D. . the count does not include changes used to implement REPLACE constraints.rollback_hook() functions) if you want to ensure that the notified update was not canceled by a later Rollback. user_data: function(Context: TSQLite3FunctionContext): pointer. The count returned by sqlite3. . Converts a sqlite3.raise an ESQLite3Exception on error SynSQLite3. The datatype after conversion is returned.dll').18 Date: June 16. reintroduce. cdecl. cdecl.18 Page 671 of 1055 .This means that an attempt is made to convert the value to an integer or floating point.returned value is one of SQLITE_INTEGER. if the value is a string that looks like a number) then the conversion is performed. which may result in an implicit type conversion: in this case. into an integer value and returns a copy of that value value_numeric_type: function(Value: TSQLite3Value): integer. and returns a copy of that value value_type: function(Value: TSQLite3Value): integer. into a floating point value and returns a copy of that value value_int64: function(Value: TSQLite3Value): Int64. 2013 value_blob: function(Value: TSQLite3Value): pointer. Converts a sqlite3. specified by its handle. Otherwise no conversion occurs.1 (page 1052). Datatype code for a sqlite3.value_*() statement.you can e.g. cdecl.value_text() or sqlite3.used after a call to sqlite3. SQLITE_BLOB or SQLITE_NULL .pas unit . and returns a copy of that value value_bytes: function(Value: TSQLite3Value): integer. SQLITE_TEXT. Converts a sqlite3. SQLITE_BLOB or SQLITE_NULL value_text: function(Value: TSQLite3Value): PUTF8Char. cdecl. specified by its handle. SQLITE_FLOAT. 1.value object. value is undefined TSQLite3LibraryDynamic = class(TSQLite3Library) Allow access to an exernal SQLite3 library engine . specified by its handle . SQLITE_FLOAT.Rev.value object. SQLITE_TEXT. Converts a sqlite3.Create.g. Used for DI-2.value object. Attempts to apply numeric affinity to the value . specified by its handle. specified by its handle . Number of bytes for a sqlite3. cdecl. cdecl.value object. .value_blob() to determine buffer size (in bytes) value_double: function(Value: TSQLite3Value): double.must be called before any sqlite3. into an UTF-8 encoded string. // release any previous instance (e.2. specified by its handle. If such a conversion is possible without loss of information (in other words.returned value is one of SQLITE_INTEGER.value object.value object. into a blob memory. replace the main sqlite3 engine with any external library: FreeAndNil(sqlite3). static) sqlite3 := TSQLite3LibraryDynamic. Initialize the specified external library . constructor Create(const LibraryName: TFileName='sqlite3.Synopse mORMot Framework Software Architecture Design 1. cdecl. 2.raise an ESQLite3Exception on any error Used for DI-2.1 (page 1052). var Values: TRawUTF8DynArray): integer.Execute the first statement in aSQL . const aSQL: RawUTF8. overload. 1.raise an ESQLite3Exception on any error Used for DI-2.this statement must get (at least) one field/column result of INTEGER . Create the exception.return count of row in integer function result (may be < length(ID)) . The corresponding error code constructor Create(const aMessage: string. override.2. overload.return result as a dynamic array of RawUTF8 in ID . Create the exception.18 Page 672 of 1055 . overload. aErrorCode: integer).1 (page 1052). aErrorCode: integer). reintroduce. Execute a SQL statement which return TEXT from the aSQL UTF-8 encoded string .2. Execute a SQL statement which return integers from the aSQL UTF-8 encoded string .return count of row in integer function result (may be < length(ID)) . reintroduce. const aSQL: RawUTF8. SynSQLite3. Unload the external library ESQLite3Exception = class(ESynException) Custom SQLite3 dedicated Exception type DB: TSQLite3DB.Rev.pas unit . getting the message from caller constructor Create(aDB: TSQLite3DB. var ID: TInt64DynArray): integer. 2013 destructor Destroy.Synopse mORMot Framework Software Architecture Design 1. The DB which raised this exception ErrorCode: integer. function Execute(aDB: TSQLite3DB.Execute the first statement in aSQL .1 (page 1052). overload.this statement must get (at least) one field/column result of TEXT .18 Date: June 16.return result as a dynamic array of Int64 in ID . function Execute(aDB: TSQLite3DB. getting the message from DB TSQLRequest = object(TObject) Wrapper to a SQLite3 request Used for DI-2. e.. first Col is 0 SynSQLite3.BLOB field value is saved as Base64. Return the generic VCL string type of this column..val21.] } . function ExecuteJSON(aDB: TSQLite3DB. reset and bound if necessary . Expand: boolean=false.val11. in the '"\uFFF0base64encodedbinary"' format and contains true BLOB data (no conversion into TEXT. const aSQL: RawUTF8. first Col is 0 . with UTF-8 encoding . '"\uFFF0base64encodedbinary"' ."col2". JSON data is serialized (used in TSQLTableJSON) { "FieldCount":1.2.raise an ESQLite3Exception on any error .Rev. Return the type of this column.if Expand is true.column_decltype() . as with TSQLTableDB) . and return a string .. Return a field as Win-Ansi (i.Synopse mORMot Framework Software Architecture Design 1."val12".JSON data is added to TStream. the ESQLite3Exception is handled and '' is returned function FieldA(Col: integer): WinAnsiString.. for direct use with any Ajax or . as declared at creation . JSON: TStream. Return a field as a blob value (RawByteString/TSQLRawBlob is an AnsiString).if any error occurs. overload. ] ."Values":["col1".pas unit .JSON format is more compact than XML and well supported .returns the number of data rows added to JSON (excluding the headers) Used for DI-2. as declared at creation .Execute the first statement in aSQL .g.BLOB field value is saved as Base64. Return a field floating point value. const aSQL: RawUTF8.NET client: [ {"col1":val11. Expand: boolean=false): PtrInt. 2013 function Execute(aDB: TSQLite3DB.18 Date: June 16.use internaly Execute() above with a TRawByteStringStream. aResultCount: PPtrInt=nil): RawUTF8. code page 1252) encoded text value.note that prior to Delphi 2009. 1.returns the number of data rows added to JSON (excluding the headers) in the integer variable mapped by aResultCount (if any) . you may loose content during conversion function FieldDouble(Col: integer): double. first Col is 0 function FieldBlob(Col: integer): RawByteString.textual type used for CREATE TABLE of the corresponding column."col2":"val12"}.. Execute one SQL statement which return the results in JSON format . e.18 Page 673 of 1055 . as returned by sqlite3. first Col is 0 function FieldBlobToStream(Col: integer): TStream.so will work for sftBlob. Execute one SQL statement which return the results in JSON format . JSON data is an array of objects.if Expand is false.textual type used for CREATE TABLE of corresponding column.caller shall release the returned TStream instance function FieldDeclaredType(Col: Integer): RawUTF8. the statement should have been prepared. Return a field as a TStream blob value. as returned by sqlite3. sftBlobDynArray and sftBlobRecord .if SQL is ''.{"col1":val21.1 (page 1052).column_decltype() function FieldDeclaredTypeS(Col: Integer): string. first Col is 0 function FieldW(Col: integer): RawUnicode. first Col is 0 .retrieve the "SQLite3" column type as returned by sqlite3. first Col is 0 function FieldS(Col: integer): string. Prepare a WinAnsi SQL statement . first Col is 0 function FieldName(Col: integer): RawUTF8.return SQLITE_OK on success.value object handle. Return TRUE if the column value is NULL. you may loose content during conversion function FieldType(Col: Integer): integer. SQLITE_NULL. The field name of the current ROW function FieldNull(Col: Integer): Boolean. Use BindReset() to reset the bindings .raise an ESQLite3Exception on any error function PrepareAnsi(DB: TSQLite3DB.pas unit . first Col is 0 function FieldValue(Col: integer): TSQLite3Value. const SQL: RawUTF8): integer. ready to be re-executed. or SQLITE_BLOB function FieldUTF8(Col: integer): RawUTF8. .any SQL statement variables that had values bound to them using the Bind*() function below retain their values. Prepare a UTF-8 encoded SQL statement .raise an ESQLite3Exception on any error function Reset: integer. Return a field RawUnicode encoded text value. first Col is 0 function Prepare(DB: TSQLite3DB. 1.compile the SQL into byte-code .i.Synopse mORMot Framework Software Architecture Design 1.parameters ? ?NNN :VV @VV $VV can be bound with Bind*() functions below . Return the field as a sqlite3.reset a prepared statement object back to its initial state. Return the field type of this column .return -1 if not found function FieldInt(Col: integer): Int64.column_type .behave the same as Prepare() function PrepareNext: integer.note that prior to Delphi 2009. SQLITE_TEXT. Prepare the next SQL command initialized in previous Prepare() . Return a field integer value.e. Return a field UTF-8 encoded text value. const SQL: WinAnsiString): integer. Return a text value value as generic VCL string.18 Page 674 of 1055 . 2013 function FieldIndex(const aColumnName: RawUTF8): integer.Rev. The field index matching this name . SQLITE_INTEGER. SQLITE_FLOAT. Reset A Prepared Statement Object .18 Date: June 16. or the previous Step error code SynSQLite3. Data: TCustomMemoryStream). Bind a Blob buffer to a parameter . with data ready to be retrieved via the Field*() methods .18 Date: June 16.raise an ESQLite3Exception on any error procedure Bind(Param: Integer.Rev.raise an ESQLite3Exception on any error SynSQLite3.the leftmost SQL parameter has an index of 1. Size: integer). overload.Synopse mORMot Framework Software Architecture Design 1. Bind a Blob TCustomMemoryStream buffer to a parameter .the leftmost SQL parameter has an index of 1.return SQLITE_DONE if the SQL commands were executed .step() result status: . overload. const Value: string). Bind a NULL value to a parameter . you may loose some content here: Bind(Param: integer. overload. but ?NNN may override it . 2013 function Step: integer.18 Page 675 of 1055 . Bind an integer value to a parameter . Reset All Bindings On A Prepared Statement .pas unit . Value: Int64). but ?NNN may override it . returning the sqlite3. Use this routine to reset all host parameter procedure BindS(Param: Integer.the leftmost SQL parameter has an index of 1.with versions prior to Delphi 2009.Contrary to the intuition of many. but ?NNN may override it . Bind a generic VCL string to a parameter . Bind a double value to a parameter . Data: pointer. but ?NNN may override it .the leftmost SQL parameter has an index of 1.raise an ESQLite3Exception on any error procedure Bind(Param: Integer. Value: RawUTF8) is the prefered method .raise an ESQLite3Exception on any error procedure BindNull(Param: Integer).raise an ESQLite3Exception on any error procedure Bind(Param: Integer.raise an ESQLite3Exception on any error procedure Bind(Param: Integer. overload. Reset() does not reset the bindings on a prepared statement. but ?NNN may override it . but ?NNN may override it .raise an ESQLite3Exception on any error procedure BindReset.the leftmost SQL parameter has an index of 1.raise an ESQLite3Exception on any error procedure Bind(Param: Integer. const Value: RawUTF8).the leftmost SQL parameter has an index of 1.the leftmost SQL parameter has an index of 1. overload. 1. Bind a UTF-8 encoded string to a parameter .return SQLITE_ROW on success. but ?NNN may override it . Evaluate An SQL Statement. Value: double). raise an ESQLite3Exception on any error Used for DI-2.2. overload.this statement must get (at least) one field/column result of TEXT .). const aSQL: RawUTF8). . Execute a SQL statement which return one integer from the aSQL UTF-8 encoded string . Zeroblobs are intended to serve as placeholders for BLOBs whose content is later written using incremental BLOB I/O routines (as with TSQLBlobStream created from TSQLDataBase. procedure Execute(aDB: TSQLite3DB.raise an ESQLite3Exception on any error procedure Close.the statement is closed . Execute a SQL statement which return one TEXT value from the aSQL UTF-8 encoded string .2.Blob() e. const aSQL: RawUTF8. overload.2.raise an ESQLite3Exception on any error Used for DI-2.1 (page 1052).1 (page 1052). Execute all SQL statements already prepared by a call to Prepare() .Synopse mORMot Framework Software Architecture Design 1.the statement is closed . const aSQL: RawUTF8. Bind a ZeroBlob buffer to a parameter .the leftmost SQL parameter has an index of 1.18 Page 676 of 1055 .Execute the first statement in aSQL .Execute the first statement in aSQL . overload. out ID: Int64).18 Date: June 16. 1.raise an ESQLite3Exception on any error SynSQLite3. 2013 procedure BindZero(Param: Integer.Close is always called internaly . Execute one SQL statement in the aSQL UTF-8 encoded string . procedure ExecuteAll.raise an ESQLite3Exception on any error Used for DI-2. procedure Execute(aDB: TSQLite3DB.2.Execute the first statement in aSQL: call Prepare() then Step once .a negative value for the Size parameter results in a zero-length BLOB .1 (page 1052).raise an ESQLite3Exception on any error Used for DI-2.uses a fixed amount of memory (just an integer to hold its size) while it is being processed. out Value: RawUTF8). Close the Request handle .call it even if an ESQLite3Exception has been raised procedure Execute(aDB: TSQLite3DB. Execute one SQL statement already prepared by a call to Prepare() . but ?NNN may override it .g.this statement must get (at least) one field/column result of INTEGER . procedure Execute.1 (page 1052).Rev. Size: integer). overload.return result as an unique Int64 in ID .pas unit . overload. Returns true if the current prepared statement makes no direct changes to the content of the database file . The ATTACH and DETACH statements also cause this property to return true since. they do not make changes to the content of the database files on disk. Append all columns values of the current Row to a JSON stream . const aSQL: RawUTF8).Transaction control statements such as BEGIN.Rev.will use WR. results will be written as ANSI text in OutFile procedure FieldsToJSON(WR: TJSONWriter. Associated SQL statement SynSQLite3. SAVEPOINT. The bound parameters count property Request: TSQLite3Statement read fRequest. DoNotFletchBlobs: boolean=false). ROLLBACK.BLOB field value is saved as Base64. var OutFile: Text).fields numerotation starts with 0 property IsReadOnly: Boolean read GetReadOnly.Close is always called internaly . Read-only access to the Request (SQLite3 statement) handle property RequestDB: TSQLite3DB read fDB. The column/field count of the current ROW . in the '"\uFFF0base64encodedbinary" format and contains true BLOB data property FieldCount: integer read fFieldCount. Execute all SQL statements in the aSQL UTF-8 encoded string. Associated prepared statement.raise an ESQLite3Exception on any error procedure ExecuteDebug(aDB: TSQLite3DB. while those statements change the configuration of a database connection. ready to be executed after binding StatementSQL: RawUTF8. overload. 1. and RELEASE cause this property to return true. 2013 procedure ExecuteAll(aDB: TSQLite3DB.pas unit . since the statements themselves do not actually modify the database but rather they control the timing of when other statements modify the database.internaly call Prepare() then Step then PrepareNext until end of aSQL .Expand to guess the expected output format .18 Page 677 of 1055 . property ParamCount: integer read GetParamCount.18 Date: June 16.Synopse mORMot Framework Software Architecture Design 1. const aSQL: RawUTF8. Execute all SQL statements in the aSQL UTF-8 encoded string . COMMIT. Read-only access to the SQLite3 database handle TSQLStatementCache = record Used to retrieve a prepared statement Statement: TSQLRequest. due to a bug in Delphi 2009/2010 compiler (at least): this structure is not initialized if defined as an object on the stack.g. TReferenceDynArray will declare 'ReferenceDynArray') property FunctionName: RawUTF8 read fSQLName. Hashing wrapper associated to the Cache[] array Count: integer.expects at least the low-level TSQLFunctionFunc implementation (in sqlite3.pas unit . The internal function prototype .Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16. The SQL function name. Intialize the cache procedure ReleaseAllDBStatements. 1. to implement optional parameters) property FunctionParametersCount: integer read fFunctionParametersCount.the same function name may be registered several times with a diverse number of parameters (e. Prepared statements with parameters for faster SQLite3 execution . The number of parameters expected by the SQL function property InternalFunction: TSQLFunctionFunc read fInternalFunction. but will be as a record :( Cache: TSQLStatementCacheDynArray.works for SQL code with ? internal parameters Caches: TDynArrayHashed. Current number of items in the Cache[] array DB: TSQLite3DB.Rev. const aFunctionName: RawUTF8='').g.ready to be assigned to sqlite3. it will be retrieved from the type information (e.create_function_v2() xFunc parameter SynSQLite3.create_function_v2() format) and the number of expected parameters . Add or retrieve a generic SQL (with ? parameters) statement from cache procedure Init(aDB: TSQLite3DB). as called from the SQL statement . 2013 TSQLStatementCached = object(TObject) Handle a cache of prepared statements . Initialize the corresponding SQL function .if the function name is not specified.18 Page 678 of 1055 . aFunctionParametersCount: Integer.is defined either as an object either as a record. reintroduce. The associated SQLite3 database instance function Prepare(const GenericSQL: RaWUTF8): PSQLRequest. Used internaly to release all prepared statements from Cache[] TSQLDataBaseSQLFunction = class(TObject) Those classes can be used to define custom SQL functions inside a TSQLDataBase constructor Create(aFunction: TSQLFunctionFunc. which is used also in the SQLite3UI unit for coherency and efficiency) .ElemSave()) if called via a Client and a JSON prepared parameter) . a RollBack is performed SynSQLite3. const aPassword: RawUTF8=''). TReferenceDynArray will declare 'ReferenceDynArray') . and will be therefore slower than those optimized versions) TSQLDataBase = class(TObject) Simple wrapper for direct SQLite3 database manipulation . and the 2nd is the array element to search (set with TDynArray.if TransactionBegin was called but not commited.ElemSave() or with BinToBase64WithMagic(aDynArray. reintroduce. the password will be used to cypher this file on disk (the main SQLite3 database file is encrypted. CONCAT . Used for DI-2.some additional SQl functions are registered: MOD. Close a database and free its memory and context .Rev.SYSTEMNOCASE collation is added (our custom fast UTF-8 case insensitive compare.g.Synopse mORMot Framework Software Architecture Design 1.c) . 2013 TSQLDataBaseSQLFunctionDynArray = class(TSQLDataBaseSQLFunction) To be used to define custom SQL functions for dynamic arrays BLOB search constructor Create(aTypeInfo: pointer.thread-safe call of all SQLite3 queries (SQLITE_THREADSAFE 0 in sqlite.if the function name is not specified.1 (page 1052).embed the SQLite3 database calls into a common object . const aFunctionName: RawUTF8=''). it will be retrieved from the type information (e.open an existing database file or create a new one if no file exists . Open a SQLite3 database file . Initialize the corresponding SQL function .raise an ESQLite3Exception on any error destructor Destroy.can cache last results for SELECT statements. if property UseCache is true: this can speed up most read queries. RANK.you should better use the already existing faster SQL functions Byte/Word/Integer/Cardinal/Int64/CurrencyDynArrayContains() if possible (this implementation will allocate each dynamic array into memory before comparison.pas unit .initialize a TRTLCriticalSection to ensure that all access to the database is atomic .if specified.ISO8601 collation is added (TDateTime stored as ISO-8601 encoded TEXT) .WIN32CASE and WIN32NOCASE collations are added (use slow but accurate Win32 CompareW) . 1. for web server or client UI e. aCompare: TDynArraySortCompare.the SQL function will expect two parameters: the first is the BLOB field content.2.18 Date: June 16.g.18 Page 679 of 1055 . SOUNDEX/SOUNDEXFR/SOUNDEXES. not the wal file during run) . override. constructor Create(const aFileName: TFileName. this statement must get (at least) one field/column result of TEXT . Execute one SQL statement returning TEXT from the aSQL UTF-8 encoded string . then reopened: it's very fast function Blob(const DBName.this statement must get a one field/column result of INTEGER .BindZero() to reserve Blob memory .if RowID=-1. Close the opened database .return result as a dynamic array of RawUTF8. VACCUUMed.close(fDB) so that it should be SQLITE_OK on success function DBOpen: integer. e.raise an ESQLite3Exception on any error function Execute(const aSQL: RawUTF8. ReadWrite: boolean=false): TSQLBlobStream.use after a TSQLRequest. aResultCount: PPtrInt=nil): RawUTF8.returns the SQLITE_* status code. table TableName in database DBName. e. var Values: TRawUTF8DynArray): integer. var ID: TInt64DynArray): integer.raise an ESQLite3Exception on any error function ExecuteJSON(const aSQL: RawUTF8.will raise an ESQLite3Exception on any error function DBClose: integer. to close temporary a DB file and allow making a backup on its content .don't use the experimental SQLite Online Backup API . Execute one SQL statement returning its results in JSON format . as TEXT result . column ColumnName.Synopse mORMot Framework Software Architecture Design 1. ColumnName: RawUTF8. as retrieved from sqlite3.Execute the first statement in aSQL .18 Page 680 of 1055 . overload.18 Date: June 16. Open a BLOB incrementally for read[/write] access . 1.pas unit .the BLOB data is encoded as '"\uFFF0base64encodedbinary"' SynSQLite3. the same BLOB that would be selected by: SELECT ColumnName FROM DBName.Create already opens the database: this method is to be used only on particular cases.TableName WHERE rowid = RowID.g.Destroy already closes the database: this method is to be used only on particular cases.database is closed. (re)open the database from file fFileName . Expand: boolean=false. Execute one SQL statement which return integers from the aSQL UTF-8 encoded string .Rev.TSQLDatabase. 2013 function Backup(const BackupFileName: TFileName): boolean. . Backup of the opened Database into an external file name .Execute the first statement in aSQL .g.return count of row in integer function result (may be < length(ID)) . RowID: Int64=-1. TableName. to close temporary a DB file and allow making a backup on its content .open() so that it should be SQLITE_OK on success function Execute(const aSQL: RawUTF8. copied. overload.return count of row in integer function result (may be < length(ID)) .return result as a dynamic array of RawUTF8 in ID . in other words.TSQLDatabase.find a BLOB located in row RowID. then the last inserted RowID is used . as retrieved from sqlite3.returns the SQLITE_* status code. e. Flush the internal SQL-based JSON cache content .this method returns the number of database rows that were changed or inserted or deleted by the most recently completed SQL statement on the database connection specified by the first parameter. out ID: Int64).Execute the first statement in aSQL .g.pas unit . .18 Page 681 of 1055 . with external tables as defined in SQLite3DB unit . Return the last Insert Rowid function LockJSON(const aSQL: RawUTF8.will also increment the global InternalState property value (if set) procedure Commit.can be prepared with TransactionBegin() . aResultCount: PPtrInt): RawUTF8. overload. or DELETE statement are counted. 1. Execute one SQL statements in aSQL UTF-8 encoded string .changes() low-level function function LastInsertRowID: Int64.Rev. Execute one SQL statement which returns one integer from the aSQL UTF-8 encoded string .if this SQL statement has an already cached JSON response. it will be filled with the returned row count of data (excluding field names) in the result procedure CacheFlush.18 Date: June 16. cache is flushed and the next call to UnLockJSON() won't add any value to the cache since this statement is not a SELECT and doesn't have to be cached! .raise no Exception on error. Count the number of rows modified by the last SQL statement .can be prepared with TransactionBegin() . but returns FALSE in such case function LastChangeCount: integer.if aResultCount does map to an integer variable. End a transaction: write all Execute() statements to the disk procedure Execute(const aSQL: RawUTF8. overload.raise an ESQLite3Exception on any error procedure Execute(const aSQL: RawUTF8). 2013 function ExecuteNoException(const aSQL: RawUTF8): boolean.Synopse mORMot Framework Software Architecture Design 1.to be called when the regular Lock/LockJSON methods are not called. Only changes that are directly specified by the INSERT. return it and don't enter the TRTLCriticalSection: no UnLockJSON() call is necessary . Enter the TRTLCriticalSection: called before any DB access .provide the SQL statement about to be executed: handle proper caching . overload.this statement must get a one field/column result of INTEGER .wrapper around the sqlite3.if this SQL statement is not a SELECT. UPDATE. Execute one SQL statements in aSQL UTF-8 encoded string .raise an ESQLite3Exception on any error SynSQLite3. Add a SQL custom function to the SQLite3 database engine .Execute the first statement in aSQL . Get all table names contained in this database file procedure Lock(const aSQL: RawUTF8).raise an ESQLite3Exception on any error procedure ExecuteAll(const aSQL: RawUTF8). Seamless execution of a SQL statement which returns one UTF-8 encoded string . Get all field names for a specified Table procedure GetTableNames(var Names: TRawUTF8DynArray). overload.'CharIndex'). overload.Synopse mORMot Framework Software Architecture Design 1.typical use may be: Demo. overload.this statement must get a one field/column result of TEXT .is the SQL statement is void.this statement must get a one field/column result of INTEGER . 1. Seamless execution of a SQL statement which returns one integer .raise an ESQLite3Exception on any error procedure ExecuteNoException(const aSQL: RawUTF8.18 Date: June 16.provide the SQL statement about to be executed: handle proper caching .returns 0 on any error procedure GetFieldNames(var Names: TRawUTF8DynArray. aFunctionParametersCount: Integer.this statement must get a one field/column result of TEXT .Execute the first statement in aSQL . out ID: Int64). overload.18 Page 682 of 1055 . Execute one SQL statement which returns one UTF-8 encoded string value .Rev. and enter the TRTLCriticalSection procedure RegisterSQLFunction(aFunction: TSQLFunctionFunc. SynSQLite3. Flush the internal statement cache.2. 2013 procedure Execute(const aSQL: RawUTF8.returns '' on any error procedure ExecuteNoException(const aSQL: RawUTF8.Execute the first statement in aSQL . const TableName: RawUTF8).can be prepared with TransactionBegin() . Execute all SQL statements in aSQL UTF-8 encoded string . out ID: RawUTF8). out ID: RawUTF8). assume a SELECT statement (no cache flush) procedure LockAndFlushCache.pas unit . Enter the TRTLCriticalSection: called before any DB access . const aFunctionName: RawUTF8).will do nothing if the same function name and parameters count have already been registered (you can register then same function name with several numbers of parameters) .RegisterSQLFunction(InternalSQLFunctionCharIndex. Destroy destructor .the resulting SQL function will expect two parameters: the first is the BLOB field content. it will be retrieved from the type information (e. Begin a transaction .'CharIndex')).ElemSave() or with BinToBase64WithMagic(aDynArray. Abort a transaction: restore the previous state of the database procedure TransactionBegin(aBehavior: TSQLDataBaseTransactionBehaviour = tbDeferred).caller must provide the JSON result for the SQL statement previously set by LockJSON() . aCompare: TDynArraySortCompare. overload.Rev.do proper caching of the JSON response for this SQL statement property BusyTimeout: Integer read fBusyTimeout write SetBusyTimeout.The default transaction behavior is tbDeferred procedure UnLock. and will be therefore slower than those optimized versions . before returning an error property Cache: TSynCache read fCache.18 Date: June 16. procedure RollBack. 2013 procedure RegisterSQLFunction(aDynArrayTypeInfo: pointer. aResultCount: PtrInt).will do nothing if the same function name and parameters count have already been registered (you can register then same function name with several numbers of parameters) .2.you may use the overloaded function.if the function name is not specified.see UseCache property and CacheFlush method SynSQLite3. and the 2nd is the array element to search (as set with TDynArray. const aFunctionName: RawUTF8=''). Sets a busy handler that sleeps for a specified amount of time (in milliseconds) when a table is locked. overload.Execute SQL statements with Execute() procedure below .the supplied aFunction instance will be used globally and freed by TSQLDataBase.must be ended with Commit on success . Add a SQL custom function to the SQLite3 database engine .must be aborted with Rollback after an ESQLite3Exception raised .RegisterSQLFunction( TSQLDataBaseSQLFunction.ElemSave()) if called via a Client and a JSON prepared parameter) . used by ExecuteJSON() method . which is a wrapper around: Demo. Leave the TRTLCriticalSection: called after any DB access procedure UnLockJSON(const aJSONResult: RawUTF8.Create(InternalSQLFunctionCharIndex.but it will be always faster than Client-Server query. TReferenceDynArray will declare 'ReferenceDynArray') .you should better use the already existing faster SQL functions Byte/Word/Integer/Cardinal/Int64/CurrencyDynArrayContains() if possible (this implementation will allocate each dynamic array into memory before comparison. in all cases) procedure RegisterSQLFunction(aFunction: TSQLDataBaseSQLFunction).pas unit .g.Synopse mORMot Framework Software Architecture Design 1.18 Page 683 of 1055 . Leave the TRTLCriticalSection: called after any DB access . 1. Access to the internal JSON cache. Add a SQL custom function for a dynamic array to the database . Synopse mORMot Framework Software Architecture Design 1. data should be safe if the application crashes. the way it locks the file . and safe until a catastrophic hardware failure occurs . 2013 property CacheSize: cardinal read GetCacheSize write SetCacheSize. since it won't work if the linked SQLite3 library is version 3.18 Date: June 16. Read-only access to the SQLite3 database handle property FileName: TFileName read fFileName.smOff is the fastest.by default. i. Read-only access to the SQLite3 database filename opened property InternalState: PCardinal read fInternalState write fInternalState.we do not handle negative values here (i. inside a critical section property LockingMode: TSQLLockingMode read GetLockingMode write SetLockingMode. which sounds a good compromise since it does not make sense to log all the JSON content retrieved from the database engine.lmExclusive gives better performance in case of a number of write transactions.this pointer is thread-safe updated. Return TRUE if a Transaction begun SynSQLite3. the change only endures for the current session. any not SELECT statement) .default lmNormal is ACID and safe . but achieve 100% ACID behavior . Access to the log instance associated with this SQLite3 database engine property LogResultMaximumSize: integer read fLogResultMaximumSize write fLogResultMaximumSize. i.Rev.pas unit . Query or change the SQlite3 file-based locking mode.default smFull is very slow.e. Query or change the SQlite3 file-based syncrhonization mode. is set to 512 bytes. Sets a maximum size (in bytes) to be logged as sllResult rows . the way it waits for the data to be flushed on hard drive .when you change the cache size using the cache_size pragma.smNormal is faster. 1. when a huge SELECT is executed property Synchronous: TSQLSynchronousMode read GetSynchronous write SetSynchronous.7. so can be used to release a mORMot server power: but you won't be able to access the database file from outside the process (like a "normal" database engine) property Log: TSynLog read fLog. Auery or change the suggested maximum number of database disk pages that SQLite will hold in memory at once per open database file .e.default suggested cache size is 2000 pages . The cache size reverts to the default value when the database is closed and reopened .18 Page 684 of 1055 .e. KB of RAM).9 and earlier property DB: TSQLite3DB read fDB.e. This integer pointer (if not nil) is incremented when any SQL statement changes the database contents (i. but database file may be corrupted in case of failure at the wrong time property TransactionActive: boolean read fTransactionActive. but our SQlite3 framework use locked access to the databse.18 Page 685 of 1055 .by default.Synopse mORMot Framework Software Architecture Design 1. With our SQLite3 framework. Query or change the Write-Ahead Logging mode for the database . override. Count: Longint): Longint.Create() property user_version: cardinal read GetUserVersion write SetUserVersion. const DBName.1 (page 1052). Reading and writing can proceed concurrently.TableName WHERE rowid = RowID. override. table TableName in database DBName.2. TableName. column ColumnName. it's not needed.ExecuteJSON() and TSQLTableDB. override.data is read/written directly from/to the SQLite3 BTree .cache is used by TSQLDataBase. RowID: Int64. but WAL provides more concurrency as readers do not block writers and a writer does not block readers.this TStream has a fixed size. but if you call directly TSQLDatabase instances in your code. refresh some hand-made triggers) property WALMode: Boolean read GetWALMode write SetWALMode. Origin: Word): Longint.beginning with version 3. . so there should be no benefit of WAL for the framework. this option is not set: only implement if you really need it.cache is flushed on any write access to the DB (any not SELECT statement) . Opens a BLOB located in row RowID. Read Count bytes from the opened BLOB in Buffer function Seek(Offset: Longint.18 Date: June 16.user-version is a 32-bit signed integer stored in the database header . in other words.WAL might be very slightly slower (perhaps 1% or 2% slower) than the traditional rollback-journal approach in applications that do mostly reads and seldom write. all ExecuteJSON() responses will be cached . Release the BLOB object function Read(var Buffer. it may be useful to you TSQLBlobStream = class(TStream) Used to read or write a BLOB Incrementaly .Rev.cache is consistent only if ExecuteJSON() Expand parameter is constant . Retrieve or set the user_version stored in the SQLite3 database file . Change the current read position SynSQLite3.g.7 of the SQLite3 engine. If this property is set.BindZero() call to reserve memory . ColumnName: RawUTF8. but Position property can be used to rewind Used for DI-2.it can be used to change the database in case of format upgrade (e. constructor Create(aDB: TSQLite3DB. destructor Destroy.pas unit .data can be written after a TSQLRequest. 1. a new "Write-Ahead Log" option (hereafter referred to as "WAL") is optionaly available . ReadWrite: boolean). 2013 property UseCache: boolean read GetUseCache write SetUseCache. the same BLOB that would be selected by: SELECT ColumnName FROM DBName. . .The first pUserData parameter to the authorizer callback is a copy of the third parameter to the sqlite3. Read-only access to the BLOB object handle Types implemented in the SynSQLite3 unit: TOnSQLStoredProc = procedure(Statement: TSQLRequest) of object. Compile-Time Authorization Callback prototype . zCol.The authorizer callback is invoked as SQL statements are being compiled by sqlite3.Here is a list of handled code constant. const zTab. .prepare2() e. cdecl.Rev.the implementation may update the database directly by using a local or shared TSQLRequest . code: Integer.called for every row of a Statement .set_authorizer() interface .The second parameter to the callback is an integer action code that specifies the particular action to be authorized: . Stored Procedure prototype. 2013 function Write(const Buffer. 1. zAuthContext: PAnsiChar): Integer. zDb.Create() must have been called with ReadWrite=true property Handle: TSQLite3Blob read fBlob. Write is allowed for in-place replacement (resizing is not allowed) . or SQLITE_DENY then the sqlite3.pas unit . SQLITE_OK.finally protection is outside it . . . since all locking and try. Count: Longint): Longint.can optionnaly trigger a ESQLite3Exception on any error TSQLAuthorizerCallback = function(pUserData: Pointer. or SQLITE_DENY to cause the entire SQL statement to be rejected with an error. and their associated zTab / zCol parameters: const SQLITE_CREATE_INDEX SQLITE_CREATE_TABLE SQLITE_CREATE_TEMP_INDEX SQLITE_CREATE_TEMP_TABLE SQLITE_CREATE_TEMP_TRIGGER SQLITE_CREATE_TEMP_VIEW SQLITE_CREATE_TRIGGER SQLITE_CREATE_VIEW SQLITE_DELETE SQLITE_DROP_INDEX SQLITE_DROP_TABLE SQLITE_DROP_TEMP_INDEX SQLITE_DROP_TEMP_TABLE SQLITE_DROP_TEMP_TRIGGER SQLITE_DROP_TEMP_VIEW SQLITE_DROP_TRIGGER SQLITE_DROP_VIEW SQLITE_INSERT zTab Index Name Table Name Index Name Table Name Trigger Name View Name Trigger Name View Name Table Name Index Name Table Name Index Name Table Name Trigger Name View Name Trigger Name View Name Table Name zCol Table Name nil Table Name nil Table Name nil Table Name nil nil Table Name nil Table Name nil Table Name nil Table Name nil nil SynSQLite3.The third through sixth parameters to the callback are zero-terminated strings that contain additional details about the action to be authorized.18 Page 686 of 1055 .the TSQLRequest may be shared and prepared before the call for even faster access than with a local TSQLRequest .Execute() below .no TSQLDataBase or higher levels objects can be used inside this method. used by TSQLDataBase.18 Date: June 16.The authorizer callback should return SQLITE_OK to allow the action. SQLITE_IGNORE to disallow the specific action but allow the SQL statement to continue to be compiled.If the authorizer callback returns any value other than SQLITE_IGNORE.g.prepare_v2() or equivalent call that triggered the authorizer will fail with an error message.Synopse mORMot Framework Software Architecture Design 1. override. 18 Page 687 of 1055 . Note that sqlite3.pas unit . etc.The 6th parameter to the authorizer callback is the name of the inner-most trigger or view that is responsible for the access attempt or nil if this access attempt is directly from top-level SQL code.) if applicable. or an error or constraint causes an implicit rollback to occur. TSQLBusyHandler = function(user: pointer. 1. s1Len: integer. just as it would be with any other rollback. then the COMMIT is converted into a ROLLBACK.For the purposes of this API.used by sqlite3.e. 'temp'.Synopse mORMot Framework Software Architecture Design 1. . count: integer): integer.If the busy callback returns 0.18 Date: June 16. .prepare_v2() and sqlite3. The rollback hook is invoked on a rollback that results from a commit hook returning non-zero. 2013 SQLITE_PRAGMA SQLITE_READ SQLITE_SELECT SQLITE_TRANSACTION SQLITE_UPDATE SQLITE_ATTACH SQLITE_DETACH SQLITE_ALTER_TABLE SQLITE_REINDEX SQLITE_ANALYZE SQLITE_CREATE_VTABLE SQLITE_DROP_VTABLE SQLITE_FUNCTION SQLITE_SAVEPOINT Pragma Name Table Name nil Operation Table Name Filename Database Name Database Name Index Name Table Name Table Name Table Name nil Operation 1st arg or nil Column Name nil nil Column Name nil nil Table Name nil nil Module Name Module Name Function Name Savepoint Name .The callback implementation must not do anything that will modify the database connection that invoked the callback. cdecl. sort and comparaison) function prototype .busy_handler(). The rollback callback is not invoked if a transaction is automatically rolled back because the database connection is closed. . SQLite3 collation (i. s1: pointer.step() both modify their database connections for the meaning of "modify" in this paragraph. then no additional attempts are made to access the database and SQLITE_BUSY or SQLITE_IOERR_BLOCKED is returned. .step() call that triggered the commit or rollback hook in the first place. the COMMIT operation is allowed to continue normally. . Commit And Rollback Notification Callback function after sqlite3. If the commit hook returns non-zero.The 5th parameter to the authorizer callback is the name of the database ('main'. a transaction is said to have been rolled back if an explicit "ROLLBACK" statement is executed.rollback_hook() registration .this function MUST use s1Len and s2Len parameters during the comparaison: s1 and s2 are not zero-terminated . Any actions to modify the database connection must be deferred until after the completion of the sqlite3.When the commit hook callback routine returns zero. . SynSQLite3.The second argument to the busy handler callback is the number of times that the busy handler has been invoked for this locking event. s2: pointer) : integer. cdecl.create_collation low-level function TSQLCommitCallback = function(pArg: Pointer): Integer.If the callback returns non-zero.commit_hook() or sqlite3. s2Len: integer. SQLite3 callback prototype to handle SQLITE_BUSY errors . cdecl. TSQLCollateFunc = function(CollateParam: pointer. then another attempt is made to open the database for reading and the cycle repeats.The first argument to the busy handler is a copy of the user pointer which is the third argument to sqlite3.Rev. which are available in argv[] (you can call ErrorWrongNumberOfArgs(Context) in case of unexpected number) . TSQLDataBase.context object.pas unit . cdecl.set to sqlite3InternalFreeObject if a Value must be released via TObject(p). After a BEGIN IMMEDIATE.result_*(Context. or exclusive .2. 1.argc is the number of supplied parameters.e. Type for a custom destructor for the text or BLOB content . Because the acquisition of locks is deferred until they are needed. argc: integer. immediate. tbImmediate. TSQLite3FunctionContext = type PtrUInt. var argv: TSQLite3ValueArray).18 Page 688 of 1055 .If the transaction is tbImmediate.1 (page 1052).value_*(argv[*]) functions to retrieve a parameter value . TSQLDestroyPtr = procedure(p: pointer). Other processes can continue to read from the database.context object is always first parameter to application-defined SQL functions.tbDeferred means that no locks are acquired on the database until the database is first accessed. however. it is possible that another thread or process could create a separate transaction and write to the database after the BEGIN on the current thread has executed. Thus with a deferred transaction. cdecl. the BEGIN statement itself does nothing to the filesystem. without waiting for the database to be used. . Internal store a SQLite3 Function Context Object .set to sqlite3InternalFree if a Value must be released via Freemem() .1 (page 1052).Rev. i. cdecl.A tbExclusive transaction causes EXCLUSIVE locks to be acquired on all databases.The context in which an SQL function executes is stored in an sqlite3.use sqlite3.2. The first read operation against a database creates a SHARED lock and the first write operation creates a RESERVED lock. 2013 TSQLDataBaseTransactionBehaviour = ( tbDeferred.*) functions TSQLite3Blob = type PtrUInt.18 Date: June 16.Synopse mORMot Framework Software Architecture Design 1. Internaly store the SQLite3 database handle Used for DI-2. After a BEGIN EXCLUSIVE. tbExclusive ).then set the result using sqlite3. which is mapped to this TSQLite3FunctionContext type . Locks are not acquired until the first read or write operation.2. Internaly store the SQLite3 blob handle Used for DI-2. no other database connection will be able to write to the database or do a BEGIN IMMEDIATE or BEGIN EXCLUSIVE.A pointer to an sqlite3. . no other database connection except for read_uncommitted connections will be able to read the database and no other connection without exception will be able to write the database until the transaction is complete. TSQLite3DB = type PtrUInt. then RESERVED locks are acquired on all databases as soon as the BEGIN command is executed.1 (page 1052). a TSQLFunctionFunc prototype Used for DI-2.TransactionBegin can be deferred. SQLite3 user function or aggregate callback prototype . SQLite3 user final aggregate callback prototype TSQLFunctionFunc = procedure(Context: TSQLite3FunctionContext. SynSQLite3.Free TSQLFunctionFinal = procedure(Context: TSQLite3FunctionContext). smFull ). Database locks obtained by a connection in lmExclusive mode may be released either by closing the database connection. Used for DI-2. The first time the database is written.Synopse mORMot Framework Software Architecture Design 1.Bind values to host parameters using the sqlite3. Simply setting the locking-mode to lmNormal is not enough . Internaly store the SQLite3 statement handle . and could be used when needed.1 (page 1052). or NULL Used for DI-2.2. Available file-level write access wait mode of the SQLite3 engine . TSQLLockingMode = ( lmNormal. an exclusive lock is obtained and held. a shared lock is obtained and held.SQLite uses the sqlite3.when synchronous is smNormal. but it is also slower. Internaly store a SQLite3 Dynamically Typed Value Object . BLOBs.Destroy the object using sqlite3.Rev. which are mapped to this TSQLite3Value type .1 (page 1052). . Do this zero or more times. the SQLite database engine will still sync at the most critical moments. There is a very small (though non-zero) chance that a power failure at just the wrong time could corrupt the database in NORMAL mode. . .This object is variously known as a "prepared statement" or a "compiled SQL statement" or simply as a "statement". 2013 TSQLite3Statement = type PtrUInt. .prepare_v2() or a related function.Values stored in sqlite3.when synchronous is smFull (which is the default setting).lmExclusive gives much better write performance.value object to represent all values that can be stored in a database table.63] of TSQLite3Value. . The first time the database is read in lmExclusive mode.lmNormal locking-mode (the default unless overridden at compile-time using SQLITE_DEFAULT_LOCKING_MODE). lmExclusive ).Run the SQL by calling sqlite3. 1. floating point values. but less often than in FULL mode.finalize()..SQLite uses dynamic typing for the values it stores . smNormal.2. TSQLite3ValueArray = array[0.value objects can be integers.Create the object using sqlite3.2. . Internaly store any array of SQLite3 value Used for DI-2. Available file-level database connection locking-mode . or by setting the locking-mode back to lmNormal using this pragma and then accessing the database file (for read or write). But in practice.when the locking-mode is set to lmExclusive. TSQLite3Value = type PtrUInt. This ensures that an operating system crash or power failure will not corrupt the database. in case of a heavy loaded mORMot server TSQLStatementCacheDynArray = array of TSQLStatementCache. the database connection never releases file-locks. Used to store all prepared statement TSQLSynchronousMode = ( smOff.locks are not released until the next time the database file is accessed.18 Page 689 of 1055 . . strings.1 (page 1052).pas unit .Reset the statement using sqlite3. SynSQLite3.18 Date: June 16. the SQLite database engine will use the xSync method of the VFS to ensure that all content is safely written to the disk surface prior to continuing. . a database connection unlocks the database file at the conclusion of each read or write transaction.bind_*() interfaces. FULL synchronous is very safe.step() one or more times.reset() then go back to "Bind" step. Trace: PUTF8Char). Internal SQLite3 type as Blob SQLITE_BUSY = 5. the data will be safe.update_hook(). SynSQLite3. TSQLTraceCallback = procedure(TraceArg: Pointer. iRowID: Int64). Sqlite_exec() return code: Unable to open the database file SQLITE_CONSTRAINT = 19.step() both modify their database connections for the meaning of "modify" in this paragraph.The second op argument is one of SQLITE_INSERT. In the case of an update. . .update_hook() registration .create_function_v2 don't care about text encoding SQLITE_AUTH = 23. Note that sqlite3. . Sqlite_exec() return code: The database file is locked SQLITE_CANTOPEN = 14. Any actions to modify the database connection must be deferred until after the completion of the sqlite3.The first pUpdateArg argument is a copy of the third argument to sqlite3.when synchronous is smOff. 2013 you are more likely to suffer a catastrophic disk failure or some other unrecoverable hardware fault. const zDb.The update hook implementation must not do anything that will modify the database connection that invoked the update hook. Sqlite_exec() return code: Abort due to contraint violation SQLITE_CORRUPT = 11. 1. inserted or deleted. . SQLite continues without syncing as soon as it has handed data off to the operating system. On the other hand. Sqlite3. after sqlite3. or SQLITE_UPDATE. op: Integer.pas unit .Rev.this procedure will be invoked at various times when an SQL statement is being run by sqlite3. depending on the operation that caused the callback to be invoked. .Synopse mORMot Framework Software Architecture Design 1. Sqlite_exec() return code: Authorization denied SQLITE_BLOB = 4. Sqlite_exec() return code: Callback routine requested an abort SQLITE_ANY = 5.step() call that triggered the update hook.18 Page 690 of 1055 . but the database might become corrupted if the operating system crashes or the computer loses power before that data has been written to the disk surface.step() TSQLUpdateCallback = procedure(pUpdateArg: Pointer. SQLITE_DELETE.The third and fourth zDB / zTbl arguments contain pointers to the database and table name containing the affected row.trace() . zTbl: PUTF8Char. some operations are as much as 50 or more times faster with synchronous OFF. Constants implemented in the SynSQLite3 unit: SQLITE_ABORT = 4.The final iRowID parameter is the rowid of the row. If the application running SQLite crashes.18 Date: June 16. cdecl.prepare_v2() and sqlite3. this is the rowid after the update takes place. cdecl. Callback function registered by sqlite3. Callback function invoked when a row is updated. Sqlite_exec() return code: Operation terminated by sqlite3.legacy generic code SQLITE_FLOAT = 2. Internal SQLite3 type as Integer SQLITE_INTERNAL = 2.Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16. Sqlite_exec() return code: A table in the database is locked SQLITE_MISMATCH = 20. Sqlite_exec() return code: Some kind of disk I/O error occurred SQLITE_LOCKED = 6. Sqlite_exec() return code: Database is empty SQLITE_ERROR = 1. Sqlite_exec() return code: File opened that is not a database file SQLITE_NOTFOUND = 12. 2013 Sqlite_exec() return code: The database disk image is malformed SQLITE_DONE = 101. Sqlite_exec() return code: Library used incorrectly SQLITE_NOLFS = 22. Sqlite_exec() return code: Uses OS features not supported on host SQLITE_NOMEM = 7.interrupt() SQLITE_IOERR = 10. Sqlite_exec() return code: An internal logic error in SQLite SQLITE_INTERRUPT = 9.step() return code: has finished executing SQLITE_EMPTY = 16. Sqlite_exec() return code: SQL error or missing database . Internal SQLite3 type as Floating point value SQLITE_FORMAT = 24. Sqlite3. Internal SQLite3 type as NULL SynSQLite3.Rev. Sqlite_exec() return code: Auxiliary database format error SQLITE_FULL = 13. Sqlite_exec() return code: A malloc() failed SQLITE_NOTADB = 26. 1. Sqlite_exec() return code: Insertion failed because database is full SQLITE_INTEGER = 1.pas unit .18 Page 691 of 1055 . Sqlite_exec() return code: Data type mismatch SQLITE_MISUSE = 21. Sqlite_exec() return code: (Internal Only) Table or record not found SQLITE_NULL = 5. Sqlite_exec() return code: Attempt to write a readonly database SQLITE_ROW = 100. using the system native byte order SQLITE_UTF16BE = 3. Sqlite_exec() return code: (Internal Only) Database lock protocol error SQLITE_RANGE = 25. Sqlite_exec() return code: no error occured SQLITE_PERM = 3. Sqlite3.malloc() before it returns .note that we discovered that under Win64. 1.18 Page 692 of 1055 . sqlite3. Sqlite_exec() return code: Access permission denied SQLITE_PROTOCOL = 15. DestroyPtr set to SQLITE_TRANSIENT for SQLite3 to make a private copy of the data into space obtained from from sqlite3. Text is UTF-16 LE encoded SQLITE_UTF16_ALIGNED = 8.result_text() expects SQLITE_TRANSIENT_VIRTUALTABLE=pointer(integer(-1)) and not pointer(-1) SQLITE_TRANSIENT_VIRTUALTABLE = pointer(integer(-1)).due to a bug of the SQlite3 engine under Win64 SQLITE_UTF16 = 4.create_collation() only SynSQLite3. DestroyPtr set to SQLITE_STATIC if data is constant and will never change . Sqlite_exec() return code: Too much data for one row of a table SQLITE_TRANSIENT = pointer(-1). Used by sqlite3.bind out of range SQLITE_READONLY = 8.this is the default behavior in our framework . Internal SQLite3 type as Text SQLITE_TOOBIG = 18. Text is UTF-16 encoded. and unable to be recompiled SQLITE_STATIC = pointer(0). 2013 SQLITE_OK = 0.step() return code: another result row is ready SQLITE_SCHEMA = 17.SQLite assumes that the text or BLOB result is in constant space and does not copy the content of the parameter nor call a destructor on the content when it has finished using that result SQLITE_TEXT = 3.pas unit . Sqlite_exec() return code: 2nd parameter to sqlite3.Synopse mORMot Framework Software Architecture Design 1. DestroyPtr set to SQLITE_TRANSIENT_VIRTUALTABLE for setting results to SQlite3 virtual tables columns .18 Date: June 16.Rev. Sqlite_exec() return code: The database schema changed. Text is UTF-16 BE encoded SQLITE_UTF16LE = 2. Text is UTF-8 encoded SQL_GET_TABLE_NAMES = 'SELECT name FROM sqlite_master WHERE type=''table'' AND name NOT LIKE ''sqlite_%''.result_error() to be called if wrong number of arguments 693 ExceptionToSqlite3Err Create a TSQLite3Module. cdecl. cdecl.18 Page 693 of 1055 .pzErr UTF-8 text buffer according to the given Delphi exception function IsSQLite3File(const FileName: TFileName): boolean.this will check the 2nd file page beginning to be a valid B-TREE page . var pzErr: PUTF8Char).result_error() to be called if wrong number of arguments procedure ExceptionToSqlite3Err(E: Exception. Check from the file beginning if sounds like a valid SQLite3 file . 2013 SQLITE_UTF8 = 1.in some cases. 1.pzErr UTF-8 text buffer according to the given Delphi exception 693 IsSQLite3File Check from the file beginning if sounds like a valid SQLite3 file 693 IsSQLite3FileEncrypte d Check if sounds like an encrypted SQLite3 file 693 sqlite3InternalFree An internal function which calls Freemem(p) 693 sqlite3InternalFreeOb ject An internal function which calls TObject(p). Wrapper around sqlite3.can be used to free some PUTF8Char pointer allocated by Delphi Getmem() procedure sqlite3InternalFreeObject(p: pointer).*() function 694 procedure ErrorWrongNumberOfArgs(Context: TSQLite3FunctionContext).'. Create a TSQLite3Module.Free .can be used to free some Delphi class instance SynSQLite3.Free 693 sqlite3_check Test the result state of a sqlite3.pas unit .Synopse mORMot Framework Software Architecture Design 1.Rev. An internal function which calls Freemem(p) . this function will return true if a database file is encrypted or not function IsSQLite3FileEncrypted(const FileName: TFileName): boolean.since encryption starts only with the 2nd page. An internal function which calls TObject(p). Check if sounds like an encrypted SQLite3 file . may return false negatives (depending on the password used) procedure sqlite3InternalFree(p: pointer). SQL statement to get all tables names in the current database file (taken from official SQLite3 documentation) Functions or procedures implemented in the SynSQLite3 unit: Functions or procedures Description Page ErrorWrongNumberOfArg s Wrapper around sqlite3.18 Date: June 16. if available from SQLite3Commons .pas unit .SQLITE_ROW.obj.18 Page 694 of 1055 . // release any previous instance sqlite3 := TSQLite3LibraryDynamic.18 Date: June 16.you may override it with TSQLLog. 1.since not all exceptions are handled specificaly by this unit. sqlite3.*() function .your project should use EITHER SynSQLite3Static unit OR create a TSQLite3LibraryDynamic instance: FreeAndNil(sqlite3). Test the result state of a sqlite3.g.open() instead of sqlite3_open() for instance . Global access to linked SQLite3 library API calls .) Variables implemented in the SynSQLite3 unit: sqlite3: TSQLite3Library. or to an external library (e. 2013 function sqlite3_check(DB: TSQLite3DB.you should call sqlite3.Create.SQLITE_DONE e.Rev.points either to the statically linked sqlite3. you may better use a common TSynLog class for the whole application or module SynSQLite3.Synopse mORMot Framework Software Architecture Design 1.raise a ESQLite3Exception if the result state is an error .g.dll under Windows) . The TSynLog class used for logging for all our SynSQlite3 related functions .return the result state otherwize (SQLITE_OK. SynSQLite3Log: TSynLogClass = TSynLog. aResult: integer): integer. 18 Date: June 16. 2013 23.allow execution of statements as such: SELECT column FROM table WHERE column REGEXP '<here goes your expression>'. version 1.pas unit Purpose: REGEXP function for SQLite3 Database using PCRE library .this unit is a part of the freeware Synopse mORMot framework.Synopse mORMot Framework Software Architecture Design 1.18 325 SynSQLite3 SQLite3 Database engine direct access . licensed under a MPL/GPL/LGPL tri-license. SynSQLite3RegEx.pas unit . version 1.18 647 Functions or procedures implemented in the SynSQLite3RegEx unit: Functions or procedures Description CreateRegExpFunction Page 695 function CreateRegExpFunction(DB: TSQLite3DB): boolean. version 1. SynSQLite3RegEx.19. Register the REGEXP SQL function to a given SQLite3 engine instance .this unit is a part of the freeware Synopse mORMot framework.18 Units used in the SynSQLite3RegEx unit: Unit Name Description Page SynCommons Common functions used by most Synopse projects .this unit is a part of the freeware Synopse mORMot framework. licensed under a MPL/GPL/LGPL tri-license. licensed under a MPL/GPL/LGPL tri-license.18 Page 695 of 1055 .Rev. 1. obj for Windows 32 bit .this unit is a part of the freeware Synopse mORMot framework. version 1. therefore.statically linked .2.Rev. constructor Create.18 Page 696 of 1055 . licensed under a MPL/GPL/LGPL tri-license.obj SQLite3 engine .this unit is a part of the freeware Synopse mORMot framework. 2013 23. version 1.the intialization section of this unit calls: sqlite3 := TSQLite3LibraryStatic. Unload the static library Functions or procedures implemented in the SynSQLite3Static unit: SynSQLite3Static. adding SynSQlite3Static to your uses clause is enough to use the statically linked SQLite3 engine with SynSQLite3 Used for DI-2.this unit is a part of the freeware Synopse mORMot framework.1 (page 1052).2. reintroduce.Create.18 Date: June 16. version 1. licensed under a MPL/GPL/LGPL tri-license.18 325 SynSQLite3 SQLite3 Database engine direct access .pas unit Purpose: SQLite3 Database engine .20.pas unit .Synopse mORMot Framework Software Architecture Design 1. SynSQLite3Static.1 The SQLite3 engine shall be embedded to the framework 1052 Units used in the SynSQLite3Static unit: Unit Name Description Page SynCommons Common functions used by most Synopse projects .18 The SynSQLite3Static unit is quoted in the following items: SWRS # Description Page DI-2. licensed under a MPL/GPL/LGPL tri-license. Fill the internal API reference s with the static . override. 1.obj SQLite3 engine 696 TSQLite3LibraryStatic = class(TSQLite3Library) Access class to the static .18 647 TSQLite3Library TSQLite3LibraryStatic SynSQLite3Static class hierarchy Objects implemented in the SynSQLite3Static unit: Objects Description Page TSQLite3LibraryStatic Access class to the static .obj engine destructor Destroy. conversion is done in-place.the OldPassWord must be correct.pas unit .the first page (first 1024 bytes) is not encrypted.use this procedure instead of the "classic" sqlite3. since its content (mostly zero) can be used to easily guess the beginning of the key . 1. NewPassword: RawUTF8).if the key is not correct. otherwize the resulting file will be corrupted .you may use instead SynCrypto unit for more secure SHA-256 and AES-256 algos .please note that this encryption is compatible only with SQlite3 files using the default page size of 1024 .18 Page 697 of 1055 .18 Date: June 16.implementation is NOT compatible with the official SQLite Encryption Extension (SEE) file format: it provides only simple XOR encryption (no RC4/AES) . a ESQLite3Exception will be raised with 'database disk image is malformed' (SQLITE_CORRUPT) at database opening SynSQLite3Static.Rev. const OldPassWord.any password can be '' to mark no encryption .rekey() API call . Use this procedure to change the password for an existing SQLite3 database file .Synopse mORMot Framework Software Architecture Design 1. therefore this procedure can handle very big files . 2013 Functions or procedures Description Page ChangeSQLEncryptTable PassWord Use this procedure to change the password for an existing SQLite3 database file 697 procedure ChangeSQLEncryptTablePassWord(const FileName: TFileName. 21.18 Page 698 of 1055 . version 1.18 325 Objects implemented in the SynSSPIAuth unit: Objects Description Page TSecContext Windows Authentication context 698 TSecHandle 698 TSecHandle = record Windows Authentication context handle TSecContext = record Windows Authentication context Types implemented in the SynSSPIAuth unit: TSecContexts = array of TSecContext. SynSSPIAuth.pas unit Purpose: Low level access to Windows Authentication for the Win32/Win64 platform . licensed under a MPL/GPL/LGPL tri-license. 1. 2013 23. licensed under a MPL/GPL/LGPL tri-license. version 1.this unit is a part of the freeware Synopse mORMot framework.Synopse mORMot Framework Software Architecture Design 1.pas unit . Dynamic array of Windows Authentication contexts .Rev.this unit is a part of the freeware Synopse framework.used to hold information between calls to ServerSSPIAuth Functions or procedures implemented in the SynSSPIAuth unit: Functions or procedures Description Page ClientSSPIAuth Client-side authentication procedure 699 FreeSecContext Free aSecContext on client or server side 699 InvalidateSecContext Sets aSecHandle fields to empty state 699 ServerSSPIAuth Server-side authentication procedure 699 ServerSSPIAuthUser Server-side function that returns authenticated user name 699 SynSSPIAuth.18 Units used in the SynSSPIAuth unit: Unit Name Description Page SynCommons Common functions used by most Synopse projects .18 Date: June 16. out aOutData: RawByteString): Boolean.Rev.aUserName contains authenticated user name SynSSPIAuth. out aUserName: RawUTF8).Synopse mORMot Framework Software Architecture Design 1.aSecContext must be received from previos success call to ServerSSPIAuth . Free aSecContext on client or server side procedure InvalidateSecContext(var aSecContext: TSecContext). Client-side authentication procedure .aSecContext holds information between function calls . const aInData: RawByteString.aOutData contains data that must be sent to server . Server-side function that returns authenticated user name . Server-side authentication procedure . 1.pas unit . client must send aOutData to server and call function again width data.if function returns True.aSecContext holds information between function calls .aOutData contains data that must be sent to client . returned from client procedure ServerSSPIAuthUser(var aSecContext: TSecContext.aInData contains data recieved from client . 2013 function ClientSSPIAuth(var aSecContext: TSecContext.18 Date: June 16.aInData contains data received from server . out aOutData: RawByteString): Boolean.if function returns True. const aInData: RawByteString. returned from servsr procedure FreeSecContext(var aSecContext: TSecContext). Sets aSecHandle fields to empty state function ServerSSPIAuth(var aSecContext: TSecContext.18 Page 699 of 1055 . server must send aOutData to client and call function again width data. Execute([]. // 200=Registry. objects are not initialized any more: we have to define this type as object before Delphi 2009.pas unit Purpose: Implement TaskDialog window (native on Vista/Seven. Task. version 1.200).create a TTaskDialog object/record on the stack will initialize all its string parameters to '' (it's a SHAME that since Delphi 2009.tiQuestion.will use the new TaskDialog API under Vista/Seven.Radios := 'Store settings in registry'#10'Store settings in XML file'.RadioRes)).18 TTaskDialogEx TObject TTaskDialog TSynButtonParent TSynButton SynTaskDialog class hierarchy Objects implemented in the SynTaskDialog unit: Objects Description Page TSynButton A generic Button to be used in the User Interface 703 TTaskDialog Implements a TaskDialog 700 TTaskDialogEx A wrapper around the TTaskDialog. licensed under a MPL/GPL/LGPL tri-license. emulated on XP) . SynTaskDialog.VerifyChecked := true.here is a typical usage: var Task: TTaskDialog.tfiInformation.Verify). Task. 2013 23.Footer := 'XML file is perhaps a better choice'. 1. Task. end. 201=XML if Task.VerifyChecked then ShowMessage(Task.set the appropriate string parameters.0. Task.pas unit . Task.Synopse mORMot Framework Software Architecture Design 1.Rev.RadioRes/SelectionRes/VerifyChecked will be used to reflect the state after dialog execution . and emulate it with pure Delphi code and standard themed VCL components under XP or 2K .18 Page 700 of 1055 .Execute method 702 TTaskDialog = object(TObject) Implements a TaskDialog .18 Date: June 16. then call Execute() with all additional parameters .[].Inst := 'Saving application settings'.this unit is a part of the freeware Synopse mORMot framework. ShowMessage(IntToStr(Task.Content := 'This is the content'. SynTaskDialog. and as record starting with Delphi 2009) .22. begin Task.Verify := 'Do no ask for this setting next time'. Task. the buttons will be created at the dialog bottom.if left void.any '\n' will be converted into a line feed . the RadioRes: integer. The main instruction (first line on top of window) .by default. any '\n' will be converted as note text (shown with smaller text under native Vista/Seven TaskDialog. The button caption to be displayed when the information is collapsed . The expanded information content text . just like the common buttons .18 Date: June 16.they will be identified with an ID number starting at 200 . A #13#10 or #10 separated list of custom radio buttons . 2013 Buttons: string. or as popup hint within Delphi emulation) Content: string. The selected radio item .they will be identified with an ID number starting at 100 .if tdfUseCommandLinks flag is set. The dialog's primary content content text . will contain the default query text .the Delphi emulation will always show the Info content (there is no collapse/expand button) InfoCollapse: string.if tdfQuery is in the flags. The footer content text . in this case. or as popup hint within Delphi emulation) SynTaskDialog.Rev.18 Page 701 of 1055 .any '\n' will be converted into a line feed Footer: string.if Selection is set.aRadioDef parameter can be set to define the default selected value .'\n' will be converted as note text (shown with smaller text under native Vista/Seven TaskDialog. Some text to be edited .Synopse mORMot Framework Software Architecture Design 1.not used under XP: the Delphi emulation will always show the Info content InfoExpanded: string.pas unit . The button caption to be displayed when the information is expanded . A #13#10 or #10 separated list of custom buttons .not used under XP: the Delphi emulation will always show the Info content Inst: string. the text is taken from the current dialog icon kind Query: string.first is numeroted 0 Radios: string. the custom buttons will be created as big button in the middle of the dialog window. 1.any '\n' will be converted into a line feed .any '\n' will be converted into a line feed Info: string. contains the selected item from the Selection list Title: string.after execution.if left void. or the Button ID (e. The associated main TTaskDialog instance SynTaskDialog.by default.info/forum/viewtopic.DialogHandle . aParent: HWND=0.Synopse mORMot Framework Software Architecture Design 1.Rev. tdfUseCommandLinksNoIcon.aParent can be set to any HWND . aFlags: TTaskDialogFlags=[]. The main title of the dialog window .if Buttons was defined.Execute method .if set. aEmulateClassicStyle: boolean = false): integer. aFooterIcon: TTaskDialogFooterIcon=tfiWarning.if aNonNative is TRUE. and tdfQuery options . A #13#10 or #10 separated list of items to be selected . but with our Delphi emulation code (via a TComboBox) SelectionRes: integer. 1. Reflect the the bottom most optional checkbox state .aWidth can be used to force a custom form width (in pixels) . will contain the final checkbox state function Execute(aCommonButtons: TCommonButtons=[]. should be set before execution . a Combo Box will be displayed to select .php?pid=2867#p2867 TTaskDialogEx = object(TObject) A wrapper around the TTaskDialog.aEmulateClassicStyle can be set to enforce conformity with the non themed user interface see @http://synopse.if Radios was defined.some common buttons can be set via aCommonButtons . mrOk for the OK button or 100 for the first custom button defined in Buttons string) . aDialogIcon: TTaskDialogIcon=tiInformation. the combo box will be in edition mode. After execution.18 Date: June 16. the Delphi emulation code will always be used . Application. aNonNative: boolean=false.18 Page 702 of 1055 . aRadioDef can set the selected Radio ID . The text of the bottom most optional checkbox VerifyChecked: BOOL. Launch the TaskDialog form . aWidth: integer=0.pas unit . aButtonDef: integer=0. aRadioDef: integer=0.this selection is not handled via the Vista/Seven TaskDialog.g.in emulation mode. the title of the application main form is used Verify: string.will return 0 on error. 2013 Selection: string. and the user will be able to edit the Query text or fill the field with one item of the selection .if Verify is not ''.aDialogIcon and aFooterIcon are used to specify the displayed icons .if tdfQuery is in the flags.used to provide a "flat" access to task dialog parameters Base: TTaskDialog. aButtonDef can set the selected Button ID . aFlags will handle only tdfUseCommandLinks. Width.is in fact a wrapper around the TTaskDialog. Btn: TCommonButton. Can be used to force a custom form width (in pixels) function Execute(aParent: HWND=0): integer. If TRUE. Used to specify the footer icon NonNative: boolean. The associated configuration flags for this Task Dialog . the Delphi emulation code will always be used RadioDef: integer.pas unit .ModalResult/Default/Cancel properties will be set as exepcted for this kind of button procedure DoDropDown.18 Date: June 16.. 2013 ButtonDef: integer.in emulation mode. it will be a row TButton with no glyph.is always a Themed button: under Delphi 6.set nothing under Delphi 6 property DropDownMenu: TSynPopupMenu read fDropDownMenu write fDropDownMenu. Used to specify the dialog icon EmulateClassicStyle: boolean. never mind. constructor CreateKind(Owner: TWinControl. The default button ID CommonButtons: TCommonButtons. Some common buttons to be displayed DialogIcon: TTaskDialogIcon.Execute method TSynButton = class(TSynButtonParent) A generic Button to be used in the User Interface . Can be used to enforce conformity with the non themed user interface Flags: TTaskDialogFlags. Drop down the associated Popup Menu procedure SetBitmap(Bmp: TBitmap).Rev. Main (and unique) method showing the dialog itself .Synopse mORMot Framework Software Architecture Design 1. aFlags will handle only tdfUseCommandLinks. Height: integer). Create a standard button instance . tdfUseCommandLinksNoIcon. Right.. since TBitBtn is not themed. Left. 1. The associated Popup Menu to drop down SynTaskDialog.. The default radio button ID Width: integer.18 Page 703 of 1055 . Set the glyph of the button .. and tdfQuery options FooterIcon: TTaskDialogFooterIcon. 2013 Types implemented in the SynTaskDialog unit: TCommonButton = ( cbOK. tdfQuery. tdfNoDefaultRadioButton.microsoft. tdfCallbackTimer. The available configuration flags for the Task Dialog . tiShield ). tdfUseCommandLinks. cbNo. tdfShowMarqueeProgressBar. tiNotUsed. tdfUseCommandLinksNoIcon.most are standard TDF_* flags used for Vista/Seven native API (see http://msdn. tdfExpandByDefault. tiWarning. tiQuestion. tfiInformation. tdfVerificationFlagChecked. implemented in pure Delphi code to handle input query . tdfExpandFooterArea. tdfRtlLayout. Return the text without the '&' characters within Variables implemented in the SynTaskDialog unit: BitmapArrow: TBitmap. cbClose ). Will map a generic Arrow picture from SynTaskDialog.85). cbCancel.aspx for TASKDIALOG_FLAGS) . tiError. tdfUseHIconFooter. tdfQueryFieldFocused ).pas unit . tfiShield ). tdfUseHIconMain. tdfQueryMasked. tiInformation. The standard kind of common buttons handled by the Task Dialog TCommonButtons = set of TCommonButton.our emulation code will handle only tdfUseCommandLinks.18 Date: June 16. tdfCanBeMinimized.Synopse mORMot Framework Software Architecture Design 1. tfiQuestion. A generic VCL popup menu TTaskDialogFlag = ( tdfEnableHyperLinks. The available main icons for the Task Dialog Functions or procedures implemented in the SynTaskDialog unit: Functions or procedures Description Page UnAmp Return the text without the '&' characters within 704 function UnAmp(const s: string): string. tdfShowProgressBar. tfiError. and tdfQuery options TTaskDialogFlags = set of TTaskDialogFlag. 1.tdfQuery and tdfQueryMasked are custom flags. cbYes. tfiWarning. cbRetry.com/en-us/library/bb787473(v=vs. tdfPositionRelativeToWindow.Rev. tdfAllowDialogCancellation. Set of available configuration flags for the Task Dialog TTaskDialogFooterIcon = ( tfiBlank. The available footer icons for the Task Dialog TTaskDialogIcon = ( tiBlank.res SynTaskDialog. tdfUseCommandLinksNoIcon.18 Page 704 of 1055 . Set of standard kind of common buttons handled by the Task Dialog TSynPopupMenu = TPopupMenu. A default Task Dialog wrapper instance . Will map a default font. VerifyFlag: PBOOL): HRESULT.will fall back to Tahoma otherwise DefaultTaskDialog: TTaskDialogEx = ( DialogIcon: tiInformation. Res: PInteger. will use it . Is filled once in the initialization block below .can be used to display some information with less parameters TaskDialogIndirect: function(AConfig: pointer.g.pas unit .Synopse mORMot Framework Software Architecture Design 1. ). make sense if TaskDialogBiggerButtons=true) SynTaskDialog. stdcall. ResRadio: PInteger. FooterIcon: tfiWarning.you can set this reference to nil to force Delphi dialogs even on Vista/Seven (e. 2013 BitmapOK: TBitmap.res DefaultFont: TFont.18 Page 705 of 1055 . 1. Will map a generic OK picture from SynTaskDialog. according to the available .Rev.if Calibri is installed.18 Date: June 16. 1.Rev. licensed under a MPL/GPL/LGPL tri-license. Socket address will be used in bind() call. SynWinSock.pas unit Purpose: Low level access to network Sockets for the Win32 platform . Return canonical name in first ai_canonname. Constants implemented in the SynWinSock unit: AI_CANONNAME = $2.18 Objects implemented in the SynWinSock unit: Objects Description TIPv6_mreq Page 706 TIPv6_mreq = record ipv6mr_interface: integer.23. version 1.Synopse mORMot Framework Software Architecture Design 1.this unit is a part of the freeware Synopse framework. Interface index. SynWinSock.18 Date: June 16. AI_NUMERICHOST = $4.18 Page 706 of 1055 .pas unit . AI_PASSIVE = $1. IPv6 multicast address. 2013 23. padding: integer. zip archive 710 TZipRead Read-only access to a .Synopse mORMot Framework Software Architecture Design 1. as used in .pas unit .this unit is a part of the freeware Synopse framework. as used in .pas unit Purpose: Low-level access to ZLib compression (1. as used in .18 Page 707 of 1055 .Rev. 2013 23. licensed under a MPL/GPL/LGPL tri-license.zip file format 708 TFileInfo Generic file information structure. as used in . SynZip.5 engine version) .24.zip file format 709 TLocalFileHeader Internal file information structure.18 Date: June 16.2.zip file format 708 TLastHeader Last header structure.18 TZStream TZipWrite TZipRead TObject TLocalFileHeader TFileInfo TFileHeader TStream TSynZipCompressor SynZip class hierarchy Objects implemented in the SynZip unit: Objects Description Page TFileHeader Directory file information structure.zip archive file 711 TZipWrite Write-only access for creating a . 1.zip file format 709 TSynZipCompressor A simple TStream descendant for compressing data into a stream 710 TZipEntry Stores an entry of a file inside a . version 1.zip archive file 711 TZStream Don't know why using objects below produce an Internal Error DT5830 under Delphi 2009 Update 3 !!!!! 708 SynZip. Rev. Size of uncompressed data zcrc32: dword. 0=stored 8=deflate 12=BZ2 14=LZMA zzipMethod: word. as used in .zip file format .18 Date: June 16. as used in . 14 nameLen: word. 1.18 Page 708 of 1055 . Time in dos format zfullSize: dword. 1 = text SynZip. Length(name) flags: word. 0 procedure SetAlgoID(Algorithm: integer). contains info about following block extraLen: word.embarcadero. 0 zzipSize: dword. 1.used in any header.com/wc/qcmain. but all other versions (including Delphi 2009 Update 2) did -> do Codegear knows about regression tests? the internal memory structure as expected by the ZLib library TFileInfo = object(TObject) Generic file information structure.aspx?d=79792 it seems that this compiler doesn't like to compile packed objects.pas unit .Synopse mORMot Framework Software Architecture Design 1.g. Crc32 checksum of uncompressed data function SameAs(aInfo: PFileInfo): boolean. 0 = binary. Size of compressed data zlastMod: integer.used at the end of the zip file to recap all entries extFileAttr: dword.zip file format .) from flags TFileHeader = object(TObject) Directory file information structure..15 (1=SynLZ e. 2013 TZStream = object(TObject) Don't know why using objects below produce an Internal Error DT5830 under Delphi 2009 Update 3 !!!!! -> see http://qc. Synopse mORMot Framework Software Architecture Design 1. SizeOf(TFileHeaders + names) headerSize: dword.pas unit . Dos file attributes madeBy: word.zip file format . 1. 0 headerOffset: dword.Rev.18 Date: June 16.zip file format . 0 localHeadOff: dword. 02014b50 PK#1#2 function IsFolder: boolean. 06054b50 PK#5#6 thisFiles: word. 04034b50 PK#3#4 TLastHeader = record Last header structure. 1 thisDisk: word. 0 SynZip. as used in . 0 intFileAttr: word.used locally inside the file stream. TFileHeader headerDisk: word. as used in . followed by the name and then the data fileInfo: TFileInfo.this header ends the file and is used to find the TFileHeader entries commentLen: word. TLocalFileHeader TLocalFileHeader = object(TObject) Internal file information structure. 14 firstDiskNo: word.18 Page 709 of 1055 . 2013 fileInfo: TFileInfo. Count: Longint): Longint. Used to return the current position.e.zip archive. Release memory function Read(var Buffer. The current CRC of the written data. Write all pending compressed data into outStream property CRC: cardinal read fCRC. i. override. the real byte written count .g. as stored in the . The number of byte written.gz backup) constructor Create(outStream: TStream.this simple version don't use any internal buffer.e. the current compressed size TZipEntry = record Stores an entry of a file inside a . 2013 totalFiles: word. override. but this one is sufficient for most common cases (e. override.g.e. This method will raise an error: it's a compression-only stream function Seek(Offset: Longint.18 Date: June 16.Synopse mORMot Framework Software Architecture Design 1. override. i. 1 TSynZipCompressor = class(TStream) A simple TStream descendant for compressing data into a stream . The information of this file. the uncompressed data CRC property SizeIn: cardinal read FStrm. 1.total_in. i.zip archive data: PAnsiChar. but rely on Zip library buffering system . this method will raise an error: it's a compression-only stream function Write(const Buffer.pas unit . Origin: Word): Longint.the version in SynZipFiles is much more powerfull. Format: TSynZipCompressorFormat = szcfRaw). CompressionLevel: Integer. a file stream) destructor Destroy. Name of the file inside the . The number of byte sent to the destination stream. Create a compression stream.not ASCIIZ: length = info.e. for on the fly .18 Page 710 of 1055 . Add some data to be compressed procedure Flush.for real seek.zip archive storedName: PAnsiChar.nameLen SynZip.total_out. i. mapped in memory info: PFileInfo. writting the compressed data into the specified stream (e. Count: Longint): Longint.zip archive .Rev. Points to the compressed data in the . the current uncompressed size property SizeOut: cardinal read FStrm. zip archive into a destination directory function UnZip(aIndex: integer): RawByteString. overload.zip archive Entry: array of TZipEntry. overload.not to be used to update a .can open a . Open a .can open a . ResType: PChar).Synopse mORMot Framework Software Architecture Design 1.zip archive into memory TZipWrite = class(TObject) Write-only access for creating a . const DestDir: TFileName): boolean.zip archive file from its File Handle constructor Create(BufZip: pByteArray. overload. const ResName: string. The files inside the .zip file.zip archive function UnZip(aIndex: integer. The number of files inside a .zip archive file directly from a resource destructor Destroy. ZipStartOffset: cardinal=0.zip archive file directly from memory constructor Create(const aFileName: TFileName.zip archive file . Open a .zip archive file content from memory Count: integer. Uncompress a file stored inside the .zip archive constructor Create(aFile: THandle. ZipStartOffset: cardinal=0.pas unit .18 Date: June 16. Size: cardinal=0). overload. Size: cardinal).converted from DOS/OEM or UTF-8 into generic (Unicode) string TZipRead = class(TObject) Read-only access to a . Name of the file inside the .zip archive file as Read Only constructor Create(Instance: THandle.zip archive file content from a resource (embedded in the executable) . but to create a new one . The total number of entries SynZip. Uncompress a file stored inside the . Release associated memory function NameToIndex(const aName: TFileName): integer. Get the index of a file inside the . override.update can be done manualy by using a TZipRead instance and the AddFromZip() method Count: integer.can open directly a specified . 1. 2013 zipName: TFileName.zip archive file .Rev. Open a .zip file (will be memory mapped for fast access) . Open a . Size: cardinal=0).18 Page 711 of 1055 . overload. overload.zip archive . without compression .a new .18 Page 712 of 1055 .warning: AddStored/AddDeflated() won't check for duplicate zip entries . CompressLevel: integer=6).pas unit .zip file .g.by default. 2010 is used if not date is supplied procedure AddFromZip(const ZipEntry: TZipEntry). Add a memory buffer to the zip file. Types implemented in the SynZip unit: NativeUInt = cardinal.zip file Handle: integer. ready to be written as a . As available in newer Delphi versions PInteger = ^Integer. not deflated (in that case.zip file in-place (the old content is not copied.this method is very fast. The associated file handle constructor Create(const aFileName: TFileName). and close destination file procedure AddDeflated(const aFileName: TFileName.Rev. Add a file from an already compressed zip entry procedure AddStored(const aZipName: TFileName.18 Date: June 16.those will be appended after the data blocks at the end of the .usefull to add the initial Setup. Define RawByteString. Buf: pointer. Append a file content into the destination file . and add it to the zip file .to be used for byte storage into an AnsiString SynZip. FileAge: integer=1+1 shl 5+30 shl 9). RemovePath: boolean=true. the 1st of January. as stored in the . Delphi 5 doesn't have those base types defined :( RawByteString = AnsiString. new data is appended at the file end) destructor Destroy. The resulting file entries. as it does exist in Delphi 2009 and up .zip file content is created constructor CreateFrom(const aFileName: TFileName). 1. Size: integer. Buf: pointer.exe file. Size: integer. and add it to the zip file procedure AddDeflated(const aZipName: TFileName. no deflate code is added to the executable) .content is stored. 2010 is used if not date is supplied procedure Append(const Content: RawByteString).Synopse mORMot Framework Software Architecture Design 1. overload. FileAge: integer=1+1 shl 5+30 shl 9). Initialize an existing . fhr: TFileHeader. 2013 Entry: array of record intName: RawByteString. Compress (using the deflate method) a memory buffer.zip file in order to add some content to it .by default. override. the 1st of January. Release associated memory.zip internal directory the corresponding file header initialize the . overload. e. Compress (using the deflate method) a file. and will increase the . CompressLevel: integer=6. end.zip catalog . The file name. overload. ZipFormat: Boolean=false) : integer. CompressionLevel: integer=6.RegisterCompress . fastest available (content of 4803 bytes is compressed into 700. (un)compress a data content using the Deflate algorithm . Compress: boolean): RawByteString.Synopse mORMot Framework Software Architecture Design 1.as expected by THttpSocket. szcfZip. Low-level check of the code returned by the ZLib library function CompressDeflate(var Data: RawByteString. srcLen.18 Date: June 16.zip archive files 714 GZRead Uncompress a . 2013 TSynZipCompressorFormat = ( szcfRaw. with a proprietary format (including CRC) 714 function Check(const Code: Integer.e.will use internaly a level compression of 1. The format used for storing data Functions or procedures implemented in the SynZip unit: Functions or procedures Description Page Check Low-level check of the code returned by the ZLib library 713 CompressDeflate (un)compress a data content using the Deflate algorithm 713 CompressGZip (un)compress a data content using the gzip algorithm 713 CompressMem In-memory ZLib DEFLATE compression 713 CompressStream ZLib DEFLATE compression from memory into a stream 714 CompressString Compress some data. i. szcfGZ ).as expected by THttpSocket.will use internaly a level compression of 1. const ValidCodes: array of Integer): integer. 1.18 Page 713 of 1055 .pas unit . and time is 440 us instead of 220 us) function CompressGZip(var Data: RawByteString.gz file content 714 UnCompressMem In-memory ZLib INFLATE decompression 714 UnCompressStream ZLib INFLATE decompression from memory into a stream 714 UncompressString Uncompress some data. dst: pointer. (un)compress a data content using the gzip algorithm .RegisterCompress . with a proprietary format (including CRC) 714 CompressZLib (un)compress a data content using the zlib algorithm 714 CRC32string Just hash aString with CRC32 algorithm 714 EventArchiveZip A TSynLogArchiveEvent handler which will compress older . fastest available (content of 4803 bytes is compressed into 700. and time is 440 us instead of 220 us) function CompressMem(src.log files into . In-memory ZLib DEFLATE compression SynZip. Compress: boolean): RawByteString. dstLen: integer. i.e.Rev. (un)compress a data content using the zlib algorithm . A TSynLogArchiveEvent handler which will compress older . Compress: boolean): RawByteString. aDestinationPath: TFileName): boolean. srcLen: integer.e.crc32 is better than adler32 for short strings function EventArchiveZip(const aOldLogFileName.g.resulting file will be named YYYYMM.return the number of bytes written into the stream . dstLen: integer) : integer.e. bad crc) function UnCompressMem(src. checkCRC: PCardinal): cardinal. ZLib INFLATE decompression from memory into a stream .log files into . with a proprietary format (including CRC) . and time is 440 us instead of 220 us) function CRC32string(const aString: RawByteString): cardinal. 2013 function CompressStream(src: pointer. it will contain thecrc32 (if aStream is nil.ArchivePath+'\log\YYYYMM.will use internaly a level compression of 1. dst: pointer. TSynLogFamily.as expected by THttpSocket. i.zip and will be located in the aDestinationPath directory. CompressionLevel: integer=6) : RawByteString. ZipFormat: Boolean=false): cardinal. CompressionLevel:integer=6. with a proprietary format (including CRC) function CompressZLib(var Data: RawByteString. Uncompress some data. srcLen. Just hash aString with CRC32 algorithm . i. Uncompress a .18 Date: June 16. ZLib DEFLATE compression from memory into a stream function CompressString(const data: RawByteString.gz file content .Synopse mORMot Framework Software Architecture Design 1.if checkCRC if not nil.RegisterCompress . aStream: TStream. failIfGrow: boolean = false.return '' if the .zip archive files .18 Page 714 of 1055 . fastest available (content of 4803 bytes is compressed into 700. 1. In-memory ZLib INFLATE decompression function UnCompressStream(src: pointer. it will fast calculate the crc of the the uncompressed memory block) function UncompressString(const data: RawByteString) : RawByteString. Compress some data. aStream: TStream.zip' function GZRead(gz: PAnsiChar. srcLen: integer.Rev.return '' in case of a decompression failure SynZip.pas unit .gz content is invalid (e. gzLen: integer): RawByteString. version 1.1.18 497 SynSSPIAuth Low level access to Windows Authentication for the Win32/Win64 platform . MD5.3 Windows Messages protocol 1049 DI-2.1 protocol 1049 DI-2.1.1.1.this unit is a part of the freeware Synopse mORMot framework.2.1. licensed under a MPL/GPL/LGPL tri-license.1 Units used in the mORMot unit: Unit Name Description Page SynCommons Common functions used by most Synopse projects .1. licensed under a MPL/GPL/LGPL tri-license.this unit is a part of the freeware Synopse framework.25. version 1. ADLER32.2.1 In-Process communication 1048 DI-2.pas unit . version 1.this unit is a part of the freeware Synopse mORMot framework.Rev. version 1.4 HTTP/1.1.implements AES.2. licensed under a MPL/GPL/LGPL tri-license.1 The SQLite3 engine shall be embedded to the framework 1052 DI-2.2 Named Pipe protocol 1048 DI-2.5 engine version) .18 707 mORMot.5 The framework shall offer a complete SOA process 1051 DI-2.this unit is a part of the freeware Synopse mORMot framework. licensed under a MPL/GPL/LGPL tri-license. licensed under a MPL/GPL/LGPL tri-license.1.pas unit Purpose: Common ORM and SOA classes for mORMot . 1. SHA256 algorithms . XOR.18 Date: June 16. 2013 23.1. based on classes RTTI (Runtime Type Information) 1050 DI-2. mORMot.Synopse mORMot Framework Software Architecture Design 1.1.optimized for speed (tuned assembler and VIA PADLOCK optional support) . version 1.2 UTF-8 JSON format shall be used to communicate 1049 DI-2.2.18 698 SynZip Low-level access to ZLib compression (1.1.18 The mORMot unit is quoted in the following items: SWRS # Description Page DI-2.2.3 The framework shall use an innovative ORM (Object-relational mapping) approach. SHA1.1.2.18 Page 715 of 1055 .18 325 SynCrypto Fast cryptographic routines (hashing and cypher) .1.this unit is a part of the freeware Synopse framework.1.1 Client-Server framework 1047 RESTful framework 1047 DI-2. Rev.18 Page 716 of 1055 . 1.18 Date: June 16.pas unit .Synopse mORMot Framework Software Architecture Design 1. 2013 EServiceException ESecurityException ESQLTableException EParsingException ESynException EORMException EModelException EInterfaceFactoryException ECommunicationException TCollection TInterfacedCollection TInterfacedObject TInterfacedObjectWithCustomCreate TJSONWriter TJSONSerializer EBusinessLayerException TTypeInfo TSQLVirtualTablePrepared TSQLVirtualTableCursorLog TSQLVirtualTableModule TSQLVirtualTableCursorIndex TSQLVirtualTableCursorJSON TSQLVirtualTableCursor TSQLVirtualTableLog TSQLVirtualTable TSQLVirtualTableJSON TSQLVirtualTableBinary TSQLTable TSQLTableJSON TSQLRestServerAuthenticationSignedURI TSQLRestServerAuthenticationSSPI TSQLRestServerAuthenticationDefault TSQLRibbonTabParameters TSQLRestServerAuthenticationURI TSQLRestServerAuthenticationNone TSQLRestServerCallBackParams TSQLRestServerStatic TSQLRestServerAuthentication TSQLRestServerRemoteDB TSQLRestServerStaticRecordBased TSQLRestServerStaticInMemory TSQLRestServerStaticInMemoryExternal TSQLRestServer TSQLRestCacheEntry TSQLRestCache TSQLRestClient TSQLRest TSQLRestClientURINamedPipe TSQLRestClientURI TSQLRestClientURIMessage TSQLRecordVirtualTableForcedID TSQLRestClientURIDll TSQLRecordProperties TSQLRecordVirtual TSQLRecordVirtualTableAutoID TSQLRecordFTS4 TSQLRecordFill TSQLRecordSigned TSQLRecordRTree TSQLRecordFTS3Porter TSQLPropInfoRTTITimeLog TSQLRecordFTS4Porter TSQLRecord TSQLRecordMany TSQLRecordFTS3 TSQLPropInfoList TSQLRecordLog TSQLPropInfoRTTIWide TSQLPropInfoRTTIDouble TSQLPropInfo TSQLAuthUser TSQLPropInfoRTTIInt64 TSQLPropInfoRTTIDateTime TSQLPropInfoRTTISet TSQLPropInfoRTTIObject TSQLPropInfoRTTIInt32 TSQLPropInfoRTTIInstance TSQLPropInfoRTTIMany TSQLPropInfoRTTIDynArray TSQLPropInfoRTTIEnum TSQLPropInfoRTTIID TSQLModelRecordProperties TSQLAuthGroup TSQLModel TSQLPropInfoRTTI TSQLLocks TObject TSQLRestServerFullMemory TSQLAccessRights TSQLPropInfoRTTICurrency TSQLPropInfoRTTIChar TServiceMethodArgument TSQLPropInfoRTTIAnsi TSQLPropInfoRTTIWinAnsi TServiceMethod TSQLPropInfoCustom TSQLPropInfoRecordRTTI TSQLPropInfoRTTIRawUTF8 TServiceFactoryServerInstance TServiceFactoryServer TSQLPropInfoRecordFixedSize TSQLPropInfoRTTIRawUnicode TServiceFactory TServiceFactoryClient TServiceContainer TServiceContainerServer TReturnInfo TServiceContainerClient TSQLPropInfoRTTIRawBlob TPropInfo TParamInfo TOnInterfaceStubExecuteParamsAbstract TOnInterfaceStubExecuteParamsJSON TMethodInfo TJSONObjectDecoder TInterfaceStubRules TInterfaceStubLog TInterfaceStub TInterfaceMock TInterfaceMockSpy TInterfaceFactory TEnumType TClassType TClassProp TAuthSession RecordRef TObjectHash TListFieldHash TSQLRestServerStats TPersistent TPersistentWithCustomCreate TSynLog TSQLLog TSynValidate TSynValidateRest TTextWriter TINIWriter TSynValidateUniqueField TSQLRestServerNamedPipeResponse TThread TSQLRestServerNamedPipe mORMot class hierarchy mORMot. simple writer to a Stream.Rev. specialized for writing an object as INI 741 TInterfacedCollection Any TCollection used between client and server shall inherit from this class 798 TInterfacedObjectWith CustomCreate Abstract parent class with threadsafe implementation of IInterface and a virtual constructor. ready to be overriden to initialize the instance 812 TInterfaceFactory Class handling interface RTTI and fake implementation class 798 TInterfaceMock Used to mock an interface implementation via expect-run-verify 807 TInterfaceMockSpy Used to mock an interface implementation via run-verify 808 TInterfaceStub Used to stub an interface implementation 803 TInterfaceStubLog Used to keep track of one stubbed method call 802 TInterfaceStubRule Define a mocking / stubing rule used internaly by TInterfaceStub 801 TInterfaceStubRules Define the rules for a given method as used internaly by TInterfaceStub 802 mORMot.Step / Field*() use 743 RecordRef Usefull object to type cast TRecordReference type value into explicit TSQLRecordClass and ID 785 TAuthSession Class used to maintain in-memory sessions 837 TClassProp A wrapper to published properties of a class 725 TClassType A wrapper to class type information.18 Page 717 of 1055 . services and mock/stubs 743 EModelException Exception raised in case of wrong Model definition 743 EORMException Generic parent class of all custom Exception types of this unit 743 EParsingException Exception raised in case of unexpected parsing error 743 ESecurityException Exception raised in case of any authentication error 743 EServiceException Exception dedicated to interface based service implementation 743 ESQLTableException Exception raised in case of incorrect TSQLTable.Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16. as defined by the Delphi RTTI 726 TINIWriter Default.g. as defined by the Delphi RTTI 725 TEnumType A wrapper to enumeration type information.pas unit . e. 2013 Objects implemented in the mORMot unit: Objects Description Page EBusinessLayerExcepti on Exception raised in case of an error in project implementation logic 743 ECommunicationExcepti on Exception raised in case of a Client-Server communication error 743 EInterfaceFactoryExce ption Exception dedicated to interface factory. 1. 1. specialized for writing an object as JSON 741 TListFieldHash Class able to handle a O(1) hashed-based search of a property in a TList 854 TMethodInfo A wrapper around a method definition 735 TOnInterfaceStubExecu teParamsAbstract Abstract parameters used by TInterfaceStub.Executes() events callbacks 799 TOnInterfaceStubExecu teParamsJSON Parameters used by TInterfaceStub.Rev. ready to be overriden to initialize the instance 812 TPropInfo A wrapper containing a property definition.pas unit .Executes() events callbacks as JSON 800 TParamInfo A wrapper around an individual method parameter definition 734 TPersistentWithCustom Create Abstract parent class with a virtual constructor.18 Page 718 of 1055 . 2013 Objects Description Page TJSONObjectDecoder Record/object helper to handle JSON object decoding 723 TJSONSerializer Simple writer to a Stream.18 Date: June 16. with GetValue() and SetValue() functions for direct Delphi / UTF-8 SQL type mapping/conversion: 729 TReturnInfo A wrapper around method returned result definition 734 TServiceContainer A global services provider class 816 TServiceContainerClie nt A services provider class to be used on the client side 818 TServiceContainerServ er A services provider class to be used on the server side 817 TServiceCustomAnswer A record type to be used as result for a function method for custom content 798 TServiceFactory An abstract service provider. for each Table 835 TSQLAuthGroup Table containing the available user access rights for authentication 836 TSQLAuthUser Table containing the Users registered for authentication 837 mORMot. as registered in TServiceContainer 809 TServiceFactoryClient A service provider implemented on the client side 815 TServiceFactoryServer A service provider implemented on the server side 812 TServiceFactoryServer Instance Server-side service provider uses this to store one internal instance 811 TServiceMethod Describe a service provider method 796 TServiceMethodArgumen t Describe a service provider method argument 795 TServiceRunningContex t Will identify the currently running service on the server side 882 TSQLAccessRights Set the User Access Rights.Synopse mORMot Framework Software Architecture Design 1. Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16.18 Page 719 of 1055 .Rev.pas unit . in a specified table 777 TSQLLog Logging class with enhanced RTTI 882 TSQLModel A Database Model (in a MVC-driven way). for storing some tables types as TSQLRecord classes 781 TSQLModelRecordProper ties ORM properties associated to a TSQLRecord within a given model 780 TSQLPropInfo Abstract parent class to store information about a published property 735 TSQLPropInfoCustom Abstract information about a record-like property defined directly in code 739 TSQLPropInfoList Handle a read-only list of ORM fields information for published properties 740 TSQLPropInfoRecordFix edSize Information about a fixed-size record property defined directly in code 740 TSQLPropInfoRecordRTT I Information about a record property defined directly in code 739 TSQLPropInfoRTTI Parent information about a published property retrieved from RTTI 737 TSQLPropInfoRTTIAnsi Information about a AnsiString published property 738 TSQLPropInfoRTTIChar Information about a character published property 738 TSQLPropInfoRTTICurre ncy Information about a fixed-decimal Currency published property 738 TSQLPropInfoRTTIDateT ime Information about a TDateTime published property 738 TSQLPropInfoRTTIDoubl e Information about a floating-point Double published property 738 TSQLPropInfoRTTIDynAr ray Information about a dynamic array published property 739 TSQLPropInfoRTTIEnum Information about a enumeration published property 738 TSQLPropInfoRTTIID Information about a TSQLRecord class TSQLRecord property 744 TSQLPropInfoRTTIInsta nce Information about a TSQLRecord class property 744 TSQLPropInfoRTTIInt32 Information about an ordinal Int32 published property 738 TSQLPropInfoRTTIInt64 Information about an ordinal Int64 published property 738 TSQLPropInfoRTTIMany Information about a TSQLRecord class TSQLRecordMany property 744 TSQLPropInfoRTTIObjec t Information about a TSQLRecord class TStrings/TRawUTF8List/TCollection property 744 mORMot. 2013 Objects Description Page TSQLLocks Used to store the locked record list. 1. implementing full-text 788 TSQLRecordFTS3Porter This base class will create a FTS3 table using the Porter Stemming algorithm 789 TSQLRecordFTS4 A base record. corresponding to an R-Tree table 787 TSQLRecordSigned Common ancestor for tables with digitally signed RawUTF8 content 794 TSQLRecordVirtual Parent of all virtual classes 780 TSQLRecordVirtualTabl eAutoID Record associated to Virtual Table implemented in Delphi. 2013 Objects Description Page TSQLPropInfoRTTIRawBl ob Information about a TSQLRawBlob published property 739 TSQLPropInfoRTTIRawUn icode Information about a RawUnicode published property 739 TSQLPropInfoRTTIRawUT F8 Information about a RawUTF8 published property 738 TSQLPropInfoRTTISet Information about a set published property 738 TSQLPropInfoRTTITimeL og Information about a TTimeLog published property 738 TSQLPropInfoRTTIWide Information about a WideString published property 739 TSQLPropInfoRTTIWinAn si Information about a WinAnsiString published property 738 TSQLQueryCustom Store one custom query parameters 777 TSQLRecord Root class for defining and mapping database records 753 TSQLRecordFill Internal data used by TSQLRecord.Rev.Synopse mORMot Framework Software Architecture Design 1.FillPrepare()/FillPrepareMany() methods 752 TSQLRecordFTS3 A base record. with a JSON-logging capability 794 TSQLRecordMany Handle "has many" and "has many through" relationships 790 TSQLRecordProperties Some information about a given TSQLRecord class properties 744 TSQLRecordRTree A base record. corresponding to a FTS3 table.pas unit . with ID generated automatically at INSERT 882 TSQLRecordVirtualTabl eForcedID Record associated to a Virtual Table implemented in Delphi. corresdonding to a FTS4 table.18 Date: June 16.18 Page 720 of 1055 . with ID forced at INSERT 882 TSQLRest A generic REpresentational State Transfer (REST) client/server class 821 TSQLRestCache Implement a fast cache content at the TSQLRest level 819 mORMot. which is an enhancement to FTS3 789 TSQLRecordFTS4Porter This base class will create a FTS4 table using the Porter Stemming algorithm 789 TSQLRecordLog A base record. 1.e. i. Synopse mORMot Framework Software Architecture Design 1. to be used as external table 858 mORMot.18 Date: June 16.18 Page 721 of 1055 . 1. stores a table settings and values 818 TSQLRestCacheEntryVal ue For TSQLRestCache.Rev.pas unit . stores a table values 818 TSQLRestClient A generic REpresentational State Transfer (REST) client 860 TSQLRestClientURI A generic REpresentational State Transfer (REST) client with URI 863 TSQLRestClientURIDll Rest client with remote access to a server through a dll 870 TSQLRestClientURIMess age Rest client with remote access to a server through Windows messages 870 TSQLRestClientURIName dPipe Rest client with remote access to a server through a Named Pipe 871 TSQLRestServer A generic REpresentational State Transfer (REST) server 843 TSQLRestServerAuthent ication Abstract class used to implement server-side authentication in TSQLRestServer 839 TSQLRestServerAuthent icationDefault MORMot secure RESTful authentication scheme 840 TSQLRestServerAuthent icationNone MORMot weak RESTful authentication scheme 841 TSQLRestServerAuthent icationSignedURI Secure authentication scheme using URL-level digital signature 840 TSQLRestServerAuthent icationSSPI Authentication using Windows Security Support Provider Interface (SSPI) 842 TSQLRestServerAuthent icationURI Weak authentication scheme using URL-level parameter 839 TSQLRestServerCallBac kParams Store calling context for a TSQLRestServerCallBack event handler 750 TSQLRestServerFullMem ory A REST server using only in-memory tables 858 TSQLRestServerNamedPi pe Server thread accepting connections from named pipes 832 TSQLRestServerNamedPi peResponse Server child thread dealing with a connection through a named pipe 833 TSQLRestServerRemoteD B A REST server using a TSQLRestClient for all its ORM process 859 TSQLRestServerStatic REST server with direct access to an external database engine 852 TSQLRestServerStaticI nMemory REST server with direct access to a memory-stored database 855 TSQLRestServerStaticI nMemoryExternal REST server with direct access to a memory database. 2013 Objects Description Page TSQLRestCacheEntry For TSQLRestCache. URI() method call 749 TSQLRibbonTabParamete rs Defines the settings for a Tab for User Interface generation 778 TSQLTable Wrapper to an ORM result table.Rev. as created by TSynLog 881 TSQLVirtualTableModul e Parent class able to define a Virtual Table module 874 TSQLVirtualTablePrepa red The WHERE and ORDER BY statements as set by TSQLVirtualTable.18 Page 722 of 1055 . and store it into its own memory 776 TSQLTableSortParams Contains the parameters used for sorting 723 TSQLVirtualTable Abstract class able to access a Virtual Table content 876 TSQLVirtualTableBinar y A TSQLRestServerStaticInMemory-based virtual table using Binary storage 881 TSQLVirtualTableCurso r Abstract class able to define a Virtual Table cursor 878 TSQLVirtualTableCurso rIndex A generic Virtual Table cursor associated to Current/Max index properties 879 TSQLVirtualTableCurso rJSON A Virtual Table cursor for reading a TSQLRestServerStaticInMemory content 879 TSQLVirtualTableCurso rLog A Virtual Table cursor for reading a TSynLogFile content 881 TSQLVirtualTableJSON A TSQLRestServerStaticInMemory-based virtual table using JSON storage 880 TSQLVirtualTableLog Implements a read/only virtual table able to access a .log file. 1.Synopse mORMot Framework Software Architecture Design 1.Prepare 873 TSQLVirtualTablePrepa redConstraint A WHERE constraint as set by the TSQLVirtualTable.URI() 834 TSQLRestServerURIPagi ngParameters If defined. the server statistics will contain precise working time process structure used to specify custom request paging parameters for TSQLRestServer 833 TSQLRestServerURIPara ms Store all parameters for a TSQLRestServer. using if necessary an associated TSQLRest instance and a TSQLRecord class 872 mORMot.18 Date: June 16. staticaly stored as UTF-8 text 768 TSQLTableJSON Get a SQL result from a JSON message.pas unit . 2013 Objects Description Page TSQLRestServerStaticR ecordBased Abstract REST server exposing some internal TSQLRecord-based methods 853 TSQLRestServerStats Used for statistics update in TSQLRestServer.Prepare() method 873 TSynValidateRest Will define a validation to be applied to a TSQLRecord field.Prepare() method 872 TSQLVirtualTablePrepa redOrderBy An ORDER BY clause as set by the TSQLVirtualTable. either FieldNames.FieldCount is 0 if was never sorted .18 Date: June 16. by GetJSONObjectAsSQL() function DecodedFieldNames: PRawUTF8Array. Size of the TEXT data (in bytes) in FieldValues[] FieldNames: array[0. Contains the decoded field names or value FieldNull: TSQLFieldBits.MAX_SQLFIELDS-1] of RawUTF8.g. 2013 Objects Description Page TSynValidateUniqueFie ld Will define a validation for a TSQLRecord Unique field 872 TTypeInfo A wrapper containing type information definition 727 TVirtualTableModulePr operties Used to store and handle the main specifications of a TSQLVirtualTableModule 874 TSQLTableSortParams = record Contains the parameters used for sorting . either Fields[] array as defined in Decode() DecodedRowID: integer.18 Page 723 of 1055 ..Synopse mORMot Framework Software Architecture Design 1.Rev.used e.): inlined mORMot..FillFrom() TJSONObjectDecoder = object(TObject) Record/object helper to handle JSON object decoding . The ID=.used to sort data again after a successfull data update with TSQLTableJSON. value as sent within the JSON object supplied to Decode() FieldCount: integer. Contains the decoded field names or value InlinedParams: boolean... Internal pointer over field names to be used after Decode() call . 1. Set to TRUE if parameters are to be :(.. Decode() will set a bit for each field set JSON null value FieldValues: array[0.pas unit .MAX_SQLFIELDS-1] of RawUTF8. Number of fields decoded in FieldNames[] and FieldValues[] FieldLen: integer. e.18 Date: June 16. 1. Decode the JSON object fields into FieldNames[] and FieldValues[] .called by GetJSONObjectAsSQL() function function EncodeAsSQLPrepared(const TableName: RawUTF8. i.if RowID is set. Occasion: TSQLOccasion): RawUTF8. Params: TJSONObjectDecoderParams. Fields[] contains column names and expects a JSON array as "VAL1". calling Decode(P: PUTF8Char) mORMot.Occasion can be only soInsert or soUpdate function SameFieldNames(const Fields: TRawUTF8DynArray): boolean. COL2=:(VAL2):' . Params: TJSONObjectDecoderParams. overload. RowID: integer=0. it will create prepared parameters like 'COL1=:("VAL1"):. 2013 function EncodeAsSQL(Update: boolean): RawUTF8.Rev.after a successfull call to Decode() procedure AssignFieldNamesTo(var Fields: TRawUTF8DynArray). Set the specified array to the fields names . const Fields: TRawUTF8DynArray. P should be a true JSON object.pas unit . according to the official SQLite3 documentation (i. Returns TRUE if the specified array match the decoded fields names .FieldValues[] content will be ignored .escape SQL strings.if Fields=nil.Synopse mORMot Framework Software Architecture Design 1. overload. ReplaceRowIDWithID: Boolean=false). RowID: Integer=0.after a successfull call to Decode() procedure Decode(var P: PUTF8Char. ' inside a string is stored as '') . a RowID column will be added within the returned content procedure Decode(JSON: RawUTF8. otherwise. in P . Encode as a SQL-ready INSERT or UPDATE statement with ? as values ..P returns the next object start or nil on unexpected end of input ."VAL2".if InlinedParams was TRUE.overloaded method expecting a RawUTF8 buffer. Encode as a SQL-ready INSERT or UPDATE statement .after a successfull call to Decode() . FieldValues[] strings will be quoted .e.if InlineParams is TRUE.after a successfull call to Decode() . stopping at '}' or ']'.18 Page 724 of 1055 . Decode the JSON object fields into FieldNames[] and FieldValues[] . ReplaceRowIDWithID: Boolean=false). defined as "COL1"="VAL1" pairs. const Fields: TRawUTF8DynArray. Next . Return the total count of the published properties in this class and all its parents function FieldProp(const PropName: shortstring): PPropInfo.Synopse mORMot Framework Software Architecture Design 1.pas extension) of the unit were the class was defined .this enumeration is very fast and doesn't require any temporary memory.18 Page 725 of 1055 . function FieldCountWithParents: integer. do something with P P := P^.. end.1.Next. P := @PropList to get the first PPropInfo. 2013 TClassProp = object(TObject) A wrapper to published properties of a class . Number of published properties in this object PropList: record Point to a TPropInfo packed array . The class type ParentInfo: PPTypeInfo. you should better use the RecordProps.. which is faster and contains the properties published in parent classes Used for DI-2. ClassType: TClass.start enumeration by getting a PClassProp with ClassProp() . as defined by the Delphi RTTI Used for DI-2. as in the TypInfo.3 (page 1050). The name (without . The number of published properties UnitName: string[255]. The parent class type information PropCount: SmallInt.pas unit .Fields[] array.use PropCount.3 (page 1050). with variable TPropInfo storage size: PropList: array[1.then the PClassProp follows: use the method ClassProp to retrieve its address mORMot.Next to get the next one: P := @PropList.GetPropInfos() PPropList usage . 1.for TSQLRecord.1. Retrieve a Field property RTTI information from a Property Name TClassType = object(TObject) A wrapper to class type information.Rev.PropCount] of TPropInfo .layout is as such. PropCount: Word. for i := 1 to PropCount do begin // .. and then P^.use TPropInfo.18 Date: June 16. i. Get the corresponding caption name.LoadResStringTranslate() if available . UnicodeString for Delphi 2009+ .always use PEnumType(typeinfo(TEnumType))^. Get the information about the published properties of this class .pas unit . containing the enumeration names OrdType: TOrdType.return "string" type. translated if necessary. from the enumeration type definition itself Used for DI-2. Fast and easy find if this class inherits from a specific class type function RTTISize: integer. i.3 (page 1050).18 Page 726 of 1055 .we use this to store the enumeration values as integer.Rev. UnicodeString for Delphi 2009+ .internally call UnCamelCase() then System. only the corresponding bits set are added function GetEnumName(const Value): PShortString. First value of enumeration type. Specify ordinal storage size and sign function GetCaption(const Value): string.return the first one if Value is invalid (>MaxValue) .Value will be converted to the matching ordinal value (byte or word) function GetCaptionStrings(UsedValuesBits: Pointer=nil): string.e. BaseType: PPTypeInfo.EnumBaseType before calling any of the methods below MaxValue: Longint.1. but the highest index MinValue: Longint. Return the size (in bytes) of this class type information . 1.e.if UsedValuesBits is not nil. as defined by the Delphi RTTI .Value will be converted to the matching ordinal value (byte or word) mORMot. without the first lowercase chars (otDone -> 'Done') . The base type of this enumeration . 2013 function ClassProp: PClassProp.BaseType or more usefull method PTypeInfo(typeinfo(TEnumType))^. A concatenation of shortstrings.return "string" type.Synopse mORMot Framework Software Architecture Design 1. ready to be display. Same as ord(high(type)): not the enumeration count. Get the corresponding enumeration name . typicaly 0 NameList: string[255]. Get all caption names.stored after UnitName memory function InheritsFrom(AClass: TClass): boolean. as lines separated by #13#10 .can be used to create class types at runtime TEnumType = object(TObject) A wrapper to enumeration type information.18 Date: June 16. but easily provide a text equivalent. from its name . 2013 function GetEnumNameOrd(Value: Integer): PShortString.return -1 if not found (don't use directly this value to avoid any GPF) function GetEnumNameValue(Value: PUTF8Char): Integer. The value type family Name: ShortString.Value will be converted to the matching ordinal value (byte or word) function GetEnumNameTrimedValue(Value: PUTF8Char): Integer. to a TStrings class . Used for DI-2.'RawUnicode'. The declared name of the type ('String'.return -1 if not found (don't use directly this value to avoid any GPF) function GetEnumNameTrimedValue(const EnumName: ShortString): Integer. only the corresponding bits set are added .g.18 Date: June 16. Get the corresponding enumeration ordinal value.return the first one if Value is invalid (>MaxValue) function GetEnumNameTrimed(const Value): RawUTF8.pas unit . from its name .AddCaptionStrings(ComboBox. overload. . overload.return -1 if not found (don't use directly this value to avoid any GPF) function GetEnumNameValue(const EnumName: ShortString): Integer. overload.) .'Word'. UsedValuesBits: Pointer=nil).EnumBaseType^.) . to populate a combo box as such: PTypeInfo(TypeInfo(TMyEnum))^.user types defined as new types have this type information: type NewType = type OldType.g. 1.1.user types defined as an alias don't have this type information: type NewType = OldType. Get the corresponding enumeration name .if UsedValuesBits is not nil.g.) mORMot.add pointer(ord(element)) as Objects[] value .. from its name without its first lowercase chars ('Done' will find otDone e.18 Page 727 of 1055 . overload.can be used e.Items). without the first lowercase chars (otDone -> 'Done') . Get the corresponding enumeration ordinal value.. TTypeInfo = object(TObject) A wrapper containing type information definition .3 (page 1050). Add caption names.Rev. ready to be display. Get the corresponding enumeration name. Get the corresponding enumeration ordinal value. Get the corresponding enumeration ordinal value.Synopse mORMot Framework Software Architecture Design 1.return -1 if not found (don't use directly this value to avoid any GPF) procedure AddCaptionStrings(Strings: TStrings. Kind: TTypeKind. from its name without its first lowercase chars ('Done' will find otDone e. or TSQLRecord.Create virtual constructor . as managed with the database driver mORMot. Get the SQL type of this Delphi type.will call TObject.18 Date: June 16. get the storage size and procision function InheritsFrom(AClass: TClass): boolean.Rev.Synopse mORMot Framework Software Architecture Design 1. for a plain TCollectionItem class function ClassSQLFieldType: TSQLFieldType.g. Get the record type information function SetEnumType: PEnumType. get the storage size and sign function RecordType: PRecordType.pas unit . 2013 function ClassCreate: TObject. Get the enumeration type information function FloatType: TFloatType. e. Get the class type information function EnumBaseType: PEnumType. For set types. Fast and easy find if a class type inherits from a specific class type function OrdType: TOrdType. Create an instance of the corresponding class . 1.Create. get the type information of the corresponding enumeration function SQLFieldType: TSQLFieldType. Get the SQL type of this Delphi class type function ClassType: PClassType.will raise EParsingException if class cannot be constructed on the fly.18 Page 728 of 1055 . For ordinal types. For gloating point types. handle Currency property as FLOAT (safely converted to/from currency) . not a valid object memory . storing the ordinal value of the enumeration (i. Delphi 2009+ generic string).handle enumerations set properties as INTEGER.handle TSQLRawBlob properties as BLOB . with records or strings within records) .you have to manually retrieve the record.handle TTimeLog properties as properietary fast INTEGER date time . Double and Extended properties as FLOAT . the following will create a NAME VARCHAR(40) field: Name: RawUTF8 index 40 read fName write fName.handle dynamic arrays as BLOB.Rev.Synopse mORMot Framework Software Architecture Design 1. e. this can be used to define a VARCHAR() length value for the textual field definition (sftUTF8Text/sftAnsiText).handle TDateTime properties as ISO-8061 encoded TEXT . but an object) .handle WinAnsiString properties as TEXT (UTF-8 decoded in WinAnsi char set) . integer. 1.WideString.18 Date: June 16.handle RawUnicode properties as TEXT (UTF-8 decoded as UTF-16 Win32 unicode) . the generic string type is handled Used for DI-2.is used by a dynamic array property for fast usage of the TSQLRecord.handle byte. Int64 properties as INTEGER .handle enumeration properties as INTEGER.e. UnicodeString (i. in the RecordSave binary format (our code is ready for that.handle TSQLRecord descendant properties as INTEGER ROWID index to another record (warning: the value contains pointer(ROWID).handle records as BLOB.g.handle TRecordReference properties as INTEGER RecordRef-like value (use TSQLRest. The property definition Name mORMot. each bit corresponding to an enumeration (therefore a set of up to 64 elements can be stored in such a field) . in the TDynArray. anything else is true) .outside SQLite3.this is the preferred field type for storing some textual content in the ORM . GetProc: PtrInt. .18 Page 729 of 1055 .3 (page 1050).1.handle RawUTF8 properties as TEXT (UTF-8 encoded) . word.handle boolean properties as INTEGER (0 is false. cardinal. 2013 TPropInfo = object(TObject) A wrapper containing a property definition.e.in fact. indexed properties are not handled yet (use faster RawUnicodeString instead of WideString and UnicodeString) . with GetValue() and SetValue() functions for direct Delphi / UTF-8 SQL type mapping/conversion: . Contains the offset of a field.SaveTo binary format (is able to handle dynamic arrays of records.Retrieve(Reference) to get a record content) .DynArray(DynArrayFieldIndex) method Name: ShortString. starting at 0 for the first element) . shortstring.handle TSQLRecordMany descendant properties as an "has many" instance (this is a particular case of TSQLRecord: it won't contain pointer(ID). Contains the index value of an indexed class data property . but Delphi doesn't create the RTTI for records so it won't work) .pas unit .handle Single. or the getter method set by 'read' Delphi declaration Index: Integer. using a integer(IDField) typecast) . or reference to a parameterless method that returns a Boolean value .this method will NOT check if the property is a dynamic array: caller must have already checked that PropType^^.fIsUnique[] function ClassFromJSON(Instance: TObject. Low-level getter of the floating-point property value of a given instance .if a property is marked as "stored AS_UNIQUE" (i. From: PUTF8Char. or call the corresponding setter method (if any).pas unit .first name index at a given class level is 0 .Synopse mORMot Framework Software Architecture Design 1. Contains the 'stored' boolean value/method (used in TPersistent saving) . var Valid: boolean): PUTF8Char.e.either integer(True) .if this field is nil (no 'write' was specified).internally call UnCamelCase() then System.18 Date: June 16.index is reset to 0 at every inherited class level PropType: PPTypeInfo. 2013 NameIndex: SmallInt.this method will check if the corresponding property is exactly currency . 1.return generic "string" type. creating a temporary instance via TTypeInfo.return 0 on any error function GetFieldAddr(Instance: TObject): pointer. "stored false"). Low-level getter of a dynamic array wrapper . Get the corresponding caption name. or the setter method set by 'write' Delphi declaration . reference to a Boolean field. The type definition of this property SetProc: PtrInt.Rev. Read an TObject published property. SetValue() use GetProc to get the field memory address to save into StoredProc: PtrInt. from the property name . Contains the offset of a field. i.e.unserialize the JSON input buffer via a call to JSONToObject() function GetCaption: string.this method will check if the corresponding property is floating-point .LoadResStringTranslate() if available function GetCurrencyValue(Instance: TObject): Currency.the default.return 0 on any error function GetDynArray(Instance: TObject): TDynArray.return NIL if both getter and setter are methods mORMot.Kind=tkDynArray function GetExtendedValue(Instance: TObject): Extended.18 Page 730 of 1055 . Contains the default value (2147483648=$80000000 indicates nodefault) when an ordinal or set property is saved as TPersistent index of the property in the current inherited class definition . integer(False). as saved by ObjectToJSON() function .will use direct in-memory reference to the object. it is created as UNIQUE in the SQL database and its bit is set in Model. Low-level getter of the currency property value of a given instance . Low-level getter of the field value memory pointer .ClassCreate . UnicodeString for Delphi 2009+ . Synopse mORMot Framework Software Architecture Design 1.g.and will return '' if it's not the case function GetHash(Instance: TObject. or an UnicodeString (for Delphi 2009+). will apply NormToUpper[] 8 bits uppercase. Low-level getter of the long string property value of a given instance .uses the generic string type: to be used within the VCL .not all kind of properties are handled: only main types .g.if CaseInsensitive is TRUE. WinAnsiString.this method will check if the corresponding property is a Long String.return 0 on any error function GetLongStrValue(Instance: TObject): RawUTF8. 1.e.this method will check if the corresponding property is ordinal .ordinal properties smaller than tkInt64 will return an Int64-converted value (e.pas unit . round strings with the ' character.Rev. TSQLRawBlob and generic Delphi 6-2007 string property function GetOrdValue(Instance: TObject): Integer. 2013 function GetGenericStringValue(Instance: TObject): string. Retrieve an unsigned 32 bit hash of the corresponding property . Return the field value as SQL statement ready .this method will check if the corresponding property is ordinal . and will return '' if it's not the case .note that this method can return a hash value of 0 function GetInt64Value(Instance: TObject): Int64.it will convert the property content into RawUTF8. handling RawUTF8 properties just like the SYSTEMNOCASE collation . and escape the text using double quotes. Low-level getter of the ordinal property value of a given instance .18 Date: June 16. according to the official SQLite3 documentation . tkInteger) .this method will check if the corresponding property is a Long String.18 Page 731 of 1055 . CaseInsensitive: boolean): cardinal.expect enumerates (and boolean) values already encoded as integer mORMot.return -1 on any error function GetSQLFromFieldValue(const FieldValue: RawUTF8): RawUTF8. Low-level getter of the ordinal property value of a given instance . Low-level getter of the long string property value of a given instance . for RawUnicode. if ToSQL is true. Compare the content of the property of two objects . result is on JSON form (false->'false' e.not all kind of properties are handled: only main types (like GetHash) . handling RawUTF8 properties just like the SYSTEMNOCASE collation function SetBinary(Instance: TObject.g.returns next char in input buffer on success.handle Delphi values into UTF-8 SQL conversion . function IsBlob: boolean.getter method (read Get*) is called if available . Return FALSE (AS_UNIQUE) if was marked as "stored AS_UNIQUE" (i.no range check: use ClassProp()^.g.GetBit64(fJSONFields.) . "stored false").) if ToSQL is true.use directly TSQLRecord.) . Return true if this property is a BLOB (TSQLRawBlob) function IsSimpleField: boolean. or nil in case of invalid content supplied e. will apply NormToUpper[] 8 bits uppercase. Read the published property value from a binary buffer .pas unit . Convert the published property value into an UTF-8 encoded text . function SetFieldAddr(Instance: TObject): pointer. result is on SQL form (false->'0' e. Low-level setter of the field value memory pointer .18 Page 732 of 1055 . or base-64 encoded stream for JSON ("\uFFF0base64encodedbinary") . or TRUE by default . Return Text+Name[+Optional] mORMot. 2013 function GetValue(Instance: TObject.Rev.Synopse mORMot Framework Software Architecture Design 1. or base-64 encoded stream for JSON ("\uFFF0base64encodedbinary") .18 Date: June 16.if Instance=nil.sftBlobDynArray.Item2: TObject.PropCount to determine the properties count . will work only at RTTI level. not with field or method (and will return TRUE if nothing is defined in the RTTI) function Next: PPropInfo. wasSQLString: PBoolean=nil): RawUTF8. Get the next property information .i) if possible (faster) function IsStored(Instance: TObject): boolean. ToSQL: boolean.PropList function SameValue(Item1. sftBlobCustom or sftBlobRecord are returned as BLOB litterals ("X'53514C697465'") if ToSQL is true.1.if CaseInsensitive is TRUE. const Optional: RawUTF8='').TEXT) but not a BLOB (TSQLRawBlob) . TCollection.e.handle TPersistent. 1. TRawUTF8List or TStrings with ObjectToJSON Used for DI-2. P: PAnsiChar): PAnsiChar.if ToSQL is false.return NIL if both getter and setter are methods procedure AppendName(var Text: RawUTF8.g.3 (page 1050). CaseInsensitive: boolean): boolean.g.FLOAT. Return true if this property is a valid simple field (INTEGER.get the first PPropInfo with ClassProp()^.BLOB field returns SQlite3 BLOB literals ("x'01234'" e. Low-level setter of the string property value of a given instance . W: TFileBufferWriter).this method will check if the corresponding property is floating-point procedure SetGenericStringValue(Instance: TObject. Low-level setter of the floating-point property value of a given instance .uses the generic string type: to be used within the VCL . Low-level getter of the long string property content of a given instance . Append the published property value into a binary buffer procedure GetRawByteStringValue(Instance: TObject.will work only for Kind=tkLString procedure GetValueVar(Instance: TObject. var Value: RawByteString). and is therefore faster than a SetValue(Dest. 2013 procedure CopyValue(Source. WinAnsiString. const Value: string).this method will check if the corresponding property is ordinal mORMot. and will call the corresponding SetLongStrValue() or SetUnicodeStrValue() method procedure SetInt64Value(Instance: TObject. Low-level setter of the long string property value of a given instance . but avoid assigning the result string variable (some speed up on multi-core CPUs. 1. Copy a published property value from one instance to another .this method will check if the corresponding property is ordinal procedure SetLongStrValue(Instance: TObject.Synopse mORMot Framework Software Architecture Design 1.pas unit .this method is the same as GetValue(). const Value: RawUTF8).GetValue(Source)) call procedure GetBinary(Instance: TObject.Rev. ToSQL: boolean. Low-level setter of the ordinal property value of a given instance . TSQLRawBlob and generic Delphi 6-2007 string property procedure SetOrdValue(Instance: TObject.just a wrapper around low-level GetLongStrProp() function . wasSQLString: PBoolean). Value: Integer). Dest: TObject).this method will check if the corresponding property is a Long String or an UnicodeString (for Delphi 2009+). Convert the published property value into an UTF-8 encoded text . const Value: Extended).it will convert the property content into RawUTF8.this method use direct copy of the low-level binary content.call GetLongStrValue() method if you want a conversion into RawUTF8 . since avoid a CPU LOCK) procedure NormalizeValue(var Value: RawUTF8). var result: RawUTF8.18 Date: June 16.true) should return the same content (true for ToSQL format) procedure SetExtendedValue(Instance: TObject. so that GetValue(Object. for RawUnicode.this method will check if the corresponding property is a Long String . Normalize the content of Value.18 Page 733 of 1055 . Low-level setter of the ordinal property value of a given instance . Value: Int64). Value: PUTF8Char).handle UTF-8 SQL to Delphi values conversion . 3 for Delphi XE and up function Param: PParamInfo.Synopse mORMot Framework Software Architecture Design 1.handle TPersistent. Expected calling convention (only relevant for x86 mode) ParamCount: Byte. 1 for EDX. TCollection. the getted field address is used .pas unit .1.expect BLOB fields encoded as SQlite3 BLOB literals ("x'01234'" e.setter method (write Set*) is called if available .is nil for procedure Version: byte.3 (page 1050).18 Page 734 of 1055 . TRawUTF8List or TStrings with JSONToObject Used for DI-2.any value >= 8 for stack-based parameter mORMot. The kind of parameter Name: ShortString.18 Date: June 16. Convert UTF-8 encoded text into the published property value . Parameter name Offset: Word.if no setter exists (no write declaration). The expected type of the returned function result . Parameter offset .i. TReturnInfo = object(TObject) A wrapper around method returned result definition CallingConvention: TCallingConvention.Rev. 2 for ECX .0 for EAX. Number of expected parameters ParamSize: Word.e.) or base-64 encoded stream for JSON ("\uFFF0base64encodedbinary") . Access to the first method parameter definition TParamInfo = object(TObject) A wrapper around an individual method parameter definition Flags: TParamFlags. both format supported by BlobToTSQLRawBlob() function . 2013 procedure SetValue(Instance: TObject. RTTI version . 1.2 up to Delphi 2010.g. Total size of data needed for stack parameters + 8 (ret-addr + pushed EBP) ReturnType: ^PTypeInfo. Item2: TObject. virtual.this default implementation will call GetValueVar() for slow comparison function GetFieldAddr(Instance: TObject): pointer. The associated method code address Len: Word.CreateFrom() or overriden constructors function CompareValue(Item1.pas unit . aFieldWidth. aPropertyIndex: integer).ParamCount to determine the appropriate count TMethodInfo = object(TObject) A wrapper around a method definition Addr: Pointer. Compare the content of the property of two objects .should not be called directly.no range check: use TReturnInfo. virtual. or be defined by code (TSQLPropInfoCustom derivated classes) constructor Create(const aName: RawUTF8.Synopse mORMot Framework Software Architecture Design 1. Wrapper returning nil and avoiding a GPF if @self=nil function ReturnInfo: PReturnInfo. aAttributes: TSQLPropInfoAttributes. reintroduce. 1. virtual.not all kind of properties are handled: only main types (like GetHash) . abstract.property information could be retrieved from RTTI (TSQLPropInfoRTTI*).18 Page 735 of 1055 . Get the next parameter information . handling RawUTF8 properties just like the SYSTEMNOCASE collation . Method name function MethodAddr: Pointer. Initialize the internal fields . Size (in bytes) of this TMethodInfo block Name: ShortString. Retrieve the associated return information TSQLPropInfo = class(TObject) Abstract parent class to store information about a published property . The parameter type information function Next: PParamInfo. CaseInsensitive: boolean): PtrInt. aSQLFieldType: TSQLFieldType.Rev.18 Date: June 16. Returns an untyped pointer to the field property memory in a given instance mORMot. will apply NormToUpper[] 8 bits uppercase. but with dedicated class methods like class function TSQLPropInfoRTTI.if CaseInsensitive is TRUE. 2013 ParamType: PPTypeInfo. this default implementation will call GetValueVar() for slow computation function GetValue(Instance: TObject. varInt64. result is on SQL form (false->'0' e.g. handling RawUTF8 properties just like the SYSTEMNOCASE collation . virtual. var aValue: TVarData. virtual.if ToSQL is true. CaseInsensitive: boolean): cardinal. Append the property value into a binary buffer procedure GetFieldVarData(Instance: TObject. varString (mapping a constant PUTF8Char). Read the property value from a binary buffer . abstract. or base-64 encoded stream for JSON ("\uFFF0base64encodedbinary") . ToSQL: boolean. or nil in case of invalid content supplied e. Set a field value from a custom TVarData sub type (not a true variant) . varInt64. Dest: TObject).pas unit .18 Page 736 of 1055 . varDouble.handle TPersistent.BLOB field returns SQlite3 BLOB literals ("x'01234'" e. abstract.Rev. var temp: RawByteString). Convert the property value into an UTF-8 encoded text . virtual.Synopse mORMot Framework Software Architecture Design 1. W: TFileBufferWriter). and varAny (BLOB with size = VLongs[0]) .g. virtual.note that this method can return a hash value of 0 .18 Date: June 16.g. varDouble. sftBlobCustom or sftBlobRecord are returned as BLOB litterals ("X'53514C697465'") if ToSQL is true. W: TJSONSerializer).not all kind of properties are handled: only main types .handle Delphi values into UTF-8 SQL conversion . P: PAnsiChar): PAnsiChar.this default implementation will call safe but slow GetValueVar() method mORMot.returns next char in input buffer on success. and is therefore faster than a SetValue(Dest. const aValue: TVarData): boolean.) if ToSQL is true.this method use direct copy of the low-level binary content.) . virtual.getter method (read Get*) is called if available .sftBlobDynArray.the temp RawByteString is used as a temporary storage for TEXT or BLOB and should be available during all access to the TVarData content procedure GetJSONValues(Instance: TObject.if CaseInsensitive is TRUE. Copy a property value from one instance to another . will apply NormToUpper[] 8 bits uppercase. and varAny (BLOB with size = VLongs[0]) procedure CopyValue(Source. Add the JSON content corresponding to the given property . abstract. 2013 function GetHash(Instance: TObject. Retrieve a field value into a custom TVarData sub type (not a true variant) . virtual. or base-64 encoded stream for JSON ("\uFFF0base64encodedbinary") .g.the field values are available via some TVarData of type varNull. function SetFieldVarData(Instance: TObject. wasSQLString: PBoolean=nil): RawUTF8. result is on JSON form (false->'false' e. varString (mapping a constant PUTF8Char). TCollection.the field values are available via some TVarData of type varNull. 1.) . TRawUTF8List or TStrings with ObjectToJSON function SetBinary(Instance: TObject. virtual.GetValue(Source)) call procedure GetBinary(Instance: TObject.if ToSQL is false. Retrieve an unsigned 32 bit hash of the corresponding property . g for TSQLRecord published properties marked as property MyProperty: RawUTF8 stored AS_UNIQUE. abstract.expect BLOB fields encoded as SQlite3 BLOB literals ("x'01234'" e. The corresponding column type name. ToSQL: boolean. Convert UTF-8 encoded text into the property value . var result: RawUTF8. abstract.handle TPersistent.) or base-64 encoded stream for JSON ("\uFFF0base64encodedbinary") .pas unit . 1.true) should return the same content (true for ToSQL format) procedure SetValue(Instance: TObject. The optional width of this field. Value: PUTF8Char.this method is the same as GetValue(). The corresponding column type.is set e. (i.18 Page 737 of 1055 . Convert the property value into an UTF-8 encoded text . virtual. both format supported by BlobToTSQLRawBlob() function . but avoid assigning the result string variable (some speed up on multi-core CPUs.contains aIsUnique e. virtual.Synopse mORMot Framework Software Architecture Design 1.this virtual method is the one to be overriden by the implementing classes procedure NormalizeValue(var Value: RawUTF8).e.handle UTF-8 SQL to Delphi values conversion . TCollection. The property definition Name property PropertyIndex: integer read fPropertyIndex. since avoid a CPU LOCK) . "stored false") property FieldWidth: integer read fFieldWidth.if no setter exists (no write declaration). by index attribute of TSQLRecord published properties as property MyProperty: RawUTF8 index 10. in external databases .setter method (write Set*) is called if available . as managed by the ORM layer property SQLFieldTypeName: PShortString read GetSQLFieldTypeName. The property index in the RTTI property SQLFieldType: TSQLFieldType read fSQLFieldType. virtual. so that GetValue(Object. wasString: boolean).18 Date: June 16. property Name: RawUTF8 read fName. as managed by the ORM layer and retrieved by the RTTI TSQLPropInfoRTTI = class(TSQLPropInfo) Parent information about a published property retrieved from RTTI mORMot. the getted field address is used .g. 2013 procedure GetValueVar(Instance: TObject. abstract.e. Normalize the content of Value.Rev.i.g. The ORM attributes of this property . wasSQLString: PBoolean). TRawUTF8List or TStrings with JSONToObject property Attributes: TSQLPropInfoAttributes read fAttributes. override. Generic way of implementing it property PropInfo: PPropInfo read fPropInfo. virtual.it will raise an EORMException in case of an unhandled type function GetFieldAddr(Instance: TObject): pointer. 1. This meta-constructor will create an instance of the exact descendant of the specified property RTTI .18 Date: June 16.Synopse mORMot Framework Software Architecture Design 1. Initialize the internal fields .can be either sftBoolean or sftEnumerate kind of property TSQLPropInfoRTTIChar = class(TSQLPropInfoRTTIInt32) Information about a character published property TSQLPropInfoRTTIInt64 = class(TSQLPropInfoRTTI) Information about an ordinal Int64 published property TSQLPropInfoRTTITimeLog = class(TSQLPropInfoRTTIInt64) Information about a TTimeLog published property .should not be called directly. but with dedicated class methods like class function CreateFrom() class function CreateFrom(aPropInfo: PPropInfo. aPropIndex: integer. reintroduce.stored as an Int64. 2013 constructor Create(aPropInfo: PPropInfo.pas unit . but with a specific class TSQLPropInfoRTTIDouble = class(TSQLPropInfoRTTIInt64) Information about a floating-point Double published property TSQLPropInfoRTTICurrency = class(TSQLPropInfoRTTIDouble) Information about a fixed-decimal Currency published property TSQLPropInfoRTTIDateTime = class(TSQLPropInfoRTTIInt64) Information about a TDateTime published property TSQLPropInfoRTTIAnsi = class(TSQLPropInfoRTTI) Information about a AnsiString published property TSQLPropInfoRTTIRawUTF8 = class(TSQLPropInfoRTTIAnsi) Information about a RawUTF8 published property TSQLPropInfoRTTIWinAnsi = class(TSQLPropInfoRTTIAnsi) Information about a WinAnsiString published property mORMot. aPropIndex: integer): TSQLPropInfo. Corresponding RTTI information TSQLPropInfoRTTIInt32 = class(TSQLPropInfoRTTI) Information about an ordinal Int32 published property TSQLPropInfoRTTISet = class(TSQLPropInfoRTTIInt32) Information about a set published property TSQLPropInfoRTTIEnum = class(TSQLPropInfoRTTIInt32) Information about a enumeration published property .Rev.18 Page 738 of 1055 . aSQLFieldType: TSQLFieldType). aPropIndex: Integer. aProperty: pointer. aText2Data: TOnSQLPropInfoRecord2Data).18 Page 739 of 1055 .Delphi does not publish RTTI for published record properties . for fast lookup by TSQLRecord. use TEXT storage and sftUTF8Custom type constructor Create(const aName: RawUTF8.will store the content as BLOB by default. aFieldWidth.g. aSQLFieldType: TSQLFieldType. and SQLFieldType as sftBlobCustom . 1. but one of its inherited classes TSQLPropInfoRecordRTTI = class(TSQLPropInfoCustom) Information about a record property defined directly in code .do not call this constructor directly.pas unit .will store the content as BLOB by default. 2013 TSQLPropInfoRTTIRawUnicode = class(TSQLPropInfoRTTIAnsi) Information about a RawUnicode published property TSQLPropInfoRTTIRawBlob = class(TSQLPropInfoRTTIAnsi) Information about a TSQLRawBlob published property TSQLPropInfoRTTIWide = class(TSQLPropInfoRTTI) Information about a WideString published property TSQLPropInfoRTTIDynArray = class(TSQLPropInfoRTTI) Information about a dynamic array published property property DynArrayIndex: integer read fFieldWidth.Synopse mORMot Framework Software Architecture Design 1.do not use this class.you can use this class to register a record property from its RTTI . use TEXT storage and sftUTF8Custom type . and SQLFieldType as sftBlobCustom . Optional index of the dynamic array published property .DynArray(DynArrayFieldIndex) TSQLPropInfoCustom = class(TSQLPropInfo) Abstract information about a record-like property defined directly in code . aData2Text: TOnSQLPropInfoRecord2Text.18 Date: June 16. aAttributes: TSQLPropInfoAttributes. reintroduce.this class will use only binary RecordLoad/RecordSave methods mORMot.if aData2Text/aText2Data are defined. Define a custom property in code . but TSQLPropInfoRecordRTTI and TSQLPropInfoRecordFixedSize .used e.if aData2Text/aText2Data are defined.Rev. aAttributes: TSQLPropInfoAttributes=[].handle any kind of record with TypeInfo() generated ..Delphi does not publish RTTI for published record properties .. public (. aText2Data: TOnSQLPropInfoRecord2Data=nil). aPropertyIndex: integer. Define a record property from its RTTI definition . aPropertyIndex: integer. end. reintroduce.simple kind of records (i. those not containing reference-counted members) do not have RTTI generated.you can specify optional aData2Text/aText2Data callbacks to store the content as textual values. 2013 constructor Create(aRecordInfo: PTypeInfo.18 Page 740 of 1055 .Synopse mORMot Framework Software Architecture Design 1.. Release internal list items function Add(aTable: TClass. const aName: RawUTF8. you will have to register it as aPropInfo := TSQLPropInfoCustom.) property FieldName: TMyRecord read fFieldName write fFieldName. use TEXT storage and sftUTF8Custom type constructor Create(aRecordSize: cardinal. overload.) fFieldName: TMyRecord. .aPropertyPointer shall be filled with the offset to the private field within a nil object. aPropertyPointer: pointer.if aData2Text/aText2Data are defined.fFieldName). aData2Text: TOnSQLPropInfoRecord2Text=nil.'FieldName'. in bytes TSQLPropInfoList = class(TObject) Handle a read-only list of ORM fields information for published properties destructor Destroy.implementation will use internally RecordLoad/RecordSave functions .main parameter is the record size. aFieldWidth: integer=0. a record with no reference-counted types within) .18 Date: June 16.optional aIsNotUnique parameter will be used .g for class TMainObject = class(TSQLRecord) (. aFieldWidth: integer=0. aItem: TSQLPropInfo): integer. and SQLFieldType as sftBlobCustom . @TMainObject(nil). aText2Data: TOnSQLPropInfoRecord2Data=nil). reintroduce. e. Add a TSQLPropInfo to the list mORMot.pas unit .e. overload.will store the content as BLOB by default. aPropertyPointer: pointer. const aName: RawUTF8. and not as BLOB TSQLPropInfoRecordFixedSize = class(TSQLPropInfoCustom) Information about a fixed-size record property defined directly in code .Rev. aAttributes: TSQLPropInfoAttributes=[]. at least in older versions of Delphi: use this constructor to define a direct property access .you can use this class to register a record property with no RTTI (i. Define an unmanaged fixed-size record property .e. 1. override..Create(TypeInfo(TMyRecord). aData2Text: TOnSQLPropInfoRecord2Text=nil. ClassName] if WithSection is true . (wide)string.the enumerates properties are stored with their integer index value .will raise an exception if out of range property List: TSQLPropInfoDynArray read fList.content can be read back using overloaded procedures ReadObject() TJSONSerializer = class(TJSONWriter) Simple writer to a Stream.Rev. since is its capacity TINIWriter = class(TTextWriter) Default.resulting content will be UTF-8 encoded .18 Page 741 of 1055 . specialized for writing an object as INI . 2013 function ByName(aName: PUTF8Char): TSQLPropInfo. must inherit from TPersistent or TSQLRecord . Write the published integer. specialized for writing an object as JSON .g. faster than string+string procedure WriteObject(Value: TObject. Int64.use an internal buffer. faster than string+string mORMot. overload.resulting JSON content will be UTF-8 encoded . boolean). reintroduce. overload. floating point values. variant properties of the object . enumerates (e. Read-only retrieval of a TSQLPropInfo item .returns nil if not found function IndexByName(aName: PUTF8Char): integer. 1. simple writer to a Stream.e.the object must have been compiled with the $M+ define. Find an item in the list . Find an item in the list . overload.returns -1 if not found property Count: integer read fCount.18 Date: June 16. Find an item in the list .add a new INI-like section with [Value.Synopse mORMot Framework Software Architecture Design 1. Returns the number of TSQLPropInfo in the list property Items[aIndex: integer]: TSQLPropInfo read GetItem. overload. WithSection: boolean=true). i.use an internal buffer.note that length(List) may not equal Count.returns -1 if not found function IndexByName(const aName: RawUTF8): integer. Find an item in the list . const SubCompName: RawUTF8=''. Quick access to the TSQLPropInfo list .won't handle shortstring properties .returns nil if not found function ByRawUTF8Name(const aName: RawUTF8): TSQLPropInfo.pas unit . all referenced TSQLRecord classes will be globally registered when TSQLRecordProperties information is retrieved class procedure RegisterCollectionForJSON(aCollection: TCollectionClass..note that any inherited classes will be serialized as the parent class mORMot. TCollection classes are processed: but you can specify here some callbacks to perform the serialization process for any class . aWriter: TJSONSerializerCustomWriter).. 1." . Relase all used memory and handles procedure AddTypedJSON(aTypeInfo: pointer. Let a given TCollection be recognized during JSON serialization . Let a given class be recognized by JSONToObject() from "ClassName":"." field to identify the class type .by default.18 Page 742 of 1055 . overload. able to write sets using RTTI class procedure RegisterClassForJSON(aItemClass: TClass).first workaround is to inherit from TInterfacedCollection .any previous registration is overriden .due to how TCollection instances are created..e. aItem: TCollectionItemClass).TObjectList item instances will be created corresponding to the serialized class name field specified." field to identify the class type .Rev. 2013 destructor Destroy. override.. var aValue).. aReader: TJSONSerializerCustomReader. Define a custom serialization for a given class . TPersistent. and JSONToNewObject() can create a new instance using the "ClassName":"..by default. so allow to (un)serialize any TCollection. Let a given class be recognized by JSONToObject() from "ClassName":"." RegisterClassForJSON() process class procedure RegisterCustomSerializer(aClass: TClass. without defining a new method and inherits from TInterfacedCollection . and JSONToNewObject() can create a new instance using the "ClassName":". override.TObjectList item instances will be created corresponding to the serialized class name field specified.Synopse mORMot Framework Software Architecture Design 1..by default. published properties serialization) ." .pas unit .18 Date: June 16. you can not create a server-side instance of TCollection directly . all referenced TSQLRecord classes will be globally registered when TSQLRecordProperties information is retrieved class procedure RegisterClassForJSON(const aItemClass: array of TClass).this method allows to recognize the needed TCollectionItem class for a given TCollection class.note that both supplied classes will be registered for the internal "ClassName":". Override method.. overload.setting both aReader=aWriter=nil will return back to the default class serialization (i. TStrings. TSQLRecord. override. boolean) properties of the object .they will be written only if FullExpand is set to true (and JSONToObject won't be able to read it) . i. must inherit from TPersistent or TSQLRecord. or has been defined with a custom serializer via RegisterCustomSerializer() .this implementation will avoid most memory allocations ESQLTableException = class(ESynException) Exception raised in case of incorrect TSQLTable. but will double all internal " and bound with " . string and enumerate (e.function ObjectToJSON() is just a wrapper over this method procedure WriteObjectAsString(Value: TObject. Options: TTextWriterWriteObjectOptions=[woDontStoreDefault]).18 Date: June 16.e. but will be written as text if woFullExpand option is set . services and mock/stubs EServiceException = class(EORMException) Exception dedicated to interface based service implementation mORMot.won't handle shortstring properties . floating point values.nested properties are serialized as nested JSON objects .Step / Field*() use EORMException = class(ESynException) Generic parent class of all custom Exception types of this unit EModelException = class(EORMException) Exception raised in case of wrong Model definition EParsingException = class(EORMException) Exception raised in case of unexpected parsing error ECommunicationException = class(EORMException) Exception raised in case of a Client-Server communication error EBusinessLayerException = class(EORMException) Exception raised in case of an error in project implementation logic ESecurityException = class(EORMException) Exception raised in case of any authentication error EInterfaceFactoryException = class(ESynException) Exception dedicated to interface factory. 2013 procedure WriteObject(Value: TObject. TDateTime (stored as ISO 8601 text). e.pas unit .will write also the properties published in the parent classes .the object must have been compiled with the $M+ define.Rev. 1.g. Same as WriteObject(). Int64.the enumerates properties are stored with their integer index value by default.any TCollection property will also be serialized as JSON array .TList objects are not handled by default .any TStrings or TRawUTF8List property will also be serialized as JSON string array . Options: TTextWriterWriteObjectOptions=[woDontStoreDefault]).g.18 Page 743 of 1055 . Serialize as JSON the published integer.Synopse mORMot Framework Software Architecture Design 1. sftMany for TSQLRecordMany properties.kind sftID. not any true class instance .sftID for TSQLRecord properties. for TSQLRecordMany properties TSQLPropInfoRTTIID = class(TSQLPropInfoRTTIInstance) Information about a TSQLRecord class TSQLRecord property .can be used e.18 Page 744 of 1055 .kind sftMany. and allows faster access to most wanted RTTI properties Used for DI-2. as TSQLPropInfoCustom custom definition mORMot.g.sftObject for e.18 Date: June 16.kind sftObject e. for TStrings TRawUTF8List TCollection TObjectList instances . List of all sftBlobCustom fields of this TSQLRecord . Direct access to the property class instance procedure SetInstance(Instance.used internaly by TSQLRecord.g. override. for which no data is stored in the table itself. 1. not any true class instance .Synopse mORMot Framework Software Architecture Design 1.have been defined e. which are pointer(RecordID).binary serialization will store textual JSON serialization of the object. which are pointer(RecordID).g. Value: TObject).g. TStrings TRawUTF8List TCollection instances constructor Create(aPropInfo: PPropInfo. 2013 TSQLPropInfoRTTIInstance = class(TSQLPropInfoRTTIInt32) Information about a TSQLRecord class property .RecordProps class . for which no data is stored in the table itself. Direct access to the property class instance property ObjectClass: TClass read fObjectClass.3 (page 1050). via a global cache handled by this unit: you can access to each record's properties via TSQLRecord.Rev.pas unit .will store the content just as an integer value TSQLPropInfoRTTIObject = class(TSQLPropInfoRTTIInstance) Information about a TSQLRecord class TStrings/TRawUTF8List/TCollection property . aPropIndex: integer. BlobCustomFields: array of TSQLPropInfo.such a global cache saves some memory for each TSQLRecord instance. aSQLFieldType: TSQLFieldType). but in a pivot table . Will setup the corresponding RecordClass property function GetInstance(Instance: TObject): TObject.1. Direct access to the property class . but in a separated pivot table TSQLRecordProperties = class(TObject) Some information about a given TSQLRecord class properties . including custom serialization TSQLPropInfoRTTIMany = class(TSQLPropInfoRTTIInstance) Information about a TSQLRecord class TSQLRecordMany property . Bit set to 1 for indicating BLOB fields of this TSQLRecord .e.e. "simple" fields .i.an unique field is defined as "stored AS_UNIQUE" (i.18 Page 745 of 1055 .since validation and filtering are used within some CPU-consuming part of the framework (like UI edition). 1.18 Date: June 16.g. 2013 BlobFields: array of TSQLPropInfoRTTI. the TSQLRawBlob and TSQLRecordMany fields are not included into this set: they must be read specificaly (in order to spare bandwidth for BLOBs) .the [boolean] is for [ReturnFirstIfNoUnique] version .Synopse mORMot Framework Software Architecture Design 1. List of all sftBlobDynArray fields of this TSQLRecord Fields: TSQLPropInfoList. All TSynFilter or TSynValidate instances registered per each field . generic sftBlob fields (not sftBlobDynArray. mostly 'Name') . as retrieved from RTTI Filters: array of TObjectList. Contains the main field index (e. List all "simple" fields of this TSQLRecord . Bit set to 1 for indicating fields to export. Set of field types appearing in this record IsUniqueFieldsBits: TSQLFieldBits. List all TSQLRecordMany fields of this TSQLRecord SimpleFields: TSQLPropInfoDynArray. i. like the TCreateTime fields which shall not be included in soUpdate but soInsert and soSelect e.i.e.g. List all fields. some fields to be ignored HasTypeFields: TSQLFieldTypes.Rev.contains -1 if no field matches ManyFields: array of TSQLPropInfoRTTIMany. "stored false") in its property definition MainField: array[boolean] of integer. List all BLOB fields of this TSQLRecord . If this class has any BLOB or TSQLRecodMany fields .for TSynTableFieldProperties there are separated Filters[] and Validates[] array.pas unit .i. sftBlobCustom nor sftBlobRecord) BlobFieldsBits: TSQLFieldBits.e. for better performance HasNotSimpleFields: boolean. Fast access to the RTTI properties attribute DynArrayFields: array of TSQLPropInfoRTTIDynArray. mORMot. generic sftBlob fields (not sftBlobDynArray. Bit set to 1 for an unique field .this array will handle special cases.e.dynamic arrays belong to simple fields: they are sent with other properties content SimpleFieldsBits: array[TSQLOccasion] of TSQLFieldBits. both filters and validation rules are grouped in the same TObjectList .by default. sftBlobCustom nor sftBlobRecord) ClassProp: PClassProp. ' . if no 'TSQL' or 'TSQLRecord' at first SQLTableNameUpperWithDot: RawUTF8.Rev. overload. Register a custom filter or validation rule to the class for a specified field . overload.can be used with IdemPChar() for fast check of a table name SQLTableRetrieveBlobFields: RawUTF8. The Table name in the database. Register a custom filter or Validate to the class for a specified field .will return the specified associated TSynFilterOrValidate instance . aFilter: TSynFilterOrValidate): TSynFilterOrValidate. Returns 'COL1=?. override. The TSQLRecord class constructor Create(aTable: TSQLRecordClass).g.Synopse mORMot Framework Software Architecture Design 1.this will be used by TSQLRecord.g.this won't change depending on the ORM settings: so it can be safely computed here and not in TSQLModelRecordProperties SQLTableUpdateBlobFields: RawUTF8. Initialize the properties content destructor Destroy.same value as SQLTableSimpleFields[false.18 Page 746 of 1055 .will return nil in case of an invalid field index mORMot. Release associated used memory function AddFilterOrValidate(const aFieldName: RawUTF8. The Table name in the database in uppercase with a final '.Filter and TSQLRecord. like the TCreateTime fields which shall not be included in soUpdate but soInsert and soSelect e. "simple" fields . 1. Returns 'COL1.COL2' with all COL* set to simple field names .false] . Number of fields to export.e.will return the specified associated TSynFilterOrValidate instance function AddFilterOrValidate(aFieldIndex: integer.COL2' with all BLOB columns names SQLTableSimpleFieldsNoRowID: RawUTF8. aFilter: TSynFilterOrValidate): TSynFilterOrValidate. 2013 SimpleFieldsCount: array[TSQLOccasion] of integer.COL2=?' with all BLOB columns names Table: TSQLRecordClass.pas unit .'TSQL' or 'TSQLRecord' chars are trimmed at the beginning of the ClassName . Returns 'COL1.' for TSQLRecordTest class .or the ClassName is returned as is.Filter and TSQLRecord. SQLTableName: RawUTF8.this will be used by TSQLRecord. 'TEST.18 Date: June 16. i.e.this array will handle special cases.Validate methods (in default implementation) . associated with this TSQLRecord class .Validate methods (in default implementation) . FALSE if any field name is not existing function IsFieldName(const PropName: RawUTF8): boolean.g. var Bits: TSQLFieldBits): boolean. WIN32CASE.Rev.this version returns nil if the property is not a BLOB field function CreateJSONWriter(JSON: TStream.can be used e. RTRIM and our custom SYSTEMNOCASE.pas unit .collations defined within our SynSQLite3 unit are named BINARY. const aFields: TSQLFieldBits.returns '' if no matching field was found function SetCustomCollation(FieldIndex: integer.returns TRUE on success. var Text: RawUTF8. i.this property is mainly the "Name" property. Return the UTF-8 encoded SQL statement source to alter the table for adding the specified field mORMot. ReturnFirstIfNoUnique: boolean=false): RawUTF8. withID: boolean. Retrieve a Field property RTTI information from a Property Name .18 Date: June 16.to be set in overriden class procedure InternalRegisterCustomProperties() so that it will be common to all database models. ready to be filled with TSQLRecord. if FieldIndex is out of range) will return TRUE .returns TRUE on success.otherwise. and returns false . for both client and server function SQLAddField(FieldIndex: integer): RawUTF8. const aCollationName: RawUTF8): boolean. var Bits: TSQLFieldBits): boolean.e. Return TRUE if the given name is either ID/RowID. Set all bits corresponding to the supplied field names .e. Expand: boolean.if ReturnFirstIfNoUnique is TRUE and no unique property is found.on error (i.GetJSONValues(W) function FieldIndexsFromBlobField(aBlobField: PPropInfo. 1.if FieldIndex=VIRTUAL_TABLE_ROWID_COLUMN (-1). appends 'RowID' or 'ID' (if ForceNoRowID=TRUE) to Text .Synopse mORMot Framework Software Architecture Design 1.do nothing if FieldIndex is not valid. FALSE if blob field is not recognized function FieldIndexsFromRawUTF8(const aFields: array of RawUTF8. KnownRowsCount: integer): TJSONSerializer. NOCASE. to override the default COLLATE SYSTEMNOCASE of RawUTF8 . the one with "stored AS_UNIQUE" (i. either a property name function MainFieldName(Table: TSQLRecordClass.e. Set all bits corresponding to the supplied field names . WIN32NOCASE . the first RawUTF8 property is returned anyway . Append a field name to a RawUTF8 Text buffer . "stored false") definition on most TSQLRecord . ISO8601. Return the first unique property of kind RawUTF8 . Set a custom SQlite3 text column collation for a specified field .18 Page 747 of 1055 . ForceNoRowID: boolean): boolean. Create a TJSONWriter. 2013 function AppendFieldName(FieldIndex: Integer. will return FALSE and append the field name to Text function BlobFieldPropFromRawUTF8(const PropName: RawUTF8): PPropInfo. can be used as such: class procedure TSQLRecordCustomProps. Return the SQLite3 field datatype for each specified field .Synopse mORMot Framework Software Architecture Design 1. ISO8601.set to '' for fields with no column created in the database (e. NOCASE. aFieldWidth: integer=0.18 Date: June 16.add an TSQLPropInfoRecordFixedSize instance to the internal list .g.add an TSQLPropInfoRecordRTTI instance to the internal list .main parameters are the record size.use this method within InternalRegisterCustomProperties overriden method to define a custom record property containing reference-counted types . aPropertyPointer: pointer.InternalRegisterCustomProperties( Props: TSQLRecordProperties). procedure SetCustomCollationForAllRawUTF8(const aCollationName: RawUTF8).RegisterCustomFixedSizeRecordProperty(self. in bytes.sizeof(TGUID).equals e. ' procedure RegisterCustomFixedSizeRecordProperty(aTable: TClass.Rev. for both client and server mORMot. const aName: RawUTF8. begin Props. ' or ' TEXT COLLATE SYSTEMNOCASE.handle any kind of record with TypeInfo() generated . RTRIM and our custom SYSTEMNOCASE.collations defined within our SynSQLite3 unit are named BINARY. those not containing reference-counted members) do not have RTTI generated.main parameters are the record RTTI information.InternalRegisterCustomProperties( Props: TSQLRecordProperties).g.g. 2013 function SQLFieldTypeToSQL(Fieldindex: integer): RawUTF8.fRecField). aData2Text: TOnSQLPropInfoRecord2Text=nil.to be set in overriden class procedure InternalRegisterCustomProperties() so that it will be common to all database models. aRecordSize: cardinal. aAttributes: TSQLPropInfoAttributes=[].typical use may be TGUID . end. WIN32NOCASE .RegisterCustomRTTIRecordProperty(self.TypeInfo(TMyRec). aPropertyPointer: pointer.'RecField'. @TSQLRecordCustomProps(nil).pas unit . end. aText2Data: TOnSQLPropInfoRecord2Data=nil).e. Set a custom SQlite3 text column collation for all RawUTF8 fields . 1. aRecordInfo: PTypeInfo. to override ALL default COLLATE SYSTEMNOCASE of RawUTF8.can be used as such: class procedure TSQLRecordCustomProps. aAttributes: TSQLPropInfoAttributes=[]. aText2Data: TOnSQLPropInfoRecord2Data=nil). Add a custom record property from its RTTI definition . and the property pointer .use this method within InternalRegisterCustomProperties overriden method to define a custom record property with no reference-counted types within (like strings) . aData2Text: TOnSQLPropInfoRecord2Text=nil. aFieldWidth: integer=0. @TSQLRecordCustomProps(nil).can be used e. const aName: RawUTF8. WIN32CASE. sftMany) . begin Props. and the property pointer . at least in older versions of Delphi . Add a custom unmanaged fixed-size record property .fGUID). procedure RegisterCustomRTTIRecordProperty(aTable: TClass.'GUID'.18 Page 748 of 1055 .simple kind of records (i. ' INTEGER. and let the generated SQLite3 file be available outside . 18 Date: June 16. points to the Dest property RTTI property RecordManySourceProp: TSQLPropInfoRTTIInstance read fRecordManySourceProp.URI() method call .Synopse mORMot Framework Software Architecture Design 1. Output parameter to be set to the HTTP status integer code . Input parameter containing the caller message body .handle enhanced REST codes: LOCK/UNLOCK/BEGIN/END/ABORT OutBody: RawUTF8. authentification and rights management) .BatchUpdate and BatchAdd methods property RecordManyDestProp: TSQLPropInfoRTTIInstance read fRecordManyDestProp. Output parameter to be set to the response message body OutHead: RawUTF8.see TSQLRestClient to check how data is expected in our RESTful format InBody: RawUTF8. Output parameter to be set to the response message header OutInternalState: cardinal. Occasion: TSQLOccasion). in TSQLRestClientURI.g. 1.g. Output parameter to be set to the database internal state OutStatus: cardinal. if the url doesn't start with Model. Input parameter containing the caller message headers Method: RawUTF8. For a TSQLRecordMany class. Associated RESTful access rights . according to the Application Security Policy (user logging. Input parameter containing the caller method .Root (caller can try another TSQLRestServer) RestAccessRights: PSQLAccessRights.is used e.g.AccessRights must be handled by the TSQLRestServer child. withID: boolean.Rev. For a TSQLRecordMany class.pas unit . points to the Source property RTTI TSQLRestServerURIParams = packed record Store all parameters for a TSQLRestServer. 2013 procedure SetSimpleFieldsExpandedJSONWriter(W: TJSONWriter.HTML_NOTFOUND=404 e. Initialize the JSON writer parameters with simple fields . some GET/POST/PUT JSON data can be specified here InHead: RawUTF8.18 Page 749 of 1055 .making access rights a parameter allows this method to be handled as pure stateless. Input parameter containing the caller URI mORMot.recreate especially the ColNames[] and other necessary properties . thread-safe and session-free Url: RawUTF8.e. URI() level .i.18 Date: June 16.18 Page 750 of 1055 .e. Associated logging instance .i. as decoded from URI scheme .this property will be set from incoming URI.equals 1 (CONST_AUTHENTICATION_NOT_USED) if authentication mode is not enabled .having a dedicated record avoid changing the implementation methods signature if the framework add some parameters to this structure . The index in the Model of the Table specified at the URI level (if any) mORMot.is undefined if Session is 0 or 1 (no authentication running) Table: TSQLRecordClass. 1.equals 0 (CONST_AUTHENTICATION_SESSION_NOT_STARTED) if the session is not started yet . The associated TSQLRecord.this property will be set from incoming URI.ID value .use UrlDecodeValue*() functions to retrieve the values Session: cardinal. URI inlined parameters .Rev.e.low-level access to the call parameters can be made via this pointer ID: integer.process should better call Results() or Success() methods to set the appropriate answer or Error() method in case of an error .IDCardinal value .you can use it to log some process on the server side Method: TSQLURIMethod.User.Synopse mORMot Framework Software Architecture Design 1. even if RESTful authentication is not enabled MethodIndex: integer. The Table as specified at the URI level (if any) TableIndex: integer. The corresponding session TAuthSession.ID. if TSQLRestServer. even if RESTful authentication is not enabled Log: ISynLog. The corresponding TAuthSession.pas unit .GroupRights. The index of the callback published method within the internal class list Parameters: PUTF8Char. 2013 TSQLRestServerCallBackParams = object(TObject) Store calling context for a TSQLRestServerCallBack event handler . The used Client-Server method (matching the corresponding HTTP Verb) . Access to all input/output parameters at TSQLRestServer.HandleAuthentication = FALSE SessionGroup: integer.is undefined if Session is 0 or 1 (no authentication running) SessionUser: integer.see TSQLRestServerCallBack for general code use Call: PSQLRestServerURIParams.User. The corresponding TAuthSession.ID value . if still in handshaking phase . if no ErrorMessage is specified."two"]} . with the supplied error text . excluding parameters . text in URI URIWithoutSignature: RawUTF8.. will return a default text corresponding to the Status code procedure Error(Format: PUTF8Char. overload.Args)) procedure Results(const Values: array of const. Handle304NotModified: boolean=false). but without the &session_signature=.expects Status to be either HTML_SUCCESS or HTML_CREATED. Use this method to send back directly a result value to the caller . Status: integer=HTML_SUCCESS. it will call Error() method . Use this method to send back an error to the caller . without the actual result content (to save bandwidth) mORMot.pas unit . as such for one value: {"result":"OneValue"} (with one value. Status: integer=HTML_BADREQUEST).if Status is an error code. Use this method to send back an error to the caller . const CustomHeader: RawUTF8=''. and will send back a JSON error message to the caller. Use this method to send back a JSON object with a "result" field . The URI address. Handle304NotModified: boolean=false). overload.expects Status to be either HTML_SUCCESS or HTML_CREATED . to TEXT_CONTENT_TYPE_HEADER if the default JSON_CONTENT_TYPE is not OK . Position of the &session_signature=. Status: integer=HTML_SUCCESS.Synopse mORMot Framework Software Architecture Design 1.if Handle304NotModified is TRUE and Status is HTML_SUCCESS. you can just call TSQLRestClientURI.this method will encode the supplied values as a {"result":"..} JSON object. overload.CustomHeader optional parameter can be set e.g.. Status: integer=HTML_BADREQUEST)..implementation is just a wrapper over Error(FormatUTF8(Format. Same as URI.. 2013 URI: RawUTF8. or a service name URISessionSignaturePos: integer..caller can set Handle304NotModified=TRUE for Status=HTML_SUCCESS procedure Returns(const Result: RawUTF8.expects Status to not be HTML_SUCCESS neither HTML_CREATED.Rev. ending procedure Error(const ErrorMessage: RawUTF8=''. 1.18 Date: June 16. the Result content will be hashed (using crc32) and in case of no modification will return HTML_NOTMODIFIED to the browser.18 Page 751 of 1055 . const Args: array of const.CallBackGetResult method to call and decode this value) or as a JSON object containing an array of values: {"result":["One". and will return as answer the supplied Result content with no transformation .can be either the table name (in RESTful protocol). slower than the direct UrlDecodeValue*() process.FillPrepare()/FillPrepareMany() methods .raise an EParsingException if the parameter is not found property InputInt[const ParamName: RawUTF8]: Int64 read GetInputInt.by default. therefore wrongly) .slower than the direct UrlDecodeValue*() process.using a dedicated class will reduce memory usage for each TSQLRecord instance (which won't need these properties most of the time) destructor Destroy. 2013 procedure Returns(const NameValuePairs: array of const. but more convenient to use .raise an EParsingException if the parameter is not found property InputUTF8[const ParamName: RawUTF8]: RawUTF8 read GetInputUTF8. but more convenient to use . it will call Error() method . override. just a status .this method will encode the supplied values e. overload. Handle304NotModified: boolean=false).implementation is just a wrapper around Returns(JSONEncode([])) .'John'.Rev."year":1972}' .use the mapping prepared with Map() method function Fill(aRow: integer. Status: integer=HTML_SUCCESS. as JSONEncode(['name'.'year'.18 Page 752 of 1055 .pas unit . Finalize the mapping function Fill(aRow: integer): Boolean. Retrieve one input parameter from its URI name as Int64 . overload. Retrieve one input parameter from its URI name as double .Synopse mORMot Framework Software Architecture Design 1.use the mapping prepared with Map() method mORMot.if Status is an error code.won't work with cross-reference mapping (FillPrepareMany) .overloaded method using a specified destination record to be filled . 1. Use this method to send back a JSON object to the caller .raise an EParsingException if the parameter is not found TSQLRecordFill = class(TObject) Internal data used by TSQLRecord.slower than the direct UrlDecodeValue*() process. Fill a TSQLRecord published properties from a TSQLTable row . but more convenient to use . aDest: TSQLRecord): Boolean. overload.expects Status to be either HTML_SUCCESS or HTML_CREATED .1972]) = '{"name":"John".18 Date: June 16. Use this method if the caller expect no data.caller can set Handle304NotModified=TRUE for Status=HTML_SUCCESS procedure Success(Status: integer=HTML_SUCCESS).just wrap the overloaded Returns() method with no result value .note that cardinal values should be type-casted to Int64() (otherwise the integer mapped value will be transmitted.g. Retrieve one input parameter from its URI name as RawUTF8 . Fill a TSQLRecord published properties from a TSQLTable row . calling this method will mark process as successfull property InputDouble[const ParamName: RawUTF8]: double read GetInputDouble. the internal temporary table is stored here for TSQLRecordMany . The TSQLTable stated as FillPrepare() parameter . Reset the mapping .g. aTable: TSQLTable.pas unit .2 (page 1049).will release TSQLRecordMany.FillPrepareMany() property FillCurrentRow: integer read fFillCurrentRow.overloaded method using a specified destination record to be filled .1.Destroy if fTable. aDest: TSQLRecord). aCheckTableName: TSQLCheckTableName). mORMot.inherits a class from TSQLRecord. 1. The current Row during a Loop property Table: TSQLTable read fTable.1. overload. DI-2. overload.1 (page 1047). Map all columns of a TSQLTable to a record mapping procedure UnMap.18 Page 753 of 1055 .use the mapping prepared with Map() method .FillClose . by TSQLRecord.won't work with cross-reference mapping (FillPrepareMany) .Dest instances as set by TSQLRecord.is called e.Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16. DI-2.use the mapping prepared with Map() method .aTableRow will point to the first column of the matching row procedure Map(aRecord: TSQLRecord. and add published properties to describe the table columns (see TPropInfo for SQL and Delphi type mapping/conversion) .will free any previous Table if necessary . 2013 procedure Fill(aTableRow: PPUtf8CharArray.1. Fill a TSQLRecord published properties from a TSQLTable row .this instance is freed by TSQLRecord.3 (page 1050).BLOB fields are decoded to auto-freeing TSQLRawBlob Used for DI-2.this published properties can be converted back into UTF-8 encoded SQL source with GetSQLValues or GetSQLSet or into JSON format with GetJSONValues .this published properties can be auto-filled from TSQLTable answer with FillPrepare() and FillRow(). Fill a TSQLRecord published properties from a TSQLTable row . or FillFrom() with TSQLTable or JSON data .aTableRow will point to the first column of the matching row procedure Fill(aTableRow: PPUtf8CharArray).OwnerMustFree=true TSQLRecord = class(TObject) Root class for defining and mapping database records .Rev. the REST method is LOCK and not GET: it tries to lock the corresponding record.PtrInt(aPublishedRecord)) or Create(aClient.Create(aClient. and will in all case create a request with :(.Rev. but a typecast to TObject(RecordID) you can also use its ID property .a published TSQLRecord property is not a class instance.Create(aClient. This constructor initializes the object as above.pas unit .is just a wrapper around Create(aClient.18 Page 754 of 1055 . overload. aID: integer. virtual. 2013 constructor Create(aClient: TSQLRest..if ForUpdate is true. const ParamsSQLWhere.): inlined parameters . .aPublishedRecord.Synopse mORMot Framework Software Architecture Design 1. the REST method is LOCK and not GET: it tries to lock the corresponding record. overload. This constructor initializes the record .[]).using '?' and BoundsSQLWhere[] is perhaps more readable in your code. using the other Create overloaded constructor: Rec := TSQLMyRecord.the FormatSQLWhere clause will replace all '%' chars with the supplied ParamsSQLWhere[] values. This constructor initializes the object as above. ForUpdate: boolean=false). ForUpdate: boolean=false).ID) . TStringList or TCollection as published property) constructor Create(aClient: TSQLRest. FormatSQLWhere: PUTF8Char. BoundsSQLWhere: array of const).'Count=?'. from a TSQLRecord published property content . then retrieve its content. and fills its content from a client or server connection . as :(. overload.you should either call: Rec := TSQLMyRecord.[aCount])..auto-instanciate any TSQLRecordMany instance defined in published properties .. using a specified WHERE clause with parameters .if ForUpdate is true. to release the record constructor Create. 1.'Count=?'. This constructor initializes the object and fills its content from a client or server connection.18 Date: June 16. then retrieve its content.Create(aClient.'Count=:(%):'[aCount].): inline parameters. caller has to call UnLock() method after Value usage.[]. or even better.g. and fills its content from a client or server connection. or (letting the inlined parameters being computed by FormatUTF8) Rec := TSQLMyRecord. and all '?' chars with BoundsSQLWhere[] values. aPublishedRecord: TSQLRecord. with automatic RawUTF8 quoting if necessary mORMot.override this method if you want to use some internal objects (e. caller has to call UnLock() method after Value usage.[aCount]). to release the record constructor Create(aClient: TSQLRest. overload. the TSQLTableJSON will be freed by TSQLRecord. and will save remote bandwidth by specifying the needed fields): notice that you should not use this optional parameter if you want to Update the retrieved record content later.pas unit .note that this method prototype changed with revision 1.the WHERE clause should use inlined parameters (like 'Name=:('Arnaud'):') for better server speed .use DateToSQL/DateTimeToSQL for TDateTime.18 Date: June 16.note that you can use FormatUTF8() as such: aRec := TSQLMyRec.for better server speed. overload. This constructor initializes the object as above. TModTime and mapped fields mORMot. or call the overloaded contructor with BoundsSQLWhere array of parameters constructor CreateAndFillPrepare(aClient: TSQLRest. const BoundsSQLWhere: array of const). This constructor initializes the object as above. 1.[]. 2013 constructor Create(aClient: TSQLRest. const BoundsSQLWhere: array of const. overload.17 of the framework: array of const used to be ParamsSQLWhere and '%' in the FormatSQLWhere statement. then call FillPrepare . and fills its content from a client or server connection.FillOne do . this one more multiple rows . FormatSQLWhere: PUTF8Char. whereas it now expects bound parameters as '?' constructor Create(aClient: TSQLRest. which is expected to follow the order of values supplied in BoundsSQLWhere open array . retrieves all records corresponding to the WHERE clause. which is expected to follow the order of values supplied in BoundsSQLWhere open array . whereas it now expects bound parameters as '?' . or directly any integer / double / currency / RawUTF8 values to be bound to the request as parameters .for better server speed. const aCustomFieldsCSV: RawUTF8=''). using a specified WHERE clause with parameters .note that this method prototype changed with revision 1.use DateToSQL/DateTimeToSQL for TDateTime.FormatUTF8('Salary>? AND Salary<?'.Destroy . the WHERE clause should use bound parameters identified as '?' in the FormatSQLWhere statement.Synopse mORMot Framework Software Architecture Design 1.[1000. const aSQLWhere: RawUTF8). and prepares itself to loop through a statement using a specified WHERE clause .2000])).previous Create(aClient) methods retrieve only one record.this method creates a TSQLTableJSON.aCustomFieldsCSV can be used to specify which fields must be retrieved (default is to retrieve all table fields. This constructor initializes the object as above..18 Page 755 of 1055 .17 of the framework: array of const used to be ParamsSQLWhere and '%' in the FormatSQLWhere statement. or directly any integer / double / currency / RawUTF8 values to be bound to the request as parameters ..you should then loop for all rows using 'while Rec. using a specified WHERE clause . but you may need to access only one or several fields.but BatchUpdate() will set only ID. since the missing fields will be left with previous values . FormatSQLWhere: PUTF8Char. overload. the WHERE clause should use bound parameters identified as '?' in the FormatSQLWhere statement. and fills its content from a client or server connection.Create(Client.Rev.' . BoundsSQLWhere: array of const.but BatchUpdate() will set only ID.FillOne do . and prepares itself to loop through a statement using a specified WHERE clause .the TSQLTableJSON will be freed by TSQLRecord. and will save remote bandwidth by specifying the needed fields): notice that you should not use this optional parameter if you want to Update the retrieved record content later. TModTime and mapped fields constructor CreateAndFillPrepare(const aJSON: RawUTF8). overload.' ..FillOne do .this method creates a TSQLTableJSON.' . and will save remote bandwidth by specifying the needed fields): notice that you should not use this optional parameter if you want to Update the retrieved record content later.. this one more multiple rows . overload. const aCustomFieldsCSV: RawUTF8=''). but you may need to access only one or several fields. overload. but you may need to access only one or several fields.this method creates a TSQLTableJSON.[1000. This constructor initializes the object as above.pas unit .[]. FormatSQLWhere: PUTF8Char. This constructor initializes the object as above. and bind all '?' chars as parameters with BoundsSQLWhere[] values .FillOne do . and prepares itself to loop through a specified JSON table . const ParamsSQLWhere. TModTime and mapped fields constructor CreateAndFillPrepare(aClient: TSQLRest. const aCustomFieldsCSV: RawUTF8='').aCustomFieldsCSV can be used to specify which fields must be retrieved (default is to retrieve all table fields.' .the TSQLTableJSON will be freed by TSQLRecord... this one more multiple rows .previous Create(aClient) methods retrieve only one record.18 Date: June 16.you should then loop for all rows using 'while Rec. then call FillPrepare .but BatchUpdate() will set only ID.you should then loop for all rows using 'while Rec.previous Create(aClient) methods retrieve only one record.18 Page 756 of 1055 . retrieves all records corresponding to the WHERE clause..note that you can use FormatUTF8() as such: aRec := TSQLMyRec. and prepares itself to loop through a statement using a specified WHERE clause . retrieves all records corresponding to the WHERE clause.the TSQLTableJSON will be freed by TSQLRecord.this method creates a TSQLTableJSON.the FormatSQLWhere clause will replace all '%' chars with the supplied ParamsSQLWhere[] supplied values. then call FillPrepare . 1.previous Create(aClient) methods retrieve only one record. or call the overloaded CreateAndFillPrepare() contructor directly with BoundsSQLWhere array of parameters . const aSQLWhere: RawUTF8.CreateAndFillPrepare(Client.aCustomFieldsCSV can be used to specify which fields must be retrieved (default is to retrieve all table fields. fill it with the supplied JSON buffer.the WHERE clause should use inlined parameters (like 'Name=:('Arnaud'):') for better server speed .2000])). since the missing fields will be left with previous values . This constructor initializes the object.Destroy mORMot..Destroy .you should then loop for all rows using 'while Rec. this one more multiple rows .Destroy . 2013 constructor CreateAndFillPrepare(aClient: TSQLRest.Synopse mORMot Framework Software Architecture Design 1.FormatUTF8('Salary>? AND Salary<?'. since the missing fields will be left with previous values . then call FillPrepare .Rev. OwnerMustFree := false) finally aProd.Categories. and prepares itself to loop through a JOINed statement .Dest. const aParamsSQLJoin.but BatchUpdate() will set only ID.. ManySelect) to avoid any GPF .g.).you SHALL call explicitely the FillClose method before using any methods of nested TSQLRecordMany instances which may override the Dest instance content (e.18 Page 757 of 1055 . const aIDs: TIntegerDynArray. but you may need to access only one or several fields.Name='for boy' and (s.*.this method creates a TSQLTableJSON.Sizes. retrieves all records corresponding to the specified IDs.* from Product p.18 Date: June 16. 'Owner=? and Categories. c. aBoundsSQLJoin: array of const).Name=? and (Sizes.Owner. 2013 constructor CreateAndFillPrepare(aClient: TSQLRest.Name=?)'.aCustomFieldsCSV can be used to specify which fields must be retrieved (default is to retrieve all table fields.id and p.and the Source property won't contain pointer(SourceID) but the main TSQLRecord instance .aProd.' '. Category c.aProd. ready to be consumed during a while FillOne do.Name='medium') .id=cc.Name=? or Sizes. including TSQLRecordMany published properties (and their nested properties) . This constructor initializes the object as above.the aFormatSQLJoin clause will define a WHERE clause for an automated JOINed statement.CreateAndFillPrepareMany(Database. ['mark'.'medium'])..'small'.source=p.id=ss.FillOne do .source=p.g..FillTable to fill a grid.g.Name='small' or s.you should then loop for all rows using 'while Rec.Destroy .the created instance will have all its TSQLRecordMany Dest property allocated with proper instance (and not only pointer(DestID) e. overload.'for boy'.Dest. and prepares itself to loop through a given list of IDs . this will execute a JOINed SELECT statement similar to the following: select p. Size s.Dest. This constructor initializes the object including all TSQLRecordMany properties.Name. and bind all '?' chars as bound parameters with aBoundsSQLJoin[] values mORMot. aFormatSQLJoin: PUTF8Char.id and s.Owner='mark' and c. if aProd<>nil then try while aProd.Name).Dest.*. const aCustomFieldsCSV: RawUTF8=''). TModTime and mapped fields constructor CreateAndFillPrepareMany(aClient: TSQLRest.dest and ss.pas unit .a typical use could be the following: aProd := TSQLProduct. Sizes ss where c..Free.' '.the TSQLTableJSON will be freed by TSQLRecord.Rev.Source=aProd) writeln(aProd. // you may also use aProd. loop (those instances will be freed by TSQLRecord. this one more multiple rows .g. aProd.' . 1.Categories.FillClose or Destroy) .Categories/Sizes instances end. // (do not forget to set aProd.' '. Categories cc.aProd. then call FillPrepare . and will save remote bandwidth by specifying the needed fields): notice that you should not use this optional parameter if you want to Update the retrieved record content later.Dest.[]. since the missing fields will be left with previous values . s.dest and cc. // will also free aProd.FillOne do // here e.previous Create(aClient) methods retrieve only one record.Dest are instantied (and Categories.FillTable. e.Synopse mORMot Framework Software Architecture Design 1.the aFormatSQLJoin clause will replace all '%' chars with the supplied aParamsSQLJoin[] supplied values.Name. Register a custom filter or Validate to the class for a specified field . Get the captions to be used for this class . but a TSQLRecordMany instance which allow to access to the pivot table data) function DynArray(const DynArrayFieldName: RawUTF8): TDynArray.3 (page 1050).Rev.if the field name is not existing or not a dynamic array.if Action is nil. Get the captions to be used for this class . Release the associated memory .will return the specified associated TSynFilterOrValidate instance .if the field index is not existing or not a dynamic array. Initialize a TDynArray wrapper to map dynamic array property values . This method create a clone of the current record. overload. virtual.e.g.Synopse mORMot Framework Software Architecture Design 1. property Currency: TCurrencyDynArray index 2 read fCurrency write fCurrency.just a wrapper calling CaptionName() virtual method function ClassProp: PClassProp.IsVoid will be TRUE function DynArray(DynArrayFieldIndex: integer): TDynArray. result. UnicodeString for Delphi 2009+ . . with same ID and properties .in particular.LoadResStringTranslate() if available .e. overload.18 Page 758 of 1055 .if Action is not nil. result. i.ForHint is set to TRUE when the record caption name is to be displayed inside the popup hint of a button (i.this overloaded version expect the dynamic array to have been defined with a not null index attribute. not the default short version) .18 Date: June 16. all fields excluding tftMany (because those fields don't contain any data.internally call UnCamelCase() then System. ForHint: boolean=false): string. published property Ints: TIntegerDynArray index 1 read fInts write fInts. the name must be fully qualified. function CreateCopy: TSQLRecord.IsVoid will be TRUE mORMot. return the caption of the table name . 2013 destructor Destroy.AddFilterOrValidate class function CaptionName(Action: PRawUTF8=nil.Validate methods (in default implementation) .e. e. return the caption of this Action (lowercase left-trimed) . release all TSQLRecordMany instance created by the constructor of this TSQLRecord class function AddFilterOrValidate(const aFieldName: RawUTF8. i. Return the RTTI property information for this record Used for DI-2.copy all COPIABLE_FIELDS.this will be used by TSQLRecord. aFilter: TSynFilterOrValidate): TSynFilterOrValidate.pas unit .1.Filter and TSQLRecord.is not part of TSQLRecordProperties because has been declared as virtual class function CaptionNameFromRTTI(Action: PShortString): string. 1.this function is just a wrapper around RecordProps. override. Initialize a TDynArray wrapper to map dynamic array property values .return "string" type. overload. whereas it now expects bound parameters as '?' . the WHERE clause should use bound parameters identified as '?' in the FormatSQLWhere statement. const aCustomFieldsCSV: RawUTF8=''): boolean.for better server speed.the Row number is taken from property FillCurrentRow .the FormatSQLWhere clause will replace all '%' chars with the supplied ParamsSQLWhere[] supplied values.then call FillRow() to get Table. and will save remote bandwidth by specifying the needed fields): notice that you should not use this optional parameter if you want to Update the retrieved record content later.a temporary TSQLTable is created then stored in an internal fTable protected field . . or directly any integer / double / currency / RawUTF8 values to be bound to the request as parameters . but you may need to access only one or several fields. false if no more Row data is available .pas unit .RowCount row values .then call FillRow() to get Table. and will save remote bandwidth by specifying the needed fields): notice that you should not use this optional parameter if you want to Update the retrieved record content later.returns true in case of success. . 1. Prepare to get values using a specified WHERE clause with '%' parameters .call FillRow() to update published properties values function FillPrepare(aClient: TSQLRest.18 Date: June 16. TModTime and mapped fields mORMot.you can also loop through all rows with while Rec.but BatchUpdate() will set only ID. TModTime and mapped fields function FillPrepare(aClient: TSQLRest.FillOne do dosomethingwith(Rec).aCustomFieldsCSV can be used to specify which fields must be retrieved (default is to retrieve all table fields. false in case of an error during SQL request .you can also loop through all rows with while Rec. Prepare to get values using a specified WHERE clause with '%' and '?' parameters . BoundsSQLWhere: array of const.use DateToSQL/DateTimeToSQL for TDateTime.returns true in case of success.RowCount row values . but you may need to access only one or several fields.FillOne do dosomethingwith(Rec).Synopse mORMot Framework Software Architecture Design 1. FormatSQLWhere: PUTF8Char. const BoundsSQLWhere: array of const. FormatSQLWhere: PUTF8Char. since the missing fields will be left with previous values . const ParamsSQLWhere.note that this method prototype changed with revision 1. overload. false in case of an error during SQL request . since the missing fields will be left with previous values .18 Page 759 of 1055 . 2013 function FillOne: boolean.Rev.aCustomFieldsCSV can be used to specify which fields must be retrieved (default is to retrieve all table fields. const aCustomFieldsCSV: RawUTF8=''): boolean. Fill all published properties of this object from the next available TSQLTable prepared row .a temporary TSQLTable is created then stored in an internal fTable protected field .17 of the framework: array of const used to be ParamsSQLWhere and '%' in the FormatSQLWhere statement.FillPrepare() must have been called before . which is expected to follow the order of values supplied in BoundsSQLWhere open array . and bind all '?' chars as bound parameters with BoundsSQLWhere[] values .but BatchUpdate() will set only ID.return true on success. g. TModTime and mapped fields) mORMot.FormatUTF8('Salary>? AND Salary<?'.then call FillRow() to get Table. const aCustomFieldsCSV: RawUTF8=''): boolean.Rev. const aSQLWhere: RawUTF8=''.returns true in case of success. const aIDs: TIntegerDynArray. since the missing fields will be left with previous values .aCustomFieldsCSV can be used to specify which fields must be retrieved (default is to retrieve all table fields. .returns true in case of success. .you can also loop through all rows with while Rec. but you may need to access only one or several fields. false in case of an error during SQL request . Prepare to get values from a SQL where statement . all rows are retrieved as fast as possible (e. and will save remote bandwidth by specifying the needed fields): notice that you should not use this optional parameter if you want to Update the retrieved record content later.note that you can use FormatUTF8() as such: aRec.you can also loop through all rows with while Rec.2000])).RowCount row values .[]. but you may need to access only one or several fields.18 Date: June 16. aCheckTableName: TSQLCheckTableName=ctnNoCheck): boolean.Synopse mORMot Framework Software Architecture Design 1. and will save remote bandwidth by specifying the needed fields): notice that you should not use this optional parameter if you want to Update the retrieved record content later.FillOne do dosomethingwith(Rec).[1000.then call FillRow() to get Table. since the missing fields will be left with previous values . overload. 1.if aSQLWhere is left to ''.FillOne do dosomethingwith(Rec).pas unit . by-passing SQLite3 virtual table modules for external databases) .but BatchUpdate() will set only ID.18 Page 760 of 1055 .but BatchUpdate() can be safely used after FillPrepare (will set only ID. TModTime and mapped fields function FillPrepare(aClient: TSQLRest.RowCount row values .FillPrepare(Client. Prepare to get values from a list of IDs . false in case of an error during SQL request . or call the overloaded FillPrepare() method directly with BoundsSQLWhere array of parameters . 2013 function FillPrepare(aClient: TSQLRest.a temporary TSQLTable is created then stored in an internal fTable protected field .aCustomFieldsCSV can be used to specify which fields must be retrieved (default is to retrieve all table fields.a temporary TSQLTable is created then stored in an internal fTable protected field .the WHERE clause should use inlined parameters (like 'Name=:('Arnaud'):') for better server speed . overload. const aCustomFieldsCSV: RawUTF8=''. * from Product p. // (do not forget to set aProd.the default aFields parameter will process all fields mORMot.Owner.Categories.Name.Name).Name. the function has to return TRUE if the filtering took place.Dest published fields will now contain a true TSQLRecord instance.Name='medium') . const aParamsSQLJoin.the Row number (property FillCurrentRow) is reset to 1 . if it's not needed nor mandatory to create a new TSynFilter class type: in this case.MAX_SQLFIELDS-1]): boolean.aProd.id and p.'for boy'.OwnerMustFree := false) this will execute a JOINed SELECT statement similar to the following: select p. Prepare to loop through a JOINed statement including TSQLRecordMany fields .g.' '.FillTable. Filter the specified fields values of the current TSQLRecord instance .Categories.'small'.Name='for boy' and (s. Filter the specified fields values of the current TSQLRecord instance . ready to loop through all rows with FillRow() .Owner='mark' and c. ready to be filled with the JOINed statement results (these instances will be released at FillClose) .Synopse mORMot Framework Software Architecture Design 1.*.]AddFilterOrValidate() .this version will call the overloaded Filter() method above . Size s. Sizes ss where c.Dest. including TSQLRecordMany published properties (and their nested properties) . this will perform all TSynFilter as registered by [RecordProps. c. false if no Row data is available function Filter(const aFields: array of RawUTF8): boolean. ManySelect) to avoid any GPF .id and s. Categories cc.18 Date: June 16. overload.FillTable to fill a grid.inherited classes may add some custom filtering here. aFormatSQLJoin: PUTF8Char.all TSQLRecordMany.the same for Source which will point to the self instance .18 Page 761 of 1055 .Name=? or Sizes.dest and ss..Dest are instantied (and Categories. ['mark'.source=p.g.Name=? and (Sizes.return true on success.Name='small' or s.' '.g.Rev.'medium']) then while aProd.Source=aProd) writeln(aProd.aProd.the FormatSQLWhere clause will replace all '%' chars with the supplied ParamsSQLWhere[] supplied values. e.returns true in case of success. FALSE otherwise function Filter(const aFields: TSQLFieldBits=[0. 1.CreateAndFillPrepareMany constructor function FillRewind: boolean.Sizes. false in case of an error during SQL request . s.id=ss. 2013 function FillPrepareMany(aClient: TSQLRest.FillOne do // here e.the aFormatSQLJoin clause will define a WHERE clause for an automated JOINed statement. // you may also use aProd. aProd. and FALSE if any default registered TSynFilter must be processed . and bind all '?' chars as parameters with BoundsSQLWhere[] values . Go to the first prepared row.source=p.Name=?)'.return TRUE if all field names were correct and processed.dest and cc.a typical use could be the following: if aProd. aBoundsSQLJoin: array of const): boolean.id=cc.Dest. 'Owner=? and Categories. overload.FillPrepareMany(Database.Dest. Category c.Dest.[].by default.is used by TSQLRecord.aProd.pas unit . virtual.Dest.*.' '.you SHALL call explicitely the FillClose method before using any methods of nested TSQLRecordMany instances which may override the Dest instance content (e. use TSQLModel fIsUnique[] array. overload. following the ORM approach of the framework. not TSQLRawBlob/TSQLRecordMany) are retrieved: BLOB fields are ignored (use direct access via dedicated methods instead) . per TSQLRecord type .is not part of TSQLRecordProperties because has been declared as virtual so that you could specify a custom SQL statement. which set the bits values to 1 if a property field was published with "stored AS_UNIQUE" (i. 1.1. Same as above.you should use strong typing and direct property access.e.will return '' in case of wrong property name . and can be ignored for regular (not virtual) tables function GetSQLSet: RawUTF8. it could be usefull to have this method available . and TSQLRecordVirtualTable*ID classes as corresponding Delphi designed virtual tables .BLOB and dynamic array fields are returned as '\uFFF0base64encodedbinary' function GetJSONValues(Expand: boolean. but returning result into a RawUTF8 .RawUnicode and RawUTF8 are created as TEXT COLLATE SYSTEMNOCASE (i.anyway. Occasion: TSQLOccasion. but use TSQLModel. 2013 function GetFieldValue(const PropName: RawUTF8): RawUTF8. class function GetSQLCreate(aModel: TSQLModel): RawUTF8. withID: boolean. UsingStream: TCustomMemoryStream=nil): RawUTF8. it will use a temporary THeapMemoryStream instance Used for DI-2. "stored false") .e.2 (page 1049). Return the UTF-8 encoded SQL source to create the table containing the published fields of a TSQLRecord child . don't call this method directly.this method will handle TSQLRecordFTS* classes like FTS* virtual tables.Rev.1. use our fast UTF8IComp() for comparaison) . Return the UTF-8 encoded SQL source to UPDATE the values contained in the current published fields of a TSQLRecord child . but in some cases (a custom Grid display.a 'ID INTEGER PRIMARY KEY' field is always created first (mapping SQLite3 RowID) .the aModel parameter is used to retrieve the Virtual Table module name. for instance). TSQLRecordRTree as RTREE virtual table. virtual.18 Page 762 of 1055 .an individual bit set in UniqueField forces the corresponding field to be marked as UNIQUE (an unique index is automaticaly created on the specified column).GetSQLCreate() . COL2='VAL2'' .e.format is 'COL1='VAL1'. Retrieve a field value from a given property name.AnsiString are created as TEXT COLLATE NOCASE (fast SQLite3 7bits compare) .is not used by the ORM (do not use prepared statements) .if UsingStream is not set.TDateTime are created as TEXT COLLATE ISO8601 (which calls our very fast ISO TEXT to Int64 conversion routine) . DI-2.only simple fields name (i.Synopse mORMot Framework Software Architecture Design 1.pas unit .18 Date: June 16. as encoded UTF-8 text .only here for conveniency mORMot.3 (page 1050). not TSQLRawBlob/TSQLRecordMany) are compared .Rev.is not used by the ORM (do not use prepared statements) .only simple fields name (i. and the vmtAutoTable trick if very fast. and we need a var for each class: so even Delphi XE syntax is not powerful enough for our purpose.only simple fields (i. Set the field values from a binary buffer . not TSQLRawBlob/TSQLRecordMany) are updated: BLOB fields are ignored (use direct update via dedicated methods instead) . 'VAL2')' if some column was ignored (BLOB e. Direct access to the TSQLRecord properties from RTTI .18 Page 763 of 1055 .pas unit . and varAny (BLOB with size = VLongs[0]) .e.the field values are available via some TVarData of type varNull.Field[] order: will return false if the Values[]. Return the UTF-8 encoded SQL source to INSERT the values contained in the current published fields of a TSQLRecord child . COL2) VALUES ('VAL1'. 'VAL2')' if all columns values are available .g. Return the TRecordReference pointing to this record function SameRecord(Reference: TSQLRecord): boolean.returns true on success. Return true if all published properties values in Other are identical to the published properties of this object . and works with all versions of Delphi . with the Count e.g.format is 'VALUES ('VAL1'.Synopse mORMot Framework Software Architecture Design 1.e.FieldType[] mORMot.work with different classes: Reference properties name must just be present in the calling object . or false in case of invalid content in P e.18 Date: June 16. varString (mapping a constant PUTF8Char).P is updated to the next pending content after the read values function SetFieldVarDatas(const Values: TVarDataDynArray): boolean.instances must be of the same class type . 1.only here for conveniency function RecordClass: TSQLRecordClass. 2013 function GetSQLValues: RawUTF8. Return true if all published properties values in Other are identical to the published properties of this object .only simple fields (i. but still have same values function SetBinaryValues(var P: PAnsiChar): Boolean.g.including 64 bit target) function RecordReference(Model: TSQLModel): TRecordReference.g. Return the Class Type of the current TSQLRecord class function RecordProps: TSQLRecordProperties.e.Values[] array must match the RecordProps.VType does not match RecordProps.TSQLRecordProperties is faster than e.) .use internal the unused vmtAutoTable VMT entry to fast retrieve of a class variable which is unique for each class ("class var" is unique only for the class within it is defined. varInt64.comparaison is much faster than SameValues() above function SameValues(Reference: TSQLRecord): boolean.) .format is '(COL1. the class function FieldProp() .compare the text representation of the values: fields may be of different type. Set all field values from a supplied array of TVarData sub type .won't read the ID field (should be read before. not TSQLRawBlob/TSQLRecordMany) are compared . varDouble. encoding or precision. . Validate the specified fields values of the current TSQLRecord instance .returns '' if all field names were correct and processed. Validate the specified fields values of the current TSQLRecord instance .Rev. associated with this TSQLRecord class .you may override this method e. The Table name in the database. TModTime / TCreateTime fields are a pure client ORM feature . if it's not needed nor mandatory to create a new TSynValidate class type: in this case.the aSimpleFields parameters must follow explicitely the order of published properties of the supplied aTable class. excepting the TSQLRawBlob and TSQLRecordMany kind (i. it will contain the first invalid field index found . const aFields: TSQLFieldBits=[0. Clear the values of all published properties.the aSimpleFields must have exactly the same count of parameters as there are "simple fields" in the published properties . or '' if the validation was successful: in this later case.note that this is computed only on the Client side. all default registered TSynValidate are processed . the function has to return an explicit error message (as a generic VCL string) if the custom validation failed.return true on success.by default.if aInvalidFieldIndex is set.pas unit . aInvalidFieldIndex: PInteger=nil): string. otherwise if may return true but will corrupt data class function SQLTableName: RawUTF8.18 Page 764 of 1055 . 2013 function SimplePropertiesFill(const aSimpleFields: array of const): boolean. virtual. Should modify the record content before writing to the Server . or an explicit error message (translated in the current language) on error . overload. Set the simple fields with the supplied values .or the ClassName is returned as is. if no 'TSQL' or 'TSQLRecord' at first .it will also check if any UNIQUE field value won't be duplicated .in particular. virtual.e.. aInvalidFieldIndex: PInteger=nil): string.'TSQL' or 'TSQLRecord' chars are trimmed at the beginning of the ClassName .Synopse mORMot Framework Software Architecture Design 1. this will perform all TSynValidate as registered by [RecordProps.the default aFields parameter will process all fields .]AddFilterOrValidate() . and also the ID property procedure ComputeFieldsBeforeWrite(aRest: TSQLRest.inherited classes may add some custom validation here. overload. const aFields: array of RawUTF8.SQLTableName function Validate(aRest: TSQLRest. before sending back the content to the remote Server: therefore.18 Date: June 16.it won't work directly at REST level mORMot. parent properties must appear first in the list .this version will call the overloaded Validate() method above .if aInvalidFieldIndex is set.caller SHOULD always call the Filter() method before calling Validate() function Validate(aRest: TSQLRest. for custom calculated fields . but be aware that the field list must match the field layout. 1. aOccasion: TSQLEvent).this default implementation will update any sftModTime / TModTime and sftCreateTime / TCreateTime properties content with the exact server time stamp .is just a wrapper around RecordProps.MAX_SQLFIELDS-1]. only so called "simple fields") .g. it will contain the first invalid field index procedure ClearProperties. JSON data may be expanded or not procedure FillFrom(aRecord: TSQLRecord). aCheckTableName: TSQLCheckTableName=ctnNoCheck). but a TSQLRecordMany instance which allow to access to the pivot table data) procedure FillFrom(Table: TSQLTable.call FillPrepare() then FillRow() procedure FillPrepare(Table: TSQLTable.18 Page 765 of 1055 . Row: integer).g. overload. overload.source object must be a parent or of the same class as the current record .FillOne loop .create a TSQLTable from the JSON data .pas unit .18 Date: June 16. overload. .Destroy will call it . Fill all published properties of this object from a TSQLTable result row .you can also loop through all rows with while Rec.used e.' trimmed before matching to the current record mORMot.is not mandatory if the TSQLRecord is released just after.the specified TSQLTable is stored in an internal fTable protected field .make an internal copy of the JSONTable RawUTF8 before calling FillFrom() below procedure FillFrom(P: PUTF8Char).release the internal hidden TSQLTable instance if necessary . Fill all published properties of this object from another object . 1. overload. Fill all published properties of this object from a JSON object result .is called implicitely by FillPrepare() call to release any previous loop . overload.JSON data may be expanded or not .e. i.. as exported by GetJSONValues() . by FillFrom methods below to avoid any GPF/memory confusion procedure FillFrom(const JSONRecord: RawUTF8). as exported by GetJSONValues() .then call FillRow() to get Table.use JSON data. Close any previous FillPrepare.copy all COPIABLE_FIELDS.Rev.use JSON data. since TSQLRecord. Fill all published properties of this object from a JSON result row .the data inside P^ is modified (unescaped and transformed): don't call FillFrom(pointer(JSONRecordUTF8)) but FillFrom(JSONRecordUTF8) which makes a temporary copy of the JSONRecordUTF8 text . Row: integer). overload.call FillPrepare() then FillRow() procedure FillFrom(const JSONTable: RawUTF8.RowCount row values .g.FillOne do dosomethingwith(Rec). all fields excluding tftMany (because those fields don't contain any data. Fill all published properties of this object from a JSON result . 2013 procedure FillClose.Synopse mORMot Framework Software Architecture Design 1. Prepare to get values from a TSQLTable result . the Field Names from the Table any pending 'TableName.set aCheckTableName if you want e. g. DI-2.see TPropInfo about proper Delphi / UTF-8 type mapping/conversion .2 (page 1049).Rev. wasString: boolean).e. Occasion: TSQLOccasion). not TSQLRawBlob/TSQLRecordMany) are retrieved: BLOB fields are ignored (use direct access via dedicated methods instead) .by default. aDest: TSQLRecord=nil).18 Date: June 16. virtual.Synopse mORMot Framework Software Architecture Design 1.e.val21."val12". DI-2. with the Count e. but it won't work with TSQLRecordMany properties (i. Same as above.NET client: {"col1":val11.if Dest is nil.FillPrepare() must have been called before .e.if withID is true. that is an INTEGER field containing the ID of the pointing record) . Fill all published properties of an object from a TSQLTable prepared row . create indexes for all TRecordReference properties. withID: boolean. for direct use with any Ajax or . JSON data is serialized (as used in TSQLTableJSON) { "fieldCount":1. and for all TSQLRecord inherited properties (i.2 (page 1049). a property defined with type TSQLRawBlob."col2".e.handle UTF-8 SQL to Delphi values conversion (see TPropInfo mapping) . since by default all BLOB properties are not set by the standard Retrieve() method (to save bandwidth) procedure GetBinaryValues(W: TFileBufferWriter). JSON data is an object.is not part of TSQLRecordProperties because has been declared as virtual mORMot.use this method to fill a BLOB property.if Dest is not nil. Virtual method called when the associated table is created in the database .if Expand is false. Value: PUTF8Char.) procedure GetJSONValues(W: TJSONSerializer)..override this method in order to initialize indexs or create default records .1. Fill a published property value of this object from a UTF-8 encoded value .Row number is from 1 to Table. const FieldName: RawUTF8). then the first ID field value is included Used for DI-2.1. Write the field values into the binary buffer .g. procedure GetJSONValues(JSON: TStream. but in a TJSONWriter (called by the first two overloaded functions) Used for DI-2.1. virtual.setter method (write Set*) is called if available .if FieldName is ''. initialization regarding this field must be processed . 2013 procedure FillRow(aRow: integer."values":["col1". so that a calculated value can be used in a custom field procedure FillValue(PropName. Expand: boolean.if Expand is true.3 (page 1050). 1.only simple fields (i.pas unit . this object values are filled . if FieldName is specified. of sftID type. overload.1. i.won't write the ID field (should be stored before. class procedure InitializeTable(Server: TSQLRestServer. this object values will be filled.3 (page 1050). overload.] } . after FillPrepareMany call) .RowCount ."col2":"val12"} .. Return the UTF-8 encoded JSON objects for the values contained in the current published fields of a TSQLRecord child .ID field is updated if first Field Name is 'ID' .val11.18 Page 766 of 1055 . initialization regarding all fields must be made.this method has been made virtual e. pas unit . Detail. Set a field value of a given property name.18 Date: June 16. Value: PUTF8Char).) or '\uFFF0base64encodedbinary' property AsTSQLRecord: pointer read GetIDAsPointer.Synopse mORMot Framework Software Architecture Design 1. since on 32 bit: Detail. even if Main itself is not a true instance property FillCurrentRow: integer read GetFillCurrentRow. Client.AsTSQLRecord. This property contains the internal state counter of the server database when the data was retrieved from it .18 Page 767 of 1055 . if any published property is a BLOB (TSQLRawBlob) property ID: integer read GetID write fID. Detail := TSQLRecordDetail.if this TSQLRecord is not a instance. it could be usefull to have this method available . which will be read by FillOne property FillTable: TSQLTable read GetTable.Main := pointer(Main. initialized to 1 by FillPrepare(). This property contains the TSQLTable after a call to FillPrepare() property HasBlob: boolean read GetHasBlob.published properties of type TSQLRecord (one-to-many relationship) do not store real class instances (only exception is if they inherit from TSQLRecordMany) . and will recognize an ID value up to 1. following the ORM approach of the framework.AsTSQLRecord will ensure that the ID is retrieved.Add(Detail).e. This property contains the current row number (beginning with 1).Add(Main).you should use strong typing and direct property access. 2013 procedure SetFieldValue(const PropName: RawUTF8. but prefered method is to typecast it via PtrInt(aProperty). for instance). since the ID is set during Retrieve or Add of the record property InternalState: cardinal read fInternalState.ID := someID in your code. This property stores the record's integer ID . 1. but a field value in a published property of type sftID (i. as such: Main := TSQLRecordMain.Main := Main.576 (i.expect BLOB and dynamic array fields encoded as SQlite3 BLOB literals ("x'01234'" e.notice: the Setter should not be used usualy. .Main := Main. // will store Main. from some encoded UTF-8 text .Create. $100000) .048. This property is set to true. but in some cases (a custom Grid display. this method will try to retrieve it. This read-only property can be used to retrieve the ID as a TSQLRecord object .you can use this value to assign a TSQLRecord instance to a published property. TSQLRecord(aID)).using Main.e.Rev.ID) compiles (whereas it won't on 64 bit) and is the same than platform-independent Detail.g.Create.may be used to check if retrieved data may be out of date mORMot.ID in MAIN column Client. . you should not have to write aRecord. because GetID() relies on some low-level Windows memory mapping trick.is especially useful on 64 bit plaform.won't do anything in case of wrong property name .AsTSQLRecord. sftCreateTime) mORMot. the TSQLRawBlob (BLOB) fields are not included into this set: they must be read specificaly (in order to spare bandwidth) . i.returns '' as string Text. or the ready to be displayed value if UTF8ToString event is set (to be used mostly with Language. or date/time format as expected by FormatDateTime() for all date time kind of fields (as sftDateTime. sftTimeLog and sftRecord/sftID .00') for sftFloat and sftCurrency columns (instead of plain JSON float value).will be implemented as TSQLTableDB for direct SQLite3 database engine call. but as instances created by TSQLRecord.Create TSQLTable = class(TObject) Wrapper to an ORM result table. FromDisplay: boolean=false): integer. UnicodeString for Delphi 2009+.2 (page 1049). for sftEnumerate. if text can by displayed directly with Get*() methods above . ready to be displayed to the VCL. Get the mean of characters length of all fields .Field: integer. out Text: string. sftTimeLog. const CustomFormat: string=''): TSQLFieldType.e.18 Page 768 of 1055 .following rows contains the data itself . constructor Create(const Tables: array of TSQLRecordClass.pas unit .you can optionaly associate the corresponding TSQLRecordClass types. 1.by default. until destroyed . e.CustomFormat can optionaly set a custom format string.Synopse mORMot Framework Software Architecture Design 1. Initialize the result table .g.first row contains the field names . sftModTime. This property returns the published property count with any valid database field except TSQLRawBlob/TSQLRecordMany .returns the Field Type . or as TSQLTableJSON for remote access through optimized JSON messages Used for DI-2. as VCL text .TSQLRecordMany fields are not accessible directly. Free associated memory and owned records function CalculateFieldLengthMean(var aResult: TIntegerDynArray. #10 or #13 char) .Client is one TSQLClient instance (used to display TRecordReference via the associated TSQLModel) .1. staticaly stored as UTF-8 text . Client: TObject. 2013 property SimpleFieldCount: integer read GetSimpleFieldCount. override. Read-only access to a particular field value.return generic string Text. const aSQL: RawUTF8).returns '' for other properties kind.##0. if UTF8ToString is nil.return the sum of all mean of character lengths function ExpandAsString(Row.Rev. i.UTF8ToString) . by which the results were computed (it will use RTTI for column typing) destructor Destroy.e.contain all result in memory.the character length is for the first line of text only (stop counting at every newline character. '%f' or '%n' or complex FormatFloat()/FormatCurr() syntax (as '#.18 Date: June 16.GetA() or GetW() can be used in a TDrawString . very fast: calculated only once for all fields function FieldLengthMeanSum: cardinal.. overload. the table) associated to a field .since TSQLTable data is PUTF8Char.return sftUnknown is all data fields are null . index (0. Get the mean of characters length of this field . Get the sum of all mean of characters length of all fields . and WideString for non Unicode versions of Delphi) . exact field type and enumerate TypeInfo() is retrieved from the Delphi RTTI.g. NeverReturnsZero: boolean=false): cardinal.pas unit .g.e. Get the Field index of a FieldName . Read-only access to a particular field value.raise an ESQLTableException if called outside valid Step() sequence . Read-only access to a particular field value.AddToReport) function FieldBuffer(const FieldName: RawUTF8): PUTF8Char.similar to Get() method. Guess the field type from first non null data row .sftBlob is returned if the field is encoded as SQLite3 BLOB literals (X'53514C697465' e.Rev.return -1 if not found. overload.similar to Get() method. Client: TObject.is nil if this table has no QueryTables property .raise an ESQLTableException if called outside valid Step() sequence .e. 1.. otherwize. Get the Field index of a FieldName .18 Page 769 of 1055 . Get the maximum number of characters of this field function FieldLengthMean(Field: integer): cardinal. #10 or #13 char) . TSQLRibbon. get from the cells content .very fast: calculated only once for all fields function FieldType(Field: integer.FieldCount-1) if found function FieldLengthMax(Field: integer.) . but for the current Step function FieldIndex(const FieldName: RawUTF8): integer.Field: integer.18 Date: June 16. UnicodeString since Delphi 2009. as VCL text . as UTF-8 encoded buffer .FieldCount-1) if found function FieldIndex(FieldName: PUTF8Char): integer. 2013 function ExpandAsSynUnicode(Row. out Text: SynUnicode): TSQLFieldType. EnumTypeInfo: PPointer=nil): TSQLFieldType. index (0. returning the content as a SynUnicode string type (i.this method is just a wrapper around ExpandAsString method.e. string type is sftUTF8Text only mORMot.Synopse mORMot Framework Software Architecture Design 1.it is used by the reporting layers of the framework (e.the character length is for the first line of text only (stop counting at every newline character.return -1 if not found. overload.very fast: calculated only once for all fields function FieldTable(Field: integer): TClass.if QueryTables[] are set. as UTF-8 encoded buffer . overload. but for the current Step function FieldBuffer(FieldIndex: Integer): PUTF8Char. Get the record class (i. i. Read-only access to a particular field value. pas unit . Same as above. Row: integer): PUTF8Char.prefered manner is to directly use REST protocol to retrieve a blob field function GetCaption(Row. as Win Ansi text function GetAsInt64(Row. Read-only access to a particular field value. overload. but create a CSV from raw PUTF8Char data mORMot.1.Field: integer): Int64. Read-only access to a particular Blob value . ready to be displayed .18 Date: June 16.mostly used with Row=0.g. Read-only access to a particular field value.Field: integer): WinAnsiString. Get all values for a specified field as CSV .e.Synopse mORMot Framework Software Architecture Design 1.value is first un-camel-cased: 'OnLine' value will return 'On line' e. UnicodeString for Delphi 2009+ .a new TBytes is created .Field: integer): integer. to get a display value from a field name . Get the Field content (encoded as UTF-8 text) from a property name . Sep: AnsiChar='. overload.Field: integer): string. as integer value function GetBlob(Row.then System.use "string" type.2 (page 1049).18 Page 770 of 1055 .return nil if not found function Get(Row. function GetRowValues(Field: integer. Read-only access to a particular field value.Blob data is converted from SQLite3 BLOB literals (X'53514C697465' e.g.e.expect SQLite3 TEXT field in ISO 8601 'YYYYMMDD hhmmss' or 'YYYY-MM-DD hh:mm:ss' format function GetJSONValues(Expand: boolean): RawUTF8.Field: integer): TDateTime.Blob data is converted from SQLite3 BLOB literals (X'53514C697465' e. i. .Field: integer): TSQLRawBlob. 1.) or Base-64 encoded content ('\uFFF0base64encodedbinary') .points to memory buffer allocated by Init() function GetA(Row. Read-only access to a particular field value. i.Field: integer): TBytes. but returning result into a RawUTF8 Used for DI-2. 2013 function FieldValue(const FieldName: RawUTF8. Read-only access to a particular field value. as Int64 value function GetAsInteger(Row.Rev.don't perform any conversion.Field: integer): PUTF8Char.) or Base-64 encoded content ('\uFFF0base64encodedbinary') .g.'): RawUTF8. Read-only access to a particular DateTime field value . as UTF-8 encoded buffer .prefered manner is to directly use REST protocol to retrieve a blob field function GetBytes(Row. Read-only access to a particular Blob value .a new TSQLRawBlob is created .LoadResStringTranslate() is called if available function GetDateTime(Row. its content is allocated to contain all WideChars (not trimed to 255. Read-only access to a particular field value. false if not possible function LengthW(Row. Return the (previously hidden) ID value.Field: integer): RawUTF8.use IDColumnHiddenValue() to get the ID of a specific row .Synopse mORMot Framework Software Architecture Design 1. Fill a unicode buffer with a particular field value .Field: integer): shortstring.return number of wide characters written in Dest^ function IDColumnHiddenValue(Row: integer): integer. as UTF-16 Unicode text .Field: integer): integer. like GetWP() above function GetWP(Row. with a hidden ID field .18 Date: June 16. FirstTimeChar: AnsiChar = 'T'): RawUTF8. as fast Unicode string text .return true is ID was succesfully hidden.pas unit .Blob data is converted from SQLite3 BLOB literals (X'53514C697465' e.) or Base-64 encoded content ('\uFFF0base64encodedbinary') .a new TCustomMemoryStream is created .Text() Iso-8601 encoded text function GetU(Row. If the ID column is available.Field: integer): RawUnicode. as RawUTF8 text function GetW(Row. 0 on error function IDColumnHide: boolean. depending on the Delphi compiler revision.Field: integer): TStream.usefull for simplier UI. Dest: PWideChar.Raw Unicode is WideChar(zero) terminated . Read-only access to a particular field value. 2013 function GetS(Row. hides it from fResults[] .Field: integer): string. 1. Read-only access to a particular field value. MaxDestChars: cardinal): integer.g.the global UTF8ToString() function will be used for the conversion: for proper i18n handling before Delphi 2009.return the result as Iso8601.Rev. as VCL string text .18 Page 771 of 1055 .Field: integer): SynUnicode. Expanded: boolean. Read-only access to a particular TTimeLog field value . you should use the overloaded method with aUTF8ToString=Language.Field: integer. either UnicodeString.UTF8ToString function GetSynUnicode(Row. Read-only access to a particular Blob value .Field: integer. Widechar length (UTF-8 decoded) of a particular field value mORMot.SynUnicode is either WideString. as Win Ansi text shortstring function GetStream(Row. to ensure fastest native Unicode process available function GetTimeLog(Row. Read-only access to a particular field value.prefered manner is to directly use REST protocol to retrieve a blob field function GetString(Row.caller shall free its instance . Read-only access to a particular field value. UTF-8 decoding will be done only if necessary: it will work only with standard western-occidental alphabet (i.. by predeceding the searched text with % for English. Create a new TSQLRecord instance for a specific Table .use this method to create a working copy of a table's record. but it will be very fast mORMot.18 Page 772 of 1055 .if UnicodeComparison is left to FALSE.use the specified TSQLRecord class or create one instance of the first associated record class (from internal QueryTables[]) .it will be much slower.end block with it function QueryRecordType: TSQLRecordClass. overload. UnicodeComparison: boolean=false): integer. Lang: TSynSoundExPronunciation=sndxNone..e. from 1 to RowCount . code page 1252) .pas unit .return the Row on success. but accurate for the whole range of UTF-8 encoding . FieldIndex: integer): integer. search will use low-level Windows API for Unicode-level conversion . . 2013 function NewRecord(RecordType: TSQLRecordClass=nil): TSQLRecord. e.returns 0 if not found.you can specify a Soundex pronunciation to use. 0 on error . StartRow. if existing function RowFromID(aID: integer): integer. WinAnsi . FieldIndex: integer. Get the Row index corresponding to a specified ID .code page 1252)..search only in the content of FieldIndex data . 1.i.Finally.the text value must already be uppercased 7-bits ANSI encoded .return the Row number. Search for a value inside the raw table data .the record will be freed when the TSQLTable will be destroyed: you don't need to make a Try. aUpperValue can optional indicate a Soundex search.Rev.e.g.Free.18 Date: June 16. or leave as sndxNone for standard case insensitive character match. Retrieve QueryTables[0].return RowCount (last row index) if this ID was not found or no ID field is available function SearchFieldEquals(const aValue: RawUTF8.if UnicodeComparison is set to TRUE. Client: TObject. Search a text value inside the table data in a specified field .Synopse mORMot Framework Software Architecture Design 1. or the matching Row number otherwise function SearchValue(const aUpperValue: RawUTF8. %% for French or %%% for Spanish (only works with WinAnsi char set . search on all fields.e. overload. it will fetch one row of data. function ToObjectList(RecordType: TSQLRecordClass=nil): TObjectList.it will be much slower.g.Synopse mORMot Framework Software Architecture Design 1.or. allocated on the stack) in optional RowVariant parameter.pas unit . %% for French or %%% for Spanish (only works with WinAnsi char set . nil if not available (bad field index or field is blob) . StartRow: integer. Client: TObject. 0 on error .Step(false.. overload. when using a variant and late-binding: var customer: variant. even if the TSQLTable is nil or void mORMot.18 Page 773 of 1055 . After a TSQLTable has been initialized. but it will be very fast function SortCompare(Field: integer): TUTF8Compare.code page 1252). . Search a text value inside the table data in all fields . UTF-8 decoding will be done only if necessary: it will work only with standard western-occidental alphabet (i.return the Row on success. RowVariant: PVariant=nil): boolean.Name).. while TableCustomers. will put the cursor on the first row of results.field type is guessed from first data row function Step(SeekFirst: boolean=false.you can specify a Soundex pronunciation to use.i. with data ready to be retrieved by Field*() .Step do writeln(Field('name')). this method can be called one or more times to iterate through all data rows .the text value must already be uppercased 7-bits ANSI encoded . Lang: TSynSoundExPronunciation=sndxNone. 2013 function SearchValue(const aUpperValue: RawUTF8. UnicodeComparison: boolean=false): integer. returning field found in FieldIndex (if not nil) .@customer) do writeln(customer.18 Date: June 16. by predeceding the searched text with % for English. . to access field values using late binding .if SeekFirst is TRUE. WinAnsi .you shall call this method before calling FieldBuffer()/Field() methods .e. otherwise. search will use low-level Windows API for Unicode-level conversion . Create a TObjectList with TSQLRecord instances corresponding to this TSQLTable result set .Rev.if UnicodeComparison is set to TRUE. but accurate for the whole range of UTF-8 encoding .return TRUE on success.you can specify a variant instance (e. or leave as sndxNone for standard case insensitive character match.always returns an instance. code page 1252) . aUpperValue can optional indicate a Soundex search. 1. exceeded RowCount) .return FALSE if no more row is available (i. Get the appropriate Sort comparaison function for a field. to be called within a loop .e. FieldIndex: PInteger.if UnicodeComparison is left to FALSE.use the specified TSQLRecord class or create instances of the first associated record class (from internal QueryTables[]) .typical use may be: while TableCustomers. ."col2":"val12"}.Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16. Delete the specified data Row from the Table . overload. the global ListSeparator variable (from SysUtils) to reflect the current system definition (some country use '. JSON data is serialized (used in TSQLTableJSON) { "fieldCount":1.'.2 (page 1049).JSON data is added to TStream.val21. Save the table in CSV format . Save the table values in JSON format . Get all values for a specified field into a dynamic Integer array procedure GetRowValues(Field: integer. don't free any memory. RowFirst: integer=0. Get all values for a specified field into a dynamic RawUTF8 array . out Values: TIntegerDynArray). Get all IDs where individual bit in Bits are set mORMot.' as decimal separator.don't delete the Column: only delete UTF-8 text in all rows for this field procedure DeleteRow(Row: integer).use e. procedure GetRowValues(Field: integer.g. var IDs: TIntegerDynArray). 1. overload.18 Page 774 of 1055 .] } .if Expand is false.only overwrite the internal fResults[] pointers.you can customize the '.don't perform any conversion.the fResults remain in the source TSQLTable: source TSQLTable has not to be destroyed before this TSQLTable procedure DeleteColumnValues(Field: integer). RowLast: integer=0). Tab: boolean. Increase a particular Field Length Mean value . will use TAB instead of '. ] . JSON data is an array of objects. aIncrease: integer). all rows are retrieved) Used for DI-2. Delete the specified Column text from the Table . for direct use with any Ajax or . nor modify the internal DataSet procedure FieldLengthMeanIncrease(aField...g. but just create an array of raw PUTF8Char data procedure IDArrayFromBits(const Bits.Rev.val11..AddBOM will add a UTF-8 Byte Order Mark at the beginning of the content procedure GetJSONValues(JSON: TStream. for instance our "douce France") .pas unit ."values":["col1".if Tab=TRUE."val12". 2013 procedure Assign(source: TSQLTable). with UTF-8 encoding . out Values: TRawUTF8DynArray).' between columns .NET client: [ {"col1":val11. AddBOM: boolean=false)."col2". Copy the parameters of a TSQLTable into this instance .to be used to customize the field appareance (e.if Expand is true. CommaSep: AnsiChar='. for adding of left checkbox for Marked[] fields) procedure GetCSVValues(Dest: TStream. overload. Expand: boolean.1.RowFirst and RowLast can be used to ask for a specified row extent of the returned data (by default..' separator .{"col1":val21. is able to make multi-field sort . PCurrentRow: PInteger=nil. otherwise default Asc[]=true value will be assumed . Sort result Rows. Return all (previously hidden) ID values procedure SetFieldLengthMean(const Lengths: array of cardinal).override internal fFieldLengthMean[] and fFieldLengthMeanSum values procedure SortBitsFirst(var Bits). Fill an existing TObjectList with TSQLRecord instances corresponding to this TSQLTable result set .use the specified TSQLRecord class or create instances of the first associated record class (from internal QueryTables[]) property FieldCount: integer read fFieldCount. i. overload.this optimized sort implementation does the comparaison first by the designed field.you can specify a Row index to be updated during the sort in PCurrentRow . FieldType: TSQLFieldType=sftUnknown.warning: IDs integer array will be sorted within this method call procedure IDColumnHiddenValues(var IDs: TIntegerDynArray). if the field value is identical.pas unit .default is sorting by ascending order (Asc=true) . const Asc: array of boolean). overload.expect as many parameters as fields in this table . var IDs: TIntegerDynArray).e.Rev. according to the Bits set to 1 first procedure SortFields(Field: integer. according to some specific fields . Asc: boolean=true. CustomCompare: TUTF8Compare=nil). This property contains the internal state counter of the server database when the data was retrieved from it . Force the mean of characters length for every field . Contains the associated SQL statement on Query mORMot.sort is very fast. and.18 Page 775 of 1055 .can be used to check if retrieved data may be out of date property OwnerMustFree: Boolean read fOwnerMustFree write fOwnerMustFree. even for huge tables (more faster than any indexed SQL query): 500. 2013 procedure IDArrayToBits(var Bits. 1. the ID value is used (it will therefore sort by time all identical values) procedure SortFields(const Fields: array of integer.both Fields[] and Asc[] array should have the same count. Get all individual bit in Bits corresponding to the supplied IDs .set any Fields[]=-1 to identify the ID column (even if is hidden) procedure ToObjectList(DestList: TObjectList.000 rows are sorted instantly . Read-only access to the number of fields for each Row in this table property InternalState: cardinal read fInternalState write fInternalState. RecordType: TSQLRecordClass=nil). if it must free it property QuerySQL: RawUTF8 read fQuerySQL. overload.Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16. Sort result Rows. Sort result Rows. If the TSQLRecord is the owner of this table. according to a specific field . 1.18 Date: June 16.contains 1.please note that the supplied JSON buffer content will be changed: if you want to reuse this JSON content. after having been copied in the protected fPrivateCopy variable Used for DI-2. JSONBuffer: PUTF8Char.first row contains field name . const aSQL. PCurrentRow: PInteger): boolean. Update the result table content from a JSON-formated Data message .then 1. 1. false if no valid JSON data was found .1 (page 1047). fFieldCount.set Refreshed to true if the content changed . function UpdateFrom(const aJSON: RawUTF8. const aSQL: RawUTF8.update all content fields (fResults[].RowCount after a valid Step() iteration TSQLTableJSON = class(TSQLTable) Get a SQL result from a JSON message.1. mORMot.the conversion into PPUTF8CharArray is made inplace and is very fast (only one memory buffer is allocated for the whole data) Used for DI-2. overload.the JSON data is parsed and formatted in-place. Read-only access to the number of data Row in this table . Create the result table from a JSON-formated Data message .RowCount rows contain the data itself property StepRow: integer read fStepRow. Read-only acccess to the current Row number.18 Page 776 of 1055 .pas unit . aJSON: RawUTF8). constructor Create(const Tables: array of TSQLRecordClass. DI-2. etc.Rev.) .1.2 (page 1049).1. 2013 property QueryTables: TSQLRecordClassDynArray read fQueryTables. overload. after a Step() call . constructor Create(const Tables: array of TSQLRecordClass. JSONBufferLen: integer).1.Synopse mORMot Framework Software Architecture Design 1.. and store it into its own memory Used for DI-2.. Contains the associated record class on Query property RowCount: integer read fRowCount.contains 0 if accessed outside valid Step() sequence call .2 (page 1049).call SortFields() or IDColumnHide if was already done for this TSQLTable ..2 (page 1049).2 (page 1049). var Refreshed: boolean. you shall make a private copy before calling this constructor and you shall NOT release the corresponding variable (fResults/JSONResults[] will point inside this memory buffer): use instead the overloaded Create constructor expecting aJSON parameter making a private copy of the data Used for DI-2.return true on parsing success.the JSON data is parsed and formatted in-place . Create the result table from a JSON-formated Data message .. fRowCount. returns true on success.. after a specified time .use EnumType^.also purge values where GetTickCount wrapped around to zero after 49. which seems correct for common usage Count: integer.Rev. but a processed buffer. The private copy of the processed data buffer .add custom query by using the TSQLRest.to be used to release locked records if the client crashed .g. The number of locked records stored in this object ID: array[0. Contains the locked record ID .default value is 30 minutes.Synopse mORMot Framework Software Architecture Design 1. Return true if a record. 2013 property PrivateInternalCopy: RawUTF8 read fPrivateCopy.GetCaption(EnumIndex) to retrieve the caption associated to this custom query mORMot.MAX_SQLLOCKS-1] of cardinal.QueryAddCustom() method . Delete all the locked IDs entries.pas unit .18 Page 777 of 1055 .filled internally by the very fast GetTickCount function (faster than TDateTime or TSystemTime/GetLocalTime) . or after the UpdateFrom() process . Lock a record.see PurgeOlderThan() method below function isLocked(aID: integer): boolean. specified by its ID . for Create constructor using aJSON parameter. 1. Contains the time and date of the lock . specified by its ID. is locked function Lock(aID: integer): boolean. false if was not already locked procedure PurgeOlderThan(MinutesFromNow: cardinal=30).an empty position is marked with 0 after UnLock() Ticks: array[0.used to purge to old entries ..available e.7 days (for consistency) TSQLQueryCustom = record Store one custom query parameters . Unlock a record.returns true on success. on which fResults[] elements point to TSQLLocks = object(TObject) Used to store the locked record list. which seems correct for common database usage . false if was already locked function UnLock(aID: integer): boolean.18 Date: June 16.this buffer is not to be access directly: this won't be a valid JSON content. in a specified table .the maximum count of the locked list if fixed to 512 by default. specified by its ID .MAX_SQLLOCKS-1] of integer. by default. CustomCaption: PResStringRec.18 Page 778 of 1055 .18 Date: June 16. The caption of the Tab. to be translated on the screen .Synopse mORMot Framework Software Architecture Design 1. User Interface Query action operators TSQLRibbonTabParameters = object(TObject) Defines the settings for a Tab for User Interface generation . The associated enumeration type Event: TSQLQueryEvent.Caption(nil) method . 2013 EnumIndex: integer.if EditExpandFieldHints is TRUE.but you can override this value by setting a pointer to a resourcestring EditExpandFieldHints: boolean. just above the field content. The associated evaluation Event handler .but you can override this value by setting a pointer to a resourcestring CustomHint: PResStringRec. The associated enumeration index in EnumType .by default.WMRefreshTimer(Msg). By default. the hints are written as text on the dialog. to be translated on the screen .pas unit . 1. Tab name is taken from TSQLRecord.Rev. by default.pas unit and TSQLModel. as taken from TSQLRecord. which will handle both WM_TIMER_REFRESH_SCREEN and WM_TIMER_REFRESH_REPORT timers: procedure TMainForm.used in mORMotToolBar. begin Ribbon.but you can enable the auto-refresh feature by setting this property to TRUE. Write hints above field during the edition of this table .Caption(nil) method .WMRefreshTimer(var Msg: TWMTimer). end. hints are displayed as standard delayed popup when the mouse hover the field editor mORMot. and creating a WM_TIMER message handler for the form. the screens are not refreshed automaticaly . The hint type of the Tab.the Operator parameter will be filled with the EnumIndex value Operators: TSQLQueryOperators.Create() overloaded method AutoRefresh: boolean.will be used to fill the Operator parameter for the Event call EnumType: PEnumType. hint will replace all %s instance by the Tab name. Displayed field length mean.e.18 Date: June 16. the detail are displayed as a report (TGDIPages component) . in percent of the client area .18 Page 779 of 1055 . If set. if the resourcestring pointed by EditFieldHints must be used to display some text above every property value on the reports EditFieldNameToHideCSV: RawUTF8.put lowercase character in order to center the field data Group: integer.i. 2013 EditFieldHints: PResStringRec. the ID column is shown mORMot. below the ribbon ListWidth: integer.OrdersJSON" or "ConnectionName") EditFieldNameWidth: integer.pas unit . details hidden) OrderFieldIndex: integer. 1.Rev.handy to hide fields containing JSON data or the name of another sftRecord/sftID (i. one char per field (A=1.e. A CSV list of field names to be hidden in both editor and default report . "RunLogJSON. If set.every field hint must be separated by a '|' character (e. decreasing) Select: RawUTF8.default value (as stated in TSQLRibbonTab. If the default report must contain the edit field hints .Synopse mORMot Framework Software Architecture Design 1.you can define some value by setting a pointer to a resourcestring EditFieldHintsToReport: boolean.g. the list is displayed in reverse order (i.list is to be separated by commas (e.this property is ignored if Layout is llClient (i.set this property to true to customize the details display . The associated field name width (in pixels) to be used for creating the edition dialog for this table FieldWidth: RawUTF8. 'The First Name|Its Company Name') .e. Width of the List. The associated hints to be displayed during the edition of this table .Z=26) . Layout of the List.e. TRecordReference/TSQLRecord published propet) fields . SQL fields to be displayed on the data lists 'ID. even if it won't be displayed on screen (enter a void item like ||) .g. Index of field used for displaying order ReverseOrder: boolean.all fields need to be listed in this text resource.Create) is 30% NoReport: boolean. Tab Group number (index starting at 0) Layout: TSQLListLayout. By default.' is always added at the beginning ShowID: boolean. g. Define if is a normal table (rSQLite3). Compute the SQL statement to be executed for a specific SELECT .equals SQLTableName by default (may be overriden e. The Table associated to this Tab TSQLRecordVirtual = class(TSQLRecord) Parent of all virtual classes . will be assigned by VirtualTableExternalRegister() to a TSQLDBConnectionProperties instance ExternalTableName: RawUTF8.pas . 2013 Table: TSQLRecordClass. Used on the Server side to specify the external DB table name . with diverse implementation patterns (e. BLOBs) will be excluded if SQLSelect='*' property Kind: TSQLRecordVirtualKind read fKind write SetKind. SQLWhere: RawUTF8): RawUTF8."stable" properties derivated from RTTI are shared in TSQLRecordProperties .g. 1. depending of the expected ID/RowID column name expected (i.18 Date: June 16.since the same TSQLRecord can be defined in several models. aSource: TSQLModelRecordProperties). Opaque structure used on the Server side to specify e.when set.e. for including a schema name or an existing table name.e. to avoid any unecessary dependency to the SynDB unit in mORMot. SQLTableSimpleFields[] and SQLSelectAll[] .18 Page 780 of 1055 .Synopse mORMot Framework Software Architecture Design 1.g.non simple fields (e. inheriting from TSQLRecordMany then calling VirtualTableExternalRegister() . an FTS3/FTS4/R-Tree virtual table or a custom TSQLVirtualTable*ID (rCustomForcedID/rCustomAutoID) . Initialize the ORM properties from the TSQLRecord RTTI and the supplied TSQLModel constructor CreateFrom(aModel: TSQLModel. Clone ORM properties from an existing TSQLModelRecordProperties to another model function SQLFromSelectWhere(const SQLSelect. all internal SQL statements will be (re)created.g.g. like SQL pre-generated patterns or external DB properties ExternalDatabase: TObject. by SQLite3DB's VirtualTableExternalRegister procedure) constructor Create(aModel: TSQLModel. internal in one. aTable: TSQLRecordClass.you can define a plain TSQLRecord class as virtual if needed . external in another).e. the DB connection .Rev.will define such a generic TObject.pas unit . aKind: TSQLRecordVirtualKind).g.in practice. this class is used to regroup all model-specific settings. with an OleDB/MSSQL/Oracle/Jet/SQLite3 backend .SQLUpdateSet and SQLInsertSet do not include ID) mORMot.but using this class will seal its state to be virtual TSQLModelRecordProperties = class(TObject) ORM properties associated to a TSQLRecord within a given model . supplied class will be redefined as non-virtual: VirtualTableExternalRegister explicit call is to be made if table should be managed as external function EventName(const Event): string. as TSQLRecord classes . Clone an existing Database Model . Get the text conversion of a given Action. const NonVisibleTables: array of TSQLRecordClass.e. 1. ready to be displayed function AddTable(aTable: TSQLRecordClass.return index in Tables[] if not existing yet and successfully added (in this case. overload. Events: PTypeInfo=nil.g. Get the text conversion of a given Event. Initialize the Database Model from an User Interface parameter structure .don't modify the order of Tables inside this Model.set the Tables to be associated with this Model. const aRoot: RawUTF8='root').Rev. Add the class if it doesn't exist yet .use this class to access the table properties: do not rely on the low-level database methods (e.18 Page 781 of 1055 .set the optional Root URI path of this Model . TabParametersSize: integer. reintroduce.share this Model between TSQLRest Client and Server . since the tables may not exist in the main SQLite3 database. aTableIndexCreated^ is set to the newly created index in Tables[]) .Synopse mORMot Framework Software Architecture Design 1. TSQLDataBase. TabParameters: PSQLRibbonTabParameters. Actions: PTypeInfo=nil. 2013 property Props: TSQLRecordProperties read fProps. overload. but in-memory or external .18 Date: June 16.pas unit .all supplied classes won't be redefined as non-virtual: VirtualTableExternalRegister explicit calls are not mandatory here constructor Create(const Tables: array of TSQLRecordClass.GetTableNames).as retrieved from RTTI TSQLModel = class(TObject) A Database Model (in a MVC-driven way). for storing some tables types as TSQLRecord classes . The shared TSQLRecordProperties information of this TSQLRecord . overload. "stored false") published properties of every TSQLRecordClass destructor Destroy. TabParametersCount. Initialize the Database Model . ready to be displayed mORMot. override. Release associated memory function ActionName(const Action): string. aTableIndexCreated: PInteger=nil): boolean.e.initialize the fIsUnique[] array from "stored AS_UNIQUE" (i.this constructor will reset all supplied classes to be defined as non-virtual (i. Kind=rSQLite3): VirtualTableExternalRegister explicit calls are to be made if tables should be managed as external constructor Create(CloneFrom: TSQLModel). const aRoot: RawUTF8='root'). if you publish some TRecordReference property in any of your tables constructor Create(Owner: TSQLRest. naive search of '.returns -1 if the table is not in the model function GetTableIndex(SQLTableName: PUTF8Char): integer.e. aFieldIndex: integer): boolean. Lock a record . Return true if a specified record is locked function isLocked(aTable: TSQLRecordClass. overload. overload. EnsureUniqueTableInFrom: boolean): integer. overload.returns true on success. overload.18 Page 782 of 1055 . aID: integer): boolean. Try to retrieve a table index from a SQL statement . overload. without TSQL[Record]) function GetTableIndexExisting(aTable: TSQLRecordClass): integer. Return the UTF-8 encoded SQL source to add the corresponding field via a "ALTER TABLE" statement function GetSQLCreate(aTableIndex: integer): RawUTF8. without TSQL[Record]) function GetTableIndex(aTable: TSQLRecordClass): integer.expects SQLTableName to be SQL-like formated (i.Synopse mORMot Framework Software Architecture Design 1. Get the index of aTable in Tables[] . Get the index of a table in Tables[] . Return true if a specified record is locked function Lock(aTable: TSQLRecordClass.returns true on success. "stored false") in its property definition . 512) function Lock(aRec: TSQLRecord): boolean.e.e.an unique field is defined as "stored AS_UNIQUE" (i. otherwise it will return the first Table specified function isLocked(aRec: TSQLRecord): boolean. overload. 512) mORMot. Return the UTF-8 encoded SQL source to create the table function GetTableIndex(const SQLTableName: RawUTF8): integer. FROM TableName' pattern in the supplied SQL . overload. i. Lock a record . Return TRUE if the specified field of this class was marked as unique . aID: integer): boolean. 1...reflects the internal private fIsUnique propery function GetSQLAddField(aTableIndex. false if was already locked or if there's no place more in the lock table (as fixed by MAX_SQLLOCKS contst. it will check that only one Table is in the FROM clause.raise an EModelException if the table is not in the model function GetTableIndexFromSQLSelect(const SQL: RawUTF8.pas unit .e.18 Date: June 16.expects SQLTableName to be SQL-like formated (i. false if was already locked or if there's no place more in the lock table (as fixed by MAX_SQLLOCKS contst. Get the index of a table in Tables[] . aFieldIndex: integer): RawUTF8. i. 2013 function GetIsUnique(aTable: TSQLRecordClass.Rev. Get the index of aTable in Tables[] .if EnsureUniqueTableInFrom is TRUE.e. then '/root/sub1/toto' and '/root/sub1?n=1' will match. i. Returns TRUE if the supplied URI matches the model's Root property .F2. SQLWhere: RawUTF8): RawUTF8..) function UnLock(aTableIndex: integer. false if was already locked or if there's no place more in the lock table (as fixed by MAX_SQLLOCKS contst.g.you can set multiple Table class in Tables: the statement will contain the table name ('SELECT T1.allows sub-domains.F3.returns true on success. overload.T1. false if was not already locked function UnLock(aTable: TSQLRecordClass.Create() in your code function RecordReference(Table: TSQLRecordClass. Unlock a specified record .e. Compute the SQL statement to be executed for a specific SELECT on Tables . whereas '/root/sub1nope/toto' won't function VirtualTableModule(aClass: TSQLRecordClass): TSQLVirtualTableClass. 512) function NewRecord(const SQLTableName: RawUTF8): TSQLRecord. Retrieve a Virtual Table module associated to a class mORMot.Rev.T2 WHERE . aID: integer): boolean.. 1. .use this to create a working copy of a table's record. false if was not already locked function URIMatch(const URI: RawUTF8): boolean. Return the TRecordReference pointing to the specified record function SQLFromSelectWhere(const Tables: array of TSQLRecordClass. false if was not already locked function UnLock(aRec: TSQLRecord): boolean.g. ID: integer): TRecordReference. overload.returns true on success. e. aID: integer): boolean.it's prefered in practice to directly call TSQLRecord*. overload.18 Page 783 of 1055 .Synopse mORMot Framework Software Architecture Design 1.returns true on success.18 Date: June 16.F1.expects SQLTableName to be SQL-like formated (i..T2. aID: integer): boolean. Unlock a specified record .T2. const SQLSelect.don't forget to Free it when not used any more (use a try.returns true on success.F1. overload. 2013 function Lock(aTableIndex.T1.F2 FROM T1.' e.e. Create a New TSQLRecord instance for a specific Table .g. Unlock a specified record . if Root='root/sub1'.pas unit . e. without TSQL[Record]) . Lock a record .finally block) . g.collations defined within our SynSQLite3 unit are named BINARY. and it will increase the code size) . 2013 function VirtualTableRegister(aClass: TSQLRecordClass.Events can be linked to actions and custom status.actions are handled by TSQLRecordForList in the mORMotToolBar. either a TSQLRecord class which has its kind set to rCustomForcedID or rCustomAutoID (e. connection parameters as expected by SQLite3DB . and let the generated SQLite3 file be available outside . const aExternalTableName: RawUTF8=''.shall be set on both Client and Server sides. aExternalDataBase: TObject=nil): boolean.optional aExternalTableName and aExternalDataBase can be used to specify e. in an Audit Trail table) mORMot. Set a custom SQlite3 text column collation for all RawUTF8 fields of all TSQLRecord of this model . linked to some buttons in the User Interface property Events: PEnumType read fEvents. after a specified time .Create() procedure PurgeOlderThan(MinutesFromNow: cardinal=30). RTRIM and our custom SYSTEMNOCASE. to provide a centralized handling of logging (e.pas unit procedure SetCustomCollationForAllRawUTF8(const aCollationName: RawUTF8). Assign an enumeration type to the possible events to be triggered with this class model .call it before TSQLRestServer. Get the enumerate type information about the possible Events to be performed with this model . to override ALL default COLLATE SYSTEMNOCASE of RawUTF8. Unlock all previously locked records property Actions: PEnumType read fActions.g. 1.g. WIN32NOCASE: if you want to use the slow but Unicode ready Windows API. otherwise some issues may occur procedure SetEvents(aEvents: PTypeInfo).default value is 30 minutes. ISO8601. aModule: TSQLVirtualTableClass.18 Date: June 16.to be called server-side only (Client don't need to know the virtual table implementation details.call with the TypeInfo() pointer result of an enumeration type .g. .g.can be used e. Delete all the locked IDs entries. set for each model: SetCustomCollationForAllRawUTF8('WIN32CASE').Rev. Performed with this model .call with the TypeInfo() pointer result of an enumeration type procedure UnLockAll. WIN32CASE.to be used to release locked records if the client crashed . Assign an enumeration type to the possible actions to be performed with this model .pas unit . Register a Virtual Table module for a specified class .18 Page 784 of 1055 .Synopse mORMot Framework Software Architecture Design 1. NOCASE.aClass parameter could be either a TSQLRecordVirtual class. which seems correct for common usage procedure SetActions(aActions: PTypeInfo).Actions are e. TSQLRecordMany calling VirtualTableExternalRegister) . pas unit .18 Date: June 16. Get a class from a table name .very fast. and will allow fast direct access to the Tables[]. thanks to the use one TSQLLocks entry by table property Owner: TSQLRest read fRestOwner write fRestOwner.Synopse mORMot Framework Software Architecture Design 1. For every table. The associated ORM information about all handled TSQLRecord class properties .18 Page 785 of 1055 .RecordProps values property Tables: TSQLRecordClassDynArray read fTables. since TRecordReference depends on it to store the Table type . 1. as 'ModelRoot/SQLTableName' RecordRef = object(TObject) Usefull object to type cast TRecordReference type value into explicit TSQLRecordClass and ID . The associated ORM information for a given TSQLRecord class . do not use RecordRef(Reference).raise an EModelException if aClass is not declared within this model .Rev. Get a class from a table TableName (don't truncate TSQLRecord* if necessary) property TableProps: TSQLModelRecordPropertiesDynArray read fTableProps. Get the classes list (TSQLRecord descendent) of all available tables property URI[aClass: TSQLRecordClass]: RawUTF8 read getURI.RecordReference(Model) or TSQLModel.since 6 bits are used for the table index.Tables[] mORMot.Retrieve(Reference) to get a record content from DB .use TSQLRest.RecordReference() methods or RecordReference() function to encode the value . the corresponding table MUST appear in the first 64 items of the associated TSQLModel.Destroy autofreeing it property Props[aClass: TSQLRecordClass]: TSQLModelRecordProperties read GetTableProps.returns the corresponding TableProps[] item if the class is known property Root: RawUTF8 read fRoot.but since Value is a copied member.expects SQLTableName to be SQL-like formated (i.this TableProps[] array will map the Tables[] array.use RecordRef(Reference). contains a locked record list .TableIndex/Table/ID/Text methods to retrieve the details of a TRecordReference encoded value .Create() in order to have Owner. 2013 property Locks: TSQLLocksDynArray read fLocks.don't change associated TSQLModel tables order. without TSQL[Record]) property TableExact[const TableName: RawUTF8]: TSQLRecordClass read GetTableExactClass.From() but rather TSQLRecord. This property value is used to auto free the database Model class .set this property after Owner.e. The Root URI path of this Database Model property Table[const SQLTableName: RawUTF8]: TSQLRecordClass read GetTable. Get the URI for a class in this Model. Return the class of the content in a specified TSQLModel function TableIndex: integer.Synopse mORMot Framework Software Architecture Design 1.since 6 bits are used for the table index. Get a ready to be displayed text from the stored Table and ID .18 Page 786 of 1055 . PtrUInt) to allow typecast as such: aClass := RecordRef(Reference). Return the ID of the content function Table(Model: TSQLModel): TSQLRecordClass. Fill Value with the corresponding parameters . aTable: TSQLRecordClass.display 'Record 2301' e. but special UTF8CompareRecord() function has to be used for sorting . The value itself .e.(value and 63) is the TableIndex in the current database Model . function ID: integer. overload.g.we use this coding and not the opposite (Table in MSB) to minimize integer values. procedure From(Model: TSQLModel.Tables[] array mORMot. 2013 Value: PtrUInt.Rev.g. aTable MUST appear in the first 64 items of the associated TSQLModel.value=0 means no reference stored .display 'Record "RecordName"' e.(value shr 6) is the ID of the record in this table .18 Date: June 16. 1. function Text(Rest: TSQLRest): RawUTF8.type definition matches TRecordReference (i. Get a ready to be displayed text from the stored Table and ID .pas unit .Table(Model). overload. aID: integer). Return the index of the content Table in the TSQLModel function Text(Model: TSQLModel): RawUTF8. an R-Tree is able to quickly find all entries that are contained within the query rectangle or which overlap the query rectangle. then use a TSQLRecordRTree joined query to make the process faster.pas unit .and maximum-value. A R-Tree is able to quickly find all events. up to 5 dimensions (i.html .e. suppose a database records the starting and ending times for a large number of events. this is exactly what the TSQLRestClient. to link a R-Tree representation to a regular TSQLRecord table . corresponding to an R-Tree table .sqlite. R-Trees also find use in time-domain range look-ups.any record which inherits from this class must have only sftFloat (double) fields. See http://www. extract some coordinates box from the regular TSQLRecord table. Will return 'MapBox_in' e.Synopse mORMot Framework Software Architecture Design 1. R-Trees are most commonly used in geospatial systems where each entry is a rectangle with minimum and maximum X and Y coordinates. 11 columns.18 Date: June 16.the ID: integer property must be set before adding a TSQLRecordRTree to the database. that were active at any time during a given time interval.org/rtree. including the ID property) .g. or all events that both started and ended within a given time interval.queries against the ID or the coordinate ranges are almost immediate: so you can e. 2013 TSQLRecordRTree = class(TSQLRecordVirtual) A base record.Rev. for example.g. And so forth.RTreeMatch method offers class function RTreeSQLFunctionName: RawUTF8. This idea is easily extended to three dimensions for use in CAD systems. e. Given a query rectangle.g. For example. for TSQLRecordMapBox mORMot.an R-Tree is a special index that is designed for doing range queries. each as minimum. 1. or all events that started during a particular time interval. grouped by pairs.18 Page 787 of 1055 . the FTS3 engine ignore all characters >= #80.any record which inherits from this class must have only sftUTF8Text (RawUTF8) fields .org/fts3. implementing full-text . but handle low-level case insentivity (i.e.this causes FTS3 to merge all existing index b-trees into a single large b-tree containing the entire index. the "simple" tokenizer is used. See http://sqlite. which is compatible with both TSQLRecord and TSQLRecordFTS3 kind of table mORMot. Optimize the FTS3 virtual table .static tables don't handle TSQLRecordFTS3 classes . to associate this TSQLRecordFTS3 to another TSQLRecord .this method must be called server-side . then store your text content in a separated FTS3 table.'text MATCH "linu*"'. the ID property can't be set at adding.by default. The most common (and effective) way to describe full-text searches is "what Google. This DocID property map the internal Row_ID property . and reflect that it points to an ID of another associated TSQLRecord . corresponding to a FTS3 table. but you can inherits from TSQLRecordFTS3Porter class if you want a better English matching.ID property is read-only.Rev. Yahoo and Altavista do with documents placed on the World Wide Web". and the full-text query system finds the set of documents that best matches those terms considering the operators and groupings the user has specified.in order to make FTS3/FTS4 queries.18 Page 788 of 1055 .FTSMatch method.but you can set a value to this property before calling the Add() method. or series of terms.this record has its fID: integer property which may be published as DocID.18 Date: June 16. if FTSMatch(TSQLMyFTS3Table.internaly. with the MATCH operator (you can use regular queries.org/fts3. but this DocID property can be written/set .a good approach is to store your data in a regular TSQLRecord table. using the Porter Stemming algorithm .org/fts3. you can have string fields . This can be an expensive operation. 1.html#tokenizer . but may speed up future queries.FTS3/FTS4 table are SQLite virtual tables which allow users to perform full-text searches on a set of documents.html . 2013 TSQLRecordFTS3 = class(TSQLRecordVirtual) A base record.e.. to be consistent with SQLite3 praxis. but you must specify 'RowID' instead of 'DocID' or 'ID' because of FTS3 Virtual table specificity): var IDs: TIntegerDynArray.pas unit .Synopse mORMot Framework Software Architecture Design 1.html#section_1_2 .'Z') so you must keep your request with the same range for upper case .by default. or the more efficient (and new) FTS4 engine (available since version 3.with Delphi 2009+. by using the TSQLRecordFTS4 type . we use RowID in the SQL statements. associated to this TSQLRecordFTS3 table via its ID/DocID . use the dedicated TSQLRest. See http://sqlite.returns TRUE on success property DocID: integer read GetID write fID.see http://sqlite.the ID/DocID property can be set when the record is added.you can select either the FTS3 engine.IDs) then // you've all matching IDs in IDs[] class function OptimizeFTS3Index(Server: TSQLRestServer): boolean. 'A'. perhaps connected by a binary operator or grouped together into a phrase.7. i. to retrieve any associated TSQLRecord (note that for a TSQLRecord record. but is calculated by the engine) . Users input a term.4). . corresdonding to a FTS4 table. 2013 TSQLRecordFTS3Porter = class(TSQLRecordFTS3) This base class will create a FTS3 table using the Porter Stemming algorithm . and their interfaces are the same. then TSQLRecordFTS3 will usually serve just as well.see http://sqlite. 1.see http://sqlite. And the added information permits some additional useful output options in the matchinfo() function.org/fts3.see http://sqlite. though if minimal disk usage or compatibility with older versions of SQLite are important.18 Page 789 of 1055 .org/fts3. This additional information allows FTS4 to use certain query performance optimizations that FTS3 cannot use. TSQLRecordFTS4 is recommended. The only difference is that FTS4 stores some additional information about the document collection in two of new FTS shadow tables.Synopse mORMot Framework Software Architecture Design 1. They share most of their code in common.html#tokenizer mORMot.html#tokenizer TSQLRecordFTS4 = class(TSQLRecordFTS3) A base record.org/fts3.FTS3 and FTS4 are nearly identical.For newer applications.Rev. .18 Date: June 16.html#section_1_1 TSQLRecordFTS4Porter = class(TSQLRecordFTS4) This base class will create a FTS4 table using the Porter Stemming algorithm . which is an enhancement to FTS3 .pas unit . published DestList: TSQLDestPivot read fDestList.by default.to read all Dest IDs after a join to the pivot table.to read all Dest records IDs. at leat two 'Source' and 'Dest' published properties must be declared as TSQLRecord children in any TSQLRecordMany descendant because they will always be needed for the 'many to many' relationship . use FillMany then FillRow.to read all Source records and the associaed "through" fields content.e. the first pointing to the source record (the one with a TSQLRecordMany published property) and the second to the destination record . TSQLSource = class.18 Page 790 of 1055 . providing optional "through" parameters if needed TSQLDest = class(TSQLRecord). FillOne and FillRewind methods . end. FillOne and FillRewind methods to loop through records . published property Source: TSQLSource read fSource. 1.many-to-many relationship is tracked using a table specifically for that relationship. it is initialized automaticaly by TSQLRecord. only two TSQLRecord (i. out DestIDs: TIntegerDynArray): boolean.Rev. Retrieve all Dest items IDs associated to the specified Source mORMot. INTEGER) fields must be created. which will define the pivot table.you should first create a type inheriting from TSQLRecordMany. aSourceID: integer. fDest: TSQLDest. use the ManyDelete() method . FillManyFromDest then FillRow.to read the Dest records and the associated "through" fields content. use the DestGet() method . use DestGetJoined constructor Create.will set protected fSourceID/fDestID fields function DestGet(aClient: TSQLRest.to retrieve an association. use the ManyAdd() method . and needed internal fields . fTime: TDateTime.pas unit . TSQLDestPivot = class(TSQLRecordMany) private fSource: TSQLSource. . turning the relationship into two one-to-many relationships pointing in opposite directions . overload.in all cases.to delete an association. // map Dest column property AssociationTime: TDateTime read fTime write fTime.to add some associations to the pivot table. end. // map Source column property Dest: TSQLDest read fDest.Create . use the ManySelect() method . named "Source" and "Dest". override.when a TSQLRecordMany published property exists in a TSQLRecord. 2013 TSQLRecordMany = class(TSQLRecord) Handle "has many" and "has many through" relationships .18 Date: June 16.Synopse mORMot Framework Software Architecture Design 1. Initialize this instance. TSQLSource = class(TSQLRecord) private fDestList: TSQLDestPivot. 18 Date: June 16. out DestIDs: TIntegerDynArray): boolean.if aSourceID is 0. 2013 function DestGet(aClient: TSQLRest.aDestWhereSQL can specify the Dest table name in the statement. 'Salary>:(1000): AND Salary<:(2000):' . Retrieve all Dest items IDs associated to the current or specified Source ID. e.[]. the value is taken from current fSourceID field (set by TSQLRecord.note that you should better use inlined parameters for faster processing on server. aSourceID: Integer): TSQLRecord.Create) . 'Salary>:(1000): AND Salary<:(2000):') according to TSQLRecordMany properties . e.Create) . overload.Create) .Synopse mORMot Framework Software Architecture Design 1. the value is taken from current fSourceID field (set by TSQLRecord. Create a Dest record. aSourceID: Integer.if aSourceID is 0.[1000.aDestWhereSQL can specify the Dest table name in the statement. Create a TSQLTable. 1. adding a WHERE condition against the Dest rows . adding a WHERE condition against the Dest rows .2000]) mORMot. after a JOIN associated to the current or specified Source ID .2000]) function DestGetJoined(aClient: TSQLRest. containing all specified Fields.pas unit . the value is taken from current fSourceID field (set by TSQLRecord. const aCustomFieldsCSV: RawUTF8=''): TSQLTable. const aDestWhereSQL: RawUTF8.note that you should better use such inlined parameters as FormatUTF8('Salary>? AND Salary<?'. overload. overload.18 Page 791 of 1055 .[1000.Rev. so you may use the more convenient function FormatUTF8('Salary>? AND Salary<?'. 'Salary>:(1000): AND Salary<:(2000):') according to TSQLRecordMany properties . jkPivotAndDestFields) .note that you should better use such inlined parameters as FormatUTF8('Salary>? AND Salary<?'. JoinKind: TSQLRecordManyJoinKind.note that if the Source record has just been added.the Table will have the fields specified by the JoinKind parameter . const aDestWhereSQL: RawUTF8. aSourceID: Integer. jkPivotFields.source ID is taken from the fSourceID field (set by TSQLRecord.Create) . e. because the condition is executed in the SQL statement by the server function DestGetJoinedTable(aClient: TSQLRest. out DestIDs: TIntegerDynArray): boolean. Retrieve all Dest items IDs associated to the current Source ID .g.if aSourceID is 0.[].[].aDestWhereSQL can specify the Dest table name in the statement.g. then FillPrepare() it to retrieve all Dest items associated to the current or specified Source ID. const aDestWhereSQL: RawUTF8.aCustomFieldsCSV can be used to specify which fields must be retrieved (for jkDestFields.default is all . fSourceID is not set.[1000.2000]) .this is faster than a manual FillMany() then loading each Dest.g. so this method will fail: please call the other overloaded method function DestGetJoined(aClient: TSQLRest. 2013 function FillMany(aClient: TSQLRest. 'Salary>:(1000): AND Salary<:(2000):') according to TSQLRecordMany properties .0.returns the Count of records corresponding to this aSource record .if source ID parameter is 0. getting also any additional 'through' columns .g." loop to iterate through all Dest items. 1.search for aID as Dest ID if isDest is TRUE .g. Retrieve all records associated to a particular source record.use a "for .FillMany(Client.[]. aSourceID: integer=0.note that you should better use such inlined parameters e. getting also any additional 'through' columns .returns the Count of records corresponding to this aSource record .18 Date: June 16.[]. function IDWhereSQL(aClient: TSQLRest.[1000.the records are stored in an internal TSQLTable.pas unit .. so you may call e.2000]) mORMot. FillOne and FillRewind methods . aID: integer.g.the optional aAndWhereSQL parameter can be used to add any additional condition to the WHERE statement (e.[1000. 'Salary>:(1000): AND Salary<:(2000):') according to TSQLRecordMany properties . so this method will fail: please specify aSourceID parameter with the one just added/created . calling FormatUTF8('Salary>? AND Salary<?'.18 Page 792 of 1055 .use a "for ..note that if the Source record has just been added. 'Salary>:(1000): AND Salary<:(2000):') according to TSQLRecordMany properties .the optional aAndWhereSQL parameter can be used to add any additional condition to the WHERE statement (e.[1000.FormatUTF8('Salary>? AND Salary<?'.the optional aAndWhereSQL parameter can be used to add any additional condition to the WHERE statement (e.[]. isDest: boolean. aRec. so you may call e." loop or a "while FillOne do ..g.g. which has a TSQLRecordMany property . which has a TSQLRecordMany property .search for aID as Source ID if isDest is FALSE . refered in the private fTable field.Create) ... const aAndWhereSQL: RawUTF8=''): integer. Retrieve all records associated to a particular Dest record. function FillManyFromDest(aClient: TSQLRest.note that you should better use inlined parameters for faster processing on server..2000])). fSourceID is not set." loop to iterate through all Dest items.2000])). the ID is taken from the fSourceID field (set by TSQLRecord.DestID.FormatUTF8('Salary>? AND Salary<?'. aRec.FillManyFromDest(Client. const aAndWhereSQL: RawUTF8=''): RawUTF8. Get the SQL WHERE statement to be used to retrieve the associated records according to a specified ID .note that you should better use inlined parameters for faster processing on server." loop or a "while FillOne do .g. aDestID: integer. and initialized via a FillPrepare call: all Dest items are therefore accessible with standard FillRow.Rev. const aAndWhereSQL: RawUTF8=''): integer.Synopse mORMot Framework Software Architecture Design 1. fSourceID is not set.if NoDuplicates is TRUE. aUseBatchMode: boolean=false): boolean.Create) . out SourceIDs: TIntegerDynArray): boolean.Create) . aDestID: Integer.source ID is taken from the fSourceID field (set by TSQLRecord. fSourceID is not set.note that if the Source record has just been added. aDestID: Integer): boolean. so this method will fail: please call the other overloaded method .Create) . overload. overload. all "through" columns are available in the TSQLRecordMany field instance function SourceGet(aClient: TSQLRest.in this case. 2013 function ManyAdd(aClient: TSQLRest. Will retrieve the record associated with the current source and a specified Dest . so this method will fail: please call the other overloaded method function ManyAdd(aClient: TSQLRest. aDestID: integer. it will use aClient.e. aDestID: Integer): boolean.Synopse mORMot Framework Software Architecture Design 1. overload. Add a Dest record to the current Source record list .returns TRUE on success. aSourceID. the existence of this Source/Dest ID pair is first checked . overload.note that if the Source record has just been added. aSourceID.will return TRUE if the pair was found and successfully deleted .if aUseBatchMode is TRUE. fSourceID is not set.if aUseBatchMode is TRUE.source ID is taken from the fSourceID field (set by TSQLRecord.BatchDelete() instead of the slower aClient.pas unit .Delete() method . aDestID: Integer. NoDuplicates: boolean=false): boolean. aDestID: Integer.source ID is taken from the fSourceID field (set by TSQLRecord.18 Date: June 16.18 Page 793 of 1055 . Add a Dest record to the Source record list . FALSE on error . Retrieve all Source items IDs associated to the specified Dest ID mORMot. 1.but you shall call it within a BatchStart / BatchSend block function ManyDelete(aClient: TSQLRest. it will use aClient.any current value of the additional fields are used to populate the newly created content (i.but you shall call it within a BatchStart / BatchSend block function ManySelect(aClient: TSQLRest. aDestID: Integer.will return TRUE if the pair was found . all published properties of this record) function ManyDelete(aClient: TSQLRest. Will delete the record associated with the current source and a specified Dest . aUseBatchMode: boolean=false): boolean.note that if the Source record has just been added.Rev.current Source and Dest properties are filled with the corresponding TRecordReference values corresponding to the supplied IDs . NoDuplicates: boolean=false): boolean. so this method will fail: please call the other overloaded method function ManySelect(aClient: TSQLRest. overload. Will retrieve the record associated with a particular Source/Dest pair .BatchDelete() instead of the slower aClient. Will delete the record associated with a particular Source/Dest pair . aSourceID. overload.Delete() method . this JSON content must follow the format retrieved by LogTableJSON and LogTableJSONFrom methods destructor Destroy.used to spare memory usage TSQLRecordSigned = class(TSQLRecord) Common ancestor for tables with digitally signed RawUTF8 content . Initialize the internal storage with a supplied JSON content . Add the value of OneLog to the Log Table JSON content . Returns the log JSON data from a given start position . Returns the JSON data as added by previous call to Log() .g.is incremented every time Log() method is called .if StartPosition=0.do nothing is value is left to 0 (which is the default) .total rows count won't never be higher than this value .Synopse mORMot Framework Software Architecture Design 1. with a JSON-logging capability . the whole Log content is returned . Returns the internal position of the Log content .use this value to later retrieve a log range with LogTableJSONFrom() function LogTableJSON: RawUTF8.Rev. Release the private fLogTableWriter and fLogTableStorage objects function LogCurrentPosition: integer.content is signed according to a specific User Name and the digital signature date and time .will be never higher than MaxLogTableRowCount below (if set) property MaxLogTableRowCount: integer read fMaxLogTableRowCount. If the associated Log Table rows count reachs this value. 1. e.JSON data is in not-expanded format .used to store a log of events into a JSON text. the first data row will be trimed .this function can be called multiple times function LogTableJSONFrom(StartPosition: integer): RawUTF8. 2013 TSQLRecordLog = class(TSQLRecord) A base record.pas unit . The current associated Log Table rows count value .18 Page 794 of 1055 .internaly uses the very secure SHA-256 hashing algorithm for performing the digital signature mORMot. const aJSON: RawUTF8). easy to be displayed with a TSQLTableToGrid . override.the ID property of the supplied OneLog record is incremented before adding property LogTableRowCount: integer read fLogTableRowCount.18 Date: June 16.multiple instances of LogCurrentPosition/LogTableJSONFrom() can be used at once procedure Log(OneLog: TSQLRecord). constructor CreateFrom(OneLog: TSQLRecord.this log can then be stored as a RawUTF8 field property into a result record.StartPosition was retrieved previously with LogCurrentPosition . ForcedSignatureTime: Int64=0): boolean. Returns true if this record content is correct according to the stored digital Signature function SetAndSignContent(const UserName: RawUTF8. Retrieve the UserName who digitally signed this record . Time and date of signature .Synopse mORMot Framework Software Architecture Design 1..may be -1 if pure register parameter with no backup on stack (x86) ParamName: PShortString.' into this property . 1. 2013 function CheckSignature(const Content: RawByteString): boolean. TServiceMethodArgument = object(TObject) Describe a service provider method argument IndexVar: integer..digital signature is allowed only once: this property is written only once .returns true if signed successfully (not already signed) function SignedBy: RawUTF8.18 Date: June 16. with the current Date and Time (SHA-256 hashing is used internaly) . Index of the associated variable in the local array[ArgsUsedCount[]] .if the signature is invalid. Reset the stored digital signature . property SignatureTime: TTimeLog read fSignatureTime write fSignatureTime. Byte offset in the CPU stack of this argument .18 Page 795 of 1055 . Use this procedure to sign the supplied Content of this record for a specified UserName. as declared in Delphi mORMot.returns '' if was not digitally signed procedure UnSign.this property is defined here to allow inherited to just declared the name in its published section: property SignatureTime.for smdConst argument.Rev.SetAndSignContent() can be called after this method property Signature: RawUTF8 read fSignature write fSignature. As the Content of this record is added to the database. const Content: RawByteString.pas unit .very secured SHA-256 hashing is used internaly . this field will contain numerical 1 value .. The argument name. contains -1 (no need to a local var: the value will be on the stack only) InStackOffset: integer.this property is defined here to allow inherited to just declared the name in its published section: property SignatureTime. its value is hashed and stored as 'UserName/03A35C92. The low-level RTTI information of this argument TypeName: PShortString. How the variable is to be passed at asm level . dynamic array or record) are identified by their type identifier .18 Page 796 of 1055 .contains 1 for RCX/XMM0L. smvString and smvWideString kind of parameter (smvRecord has it to false. We do not handle all kind of Delphi variables ValueVar: TServiceMethodValueVar.Synopse mORMot Framework Software Architecture Design 1. How the variable may be stored function SerializeToContract: RawUTF8. as declared in Delphi ValueDirection: TServiceMethodValueDirection.Args[0] always is smvSelf . Serialize the argument into the TServiceContainer. 2013 RegisterIdent: integer. and 4 for R9/XMM3L. an additional smdResult argument is appended mORMot. 2 for RDX/XMM1L. 2 for EDX and 3 for ECX registers (for x86) . Size (in bytes) of this smvv64 ordinal value .contains 0 if parameter is not a register .vIsString is included for smvRawUTF8. Used to specify if the argument is passed as register . The type name.g. and also smvVariant/smvRawJSON) . depending of the associated kind of enumeration TypeInfo: PTypeInfo. or is a record or a reference-counted type result) ValueType: TServiceMethodValueType. The variable direction as defined at code level ValueKindAsm: set of (vIsString.g. Size (in bytes) of this argument on the stack SizeInStorage: integer.e. Describe expected method arguments .so contract does not extend up to the content of such high-level structures TServiceMethod = object(TObject) Describe a service provider method Args: TServiceMethodArgumentDynArray. 1.Contract JSON format . vPassedByReference).non standard types (e. clas.vPassedByReference is included if the parameter is passed as reference (i.e.pas unit .if method is a function.contains 1 for EAX. with a backing store on the stack (for x64) SizeInStack: integer. defined as var/out. enumerate. 3 for R8/XMM2L.Rev.18 Date: June 16. even if they are Base-64 encoded within the JSON content. 18 Page 797 of 1055 . Res: TTextWriter. Par: PUTF8Char.Rev.this property value is hashed internaly for faster access function InternalExecute(Instances: array of pointer.Synopse mORMot Framework Software Architecture Design 1. a custom Header+Content BLOB transfert. false for booleans. The number of input const / var parameters in Args[] ArgsOutFirst: integer. formatted as a JSON array .g. Needed CPU stack size (in bytes) for all arguments .any var/out and potential function result will be set as a JSON array of values.is -1 if the method is defined as a (not a function) ArgsResultIsServiceCustomAnswer: boolean. Execute the corresponding method of a given TInterfacedObject instance .that is.will retrieve a JSON array of parameters from Par .under x64.Add) . a void record serialized as expected (including customized serialization) and null for objects MethodIndex: integer.example of content may be '[]' for a procedure or '[0]' for a function . The index of the first var / out / result argument in Args[] ArgsOutLast: integer. not a JSON object ArgsSizeInStack: cardinal. _AddRef. does not include the backup space for the four registers ArgsUsed: TServiceMethodValueTypes. [] for dynamic arrays.will append a JSON array of results in Res. The index of the last var / out / result argument in Args[] ArgsOutputValuesCount: cardinal. Contains all used kind of arguments ArgsUsedCount: array[TServiceMethodValueVar] of integer.our custom methods start at index 3 (RESERVED_VTABLE_SLOTS). with 0 for numerical values.basicaly the method name as declared in Delphi code (e.18 Date: June 16. "" for textual values. Contains the count of variables for all used kind of arguments DefaultResult: RawUTF8. since QueryInterface. The index of the result pseudo-argument in Args[] . 2013 ArgsInputValuesCount: cardinal. The number of input var / out parameters + in Args[] ArgsResultIndex: integer. var aHead: RawUTF8. and _Release are always defined by default URI: RawUTF8. The method URI . 1. True if the result is a TServiceCustomAnswer record . The method default result.pas unit . 'Add' for ICalculator. Options: TServiceMethodOptions): boolean. Method index in the original interface . or set an Error message mORMot. useful to set the response mime-type . this field SHALL be set (<>'') (otherwise it will transmitted with default JSON object format) TInterfacedCollection = class(TCollection) Any TCollection used between client and server shall inherit from this class .pas unit .a thread-safe global list of such class instances is implemented to cache information for better speed: use class function TInterfaceFactory.do not call this constructor directly.Synopse mORMot Framework Software Architecture Design 1.Get() function CheckMethodIndex(const aMethodName: RawUTF8): integer. 1. The response body Header: RawUTF8. but TInterfaceFactory. binary.18 Date: June 16. and it may be used with plain AJAX or HTML requests (via POST).Get() and not manual TInterfaceFactory.another possibility is to register a TCollection/TCollectionItem pair via a call to TJSONSerializer.will raise an EInterfaceFactoryException if the method is not known mORMot.this kind of answer will be understood by our TServiceContainerClient implementation. reintroduce. call once Get(TypeInfo(IMyInterface)) or RegisterInterfaces() constructor Create(aInterface: PTypeInfo). Find the index of a particular method in internal Methods[] list . the TEXT_CONTENT_TYPE_HEADER or HTML_CONTENT_TYPE_HEADER constants or GetMimeContentType() function .g.g.won't find the default AddRef/Release/QueryInterface methods .Rev. and prepare all internal structures for later use .all answers are pure JSON object by default: using this kind of record as result will allow a response of any type (e.RegisterCollectionForJSON() constructor Create. HTML or text) . 2013 TServiceCustomAnswer = record A record type to be used as result for a function method for custom content . virtual. This constructor which will call GetClass to initialize the collection TInterfaceFactory = class(TObject) Class handling interface RTTI and fake implementation class .Create / Free .in order to be handled as expected.if you want to specify the interfaces by name or TGUID. as encoded in the HTTP header .it will check and retrieve all methods of the supplied interface.you should override the GetClass virtual method to provide the expected collection item class to be used on server side . Initialize the internal properties from the supplied interface RTTI . The response type.18 Page 798 of 1055 .see e. to retrieve some custom content Content: RawByteString. The declared internal methods . overload. returns nil class procedure RegisterInterfaces(const aInterfaces: array of PTypeInfo).will return -1 if the method is not known class function Get(aInterface: PTypeInfo): TInterfaceFactory.this method will also register the class to further class function Get(const aGUID: TGUID): TInterfaceFactory. 2013 function CreateFakeInstance(aInvoke: TOnFakeInstanceInvoke.if the supplied TGUID has not been previously registered.so that you can use TInterfaceFactory.you shall have registered the interface by a previous call to the overloaded Get(TypeInfo(IMyInterface)) method or RegisterInterfaces() . for server notification) function FindMethodIndex(const aMethodName: RawUTF8): integer. The registered Interface GUID property InterfaceTypeInfo: PTypeInfo read fInterfaceTypeInfo.Synopse mORMot Framework Software Architecture Design 1. Register one or several interfaces to the global interface factory cache . The registered Interface low-level Delphi RTTI type property Methods: TServiceMethodDynArray read fMethods.Executes() events callbacks mORMot. This is the main entry point to the global interface factory cache . overload.optional aNotifyDestroy event will be called when the fake implementation instance will be released (e.won't find the default AddRef/Release/QueryInterface methods . Retrieve an interface factory from cache. 'IMyInterface') .access to this method is thread-safe .list does not contain default AddRef/Release/QueryInterface methods property MethodsCount: cardinal read fMethodsCount. from its name (e.Get(aGUID) or Get( property InterfaceIID: TGUID read fInterfaceIID.you shall have registered the interface by a previous call to the overloaded Get(TypeInfo(IMyInterface)) method or RegisterInterfaces() .does not include the default AddRef/Release/QueryInterface methods TOnInterfaceStubExecuteParamsAbstract = class(TObject) Abstract parameters used by TInterfaceStub. 1. Find the index of a particular method in internal Methods[] list .18 Page 799 of 1055 .18 Date: June 16.g.Rev. overload.access to this method is thread-safe .g.if the supplied TGUID has not been previously registered.access to this method is thread-safe . from its TGUID . Create a fake class instance implementing the corresponding interface . returns nil class function Get(const aInterfaceName: RawUTF8): TInterfaceFactory. Retrieve an interface factory from cache. aNotifyDestroy: TOnFakeInstanceDestroy=nil): TInterfacedObject.aInvoke event will be called at method execution . The number of internal methods .pas unit . const aParams.. overload.just a wrapper around JSONEncodeArrayOfConst([. A method to return an array of values into Result . result := 42. so is faster than TOnInterfaceStubExecuteParamsVariant procedure Returns(const Values: array of const).. begin // Ctxt. Call this method if the callback implementation failed procedure Error(const aErrorMessage: RawUTF8).20'.pas unit . virtual. Pointer to the method which is to be executed property Sender: TInterfaceStub read fSender.42]' Ctxt.Executes() events callbacks as JSON . result := true.this class will expect input and output parameters to be encoded as JSON arrays.Params))+1.18 Date: June 16. overload. aMethod: PServiceMethod. to emulate this native implementation: function Bar(var i: Integer): Integer.Executes() definition property Method: PServiceMethod read fMethod.will raise an exception if the associated Sender generator is not a TInterfaceMock TOnInterfaceStubExecuteParamsJSON = class(TOnInterfaceStubExecuteParamsAbstract) Parameters used by TInterfaceStub. 1.Rev. property Params: RawUTF8 read fParams. defined at TInterfaceStub. Call this method if the callback implementation failed property EventParams: RawUTF8 read fEventParams.42]). mORMot.18 Page 800 of 1055 .can be used as such: function TFooTestCase. Constructor of one parameters marshalling instance procedure Error(Format: PUTF8Char.]) . begin inc(i). const Args: array of const).order follows the method const and var parameters Stub. 2013 constructor Create(aSender: TInterfaceStub.Add(10.ExecuteBar(var Ctxt: TOnInterfaceStubExecuteParamsJSON): Boolean.Synopse mORMot Framework Software Architecture Design 1.20) -> Params = '10.Returns([GetInteger(pointer(Ctxt. A custom message. The mocking generator associated test case . The stubbing / mocking generator property TestCase: TSynTestCase read GetSenderAsMockTestCase. end.aEventParams: RawUTF8). end. Incoming parameters array encoded as JSON array without braces .Result := '[i+1.Params := '[i]' -> Ctxt. TInterfaceStub/TInterfaceMock will check it in their Destroy destructor. Values contains Exception.18 Page 801 of 1055 . 1.use Returns() method to create the JSON array directly.every var. serialized as a JSON array .Rev.either a TOnInterfaceStubExecuteJSON.for TInterfaceStub.ExpectsTrace() . from an array of values TInterfaceStubRule = record Define a mocking / stubing rule used internaly by TInterfaceStub ExceptionClass: ExceptClass. using the fLogs[] content Kind: TInterfaceStubRuleKind.e. The exception class to be raised . Comparison operator set by TInterfaceStub.if equals ''.ExpectsCount() . The event handler to be executed . it will be the default for this method RulePassCount: cardinal.Synopse mORMot Framework Software Architecture Design 1. Log trace value set by TInterfaceStub.ExpectsCount() weak rule Params: RawUTF8. using the comparison stated by ExpectedPassCountOperator ExpectedPassCountOperator: TSQLQueryOperator.isUndefined is used for a TInterfaceStub. in the same order than the stubbed method declaration .Executes(). The type of this rule .ExpectsCount() . 2013 property Result: RawUTF8 write fResult. the rule is not parametrized .Message Execute: TNotifyEvent.qoGreaterThanOrEqualTo are relevant here ExpectedTraceHash: cardinal.for TInterfaceStub. or a TOnInterfaceStubExecuteVariant ExpectedPassCount: cardinal.value to be compared to the number of times this rule has been executed . The number of times this rule has been executed mORMot. out parameter or the function result shall be encoded as a JSON array into this variable. Expected pass count value set by TInterfaceStub.18 Date: June 16. Outgoing values array encoded as JSON . Optional expected parameters.value to be compared to the Hash32() value of the execution log trace .only qoEqualTo. Values is transmitted as aResult parameter .i.TInterfaceStub/TInterfaceMock will check it in their Destroy destructor..Raises().pas unit . for TInterfaceStub.for TInterfaceStub. The method called . 1. const aEvent: TNotifyEvent=nil. Any non default result returned after execution .Fails() is the returned error message for TInterfaceStub exception or TInterfaceMock associated test case TInterfaceStubRules = object(TObject) Define the rules for a given method as used internaly by TInterfaceStub DefaultRule: integer.pas unit . Register a rule TInterfaceStubLog = object(TObject) Used to keep track of one stubbed method call CustomResults: RawUTF8. Index in Rules[] of the default rule. is the returned result. The number of times this method has been executed Rules: array of TInterfaceStubRule.g.a pointer to the existing information in shared TInterfaceFactory Params: RawUTF8. The mocking / stubing rules associated to this method function FindRuleIndex(const aParams: RawUTF8): integer. aExceptionClass: ExceptClass=nil. Find a rule index from its Params content function FindStrongRuleIndex(const aParams: RawUTF8): integer. aValues: RawUTF8. the one with Params='' MethodPassCount: cardinal. is the aEventParams parameter transmitted to Execute event handler (could be used to e.Returns(). const aParams. Values associated to the rule .for TInterfaceStub.for TInterfaceStub. serialized as a JSON array (including var / out parameters then any function result) .e.Executes().Message associated to one ExceptionClass . is the Exception. always contain the error message Method: PServiceMethod. customize the handler) .if WasError is TRUE.Raises().18 Date: June 16. 2013 Values: RawUTF8.DefaultResult has been returned . aValue: cardinal=0). aKind: TInterfaceStubRuleKind. if equals '').Rev. Method^. The parameters at execution call mORMot.if not set (i.18 Page 802 of 1055 . aExpectedPassCountOperator: TSQLQueryOperator=qoNone.e. i. Find a strong rule index from its Params content procedure AddRule(Sender: TInterfaceStub.Synopse mORMot Framework Software Architecture Design 1. this method will return Method^.g.so you do not need to protect TInterfaceStub.DefaultResult procedure AddAsText(WR: TTextWriter. Initialize an interface stub from an interface name (e.under Windows. overload. Initialize an interface stub from an interface GUID .g.. The result returned after execution . its associated TInterfaceStub will be freed .18 Page 803 of 1055 .typical output is as such: Add(10. if EInterfaceFactoryException was raised for TInterfaceStub.18 Date: June 16.0) error "divide by zero".e.define the expected workflow in a fluent interface using Executes / Fails / Returns / Raises . if WasError is TRUE: Divide(20.if the supplied TGUID has not been previously registered.Create with a try.this class will be inherited by TInterfaceMock which will contain some additional methods dedicated to mocking behavior (e. 1.you shall have registered the interface by a previous call to TInterfaceFactory.Rev.Get(TypeInfo(IMyInterface)) or RegisterInterfaces() .you shall have registered the interface by a previous call to TInterfaceFactory.each instance of this class will be owned by its generated fake implementation class (retrieved at constructor out parameter): when the stubed/mocked interface is freed. or.i. reintroduce. out aStubbedInterface). in milliseconds . Append the log in textual format . raise an Exception mORMot.finally clause. or if TInterfaceMock did notify its associated TSynTestCase via a Check() . TInterfaceStub = class(TObject) Used to stub an interface implementation . 'IMyInterface') .Synopse mORMot Framework Software Architecture Design 1. aScope: TInterfaceStubLogLayouts). since it will be released when no more needed constructor Create(const aInterfaceName: RawUTF8. raise an Exception constructor Create(const aGUID: TGUID. if filled with GetTickCount() API returned value WasError: boolean.CustomResults/Results will contain the error message function Results: RawUTF8.20)=[30].Get(TypeInfo(IMyInterface)) or RegisterInterfaces() . out aStubbedInterface). overload. reintroduce. including in tests) . Call timestamp.pas unit . Set to TRUE if this calls failed .if the supplied name has not been previously registered. 2013 TimeStamp: cardinal. overload. aParams: RawUTF8.18 Page 804 of 1055 .assign the fake class instance to the SubbedInterface variable: var I: ICalculator. aValue: cardinal): TInterfaceStub. function Executes(const aMethodName: RawUTF8.raise an Exception if the method name does not exist for this interface function ExpectsCount(const aMethodName: RawUTF8. aValue: cardinal): TInterfaceStub. 2013 constructor Create(aInterface: PTypeInfo.optional aEventParams parameter will be transmitted to aEvent handler . Initialize an interface stub from TypeInfo(IMyInterface) . aOperator: TSQLQueryOperator. Check(I.if execution context matches the supplied aParams value. reintroduce. const aEventParams: RawUTF8=''): TInterfaceStub.optional aEventParams parameter will be transmitted to aEvent handler . aEvent: TOnInterfaceStubExecuteJSON. aParams: RawUTF8. Add a pass count expectation rule for a given method . overload. const aEventParams: RawUTF8=''): TInterfaceStub. out aStubbedInterface).only qoEqualTo.I). Add an execution rule for a given method and a set of parameters. TInterfaceStub.raise an Exception if the method name does not exist for this interface function Executes(const aMethodName. Add a pass count expectation rule for a given method and a set of parameters .20)=0. overload.raise an Exception if the method name does not exist for this interface mORMot. with JSON marshalling . overload..only qoEqualTo.qoGreaterThanOrEqualTo are relevant here .Rev. overload.qoGreaterThanOrEqualTo are relevant here .'Default result'). aOperator: TSQLQueryOperator. aEvent is triggered .it will raise EInterfaceFactoryException for TInterfaceStub. aEvent is triggered . with JSON marshalling . but TInterfaceMock will push the failure to the associated test case .Synopse mORMot Framework Software Architecture Design 1.Add(10. overload. 1. Add an execution rule for a given method.raise an Exception if the method name does not exist for this interface function ExpectsCount(const aMethodName.optional aEventParams parameter will be transmitted to aEvent handler .raise an Exception if the method name does not exist for this interface function Executes(const aMethodName: RawUTF8. aEvent: TOnInterfaceStubExecuteJSON.it will raise EInterfaceFactoryException for TInterfaceStub.if execution context matches the supplied aParams value. but TInterfaceMock will push the failure to the associated test case ..18 Date: June 16.those rules will be evaluated at Destroy execution .those rules will be evaluated at Destroy execution .Create(TypeInfo(ICalculator). with JSON marshalling . const aParams: array of const.pas unit . aEvent: TOnInterfaceStubExecuteJSON. Add an execution rule for a given method and a set of parameters. const aEventParams: RawUTF8=''): TInterfaceStub. aValue: cardinal): TInterfaceStub. overload. Add a pass count expectation rule for a given method and a set of parameters . Add a hash-based execution expectation rule for a given method and a set of parameters .it will raise EInterfaceFactoryException for TInterfaceStub.an error will be returned to the caller.those rules will be evaluated at Destroy execution .raise an Exception if the method name does not exist for this interface function ExpectsTrace(const aMethodName: RawUTF8.those rules will be evaluated at Destroy execution . but TInterfaceMock will push the failure to the associated test case . const aParams: array of const. aParams: RawUTF8. overload. aValue: cardinal): TInterfaceStub. but TInterfaceMock will push the failure to the associated test case . with aErrorMsg as message .Synopse mORMot Framework Software Architecture Design 1.it will raise EInterfaceFactoryException for TInterfaceStub.raise an Exception if the method name does not exist for this interface function ExpectsTrace(aValue: cardinal): TInterfaceStub. aValue: cardinal): TInterfaceStub.only qoEqualTo.supplied aValue is a Hash32() of the trace in LogAsText format .it will raise EInterfaceFactoryException for TInterfaceStub. but TInterfaceMock will push the failure to the associated test case function ExpectsTrace(const aMethodName: RawUTF8. 2013 function ExpectsCount(const aMethodName: RawUTF8. const aErrorMsg: RawUTF8): TInterfaceStub. but TInterfaceMock will push the failure to the associated test case .it will raise EInterfaceFactoryException for TInterfaceStub. 1. overload..qoGreaterThanOrEqualTo are relevant here .raise an Exception if the method name does not exist for this interface mORMot.supplied aValue is a Hash32() of the trace in LogAsText format . aValue: cardinal): TInterfaceStub. Add a hash-based execution expectation rule for the whole interface .it will raise EInterfaceFactoryException for TInterfaceStub. overload. const aParams: array of const. but TInterfaceMock will push the failure to the associated test case .Rev. Add an error rule for a given method and a set of parameters . Add a hash-based execution expectation rule for a given method . aOperator: TSQLQueryOperator.raise an Exception if the method name does not exist for this interface function Fails(const aMethodName: RawUTF8.those rules will be evaluated at Destroy execution . Add a hash-based execution expectation rule for a given method and a set of parameters . overload.18 Page 805 of 1055 . const aParams: array of const.those rules will be evaluated at Destroy execution .supplied aValue is a Hash32() of the trace in LogAsText format .raise an Exception if the method name does not exist for this interface function ExpectsTrace(const aMethodName.those rules will be evaluated at Destroy execution . overload.18 Date: June 16.it will raise EInterfaceFactoryException for TInterfaceStub.pas unit . but TInterfaceMock will push the failure to the associated test case .supplied aValue is a Hash32() of the trace in LogAsText format . const aMessage: string): TInterfaceStub. overload.18 Date: June 16. Add an evaluation rule for a given method and a set of parameters . overload.will create and raise the specified exception for this method.aExpectedResults will be returned to the caller after conversion to a JSON array .raise an Exception if the method name does not exist for this interface mORMot. aExpectedResults: array of const): TInterfaceStub. but TInterfaceMock will push the failure to the associated test case .will create and raise the specified exception for this method. Add an exception rule for a given method and a set of parameters .an error will be returned to the caller. Add an evaluation rule for a given method . overload.raise an Exception if the method name does not exist for this interface function Fails(const aMethodName. aException: ExceptClass. const aParams.aExpectedResults JSON array will be returned to the caller . overload. const aMessage: string): TInterfaceStub. Add an exception rule for a given method . aErrorMsg: RawUTF8): TInterfaceStub. aParams. with aErrorMsg as message .Synopse mORMot Framework Software Architecture Design 1.Rev. overload.raise an Exception if the method name does not exist for this interface function Returns(const aMethodName. overload. aParams: RawUTF8. Add an evaluation rule for a given method .raise an Exception if the method name does not exist for this interface function Raises(const aMethodName. aErrorMsg: RawUTF8): TInterfaceStub.raise an Exception if the method name does not exist for this interface function Returns(const aMethodName: RawUTF8.18 Page 806 of 1055 .pas unit . Add an error rule for a given method and a set of parameters .will create and raise the specified exception for this method . overload. Add an error rule for a given method . aExpectedResults: RawUTF8): TInterfaceStub. aException: ExceptClass. const aMessage: string): TInterfaceStub. if the execution context matches the supplied aParams value .raise an Exception if the method name does not exist for this interface function Raises(const aMethodName: RawUTF8.it will raise EInterfaceFactoryException for TInterfaceStub.it will raise EInterfaceFactoryException for TInterfaceStub. aException: ExceptClass.raise an Exception if the method name does not exist for this interface function Returns(const aMethodName: RawUTF8.raise an Exception if the method name does not exist for this interface function Raises(const aMethodName: RawUTF8. Add an exception rule for a given method and a set of parameters . but TInterfaceMock will push the failure to the associated test case . if the execution context matches the supplied aParams value .aExpectedResults JSON array will be returned to the caller . const aParams: array of const. const aExpectedResults: array of const): TInterfaceStub. 1. overload. with aErrorMsg as message . 2013 function Fails(const aMethodName.an error will be returned to the caller. 18 Page 807 of 1055 . aParams.you shall have registered the interface by a previous call to TInterfaceFactory.you can use the SetOptions() method in a fluent-style interface TInterfaceMock = class(TInterfaceStub) Used to mock an interface implementation via expect-run-verify . ExpectsCount() or ExpectsTrace() rule activation.TInterfaceStub will raise an exception on Fails(). Set the optional stubing/mocking options . Access to the registered Interface RTTI information property Log: TInterfaceStubLogDynArray read fLogs.aExpectedResults JSON array will be returned to the caller . The stubbed method execution trace converted as one numerical hash .returns Hash32(LogAsText) property Options: TInterfaceStubOptions read fOptions write IntSetOptions.typical output is a list of calls separated by commas: Add(10. and verification is performed when the instance is released . The stubbed method execution trace items property LogAsText: RawUTF8 read GetLogAsText.Get(TypeInfo(IMyInterface)) or RegisterInterfaces() . overload. Initialize an interface mock from an interface name (e.Check() will be called in case of mocking failure . but TInterfaceMock will call TSynTestCase.Synopse mORMot Framework Software Architecture Design 1. aExpectedResults: RawUTF8): TInterfaceStub.Rev. overload. expectations are defined before running the test. raise an Exception mORMot.this class will follow the expect-run-verify pattern. aTestCase: TSynTestCase). out aMockedInterface. 1. Add an evaluation rule for a given method and a set of parameters .e. as expected by a mocked interface .20)=[30].18 Date: June 16. The stubbed method execution trace number of items property LogHash: cardinal read GetLogHash.use TInterfaceMockSpy if you prefer the more explicit run-verify pattern constructor Create(const aInterfaceName: RawUTF8.if the supplied name has not been previously registered. Optional stubing/mocking options .0) error "divide by zero" property LogCount: Integer read fLogCount.aTestCase.Divide(20. but in a fluent-style interface property InterfaceFactory: TInterfaceFactory read fInterface.Check() with no exception with such rules. i. reintroduce.pas unit . 'IMyInterface') .raise an Exception if the method name does not exist for this interface function SetOptions(Options: TInterfaceStubOptions): TInterfaceStub. 2013 function Returns(const aMethodName.g. The stubbed method execution trace converted as text .same as the Options property. out aMockedInterface. reintroduce.text trace format will follow specified scope.35)=[37]'. i.e. Initialize an interface mock from TypeInfo(IMyInterface) .Synopse mORMot Framework Software Architecture Design 1.35].'[37]'). reintroduce. Check an execution trace for a specified method and parameters . or include parameters and function results: Verify('Add'. aTrace: RawUTF8). but all calls are internally logged (i. overload.g. 1. const aTrace: RawUTF8).'(10.Get(TypeInfo(IMyInterface)) or RegisterInterfaces() .e. no expectation is to be declared at first. raise an Exception constructor Create(aInterface: PTypeInfo. overload.if aMethodName does not exists or aScope=chkName.[2.Check() will be called in case of mocking failure .'(10.18 Date: June 16.Rev.(2. Initialize an interface mock from an interface GUID .if the supplied TGUID has not been previously registered. overload. e. aParams.'2. it force imoLogMethodCallsAndResults option to be defined).aTestCase. aTestCase: TSynTestCase). Check an execution trace for a specified method .30)=[300]. Verify('Add'. overload.Check() will be called in case of mocking failure property TestCase: TSynTestCase read fTestCase.30).text trace format shall contain only results.35)'. Check an execution trace for a specified method and parameters .you shall have registered the interface by a previous call to TInterfaceFactory. will raise an exception procedure Verify(const aMethodName. Verify('Add'. Verify('Add'.text trace format shall contain only results. out aMockedInterface. overload.35'.'[37]').(2. aScope: TInterfaceMockSpyCheck). aTrace: RawUTF8.aTestCase.g. The associated test case TInterfaceMockSpy = class(TInterfaceMock) Used to mock an interface implementation via run-verify .18 Page 808 of 1055 . e.chkNameParamsResults). aTestCase: TSynTestCase).g. and can afterwards been check via Verify() calls procedure Verify(const aMethodName.this class will implement a so called "test-spy" mocking pattern. e. const aParams: array of const.chkNameParams). . procedure Verify(const aMethodName: RawUTF8. 2013 constructor Create(const aGUID: TGUID.pas unit . mORMot. TSQLRestClientURI will have to register an interface remote access as: Client.30)=[300].parameters shall be defined as a JSON array of values procedure Verify(const aMethodName: RawUTF8. .chkName).Rev. aCount: cardinal=0). or by a on-the-fly generated fake TInterfacedObject class communicating via JSON on a client . available as one TSQLServiceContainer item from TSQLRest.TSQLRestServer will have to register an interface implementation as: Server. Check an execution trace for the global interface .ServiceRegister(TServiceCalculator.g. aOperator: TSQLQueryOperator=qoGreaterThan.Add(2. and prepare all internal structures for its serialized execution mORMot. or may include parameters: Verify('Multiply(10.Add(10. e.it will check and retrieve all methods of the supplied interface. 2013 procedure Verify(const aTrace: RawUTF8.GUID(IID_ICalculator). aInstanceCreation: TServiceInstanceImplementation. aOperator: TSQLQueryOperator=qoGreaterThan. Check that a method has been called a specify number of times procedure Verify(const aMethodName.35)=[37]'. overload.20). aCount: cardinal=0).5 (page 1051). const aParams: array of const. e.Services property . procedure Verify(const aMethodName: RawUTF8. aParams: RawUTF8. as: if Services.18 Date: June 16.parameters shall be defined as a JSON array of values TServiceFactory = class(TObject) An abstract service provider.text trace format shall follow method calls. constructor Create(aRest: TSQLRest.then TSQLRestServer and TSQLRestClientURI will both have access to the service. Check a method calls count with a set of parameters .g. 1.30). aInterface: PTypeInfo. Initialize the service provider parameters .pas unit . overload.Get(I) then result := I.this will be either implemented by a registered TInterfacedObject on the server.sicShared). overload. via their Services property.Add'. or include parameters and function results: Verify('Multiply(10. const aContractExpected: RawUTF8). Check a method calls count with a set of parameters .ServiceRegister([TypeInfo(ICalculator)]. Used for DI-2. aOperator: TSQLQueryOperator=qoGreaterThan.chkNameParamsResults).sicShared)).Add(2.18 Page 809 of 1055 .chkNameParams).each registered interface has its own TServiceFactory instance. note that the implementation (TServiceCalculator) remain on the server side only: the client only needs the ICalculator interface . aScope: TInterfaceMockSpyCheck). overload.35)'. Verify('Multiply.[TypeInfo(ICalculator)].1.Synopse mORMot Framework Software Architecture Design 1. aCount: cardinal=0). as registered in TServiceContainer . Synopse mORMot Framework Software Architecture Design 1. will contain ContractHash property value (for security) .this may be used instead of the JSON signature.Add(n1. "methods":[{"method":"Add".n2: integer): integer."type":"integer"} ]}]} property ContractExpected: RawUTF8 read fContractExpected write fContractExpected.a "contract" is in fact the used interface signature."type":"self"}. if you do not want to publish the available methods. both TServiceFactoryClient and TServiceFactoryServer instances must have a matching ContractExpected .Rev. serialized as a JSON object . but want to check for the proper synchronization of both client and server) .is always available on TServiceFactoryServer. for security reasons) property Contract: RawUTF8 read fContract. its implementation mode (InstanceCreation) and all its methods definitions .18 Date: June 16."type":"integer"}.a possible value for a one-method interface defined as such: function ICalculator.g."direction":"in".Services. A hash of the service contract. Retrieve an instance of this interface . i. virtual. to be checked in TServiceFactoryClient."params":[]} (e.pas unit .) {"method":"_contract_". Retrieve the published signature of this interface .. as expected by both client and server .by default. use I function RetrieveSignature: RawUTF8. {"argument":"n2". abstract. The published service contract. {"argument":"Result".PublishSignature is set to TRUE (which is not the default setting. 1.Get(I) then ... virtual."type":"integer"}.e.e.can be used as such to resolve an I: ICalculator interface if fClient. may be returned as the following JSON object: {"contract":"Calculator".Create constructor) property ContractHash: RawUTF8 read fContractHash. {"argument":"n1". a custom version number) .this virtual method will be overriden to reflect the expected behavior of client or server side ._contract_ or (if rmJSON_RPC is used): POST /root/Interface (. 2013 function Get(out Obj): Boolean.in this case.this value is returned by a '_contract_' pseudo-method name."direction":"in". with the URI: POST /root/Interface."direction":"out". but TServiceFactoryClient will be able to retrieve it only if TServiceContainerServer..18 Page 810 of 1055 .but you can override this value using plain Contract or any custom value (e."direction":"in". abstract.a possible value may be: "C351335A7406374C" mORMot. The service contract. serialized as a JSON string ."implementation":"shared". "arguments":[{"argument":"Self". to enhance security (i.g.Info(TypeInfo(ICalculator)). this class will be accessed only to retrieve a remote access instance. Last time stamp access of this instance procedure SafeFreeInstance(ReleaseInMainThread: boolean). 1. 2013 property InstanceCreation: TServiceInstanceImplementation read fInstanceCreation.can be substituted to the clear InterfaceURI name property InterfaceTypeInfo: PTypeInfo read GetInterfaceTypeInfo.just maps InterfaceFactory. ['{c9a646d3-9c61-4cb7-bfcd-ee2522c8f633}'] into '00amyWGct0y_ze4lIsj2Mw' .pas unit . i.used by TServiceFactoryServer in sicClientDriven.18 Page 811 of 1055 .direct FreeAndNil(Instance) may lead to A/V if self has been assigned to an interface to any sub-method on the server side -> dec(RefCount) mORMot.g. The registered Interface GUID .e. The internal Instance ID.InterfaceTypeInfo property InterfaceURI: RawUTF8 read fInterfaceURI. e.just maps InterfaceFactory. sicPerSession. The implementation instance itself InstanceID: Cardinal. The registered Interface low-level Delphi RTTI type . e.Rev.18 Date: June 16. Access to the registered Interface RTTI information property InterfaceIID: TGUID read GetInterfaceIID.InterfaceIID property InterfaceMangledURI: RawUTF8 read fInterfaceMangledURI. The associated RESTful instance TServiceFactoryServerInstance = object(TObject) Server-side service provider uses this to store one internal instance . How each class instance is to be created .only relevant on the server side.in fact this is the Interface name without the initial 'I'.Synopse mORMot Framework Software Architecture Design 1. sicPerUser or sicPerGroup mode Instance: TInterfacedObject. The registered Interface URI . 'Calculator' for ICalculator property Rest: TSQLRest read fRest. sicSingle property InterfaceFactory: TInterfaceFactory read fInterface. The registered Interface mangled URI .in fact this is encoding the GUID using BinToBase64URI(). on the client side.g.is set to 0 when an entry in the array is free LastAccess: Cardinal. Used to release the implementation instance . as remotely sent in "id":1 . DenyAll.will handle the implementation class instances of a given interface .Rev. This virtual constructor will be called at instance creation TPersistentWithCustomCreate = class(TPersistent) Abstract parent class with a virtual constructor. sicPerSession. This virtual constructor will be called at instance creation TServiceFactoryServer = class(TServiceFactory) A service provider implemented on the server side .ServiceRegister() if you need an interfaced object with a virtual constructor constructor Create.Services property .expect an direct server-side implementation class (inheriting from TInterfacedClass or from TInterfacedObjectWithCustomCreate if you need an overriden constructor) . reintroduce.18 Page 812 of 1055 . all methods are allowed to execution: you can call AllowAll. aTimeOutSec: cardinal=30*60). aInterface: PTypeInfo.e.you should usualy have to call the TSQLRestServer.18 Date: June 16.each registered interface has its own TServiceFactoryServer instance. Allow or Deny in order to specify your exact security policy Used for DI-2. interface will be forced in sicSingle mode .1. available as one TSQLServiceContainerServer item from TSQLRest. any internal TServiceFactoryServerInstance instances (any shared instance.if the time out is 0. 1. ready to be overriden to initialize the instance . constructor Create(aRestServer: TSQLRestServer. 2013 TInterfacedObjectWithCustomCreate = class(TInterfacedObject) Abstract parent class with threadsafe implementation of IInterface and a virtual constructor. const aContractExpected: RawUTF8=''.for sicClientDriven.pas unit . and all still living instances in sicClientDrive mode) mORMot. ready to be overriden to initialize the instance .you can specify such a class if you need an interfaced object with a virtual constructor constructor Create.you can specify such a class to TSQLRestServer.Synopse mORMot Framework Software Architecture Design 1. aInstanceCreation: TServiceInstanceImplementation. Release all used memory .by default.ServiceRegister() method instead of calling this constructor directly destructor Destroy. sicPerUser or sicPerGroup modes. aImplementationClass: TInterfacedClass. virtual. virtual.5 (page 1051). a time out (in seconds) can be defined . override.g. Initialize the service provider on the server side . you can retrieve a TSQLAuthGroup ID from its identifier.this method returns self in order to allow direct chaining of security calls.methods names should be specified as an array (e.Rev. Allow all methods execution for the specified TSQLAuthGroup ID(s) . ['Add'.this method returns self in order to allow direct chaining of security calls.MainFieldID(TSQLAuthGroup.all Groups will be affected by this method (on both client and server sides) .g. 1.'User'). retrieving the Group ID from its main field .this method returns self in order to allow direct chaining of security calls.'Multiply']) .18 Date: June 16.you can retrieve a TSQLAuthGroup ID from its identifier.is just a wrapper around the other AllowByID() method.'Multiply']) . in a fluent interface function AllowAllByID(const aGroupID: array of integer): TServiceFactoryServer.all Groups will be affected by this method (on both client and server sides) . in a fluent interface function AllowByID(const aMethod: array of RawUTF8. ['Add'.18 Page 813 of 1055 . Deny specific methods execution for the all TSQLAuthGroup .g.this method returns self in order to allow direct chaining of security calls. in a fluent interface function AllowAllByName(const aGroup: array of RawUTF8): TServiceFactoryServer. Allow specific methods execution for the specified TSQLAuthGroup name(s) .this method returns self in order to allow direct chaining of security calls.'Multiply']) .g.this method returns self in order to allow direct chaining of security calls. ['Add'.the specified group ID(s) will be used to authorize remote service calls from the client side . in a fluent interface mORMot.is just a wrapper around the other AllowAllByID() method. in a fluent interface function DenyAll: TServiceFactoryServer.methods names should be specified as an array (e. const aGroup: array of RawUTF8): TServiceFactoryServer.'Multiply']) .the specified group ID(s) will be used to authorize remote service calls from the client side . in a fluent interface function AllowAll: TServiceFactoryServer.methods names should be specified as an array (e.'User'). .MainFieldID(TSQLAuthGroup. as such: UserGroupID := fServer.pas unit . 2013 function Allow(const aMethod: array of RawUTF8): TServiceFactoryServer.Synopse mORMot Framework Software Architecture Design 1. as such: UserGroupID := fServer. Allow all methods execution for the specified TSQLAuthGroup names .g. Allow specific methods execution for the all TSQLAuthGroup . in a fluent interface function Deny(const aMethod: array of RawUTF8): TServiceFactoryServer. Allow all methods execution for all TSQLAuthGroup . ['Add'. retrieving the Group ID from its main field . .all Groups will be affected by this method (on both client and server sides) . const aGroupID: array of integer): TServiceFactoryServer. Allow specific methods execution for the specified TSQLAuthGroup ID(s) .this method returns self in order to allow direct chaining of security calls.methods names should be specified as an array (e.this method returns self in order to allow direct chaining of security calls.all Groups will be affected by this method (on both client and server sides) . Deny all methods execution for all TSQLAuthGroup . in a fluent interface function AllowByName(const aMethod: array of RawUTF8. override.this method returns self in order to allow direct chaining of security calls. Deny all methods execution for the specified TSQLAuthGroup ID(s) .is always available on TServiceFactoryServer.Rev.'User'). ['Add'.methods names should be specified as an array (e.you can retrieve a TSQLAuthGroup ID from its identifier.MainFieldID(TSQLAuthGroup.g.this method returns self in order to allow direct chaining of security calls. . as such: UserGroupID := fServer. in a fluent interface function DenyByName(const aMethod: array of RawUTF8.the specified group ID(s) will be used to unauthorize remote service calls from the client side .18 Date: June 16.MainFieldID(TSQLAuthGroup. 2013 function DenyAllByID(const aGroupID: array of integer): TServiceFactoryServer. const aGroup: array of RawUTF8): TServiceFactoryServer. from server side: in fact. override.all other kind of instance creation will behave the same as sicSingle when accessed directly from this method. user nor group function RestServer: TSQLRestServer. as such: UserGroupID := fServer.'User'). i. retrieving the Group ID from its main field .e.this method returns self in order to allow direct chaining of security calls. Deny specific methods execution for the specified TSQLAuthGroup name(s) . 1. on the server side. in a fluent interface function DenyAllByName(const aGroup: array of RawUTF8): TServiceFactoryServer. Dent all methods execution for the specified TSQLAuthGroup names . const aGroupID: array of integer): TServiceFactoryServer.18 Page 814 of 1055 .the specified group ID(s) will be used to authorize remote service calls from the client side . session. Just typecast the associated TSQLRest instance to a true TSQLRestServer function RetrieveSignature: RawUTF8.g. Retrieve the published signature of this interface .is just a wrapper around the other DenyAllByID() method.you can retrieve a TSQLAuthGroup ID from its identifier. overload. retrieving the Group ID from its main field . in a fluent interface function Get(out Obj): Boolean.Synopse mORMot Framework Software Architecture Design 1.methods names should be specified as an array (e. Deny specific methods execution for the specified TSQLAuthGroup ID(s) . .is just a wrapper around the other DenyByID() method. but TServiceFactoryClient will be able to retrieve it only if TServiceContainerServer. ['Add'. for security reasons) mORMot.'Multiply']) . there is no notion of client.sicPerThread mode will retrieve the instance corresponding to the current running thread .pas unit .sicShared mode will retrieve the shared instance .this method returns self in order to allow direct chaining of security calls.PublishSignature is set to TRUE (which is not the default setting. in a fluent interface function DenyByID(const aMethod: array of RawUTF8.'Multiply']) . Retrieve an instance of this interface from the server side . also set the inherited TServiceInstanceImplementation property . Retrieve an instance of this interface from the server side mORMot. Finalize the service provider used instance .for sicClientDriven.18 Page 815 of 1055 .it will check and retrieve all methods of the supplied interface. override. in a fluent interface property TimeoutSec: cardinal read GetTimeoutSec write SetTimeoutSecInt.pas unit .18 Date: June 16.g. aInterface: PTypeInfo.e. but thread-safe function SetTimeoutSec(value: cardinal): TServiceFactoryServer.will emulate "fake" implementation class instance of a given interface and call remotely the server to process the actual implementation Used for DI-2. const aContractExpected: RawUTF8='').'Multiply']) . sicPerSession.Synchronize() call . sicPerSession. Define the the instance life time-out.raise an exception for other kind of execution .this method returns self in order to allow direct chaining of setting calls for the service.initialize fSharedInstance if aInstanceCreation is sicShared . ['Add'. either by comparing the default signature (based on methods and arguments).raise an exception for other kind of execution . The instance life time-out. Initialize the service provider parameters . in seconds .e.1.g.you can also use the SetTimeOutSec() fluent function instead TServiceFactoryClient = class(TServiceFactory) A service provider implemented on the client side . sicPerUser or sicPerGroup modes . Define execution options for a given set of methods .it will also ensure that the corresponding TServiceFactory. sicPerUser or sicPerGroup modes . 1.Services property . 2013 function SetOptions(const aMethod: array of RawUTF8. in seconds .5 (page 1051). []).slower. override. constructor Create(aRest: TSQLRest.methods names should be specified as an array (e.Synopse mORMot Framework Software Architecture Design 1. aInstanceCreation: TServiceInstanceImplementation. either by using the supplied expected contract (which may be a custom version number) destructor Destroy.if no method name is given (i. the shared fake implementation instance function Get(out Obj): Boolean.Contract matches on both client and server sides.each registered interface has its own TServiceFactoryClient instance. option will be set for all methods .include optExecInMainThread will force the method(s) to be called within a RunningThread.for sicClientDriven.Rev. and prepare all internal structures for its serialized execution . aOptions: TServiceMethodOptions): TServiceFactoryServer. available as one TSQLServiceContainerClient item from TSQLRest. Synopse mORMot Framework Software Architecture Design 1. overload. overload. Retrieve a service provider from its index in the list .overloaded method returning the corresponding service factory client. use I function Index(aIndex: integer): TServiceFactory.will return true if some interfaces have been added .ServiceRegister or even by TSQLRestServer. constructor Create(aRest: TSQLRest). aContractExpected: RawUTF8=''): boolean.returns nil if the GUID does not match any registered interface .. Method called on the client side to register a service via its interface(s) . Method called on the client side to register a service via one interface . Return the number of registered service interfaces function GUID(const aGUID: TGUID): TServiceFactory. Retrieve a service provider from its GUID .g.Get(I) then . with an optional custom contract to be used instead of methods signature (only for the first interface) function Count: integer.ServiceRegister(aClient: TSQLRest.18 Page 816 of 1055 . or nil on error function AddInterface(const aInterfaces: array of PTypeInfo. const aContractExpected: RawUTF8=''): TServiceFactoryClient.. overload.will check for the availability of the interfaces on the server side. Release all registered services function AddInterface(aInterface: PTypeInfo.AddImplementation() instead for normal server side implementation .PublishSignature is set to TRUE (which is not the default setting..will add a TServiceFactoryClient instance to the internal list . aInstanceCreation: TServiceInstanceImplementation.5 (page 1051).GUID(IID_ICalculator). overload.1.18 Date: June 16.this function is always available on TServiceFactoryServer side TServiceContainer = class(TObject) A global services provider class . aInstanceCreation: TServiceInstanceImplementation.used to maintain a list of interfaces implementation Used for DI-2. Initialize the list destructor Destroy..will raise an exception on error .use TServiceContainerServer.on match.Services.) for a remote access . for security reasons) . by TSQLRestClientURI. override.can be used as such to resolve an I: ICalculator interface if fClient.returns nil if out of range index mORMot. override. Retrieve the published signature of this interface .TServiceFactoryClient will be able to retrieve it only if TServiceContainerServer. 1.pas unit . 2013 function RetrieveSignature: RawUTF8.Rev. it will return the service the corresponding interface factory .is called e. '00amyWGct0y_ze4lIsj2Mw' or 'Calculator'.this will maintain a list of true implementation classes Used for DI-2.g. the mangled URI value will be expected instead (may enhance security) . '00amyWGct0y_ze4lIsj2Mw' property Rest: TSQLRest read fRest. The associated RESTful instance property Services[const aURI: RawUTF8]: TServiceFactory read GetService.Synopse mORMot Framework Software Architecture Design 1. Set if the URI is expected to be mangled from the GUID . overload.it expects the supplied URI variable to be e. Method called on the server side to register a service via its interface(s) and a specified implementation class . 1.e..if this property is set to TRUE. it will return the service the corresponding interface factory . if any of the supplied interfaces is not implemented by the given class) . aInstanceCreation: TServiceInstanceImplementation): TServiceFactoryServer.the same implementation class can be used to handle several interfaces (just as Delphi allows to do natively) mORMot.e.on match. virtual. the one corresponding to the first item of the aInterfaces array).will return the first of the registered TServiceFactoryServer created on success (i.g.returns nil if the URI does not match any registered interface TServiceContainerServer = class(TServiceContainer) A services provider class to be used on the server side . it will return the service the corresponding interface factory .can be used as such to resolve an I: ICalculator interface if fClient.1. use I property ExpectMangledURI: boolean read fExpectMangledURI write SetExpectMangledURI.Rev.pas unit ..returns nil if the type information does not match any registered interface . 2013 function Info(aTypeInfo: PTypeInfo): TServiceFactory.5 (page 1051). Retrieve a service provider from its type information .will raise an exception on error .will add a TServiceFactoryServer instance to the internal list . the clear service name is expected to be supplied at the URI level (e. or nil if registration failed (e.g. function AddImplementation(aImplementationClass: TInterfacedClass.by default (FALSE).18 Page 817 of 1055 .on match. 'Calculator') . Retrieve a service provider from its URI . depending on the ExpectMangledURI property .g.Services.Get(I) then . const aInterfaces: array of PTypeInfo.18 Date: June 16.Info(TypeInfo(ICalculator)). Retrieve a service provider from its type information . encoded as a JSON object .g. Corresponding ID JSON: RawUTF8.18 Date: June 16. The whole specified Table content will be cached CacheEnable: boolean.e. which will remotely call the server to make the actual process Used for DI-2.equals 0 licwhen there is no JSON value cached TSQLRestCacheEntry = object(TObject) For TSQLRestCache.ContractExpected TServiceContainerClient = class(TServiceContainer) A services provider class to be used on the client side . if was not set. 2013 property PublishSignature: boolean read fPublishSignature write fPublishSignature. in-memory table) Count: integer. function Info(aTypeInfo: PTypeInfo): TServiceFactory.in this case. Defines if the "method":"_signature_" or /root/Interface. GetTickCount value when this cached value was stored . if was not yet made . JSON encoded UTF-8 serialization of the record TimeStamp: cardinal._signature pseudo method is available to retrieve the whole interface signature. for security reasons: only "_contract_" pseudo method is available see TServiceContainer.is set to FALSE by default.this overriden method will register the interface.18 Page 818 of 1055 .5 (page 1051).i. stores a table settings and values CacheAll: boolean.this will maintain a list of fake implementation classes. override. stores a table values ID: integer.pas unit . Used to lock the table cache for multi thread safety mORMot. the interface will be registered with sicClientDriven implementation method TSQLRestCacheEntryValue = record For TSQLRestCache. The number of entries stored in Values[] Mutex: TRTLCriticalSection. TRUE if this table should use caching . overload. or worth it for this table (e.Synopse mORMot Framework Software Architecture Design 1. 1.1.Rev. this caching will be located at the TSQLRest level.18 Date: June 16.Synopse mORMot Framework Software Architecture Design 1. a complex direct SQL UPDATE or via TSQLRecordMany pattern won't be taken in account) . Release the cache instance function CachedEntries: cardinal. TDynArray wrapper around the Values[] array Values: TSQLRestCacheEntryValueDynArray.only Simple fields are cached: e.pas unit . var aJSON: RawUTF8): boolean. Retrieve a JSON serialization of a given ID from cache procedure FlushCacheAllEntries. All cached IDs and JSON content function RetrieveJSON(aID: integer. Returns the number of JSON serialization records within this cache mORMot. 2013 TimeOut: Cardinal. overload. Create a cache instance .g. ADD. Flush cache for a given Value[] index procedure SetJSON(aID: integer. Update/refresh the cached JSON serialization of a supplied Record TSQLRestCache = class(TObject) Implement a fast cache content at the TSQLRest level . reintroduce. Time out value (in ms) . aValue: TSQLRecord): boolean. Update/refresh the cached JSON serialization of a given ID procedure SetJSON(aRecord: TSQLRecord). Unserialize a JSON cached record of a given ID function RetrieveJSON(aID: integer.only caching synchronization is about the following RESTful basic commands: RETRIEVE.purpose of this caching mechanism is to speed up retrieval of some common values at either Client or Server level (like configuration settings) .the associated TSQLModel will be used internaly destructor Destroy.18 Page 819 of 1055 . overload. overload.Rev. const aJSON: RawUTF8). Flush cache for all Value[] procedure FlushCacheEntry(Index: Integer). that is no automated synchronization is implemented between TSQLRestClient and TSQLRestServer: you shall ensure that your code won't fail due to this restriction constructor Create(aRest: TSQLRest).this cache is thread-safe (access is locked per table) . caching will never expire Value: TDynArray. the BLOB fields are not stored .if 0. override. overload. DELETION and UPDATE (that is. 1. serializing the supplied aRecord content as JSON (not in the case of seDelete) mORMot. aID: Integer): boolean.if aTimeOut is left to its default 0 value.this overloaded method will call the other Trace method. do nothing .18 Page 820 of 1055 .will cache the specified aRecord.this will flush all stored JSON content.return true on success function SetTimeOut(aTable: TSQLRecordClass.if this item is already cached. Returns the memory used by JSON serialization records within this cache function SetCache(aTable: TSQLRecordClass. Activate the internal caching for a whole Table .return true on success procedure Clear.return true on success function SetCache(aRecord: TSQLRecord): boolean.this will flush all stored JSON content. aTimeout: Integer): boolean. Activate the internal caching for a given TSQLRecord .this will flush the stored JSON content for this record (and table settings will be kept) procedure Notify(aRecord: TSQLRecord. 2013 function CachedMemory: cardinal. and destroy all settings .pas unit .Synopse mORMot Framework Software Architecture Design 1. AND destroy the settings (SetCache/SetTimeOut) to default (i. overload. Flush the cache for a given record . Flush the cache for a given table .any cached item of this table will be flushed . overload.time out setting is common to all items of the table .Rev. overload. Flush the cache. overload.this will flush all stored JSON content. TSQLRest instance shall call this method when a record is added or updated . aID: integer). Activate the internal caching for a given TSQLRecord . overload.ID item . do nothing . overload. overload. but keep the settings (SetCache/SetTimeOut) as before procedure Flush(aTable: TSQLRecordClass).e. caching will never expire . but keep the settings (SetCache/SetTimeOut) as before for this table procedure Flush(aTable: TSQLRecordClass.18 Date: June 16.return true on success function SetCache(aTable: TSQLRecordClass): boolean. 1.if this item is already cached. aAction: TSQLOccasion). no cache enabled) procedure Flush. Flush the cache . Set the internal caching time out delay (in ms) for a given table . ForceID: boolean=false): integer. aAction: TSQLOccasion). Value. overload. client sends the current content of Value with the request.18 Page 821 of 1055 . returns 0 .1. and TSQLRecordClass to be specified as its index in Rest. abstract.ID is updated with the new ROWID .this method is dedicated for a record deletion . override.Synopse mORMot Framework Software Architecture Design 1.1.ID field to use this ID for adding the record (instead of a database-generated ID) . client sends the Value. const aJSON: RawUTF8.the TSQLRawBlob(BLOB) fields values are not set by this method. SendData: boolean. overload. Read-only access to the associated TSQLRest instance TSQLRest = class(TObject) A generic REpresentational State Transfer (REST) client/server class Used for DI-2. aID: integer. with dedicated methods to access to the separated pivot table mORMot. Create a new member (implements REST POST Collection) . TSQLRest instance shall call this method when a record is deleted .pas unit . overload. QueryCustom: array of TSQLQueryCustom.Create. overload.if SendData is true. TSQLRest instance shall call this method when a record is deleted . on error.Tables[] procedure Notify(aTable: TSQLRecordClass.on success.e.the TSQLRecordMany fields are not set either: they are separate instances created by TSQLRecordMany. aAction: TSQLOccasion).1 (page 1047).TSQLRecordClass to be specified as its index in Rest.Tables[] procedure NotifyDeletion(aTable: TSQLRecordClass.18 Date: June 16.1 (page 1047). added or updated . 2013 procedure Notify(aTableIndex: integer. overload.Model.1.this overloaded method expects the content to be specified as JSON object. to preserve bandwidth . aID: integer). TSQLRest instance shall call this method when a record is added or updated . const aJSON: RawUTF8. 1. virtual. virtual. Release internal used instances .Model.this method is dedicated for a record deletion property Rest: TSQLRest read fRest. returns the new ROWID value.this overloaded method expects the content to be specified as JSON object procedure NotifyDeletion(aTableIndex. otherwize record is created with default values .on success. release associated TSQLModel or TServiceContainer function Add(Value: TSQLRecord. TSQLRest instance shall call this method when a record is retrieved. and associate it to a specified database Model destructor Destroy. aID: integer). Initialize the class.g.if ForceID is true. aID: integer. The custom queries parameters for User Interface Query action constructor Create(aModel: TSQLModel).Rev. DI-2. 18 Date: June 16.this default method call RecordCanBeUpdated() to check if it is possible function Delete(Table: TSQLRecordClass. 1. then will delete each row using protected EngineDeleteWhere() virtual method function Delete(Table: TSQLRecordClass.[]. virtual.return a result table on success. client sends this ID to be used when adding the record (instead of a database-generated ID) .BoundsSQLWhere)) function ExecuteList(const Tables: array of TSQLRecordClass. nil on failure function FTSMatch(Table: TSQLRecordFTS3Class. Delete a member (implements REST DELETE Member) .if ForcedID is set to non null. abstract. 2013 function Add(aTable: TSQLRecordClass. Create a new member.it will run Delete(Table. const WhereClause: RawUTF8. var DocID: TIntegerDynArray): boolean. ForcedID: integer=0): integer.. const aSimpleFields: array of const.example of use: FTSMatch(TSQLMessage. returns the new ROWID value. the WHERE clause should use bound parameters identified as '?' in the FormatSQLWhere statement.'Body MATCH :("linu*"):'.return true on success .Rev. virtual. overload. const BoundsSQLWhere: array of const): boolean.): is always a good idea) mORMot. Delete a member with a WHERE clause (implements REST DELETE Member) .. FormatSQLWhere: PUTF8Char.18 Page 822 of 1055 .the aSimpleFields parameters must follow explicitely the order of published properties of the supplied aTable class. overload. overload. const SQL: RawUTF8): TSQLTableJSON.pas unit . Execute directly a SQL statement. only so called "simple fields") .the aSimpleFields must have exactly the same count of parameters as there are "simple fields" in the published properties . from a supplied list of field values .return true on success . Dedicated method used to retrieve free-text matching DocIDs . const SQLWhere: RawUTF8): boolean. on error. overload. overload. Delete a member with a WHERE clause (implements REST DELETE Member) .use DateToSQL/DateTimeToSQL for TDateTime. virtual. excepting the TSQLRawBlob and TSQLRecordMany kind (i. expecting a list of results .FormatUTF8(FormatSQLWhere.on success. ID: integer): boolean.Synopse mORMot Framework Software Architecture Design 1. returns 0 .return true on success .call internaly the Add virtual method above function Delete(Table: TSQLRecordClass.for better server speed.this default method call OneFieldValues() to retrieve all matching IDs.this method will work for both TSQLRecordFTS3 and TSQLRecordFTS4 . or directly any integer / double / currency / RawUTF8 values to be bound to the request as parameters .this method expects the column/field names to be supplied in the MATCH statement clause . which is expected to follow the order of values supplied in BoundsSQLWhere open array .IntResult) (using inlined parameters via :(.e. FTSMatch(TSQLDocuments.Rev.call internaly InternalListJSON() to get the list mORMot.0.'linu*'.. which is the fastest way of ranking according to http://www. const FieldName: array of RawUTF8. Dedicated method used to retrieve free-text matching DocIDs with enhanced ranking information .use OneFieldValue() method to get the field value .returns TRUE if any matching ID was found (i. 2013 function FTSMatch(Table: TSQLRecordFTS3Class. Get the UTF-8 encoded value of some fields with a Where Clause .): is always a good idea) .return true on success. false on SQL error or no result .use GetMainFieldName() method to get the main field name . it will return [] if no matching record was found .['Name']. const Values: array of RawUTF8. var DocID: TIntegerDynArray. the first RawUTF8 property is returned anyway function MultiFieldValue(Table: TSQLRecordClass.search field is mainly the "Name" property.IntResult. overload.sqlite. var FieldValue: array of RawUTF8. "stored false") definition on most TSQLRecord . Return the ID of the record which main field match the specified value .if any of the Values[] is not existing. if length(IDs)>0) function MainFieldValue(Table: TSQLRecordClass.0.1. ID: Integer.0.this method will work for both TSQLRecordFTS3 and TSQLRecordFTS4 .Name. "stored false") definition on most TSQLRecord .FieldValue[] will have the same length as FieldName[] .e.example of use: MultiFieldValue(TSQLRecord.if ReturnFirstIfNoUnique is TRUE and no unique property is found. i.html#appendix_a SELECT RowID FROM Documents WHERE Documents MATCH 'linu*' ORDER BY rank(matchinfo(Documents). the one with "stored AS_UNIQUE" (i.example of use: FTSMatch(TSQLDocuments. const MatchClause: RawUTF8. Retrieve the main field (mostly 'Name') value of the specified record .[1. var IDs: TIntegerDynArray): boolean. and except some floating-point constants for weigthing each column (there must be the same number of PerFieldWeight parameters as there are columns in the TSQLRecordFTS3 table) . then no ID will appear in the IDs[] array .e.e.pas unit .IntResult. const Value: RawUTF8): integer.e.0. ReturnFirstIfNoUnique: boolean=false): RawUTF8. const PerFieldWeight: array of double): boolean.'"linu*"'.5) DESC function MainFieldID(Table: TSQLRecordClass. i. overload.18 Page 823 of 1055 .18 Date: June 16.e.return '' if no such field or record exists . Return the IDs of the record which main field match the specified values .org/fts3.returns 0 if no matching record was found function MainFieldIDs(Table: TSQLRecordClass.'ID=:(23):') (using inlined parameters via :(.search field is mainly the "Name" property. 1.. const WhereClause: RawUTF8): boolean.this method will search in all FTS3 columns. the one with "stored AS_UNIQUE" (i.5]) will perform a SQL query as such.g.Synopse mORMot Framework Software Architecture Design 1.5]) which will sort the results by the rank obtained with the 1st column/field beeing given twice the weighting of those in the 2nd (and last) column .[1.e. 'Salary>=?'..call internaly MultiFieldValues() to get the list function MultiFieldValues(Table: TSQLRecordClass. const BoundsSQLWhere: array of const): TSQLTableJSON. expecting a list of resutls . const FieldNames: RawUTF8.['Name'].in this version. and all '?' chars with Bounds[] (inlining them with :(. nil on failure . var FieldValue: array of RawUTF8.. const Args.example of use: aList := aClient.[aID]). false on SQL error or no result . Execute directly a SQL statement. const WhereClause: RawUTF8=''): TSQLTableJSON.example of use: MultiFieldValue(TSQLRecord.call internaly MultiFieldValues() to get the list .18 Page 824 of 1055 .MultiFieldValues(TSQLRecord. overload. nil on failure . WhereID: integer): boolean.pas unit . const FieldName: array of RawUTF8. binding all '?' chars with Args[] values . overload.[aMinSalary]). expecting a list of resutls .18 Date: June 16.FirstName'.Synopse mORMot Framework Software Architecture Design 1. nil on failure .): in WhereClause is always a good idea mORMot.23) . the WHERE clause can be created with the same format as FormatUTF8() function. Execute directly a SQL statement.'Name'.. 1.if FieldNames=''. 2013 function MultiFieldValue(Table: TSQLRecordClass.'Name.call internaly InternalListJSON() to get the list . all simple fields content is retrieved .return a result table on success. virtual. all simple fields content is retrieved .'%=?'. Execute directly a SQL statement.example of use: Table := MultiFieldValues(TSQLRecord.return true on success. Bounds: array of const): TSQLTableJSON.return a result table on success.using inlined parameters via :(.return a result table on success. all simple fields content is retrieved .Name.note that this method prototype changed with revision 1.. WhereClauseFormat: PUTF8Char. whereas it now expects bound parameters as '?' function MultiFieldValues(Table: TSQLRecordClass.if FieldNames=''. . overload. FieldNames: RawUTF8. . overload.FieldValue[] will have the same length as FieldName[] .Rev.['ID']. Get the UTF-8 encoded value of some fields from its ID . const FieldNames: RawUTF8. WhereClauseFormat: PUTF8Char.): and auto-quoting strings) .call internaly InternalListJSON() to get the list function MultiFieldValues(Table: TSQLRecordClass. expecting a list of resutls .17 of the framework: array of const used to be Args and '%' in the WhereClauseFormat statement. replacing all '%' chars with Args[].if FieldNames=''.this overloaded function will call FormatUTF8 to create the Where Clause from supplied parameters. ..'FirstName'.Rev. const FieldName: RawUTF8.'ID=:(23):') you should better call the corresponding overloaded method as such: aClient.Data) (using inlined parameters via :(. const WhereClause: RawUTF8=''.example of use . Get the UTF-8 encoded value of an unique field with a Where Clause . const FieldName: RawUTF8. const Separator: RawUTF8='.'Name'. 1.Synopse mORMot Framework Software Architecture Design 1..example of use: OneFieldValue(TSQLRecord.leave WhereClause void to get all records .call internaly InternalListJSON() to get the value function OneFieldValue(Table: TSQLRecordClass.'Name'.): aClient. const Args.[].this overloaded function will call FormatUTF8 to create the Where Clause from supplied parameters.17 of the framework: array of const used to be Args and '%' in the FormatSQLWhere statement.OneFieldValue(TSQLRecord. whereas it now expects bound parameters as '?' function OneFieldValues(Table: TSQLRecordClass.example of use: OneFieldValue(TSQLRecord.using inlined parameters via :(. Get the UTF-8 encoded value of an unique field from its ID . and all '?' chars with Bounds[] (inlining them with :(.'Name'. const FieldName: RawUTF8.OneFieldValue(TSQLRecord.[aID]) which is the same as calling: aClient.including inlined parameters via :(.'Name'.[aID]) .example of use: OneFieldValue(TSQLRecord.pas unit .'): RawUTF8. replacing all '%' chars with Args[]. overload..this overloaded function will call FormatUTF8 to create the Where Clause from supplied parameters.call internaly InternalListJSON() to get the value function OneFieldValue(Table: TSQLRecordClass. WhereClauseFmt: PUTF8Char.call internaly InternalListJSON() to get the value .example of use: aClient.call internaly InternalListJSON() to get the list .'Name'.'ID=?'.): and auto-quoting strings) .[aID]) .note that this method prototype changed with revision 1. const FieldName: RawUTF8.'ID=?'.'Name'.18 Date: June 16..OneFieldValue(TSQLRecord. 2013 function OneFieldValue(Table: TSQLRecordClass.'%=?'.): in WhereClause is always a good idea mORMot. Get the UTF-8 encoded value of an unique field with a Where Clause .FormatUTF8('ID=?'. binding all '?' chars with Args[] values .OneFieldValue(TSQLRecord.call internaly InternalListJSON() to get the value function OneFieldValue(Table: TSQLRecordClass.18 Page 825 of 1055 . Get the UTF-8 encoded value of an unique field with a Where Clause . overload.[23])) . WhereClause: RawUTF8): RawUTF8.'Name=:("Smith")'. Bounds: array of const): RawUTF8...['ID']. const BoundsSQLWhere: array of const): RawUTF8. FormatSQLWhere: PUTF8Char.23) . overload.. Get the CSV-encoded UTF-8 encoded values of an unique field with a Where Clause . const FieldName. WhereID: integer): RawUTF8. overload. overload.): is always a good idea) . Data) (using inlined parameters via :(.Rev.. 1. const WhereClause: RawUTF8.. Get the string-encoded values of an unique field into some TStrings .call internaly InternalListJSON() to get the list . FALSE if no data was retrieved function OneFieldValues(Table: TSQLRecordClass. Reference: PUTF8Char): boolean.18 Date: June 16. const FieldName.example of use: OneFieldValue(TSQLRecordPeople. FALSE if no data was retrieved ..Items[] will be filled with string-encoded values of the given field) . const FieldName: RawUTF8.leave WhereClause void to get all records ..Objects[] where ID=IDToIndex^ . Get the integer value of an unique field with a Where Clause . pointer(@SoundEx)) mORMot.call internaly InternalListJSON() to get the list class function QueryIsTrue(aTable: TSQLRecordClass. 2013 function OneFieldValues(Table: TSQLRecordClass.Objects[] will be filled with pointer(ID) .for qoContains and qoBeginWith.using inlined parameters via :(. const WhereClause: RawUTF8.for qoSoundsLike* operators.'Name=:("Smith"):'. var Data: TIntegerDynArray): boolean.Data) (using inlined parameters via :(.returns TRUE on success.is TSQLQueryEvent prototype compatible .e.'ID'. overload.leave WhereClause void to get all records . overload.example of use: OneFieldValue(TSQLRecord.. Get the UTF-8 encoded values of an unique field with a Where Clause . its value will be replaced with the index in Strings.if IDToIndex is set.call internaly InternalListJSON() to get the list .): is always a good idea) .): is always a good idea) . WhereClause: RawUTF8.returns TRUE on success.18 Page 826 of 1055 . overload. but a typecase of a prepared TSynSoundEx object instance (i. const FieldName: RawUTF8.): in WhereClause is always a good idea function OneFieldValues(Table: TSQLRecordClass.pas unit .'FirstName'.Synopse mORMot Framework Software Architecture Design 1. FieldType: TSQLFieldType. Evaluate a basic operation for implementing User Interface Query action . Value: PUTF8Char. var Data: TRawUTF8DynArray): boolean. Strings: TStrings. IDToIndex: PInteger=nil): Boolean. aID: integer..aID parameter is ignored in this function implementation (expect only this parameter to be not equal to 0) . the Reference is expected to be already uppercase .'Name=:("Smith"):'. Operator: integer. Reference is not a PUTF8Char.expect both Value and Reference to be UTF-8 encoded (as in TSQLTable or TSQLTableToGrid) . return true on success .18 Page 827 of 1055 . with dedicated methods to access to the separated pivot table function Retrieve(aID: integer.the TSQLRawBlob (BLOB) fields are not retrieved by this method.the TSQLRecordMany fields are not retrieved either: they are separate instances created by TSQLRecordMany. virtual.returns nil on any error (invalid Reference e. const Args.. with the appropriated class stored in Reference . abstract. to preserve bandwidth: use the RetrieveBlob() methods for handling BLOB fields. virtual. overload. to release the record . Get a member from its TRecordReference property content .) .Rev. with dedicated methods to access to the separated pivot table function Retrieve(WhereClauseFmt: PUTF8Char.if ForUpdate is true. then retrieve its content. caller has to call UnLock() method after Value usage. this implementation Create an instance. but this overloaded function will call FormatUTF8 to create the Where Clause from supplied parameters. or set globaly the TSQLRestClientURI.18 Date: June 16.pas unit .Bounds: array of const.Create.): and auto-quoting strings) mORMot. 1. replacing all '%' chars with Args[]. ForUpdate: boolean=false): boolean.. to release the record .Create. overload. 2013 function Retrieve(Reference: TRecordReference.ForceBlobTransfert property to TRUE . the REST method is LOCK and not GET: it tries to lock the corresponding record. there is no default implementation . Get a member from a SQL statement (implements REST GET member) . ForUpdate: boolean=false): TSQLRecord.instead of the other Retrieve() methods. or set globaly the TSQLRestClientURI. i.the TSQLRawBlob(BLOB) fields are not retrieved by this method. then retrieve its content. caller has to call UnLock() method after Value usage. Value: TSQLRecord.it must be implemented 100% RestFul with a GET ModelRoot/TableName/ID and handle the LOCK command if necessary: real RESTful class should implement a GET member from URI in an overriden method . to preserve bandwidth: use the RetrieveBlob() methods for handling BLOB fields.g. the REST method is LOCK and not GET: it tries to lock the corresponding record. Get a member from its ID .e. and all '?' chars with Bounds[] (inlining them with :(.same as Retrieve(const SQLWhere: RawUTF8. Value: TSQLRecord) method.if ForUpdate is true.ForceBlobTransfert property to TRUE (that is. by default "Lazy loading" is enabled. but can be disabled on purpose) . Value: TSQLRecord): boolean.return true on success .Synopse mORMot Framework Software Architecture Design 1.this method is defined as abstract.the TSQLRecordMany fields are not retrieved either: they are separate instances created by TSQLRecordMany. overload.Execute 'SELECT * FROM TableName WHERE ID=:(aID): LIMIT 1' SQL Statememt . aValue: TSQLRecord): boolean. virtual.return a TObjectList on success (possibly with Count=0) . overload.18 Date: June 16.Synopse mORMot Framework Software Architecture Design 1. i. Get a member from a published property TSQLRecord . const BoundsSQLWhere: array of const.ForceBlobTransfert property to TRUE . to preserve bandwidth: use the RetrieveBlob() methods for handling BLOB fields.Create. abstract. 2013 function Retrieve(const SQLWhere: RawUTF8.implements REST GET member with a supplied member ID and a blob field name .ID.return true on success ..this method retrieve the blob data as a TSQLRawBlob string function RetrieveBlobFields(Value: TSQLRecord): boolean. aID: integer.those properties are not class instances. const BlobFieldName: RawUTF8.is just a wrapper around Retrieve(aPublishedRecord.return true on success . overload. Get all BLOB fields of the supplied value from the remote server .since no record is specified.return nil on error mORMot. Get a blob field content from its record ID and supplied blob field name .aValue) . const BlobFieldName: RawUTF8.caller is responsible of freeing the instance . virtual.call internaly e. Value: TSQLRecord): boolean. aID: integer. overload.this TObjectList will contain a list of all matching records . or set globaly the TSQLRestClientURI. const aCustomFieldsCSV: RawUTF8=''): TObjectList. FormatSQLWhere: PUTF8Char.e.the TSQLRecordMany fields are not retrieved either: they are separate instances created by TSQLRecordMany..the TSQLRawBlob (BLOB) fields are not retrieved by this method.default implementation call InternalListJSON().): in SQLWhere is always a good idea) . locking is pointless here .implements REST GET member with a supplied member ID and a blob field name .pas unit .g. out BlobStream: THeapMemoryStream): boolean. there is no default implementation: it must be implemented 100% RestFul with a GET ModelRoot/TableName/ID/BlobFieldName request for example .Rev. but TObject(aRecordID) .this method will create a TStream instance (which must be freed by the caller after use) and fill it with the blob data function RetrieveBlob(Table: TSQLRecordClass. Get a member from a SQL statement (implements REST GET member) .Retrieve method when ForceBlobTransfert is TRUE function RetrieveList(Table: TSQLRecordClass.return true on success . with dedicated methods to access to the separated pivot table function Retrieve(aPublishedRecord. by TSQLRestClient. virtual.return true on success function RetrieveBlob(Table: TSQLRecordClass. 1. and fill Value from a temporary TSQLTable . Get a list of members from a SQL statement (implements REST GET member) .Execute 'SELECT * FROM TableName WHERE SQLWhere LIMIT 1' SQL Statememt (using inlined parameters via :(. Get a blob field content from its record ID and supplied blob field name .18 Page 828 of 1055 .this method is defined as abstract. overload. out BlobData: TSQLRawBlob): boolean. . virtual. Unlock the corresponding record .returns true on success function UnLock(Table: TSQLRecordClass. overload.calls internaly a "SELECT RowID FROM TableName LIMIT 1" SQL statement.use our custom UNLOCK REST-like method .in the current implementation.default implementation just handle the protected fTransactionActive flag . you can use the dedicated TSQLRestClientURI.return true if no transaction is active.Synopse mORMot Framework Software Architecture Design 1. false otherwize .in aClient-Server environment with multiple Clients connected at the same time.18 Date: June 16...use our custom UNLOCK REST-like method .the supplied SessionID will allow multi-user transaction safety on the Server-Side: all database modification from another session will wait for the global transaction to be finished. the SessionID is just ignored (TSQLRestClient will override this method with a default SessionID=CONST_AUTHENTICATION_NOT_USED=1 parameter) function UnLock(Rec: TSQLRecord): boolean.to be used to speed up some SQL statements like Add/Update/Delete methods above . SessionID: cardinal): boolean.18 Page 829 of 1055 .must be aborted with Rollback if any SQL statement failed .Rev. overload. raise exceptions on error Client. Get the row count of a specified table .returns true on success mORMot.in the current implementation.TransactionBegin(TSQLRecordPeopleObject) then try //.return -1 on error . you should check the returned value.in a multi-threaded or Client-Server with multiple concurent Client connections.calls internaly the "SELECT Count(*) FROM TableName. 1. except Client. TransactionBeginRetry() method .com/questions/8988915 function TableRowCount(Table: TSQLRecordClass): integer. modify the database content.return the row count of the table on success . virtual. Check if there is some data rows in a specified table ." SQL statement function TransactionBegin(aTable: TSQLRecordClass. on Client-side.see @http://stackoverflow. as such: if Client. which is much faster than testing if "SELECT count(*)" equals 0 . abstract.RollBack. virtual.must be ended with Commit on success .Commit. 2013 function TableHasRows(Table: TSQLRecordClass): boolean. // in case of error end. Begin a transaction (implements REST BEGIN Member) .calls internally UnLock() above . nested transactions are not allowed . the aTable parameter is not used yet . virtual. aID: integer): boolean..pas unit . Unlock the corresponding record . aID: integer.18 Page 830 of 1055 . aID: integer.this default method call RecordCanBeUpdated() to check if the action is allowed . BlobSize: integer): boolean.implements REST PUT member with a supplied member ID and field name .Rev.the TSQLRawBlob(BLOB) fields values are not updated by this method. BlobData: TStream): boolean.return true on success .implements REST PUT Member .the aSimpleFields parameters must follow explicitely the order of published properties of the supplied aTable class.e.return true on success .this method must be overriden to provide effective data update .the TSQLRecordMany fields are not set either: they are separate instances created by TSQLRecordMany. 1.implements REST PUT member with a supplied member ID and field name .call internaly the Update virtual method above function Update(Value: TSQLRecord): boolean.implements REST PUT member with a supplied member ID and field name .the aSimpleFields must have exactly the same count of parameters as there are "simple fields" in the published properties . Update a record from a supplied list of field values . aID: integer. aID: integer. excepting the TSQLRawBlob and TSQLRecordMany kind (i. abstract.this method expect the Blob data to be supplied as a TStream: it will send the whole stream content (from its beginning position upto its current size) to the database engine function UpdateBlob(Table: TSQLRecordClass.Create.this default method call RecordCanBeUpdated() to check if the action is allowed .return true on success .Synopse mORMot Framework Software Architecture Design 1. const BlobFieldName: RawUTF8. overload.18 Date: June 16. const BlobData: TSQLRawBlob): boolean. Update a blob field from its record ID and blob field name . const BlobFieldName: RawUTF8. to preserve bandwidth: use the UpdateBlob() methods for handling BLOB fields . overload. only so called "simple fields") .this default method call RecordCanBeUpdated() to check if the action is allowed . virtual. overload. with dedicated methods to access to the separated pivot table function UpdateBlob(Table: TSQLRecordClass. Update a blob field from its record ID and supplied blob field name . overload.return true on success . const aSimpleFields: array of const): boolean.implements REST PUT Member .this default method call RecordCanBeUpdated() to check if the action is allowed . const BlobFieldName: RawUTF8.this method expect the Blob data to be supplied as direct memory pointer and size mORMot. overload. Update a blob field from its record ID and blob field name . BlobData: pointer.return true on success .pas unit . virtual. Update a record from Value fields content . 2013 function Update(aTable: TSQLRecordClass.this method expect the Blob data to be supplied as TSQLRawBlob function UpdateBlob(Table: TSQLRecordClass. returns FALSE on error (e. End a transaction (implements REST END Member) .18 Date: June 16.URI will wait up to 2 seconds in order to acquire the right to write on the database before returning a "408 Request Time-out" status error mORMot.Rev. virtual. 2013 function UpdateBlobFields(Value: TSQLRecord): boolean.e. virtual. const aOperators: TSQLQueryOperators).default value is 2000. on Client-side.and associated operators procedure RollBack(SessionID: cardinal). i.write all pending SQL statements to the disk . the SessionID is just ignored (TSQLRestClient will override this method with a default SessionID=CONST_AUTHENTICATION_NOT_USED=1 parameter) procedure QueryAddCustom(aTypeInfo: pointer. if Value is invalid or with db/transmission) procedure Commit(SessionID: cardinal).default implementation just reset the protected fTransactionActive flag . aEvent: TSQLQueryEvent.default implementation just reset the protected fTransactionActive flag . virtual. on Client-side.the supplied SessionID will allow multi-user transaction safety on the Server-Side: all database modification from another session will wait for the global transaction to be finished.the supplied SessionID will allow multi-user transaction safety on the Server-Side: all database modification from another session will wait for the global transaction to be finished. to avoid several calls to UpdateBlob() .one event handler with an enumeration type containing all available query names .called internaly by Add and Update methods when ForceBlobTransfert is TRUE . Update all BLOB fields of the supplied Value . before the call to TransactionBegin .18 Page 831 of 1055 .uses the UpdateBlob() method to send the BLOB properties content to the Server . the SessionID is just ignored (TSQLRestClient will override this method with a default SessionID=CONST_AUTHENTICATION_NOT_USED=1 parameter) property AcquireWriteTimeOut: cardinal read fAcquireWriteTimeOut write fAcquireWriteTimeOut.Synopse mORMot Framework Software Architecture Design 1.you can use this method by hand.restore the previous state of the database.returns TRUE on success (or if there is no BLOB field) . 1. the server will identify transactions using the client Session ID: this property will set the time out wait period .pas unit .in order to handle safe transactions and multi-thread safe writing. The time (in mili seconds) which the server will wait for acquiring a write acccess to the database . Add a custom query .g. TSQLRestServer. Abort a transaction (implements REST ABORT Member) . Synopse mORMot Framework Software Architecture Design 1.. UPDATE and DELETE (that is.may be nil if no service interface has been registered yet: so be aware that the following line may trigger an access violation if no ICalculator is defined on server side: if fServer. i. MSSQL and MySQL external databases) .SetTimeOut() methods to set the appropriate configuration for this particular TSQLRest instance property Model: TSQLModel read fModel.use Cache. that is no automated synchronization is implemented between TSQLRestClient and TSQLRestServer: you shall ensure that your code won't fail due to this restriction .this property will return the timestamp as TTimeLog / Iso8601 / Int64 after correction from the Server returned time-stamp (if any) . property ServicesRouting: TServiceRoutingMode read fRouting write fRouting. which is more secure (since will use our RESTful authentication scheme). 2013 property Cache: TSQLRestCache read GetCache..g.this caching will be located at the TSQLRest level.e.ServerTimeStamp property for Oracle. a complex direct SQL UPDATE or via TSQLRecordMany pattern won't be taken in account .you can use this value in a WHERE clause for a query. property Services: TServiceContainer read fServices.Services['Calculator']. as such: aRec. The routing mode of the service remote request .ServerTimeStamp)]).pas unit .only caching synchronization is about the direct RESTful/CRUD commands: RETRIEVE.CreateAndFillPrepare(Client.'Datum<=?'.default implementation will return the executable time. by TSQLRecord.ComputeFieldsBeforeWrite to update TModTime and TCreateTime published fields .SetCache() and Cache.you can set the server-side time offset by setting a value to this property (e. The current Date and Time. 1. will use an URI-based layout (rmREST).only exception is TSQLRestServerStatic tables accessed as SQLite3 virtual table) .Rev. ADD. if the client would rather use this alternative pattern TSQLRestServerNamedPipe = class(TThread) Server thread accepting connections from named pipes mORMot.but rmJSON_RPC can be set (on BOTH client and server sides).g.purpose of this caching mechanism is to speed up retrieval of some common values at either Client or Server level (like configuration settings) . The Database Model associated with this REST Client or Server property ServerTimeStamp: TTimeLog read GetServerTimeStamp write SetServerTimeStamp.is used e. Iso8601Now . Access to the interface-based services list .Get(Calc)) then .by default.[Iso8601ToSQL(Client. as retrieved from the server . and also 10% faster . using TSQLDBConnection. Access the internal caching parameters for a given TSQLRecord .18 Page 832 of 1055 .18 Date: June 16. Synopse mORMot Framework Software Architecture Design 1.Create) . especially when used with external databases (since all data is retrieved before paging.warning: using paging can be VERY expensive on Server side. Create the server thread destructor Destroy.pas unit . Returned JSON field value of optional total row counts .fChildCount TSQLRestServerURIPagingParameters = record If defined. Parameter name used to specify the request the page size (LIMIT clause) . Release all associated memory.computing total row counts can be very expensive. no total row counts field . Release all associated memory.default value is 'RESULTS=' Select: PUTF8Char.default values are the one used for YUI component paging (i.default value is 'SELECT=' SendTotalRowsCountFmt: PUTF8Char. 2013 constructor Create(aServer: TSQLRestServer. i.default value is nil. Parameter name used to specify the request sort direction . and % will be set with the value) mORMot. the server statistics will contain precise working time process structure used to specify custom request paging parameters for TSQLRestServer . override. override. 1. The associated pipe name TSQLRestServerNamedPipeResponse = class(TThread) Server child thread dealing with a connection through a named pipe constructor Create(aServer: TSQLRestServer. Create the child connection thread destructor Destroy.e.18 Page 833 of 1055 . when SQLite3 works in virtual mode) Dir: PUTF8Char. depending on the database back-end used (especially for external databases) . const PipeName: TFileName). PAGINGPARAMETERS_YAHOO constant."totalRows":%' value (note that the initial ". and wait for all TSQLRestServerNamedPipeResponse children to be terminated property PipeName: TFileName read fPipeName. to '.can be set e.Rev.g. aPipe: cardinal). as set by TSQLRestServer. Parameter name used to specify the request field names ." is expected by the produced JSON content. and decrement fMasterThread.default value is 'DIR=' Results: PUTF8Char. aMasterThread: TSQLRestServerNamedPipe.e.18 Date: June 16. High-resolution performance counter of the time used to process the requests . Get a standard message to be displayed with the above statistics .pas unit .this value depend on the high-resolution performance counter frequency .18 Date: June 16.default value is 'WHERE=' TSQLRestServerStats = class(TPersistent) Used for statistics update in TSQLRestServer.Rev. 1. Max count of connected clients property IncomingBytes: QWord read fIncomingBytes. Percent (0. 2013 Sort: PUTF8Char. Update ClientsCurrent and ClientsMax procedure ClientDisconnect. Parameter name used to specify the request sort order . Count of invalid request property Modified: QWord read fModified.use ProcessTime property below to get the time in seconds function Changed: boolean. Current count of connected clients property ClientsMax: QWord read fClientsMax.100) of request which modified the data procedure ClientConnect.18 Page 834 of 1055 .. Update ClientsCurrent and ClientsMax property ClientsCurrent: QWord read fClientsCurrent. Parameter name used to specify the request WHERE clause .Synopse mORMot Framework Software Architecture Design 1.default value is 'SORT=' StartIndex: PUTF8Char. Return true if IncomingBytes value changed since last call function DebugMessage: RawUTF8. Size of data requests processed in bytes (without the transfert protocol overhead) property Invalid: QWord read fInvalid. Parameter name used to specify the request starting offset . Size of data responses generated in bytes (without the transfert protocol overhead) mORMot.URI() ProcessTimeCounter: Int64.default value is 'STARTINDEX=' Where: PUTF8Char.return the published properties of this class as a JSON object function ModifPercent: cardinal. Count of requests which modified the data property OutcomingBytes: QWord read fOutcomingBytes. Unserialize the content from TEXT . DELETE method (delete record) table access bits GET: TSQLFieldTables.e. Set of allowed actions on the server side DELETE: TSQLFieldTables. aRights: TSQLOccasions). overload. it will be OK.one property for every and each URI method (GET/POST/PUT/DELETE) .UpdateFromServer() is called only for refreshing a direct statement.Rev. overload.Synopse mORMot Framework Software Architecture Design 1.AccessRights CSV format mORMot. C. Serialize the content as TEXT . Wrapper method which can be used to set the CRUD abilities over a table . Count of valid responses (returned status code 200/HTML_SUCCESS or 201/HTML_CREATED) property ServiceCalls: QWord read fServices. as used in TSQLRestClientURI.URI() method .18 Date: June 16. U. on 'ModelRoot' URI with a SQL statement as SentData.C=Create.one bit for every and each Table in Model.18 Page 835 of 1055 . the PUT access bits will be read instead of the GET bits value POST: TSQLFieldTables. Wrapper method which can be used to set the CRUD abilities over a table .use the TSQLAuthGroup. 2013 property ProcessTime: RawUTF8 read GetProcessTimeString.pas unit .if the REST request is LOCK. for each Table . U=Update.AccessRights CSV format procedure Edit(aTableIndex: integer.Tables[] AllowRemoteExecute: TSQLAllowRemoteExecute.use TSQLOccasion set as parameter procedure Edit(aTableIndex: integer. 1. R.UpdateFromServer) is always valid. whatever the bits here are: since TSQLRestClientURI. GET method (retrieve record) table access bits . the PUT access bits will be read instead of the GET bits value function ToString: RawUTF8. PUT method (update record) table access bits .if the REST request is LOCK. POST method (create record) table access bits PUT: TSQLFieldTables.note that a GET request with a SQL statement without a table (i. Count of the remote service calls TSQLAccessRights = object(TObject) Set the User Access Rights. The global time spent in the server process property Responses: QWord read fResponses. R=Read.use the TSQLAuthGroup. D=Delete rights procedure FromString(P: PUTF8Char). D: Boolean). you can improve this by overriding the TSQLRestServer. but only 'Admin' group users will be able to remotly modify the content of those table property AccessRights: RawUTF8 index 1600 read fAccessRights write fAccessRights. ready to be displayed . 'Supervisor'. 2013 TSQLAuthGroup = class(TSQLRecord) Table containing the available user access rights for authentication . "stored false") attribute) .Rev. and 'User' rows in the AuthUser table (with 'synopse' as default password).e.by default.g. override. 1. const FieldName: RawUTF8). 'User' and 'Guest' groups.so you can retrieve a TSQLAuthGroup ID from its identifier. by the binary TSQLFieldTables layout.content is converted into/from text format via AccessRight DB property (so it will be not fixed e.on a new database.you MUST override those default 'synopse' password to a custom value . the MAX_SQLTABLES constant value) mORMot. Corresponding TSQLAccessRights for this authentication group . you can change and tune the settings of the AuthGroup and AuthUser tables. to allow authentication support . Called when the associated table is created in the database . A textual representation of a TSQLAccessRights buffer property Ident: RawUTF8 index 50 read fIdent write fIdent stored AS_UNIQUE.'User'). and Guest won't have access to the interface-based remote JSON-RPC service (no reService) .e. as such: UserGroupID := fClient.of course. AuthUser and AuthGroup).e. with the following access rights to the AuthGroup table: Admin Supervisor User Guest POST SQL Yes No No No Service Yes Yes Yes No Auth R Yes Yes No No Auth W Yes No No No Tables R Yes Yes Yes Yes Tables W Yes Yes Yes No 'Admin' will be the only able to execute remote not SELECT SQL statements for POST commands (reSQL in TSQLAccessRights. property SessionTimeout: integer read fSessionTimeOut write fSessionTimeOut. if TSQLAuthUser and TSQLAuthGroup tables are defined in the associated TSQLModel.AllowRemoteExecute) and modify the Auth tables (i. it this will add 'Admin'. it won't be accessible remotely by anyone class procedure InitializeTable(Server: TSQLRestServer.MainFieldID(TSQLAuthGroup.the same identifier can be used only once (this column is marked as unique via a "stored AS_UNIQUE" (i.this class should be added to the TSQLModel. and associated 'Admin'.pas unit . The access right identifier. together with TSQLAuthUser. The number of minutes a session is kept alive property SQLAccessRights: TSQLAccessRights read GetSQLAccessRights write SetSQLAccessRights.18 Page 836 of 1055 . i.18 Date: June 16.Synopse mORMot Framework Software Architecture Design 1. 'Supervisor'. aUser: TSQLAuthUser.in fact.this class should be added to the TSQLModel.the User field is a true instance. The User identification Name. Some custom data. will also retrieve the aUser.e. Able to set the PasswordHashHexa field from a plain password content .by default. The hexa encoded associated SHA-256 hash of the password property PasswordPlain: RawUTF8 write SetPasswordPlain.attribute).User instance.raise an exception on any error . 1. for performance and security reasons .pas unit . together with TSQLAuthGroup. hashed in TSQLRestServerStaticInMemory) property PasswordHashHexa: RawUTF8 index 64 read fPasswordHashHexa write fPasswordHashHexa. GroupRights property will contain a real TSQLAuthGroup instance for fast retrieval in TSQLRestServer. you could use the TSynValidatePassWord filter to this table property Data: TSQLRawBlob read fData write fData.i.to enhance security.this aUser instance will be handled by the class until Destroy . copy of the corresponding database content (for better speed) constructor Create(aServer: TSQLRestServer. to allow authentication support .Data BLOB field content mORMot. and therefore indexed in the database (e.access rights are managed by group . aContext: PSQLRestServerURIParams).Server application may store here custom data . associated to the User .18 Date: June 16. The User Name.URI . 2013 TSQLAuthUser = class(TSQLRecord) Table containing the Users registered for authentication .this is not a TSQLRecord table so won't be remotely accessible. as may be displayed or printed property GroupRights: TSQLAuthGroup read fGroup write fGroup.g.in TAuthSession.note that 'Group' field name is not allowed by SQLite property LogonName: RawUTF8 index 20 read fLogonName write fLogonName stored AS_UNIQUE.on success. The associated access rights of this user . "stored false" . PasswordHashHexa := SHA256('salt'+PasswordPlain) in UTF-8 TAuthSession = class(TObject) Class used to maintain in-memory sessions . it won't be accessible remotely by anyone .Rev. as entered at log-in . Initialize a session instance with the supplied TSQLAuthUser instance .the same identifier can be used only once (this column is marked as unique via a "stored AS_UNIQUE" .Synopse mORMot Framework Software Architecture Design 1.18 Page 837 of 1055 .its content is not used by the framework but 'may' be used by your application property DisplayName: RawUTF8 index 50 read fDisplayName write fDisplayName. aURLlength: integer): boolean.is extracted from SentHeaders properties property ID: RawUTF8 read fID. The associated User .TSQLAuthGroup. if any . if any .. The remote IP. The number of millisedons a session is kept alive .never equals to 1 (CONST_AUTHENTICATION_NOT_USED.0..g. authentication mode is not enabled).extracted from User. i. and User.. to '?session_signature=.SessionTimeout .allow direct comparison with GetTickCount API call property User: TSQLAuthUser read fUser.TSQLAuthGroup.Synopse mORMot Framework Software Architecture Design 1. Will release the User and User. Check if the session_signature=. as text property IDCardinal: cardinal read fIDCardinal. override.e.0' property Timeout: cardinal read fTimeOut.can contain e.18 Page 838 of 1055 .SQLAccessRights property ConnectionID: RawUTF8 read fConnectionID. session still in handshaking phase) property LastAccess: cardinal read fLastAccess.is extracted from SentHeaders properties property SentHeaders: RawUTF8 read fSentHeaders.will expect the format as generated by TSQLRestClientURI.extracted from User. parameter is correct .GroupRights instances function IsValidURL(const aURL: RawUTF8. is expected at the end of the URL.Rev. 'RemoteIp: 127.GroupRights will contain also a true TSQLAuthGroup instance mORMot.pas unit .e.1' or 'User-Agent: Mozilla/4. Set by the Access method to the current time stamp property PrivateKey: RawUTF8 read fPrivateKey. The session ID number. A remote connection identifier. aURL[aURLLength+1] will point e. 2013 destructor Destroy.18 Date: June 16.this is a true TSQLAuthUser instance.': the caller must ensure that aURL[] follows this expected layout . The transmitted HTTP headers.. 1.session_signature=. i. if any .0.. as numerical value .g. Copy of the associated user access rights . i. The session ID number.SessionSign() property AccessRights: TSQLAccessRights read fAccessRights.. The hexadecimal private key as returned to the connected client as 'SessionID+PrivateKey' property RemoteIP: RawUTF8 read fRemoteIP. nor 0 (CONST_AUTHENTICATION_SESSION_NOT_STARTED.e. SetUser() if you need a custom authentication class .call this method instead of TSQLRestClientURI. abstract.returns a session instance corresponding to the remote request .inherit from this class to implement expected authentication scheme constructor Create(aServer: TSQLRestServer). virtual.returns FALSE to let the next registered TSQLRestServerAuthentication class to try implementing the content .you can define several authentication schemes for the same server function Auth(var Ctxt: TSQLRestServerCallBackParams): boolean.. virtual.returns nil if this remote request does not match this authentication .Rev. value . aPassword: RawUTF8.Ctxt. abstract.used by TSQLRestClientURI. virtual. call TSQLRestServer.18 Date: June 16.fSessionCriticalSection TSQLRestServerAuthenticationURI = class(TSQLRestServerAuthentication) Weak authentication scheme using URL-level parameter class function ClientSessionSign(Sender: TSQLRestClientURI.pas unit . virtual.append '&session_signature=SessionID' to the url mORMot.method execution is protected by TSQLRestServer. aHashedPassword: Boolean=false): boolean. virtual. Called by the Server to implement the Auth RESTful method . Class method to be used on client side to create a remote session . const aUserName. Initialize the authentication method to a specified server .e.18 Page 839 of 1055 .fSessionCriticalSection class function ClientSessionSign(Sender: TSQLRestClientURI.Synopse mORMot Framework Software Architecture Design 1.method execution is protected by TSQLRestServer.Parameters has been tested to contain an UserName=. override.shall match the method as expected by RetrieveSession() virtual method class function ClientSetUser(Sender: TSQLRestClientURI.returns true on success function RetrieveSession(var Ctxt: TSQLRestServerCallBackParams): TAuthSession.URI() . abstract.. Class method to be called on client side to sign an URI . Class method to be called on client side to add the SessionID to the URI . abstract. 1. i. Called by the Server to check if the execution context match a session . const url: RawUTF8): RawUTF8. const url: RawUTF8): RawUTF8. 2013 TSQLRestServerAuthentication = class(TObject) Abstract class used to implement server-side authentication in TSQLRestServer .will call the ModelRoot/Auth service.overriden method shall return TRUE if the request has been handled .Auth() published method to create a session for this user . Class method to be called on client side to sign an URI . 2013 function RetrieveSession(var Ctxt: TSQLRestServerCallBackParams): TAuthSession. parameter to be a valid digital signature TSQLRestServerAuthenticationDefault = class(TSQLRestServerAuthenticationSignedURI) MORMot secure RESTful authentication scheme .' parameter TSQLRestServerAuthenticationSignedURI = class(TSQLRestServerAuthenticationURI) Secure authentication scheme using URL-level digital signature class function ClientSessionSign(Sender: TSQLRestClientURI. 1.Synopse mORMot Framework Software Architecture Design 1..append '&session_signature=SessionID+.18 Page 840 of 1055 ... const url: RawUTF8): RawUTF8..retrieve the session ID from 'session_signature=..generate the digital signature as expected by overriden RetrieveSession() . Will check URI-level signature .check session_signature=.Rev... in particular.18 Date: June 16. override.will use the TAuthSession.pas unit . override. timestamp resolution is about 256 ms in the current implementation .this method will use a password stored via safe SHA-256 hashing in the TSQLAuthUser ORM table mORMot. Will check URI-level signature . override.' to the url function RetrieveSession(var Ctxt: TSQLRestServerCallBackParams): TAuthSession.IsValidURL() format. const aUserName.this method will authenticate with a given username.the returned HexaSessionPrivateKey content will identify the current user logged and its corresponding session (the same user may have several sessions opened at once.Synopse mORMot Framework Software Architecture Design 1. just as stored in PasswordHashHexa (i.when you don't need the session any more (e.. 2013 function Auth(var Ctxt: TSQLRestServerCallBackParams): boolean.. i.then the private session key must be added to every query sent to the server as a session_signature=???? parameter.g. .if aHashedPassword is TRUE.Auth() published method to create a session for this user: so TSQLRestServerAuthenticationDefault should be registered on server side . will open the corresponding session and return 'SessionID+HexaSessionPrivateKey' The Password parameter as sent for the 2nd request will be computed as Sha256(ModelRoot+Nonce+ClientNonce+UserName+Sha256('salt'+PassWord)) .. TSQLAuthUser.&ClientNonce=.. 1.will call the ModelRoot/Auth service.. you can call the service as such: GET ModelRoot/auth?UserName=. -> if password is OK.html class function ClientSetUser(Sender: TSQLRestClientURI. call TSQLRestServer. but no signature mORMot. which will be computed as such: ModelRoot/url?A=1&B=2&session_signature=012345670123456701234567 were the session_signature= parameter will be computed as such: Hexa8(SessionID)+Hexa8(TimeStamp)+ Hexa8(crc32('SessionID+HexaSessionPrivateKey'+Sha256('salt'+PassWord)+ Hexa8(TimeStamp)+url)) with url='ModelRoot/url?A=1&B=2' this query authentication uses crc32 for hashing instead of SHA-256 in in order to lower the Server-side CPU consumption. SHA256('salt'+Value) as in TSQLAuthUser. Class method used on client side to create a remote session . -> returns an hexadecimal nonce contents (valid for 5 minutes) GET ModelRoot/auth?UserName=.&Session=.to be called in a two pass "challenging" algorithm: GET ModelRoot/auth?UserName=.18 Page 841 of 1055 ..PasswordHashHexa) and client-side TimeStamp are inserted inside the session_signature calculation to prevent naive man-in-the-middle attack (MITM) ... aHashedPassword: Boolean=false): boolean..the session ID will be used to retrieve the rights associated with the user which opened the session via a successful call to the Auth service . override.pas unit .18 Date: June 16. if the TSQLRestClientURI instance is destroyed).Rev.e.for a way of computing SHA-256 in JavaScript..info/javascript-sha256. Will try to handle the Auth RESTful method with mORMot authentication .webtoolkit.SetPasswordPlain method) .e. see for instance @http://www.&PassWord=. override. each with its own private key) . the salted password (i.e. aPassword: RawUTF8..SetUser() method TSQLRestServerAuthenticationNone = class(TSQLRestServerAuthenticationURI) MORMot weak RESTful authentication scheme . the aPassword parameter is expected to contain the already-hashed value.is called by TSQLRestClientURI.. SetUser() method: you have to write: TSQLRestServerAuthenticationNone..to be called in a weak one pass request: GET ModelRoot/auth?UserName=..'User'). override. override. i.. Will check URI-level signature .ClientSetUser(Client. Class method used on client side to create a remote session . aHashedPassword: Boolean=false): boolean. function RetrieveSession(var Ctxt: TSQLRestServerCallBackParams): TAuthSession.18 Date: June 16. as implemented by TSQLRestServerAuthenticationSignedURI.Synopse mORMot Framework Software Architecture Design 1.the client-side logged user will be identified as valid. will open the corresponding session and return 'SessionID+HexaSessionPrivateKey' class function ClientSetUser(Sender: TSQLRestClientURI. Will try to handle the Auth RESTful method with Windows SSPI API . call TSQLRestServer. 1.e.to be called in a two pass "challenging" algorithm. override.is not called by TSQLRestClientURI. override. 2013 function Auth(var Ctxt: TSQLRestServerCallBackParams): boolean. Initialize the authentication method to a specified server destructor Destroy.here aPassword and aHashedPassword are ignored . according to a Windows SSPI API secure challenge mORMot.will call the ModelRoot/Auth service.. Will try to handle the Auth RESTful method with mORMot authentication .' parameter TSQLRestServerAuthenticationSSPI = class(TSQLRestServerAuthenticationSignedURI) Authentication using Windows Security Support Provider Interface (SSPI) constructor Create(aServer: TSQLRestServer).pas unit . -> if the specified user name exists. Finalize internal memory structures function Auth(var Ctxt: TSQLRestServerCallBackParams): boolean.retrieve the session ID from 'session_signature=. const aPassword: RawUTF8=''.Auth method .Auth() published method to create a session for this user: so TSQLRestServerAuthenticationNone should be registered on server side .Rev. override. override.18 Page 842 of 1055 . const aUserName: RawUTF8. 1.is called BEFORE deletion.1 (page 1048).1.to be used only server-side.here aUserName.Create() constructor mORMot. Class method used on client side to create a remote session .2.1 (page 1052).descendent must implement the protected EngineList() Retrieve() Add() Update() Delete() methods .1. DI-2. DI-2.1.it may be used by client to avoid retrieve data only if necessary . This property can be used to specify the URI parmeters to be used for query paging .1.to be used only server-side.2. table TSQLAuthUser shall contain an entry for the logged Windows user. const aUserName: RawUTF8=''.2 (page 1048).18 Page 843 of 1055 .1).4 (page 1049). DI-2.pas unit .18 Date: June 16. call TSQLRestServer. not to synchronize some clients: the framework is designed around a stateless RESTful architecture (like HTTP/1.is set by default to PAGINGPARAMETERS_YAHOO constant by TSQLRestServer. not to synchronize some clients: the framework is designed around a stateless RESTful architecture (like HTTP/1. aPassword and aHashedPassword are ignored . in which clients ask the server for refresh (see TSQLRestClientURI. aHashedPassword: Boolean=false): boolean.e. with the LoginName in form 'DomainName\UserName' . DI-2.2.automatic call of this methods by a generic URI() RESTful function .1 (page 1047).1.Synopse mORMot Framework Software Architecture Design 1.1 (page 1047).2.SetUser() method TSQLRestServer = class(TSQLRest) A generic REpresentational State Transfer (REST) server .1.1. and AFTER insertion or update . i.is called AFTER update of one or several blobs.Rev. InternalState: Cardinal. on any not SELECT statement) .its value can be published to the client on every remote request .UpdateFromServer) OnUpdateEvent: TNotifySQLEvent.e. 2013 class function ClientSetUser(Sender: TSQLRestClientURI. A method can be specified here to trigger events after any blob update .1. A method can be specified here to trigger events after any table update . in which clients ask the server for refresh (see TSQLRestClientURI. this feature is not activated on the server.1.is called by TSQLRestClientURI.will call the ModelRoot/Auth service. and is expected to be thread-safe Used for DI-2.Windows SSPI authentication will be performed .Auth() published method to create a session for this user: so TSQLRestServerAuthenticationSSPI should be registered on server side . This integer property is incremented by the database engine when any SQL statement changes the database contents (i.1. never on delete nor insert .UpdateFromServer) URIPagingParameters: TSQLRestServerURIPagingParameters. and the client must ignore it and always retrieve the content OnBlobUpdateEvent: TNotifyFieldSQLEvent. override.1).2.if its value is 0.in this case. const aPassword: RawUTF8=''.1. DI-2. DI-2.3 (page 1049).any published method of descendants must match TSQLRestServerCallBack prototype. overload. will add TSQLAuthUser and TSQLAuthGroup to the TSQLModel (if not already there) destructor Destroy.on success. and more cross-database engine compatible)S function CloseServerMessage: boolean. and handle all integrity check within this method (it's therefore less error-prone. const IndexName: RawUTF8=''): boolean. Release memory and any existing pipe initialized by ExportServer() function Add(Value: TSQLRecord.18 Page 844 of 1055 .will call CreateSQLMultiIndex() internaly function CreateSQLIndex(Table: TSQLRecordClass. Unique: boolean): boolean. virtual. Unique: boolean.delete all available TRecordReference properties pointing to this record in the database Model. override. Unique: boolean.18 Date: June 16.delete all available TSQLRecord properties pointing to this record in the database Model. aHandleUserAuthentication: boolean=false). const FieldNames: array of RawUTF8. This method is called internally after any successfull deletion to ensure relational database coherency . returns the new ROWID value. Create an index for the specific FieldName . reintroduce. const FieldName: RawUTF8. override.ID is stored to the virtual table function AfterDeleteForceCoherency(Table: TSQLRecordClass. Value.important notice: we don't use FOREIGN KEY constraints in this framework.if aValue is TSQLRecordFTS3. aID: integer): boolean. SendData: boolean.if HandleUserAuthentication is true. Create one index for all specific FieldNames at once mORMot. for database coherency .ID is updated with the new ROWID . for database coherency .e. overload. Implement Server-Side TSQLRest adding . ForceID: boolean=false): integer. all R/W access) by default .uses internally EngineAdd() function for calling the database engine . returns 0 . End any currently initialized named pipe server function CreateSQLIndex(Table: TSQLRecordClass. on error.if HandleUserAuthentication is false.Rev. Value. will set URI access rights to 'Supervisor' (i. const FieldNames: array of RawUTF8. 1.pas unit .on success. Server initialization with a specified Database Model . IndexName: RawUTF8=''): boolean. Create one or multiple index(es) for the specific FieldName(s) function CreateSQLMultiIndex(Table: TSQLRecordClass. 2013 constructor Create(aModel: TSQLModel.Synopse mORMot Framework Software Architecture Design 1.call corresponding fStaticData[] if necessary . End any currently initialized message-oriented server function CloseServerNamedPipe: boolean. virtual. Rev.1.override this method for proper calling the database engine . 2013 function Delete(Table: TSQLRecordClass.2. by using Windows messages .call corresponding fStaticData[] if necessary .returns false if a TSQLRestServer was already exported . coherency checking and notifications together with a low-level SQL deletion work (if possible) function Delete(Table: TSQLRecordClass.ProcessMessages) .the data is sent and received by using the standard and fast WM_COPYDATA message .Windows messages are very fast (faster than named pipe and much faster than HTTP).return true on success .1.18 Page 845 of 1055 . override. with Application.client must release all memory acquired by URIRequest() with GlobalFree() function ExportServerMessage(const ServerWindowName: string): boolean.create a new Window Class with the supplied class name (UnicodeString since Delphi 2009 for direct use of Wide Win32 API). Execute directly a SQL statement.will call EngineList() abstract method to retrieve its JSON content function ExportServer: boolean.the main server instance has to process the windows messages regularely (e.returns true on success. ID: integer): boolean.this method must be implemented to be thread-safe function ExecuteList(const Tables: array of TSQLRecordClass.returns true if the URIRequest() function is set to this TSQLRestServer .allows only one ExportServer*() by running process . and instanciate a window which will handle pending WM_COPYDATA messages .) will be used to create a Window name identifier . virtual.don't call this method in normal cases . override. expecting a list of results . but only work localy on the same computer .18 Date: June 16.g. override. const SQL: RawUTF8): TSQLTableJSON.3 (page 1049).pas unit . false otherwize (ServerWindowName already used?) Used for DI-2.will process all ORM-level validation. for relational database coherency function EngineExecuteAll(const aSQL: RawUTF8): boolean. 1.return a result table on success. mORMot. Declare the server on the local machine to be accessible for local client connection. overload. nil on failure .uses internally EngineDelete() function for calling the database engine .ServerWindowName ('DBSERVER' e. Implement Server-Side TSQLRest deletion with a WHERE clause .this record is also erased in all available TRecordReference properties in the database Model. Implement Server-Side TSQLRest deletion .g. Grant access to this database content from a dll using the global URIRequest() function . Execute directly all SQL statement (POST SQL on ModelRoot URI) . const SQLWhere: RawUTF8): boolean. abstract.Synopse mORMot Framework Software Architecture Design 1. if any of the supplied interfaces is not correct or is not available on the server) .if ForUpdate is true.g. Declare the server on the local machine as a Named Pipe: allows TSQLRestClientURINamedPipe local or remote client connection .this server identifier is appended to '\\.pas unit . Register a remote Service via its interface . override.Synopse mORMot Framework Software Architecture Design 1. ForUpdate: boolean=false): boolean. if any function ServiceRegister(aClient: TSQLRest. false if registration failed (e.that is. function Retrieve(aID: integer. out BlobData: TSQLRawBlob): boolean.uses internally EngineRetrieve() function for calling the database engine (via fStaticData[] if the table is stored as Static) . 2013 function ExportServerNamedPipe(const ServerApplicationName: TFileName): boolean. but execution will take place on a remote server .1.call corresponding fStaticData[] if necessary .) will be used to create a named pipe server identifier. false otherwize (ServerApplicationName already used?) Used for DI-2.you can specify an optional custom contract for the first interface mORMot.Rev.this methods expects a list of interfaces to be registered to the client (e.Services property. Implement Server-Side TSQLRest Retrieval (GET or LOCK methods) .ServerApplicationName ('DBSERVER' e.18 Date: June 16.g. Value: TSQLRecord.1.will return true on success. const aContractExpected: RawUTF8=''): boolean. then retrieve its content.this overriden method will execute the direct static class. overload.2. override. override.this server identifier may also contain a fully qualified path ('\\.this method retrieve the blob data as a TSQLRawBlob string function RetrieveBlobFields(Value: TSQLRecord): boolean.allows only one ExportServer*() by running process . the REST method is LOCK and not GET: it tries to lock the corresponding record.) . Implement Server-Side TSQLRest blob field content retrieval .may be used e.uses internally EngineRetrieveBlob() function for calling the database engine .\pipe\mORMot_DBSERVER' e.implements REST GET member with a supplied member ID and a blob field name .handles locking if necessary .instance implementation pattern will be set by the appropriate parameter .) . const aInterfaces: array of PTypeInfo. Get all BLOB fields of the supplied value from the remote server . virtual.g.g. [TypeInfo(IMyInterface)]) . it is of UnicodeString type since Delphi 2009 (use of Unicode FileOpen() version) .returns true on success. accessed via the supplied TSQLRest(ClientURI) instance: it can be available in the main TSQLRestServer. caller has to call UnLock() method after Value usage.2 (page 1048). aInstanceCreation: TServiceInstanceImplementation=sicSingle. aID: integer.\pipe\ApplicationName' e.\pipe\mORMot_' to obtain the full pipe name to initiate ('\\. server side will be called to check for the availability of each interface .g. to release the record function RetrieveBlob(Table: TSQLRecordClass.g.18 Page 846 of 1055 . 1. const BlobFieldName: RawUTF8. for dedicated hosting of services (in a DMZ for instance) .this overloaded method will register a remote Service. Overriden method for direct static class call (if any) function UnLock(Table: TSQLRecordClass.18 Page 847 of 1055 .CreateMissingTables. aServerClass: TSQLRestServerStaticClass=nil): TSQLRestServerStatic.can load the table content from a file if a file name is specified (could be either JSON or compressed Binary format on disk) . aInstanceCreation: TServiceInstanceImplementation=sicSingle): TServiceFactoryServer.class can be any TInterfacedObject.VirtualTableRegister() call before TSQLRestServer. override. and the exact list of interfaces to be registered to the server (e. since no complete SQL interpreter can be implemented by TSQLRestServerStatic. you should better use a Virtual Table class.return nil on any error. Create an external static in-memory database for a specific class . override. or an EModelException if the class is not in the database model function TableHasRows(Table: TSQLRecordClass): boolean.Create . but TInterfacedObjectWithCustomCreate can be used if you need an overriden constructor .locking is handled by TSQLServer.instance implementation pattern will be set by the appropriate parameter . aBinaryFile: boolean=false.e. virtual.g. Implement Server-Side TSQLRest unlocking .this data handles basic REST commands. 1.Rev.g. if any of the supplied interfaces is not implemented by the given class) . aID: integer): boolean.will return the first of the registered TServiceFactoryServer created on success (i. the table will be created as a regular table by the main database engine. it will create a TSQLRestServerStaticInMemory instance . warning: if you don't call this method before CreateMissingTable method is called.Synopse mORMot Framework Software Architecture Design 1.implements our custom UNLOCK REST-like method . before TSQLRestServerDB. inheriting e. 2013 function ServiceRegister(aImplementationClass: TInterfacedClass. const aInterfaces: array of PTypeInfo. Register a Service on the server side . the one corresponding to the first item of the aInterfaces array).Model .you can define a particular external engine by setting a custom class . overload.this methods expects a class to be supplied. and won't be static . [TypeInfo(IMyInterface)]) and implemented by this class . from TSQLRecordVirtualTableAutoID associated with TSQLVirtualTableJSON/Binary via a Model. Overriden method for direct static class call (if any) function TableRowCount(Table: TSQLRecordClass): integer.18 Date: June 16.the same implementation class can be used to handle several interfaces (just as Delphi allows to do natively) function StaticDataCreate(aClass: TSQLRecordClass.by default.returns true on success mORMot.g.you can use the returned TServiceFactoryServer instance to set the expected security parameters associated with this interface .call it just after Create. to provide full SQL process.pas unit . or nil if registration failed (e. override. const aFileName: TFileName = ''. ModelRoot/CacheFlush/TableName/ID URI will flush the content of the specified record .method parameters signature matches TSQLRestServerCallBack type procedure Stat(var Ctxt: TSQLRestServerCallBackParams). if any procedure Auth(var Ctxt: TSQLRestServerCallBackParams). and will return the server time stamp TTimeLog/Int64 value as RawUTF8 . and will flush the server cache .Synopse mORMot Framework Software Architecture Design 1..expect input as JSON commands .call corresponding fStaticData[] if necessary function UpdateBlob(Table: TSQLRecordClass. This method will be accessible from the ModelRoot/Batch URI. and will be called by the client for authentication and session management .. const BlobFieldName: RawUTF8. and will retrieve some statistics as a JSON object . This method will be accessible from ModelRoot/Stat URI.this method expect the blob data to be supplied as a TSQLRawBlob string function UpdateBlobFields(Value: TSQLRecord): boolean.18 Page 848 of 1055 .. Update all BLOB fields of the supplied Value .see TSQLRestServer.uses internally EngineUpdate() function for calling the database engine .Rev. 2013 function Update(Value: TSQLRecord): boolean. '{"Table":["cmd":values.this global callback method is thread-safe procedure Batch(var Ctxt: TSQLRestServerCallBackParams)..RunBatch. i.. const BlobData: TSQLRawBlob): boolean.]}' or for multiple tables: '["cmd@Table":values. This method will be accessible from ModelRoot/Auth URI.ModelRoot/CacheFlush URI will flush the whole Server cache.pas unit .this overriden method will execute the direct static class. Implement Server-Side TSQLRest blob field content update . aID: integer. Implement Server-Side TSQLRest update .method parameters signature matches TSQLRestServerCallBack type mORMot.only accepted context HTTP verb is PUT (for thread-safe and security reasons) procedure CacheFlush(var Ctxt: TSQLRestServerCallBackParams). for all tables . override. override. This method will be accessible from the ModelRoot/CacheFlush URI.implements REST PUT member with a supplied member ID and field name . This method will be accessible from the ModelRoot/TimeStamp URI. 1.uses internally EngineUpdateBlob() function for calling the database engine .18 Date: June 16.ModelRoot/CacheFlush/TableName URI will flush the specified table cache . override..e.this method shall be called by the clients when the Server cache could be not refreshed .]' with cmd in POST/PUT with {object} as value or DELETE with ID .method parameters signature matches TSQLRestServerCallBack type .method parameters signature matches TSQLRestServerCallBack type procedure TimeStamp(var Ctxt: TSQLRestServerCallBackParams). and will execute a set of RESTful commands . g. for optExecInMainThread option in TServiceMethod. virtual.Synopse mORMot Framework Software Architecture Design 1. 2013 procedure AnswerToMessage(var Msg: TWMCopyData).it will answer to the Client with another WM_COPYDATA message .caller must specify the TThread instance running .this method is called automaticaly if ExportServerMessage() method was initilialized . procedure AuthenticationRegister(aMethod: TSQLRestServerAuthenticationClass). but will use the main thread of your application procedure AuthenticationRegister(const aMethods: array of TSQLRestServerAuthenticationClass).Create() constructor is called with aHandleUserAuthentication set to TRUE. End a transaction (implements REST END Member) .this default implementation will call the methods of all its internal TSQLRestServerStatic instances . overload.g. Implement a message-based server response . You can call this method in TThread. override. overload. and use the TSQLRestClientURIMessage class to access the server instance from your clients .write all pending TSQLVirtualTableJSON data to the disk mORMot.TSQLRestServerAuthenticationSSPI ]). it may fail to prepare resources procedure Commit(SessionID: cardinal).this method shall be called from the thread just initiated: e.Execute to ensure that the thread will be taken in account during process . message WM_COPYDATA. Call this method to remove several authentication methods to the server procedure AuthenticationUnregister(aMethod: TSQLRestServerAuthenticationClass).Rev. if you call it from the main thread. Call this method to add several authentication methods to the server . overload.18 Page 849 of 1055 . Call this method to add an authentication method to the server procedure AuthenticationUnregister(const aMethods: array of TSQLRestServerAuthenticationClass).you can also call this method from the WM_COPYDATA message handler of your main form.message oriented architecture doesn't need any thread.pas unit .used e. it will register the two following classes: AuthenticationRegister([TSQLRestServerAuthenticationDefault.18 Date: June 16. 1.InternalExecute .if TSQLRestServer. overload. Call this method to remove an authentication method to the server procedure BeginCurrentThread(Sender: TThread). g. Implement a generic local.2. virtual. only Auth and TimeStamp methods do not require the RESTful authentication of the URI.yahoo.Rev.CacheFlush method procedure ServiceMethodByPassAuthentication(const aMethodName: RawUTF8). "dir". virtual. piped or HTTP/1.g.by default.g.this default implementation will call the methods of all its internal TSQLRestServerStatic instances. virtual.this method should also create additional fields. all REST/CRUD requests and direct SQL statements are scanned and identified as potentially able to change the internal SQL/JSON cache used at SQLite3 database level. as expected by the YUI DataSource Request Syntax for data pagination . You can call this method just before a thread is finished to ensure e.g. allowing e.Synopse mORMot Framework Software Architecture Design 1.for 'GET ModelRoot/TableName'.you must call explicitely this before having called StaticDataCreate() . either "sort". TSQLRestServerStaticExternal instances to clean their thread-specific connections . if you call it from the main thread.default implementation calls protected methods EngineList() Retrieve() Add() Update() Delete() UnLock() EngineExecute() above. field renaming or field deleting are not allowed in the FrameWork (in such cases. TSQLRestServerStaticExternal classes defined in SQLite3DB) could flush the database content without proper notification .it is set e.see http://developer.1. but SQlite3 unit will call TSQLDataBase. you must create a new TSQLRecord type) .18 Page 850 of 1055 . if the TSQLRecord definition has been modified. SQLite3 or TSQLRestServerFullInMemory) procedure EndCurrentThread(Sender: TObject).18 Date: June 16. Call this method when the internal DB content is known to be invalid . for returning some HTML content from a public URI) procedure URI(var Call: TSQLRestServerURIParams). or by TSQLRestServerNamedPipeResponse for named-pipe server cleaning procedure FlushInternalDBCache. from the client side . mORMot.1.this is the main entry point of the server.g. that the associated external DB connection will be released . 2013 procedure CreateMissingTables(user_version: cardinal=0).overriden versions should implement it as expected by the underlying storage engine (e.this method shall be called from the thread about to be terminated: e.4 (page 1049). but some virtual tables (e. 1. you may call this method to add another method to the list (e. it may fail to release resources .this virtual method do nothing by default .this default implementation just do nothing. "startIndex".g. which must be overriden by the TSQLRestServer child .pas unit . Missing tables are created if they don't exist yet for every TSQLRecord class of the Database Model . "results". url parameters can be either "select" and "where" (to specify a SQL Query.1 provider .by default.g.com/yui/datatable/#data Used for DI-2. from the SQLFromSelectWhere function). only field adding is mandatory. virtual.all table description (even Unique feature) is retrieved from the Model . by TSQLite3HttpServer to be called from HTTP threads. Call this method to disable Authentication method check for a given published method name . g.ExportServerNamedPipe: if you use named pipes for communication. 2013 property HandleAuthentication: boolean read fHandleAuthentication. if the associated TSQLModel contains TSQLAuthUser and TSQLAuthGroup tables (set by constructor) property NoAJAXJSON: boolean read fNoAJAXJSON write SetNoAJAXJSON. Retrieve the TSQLRestServerStatic instance used to store and manage a specified TSQLRecordClass in memory .associated e.g.By default. parsing will be also faster and memory usage will be lower .the "expanded" or standard/AJAX layout allows you to create pure JavaScript objects from the JSON content.this property will return nil if there is no Virtual Table associated or if the corresponding module is not a TSQLVirtualTable (e. you probably won't use javascript because browser communicates via HTTP! .e. NoAJAXJSON property is set to FALSE. Set to true if the server will handle per-user authentication and access right management . to a 'JSON' or 'Binary' virtual table module. "pure" static tables registered by StaticDataCreate would be accessible only via StaticDataServer[]. NoAJAXJSON property is set to TRUE. You could force its value to TRUE and you'd save some bandwidth if you don't use javascript: even the parsing of the JSON Content will be faster with Delphi client if JSON content is not expanded .Synopse mORMot Framework Software Architecture Design 1. 1.VirtualTableRegister method or the VirtualTableExternalRegister() global function mORMot. Retrieve a running TSQLRestServerStatic virtual table .but transmitted JSON data is much smaller if set it's set to FALSE.18 Page 851 of 1055 .18 Date: June 16. reflects exactly the layout of the SQL request . and if you use a Delphi Client. the NoAJAXJSON property is set to TRUE in TSQLRestServer.i.pas unit .But otherwise.Rev. because the field name / JavaScript object property name is supplied for every value . or may return a TSQLRestServerStaticExternal instance (as defined in SQLite3DB) . Set this property to true to transmit the JSON data in a "not expanded" format .not directly compatible with Javascript object list decode: not to be used in AJAX environnement (like in TSQLite3HttpServer) . not via StaticVirtualTable[]) .the "not expanded" layout.has been associated by the TSQLModel. then all next lines are the field content property StaticDataServer[aClass: TSQLRecordClass]: TSQLRestServerStatic read GetStaticDataServer.has been associated by the StaticDataCreate method property StaticVirtualTable[aClass: TSQLRecordClass]: TSQLRestServerStatic read GetVirtualTable.first line contains the field names. 18 Date: June 16. Overriden method for direct in-memory database engine call .18 Page 852 of 1055 .store the results into the ResultID dynamic array . FieldValue: RawUTF8. if some values have been added to ResultID) . Overriden method for direct in-memory database engine call .g. This property can be left to its TRUE default value.data encoding on file is UTF-8 JSON format by default. 1.e. joined SELECT) will rely on the main SQL engine . GET/POST/PUT/DELETE of individual records (or BLOB fields) from URI() will call directly the corresponding TSQLRestServerStatic instance. virtual. abstract. aBinaryFile: boolean=false). i. 2013 property StaticVirtualTableDirect: boolean read fVirtualTableDirect write fVirtualTableDirect. override.this abstract class is to be overriden with a proper implementation (like our TSQLRestServerStaticInMemory class) constructor Create(aClass: TSQLRecordClass. Search for a field value. Access to the Server statistics TSQLRestServerStatic = class(TSQLRestServer) REST server with direct access to an external database engine . Initialize the server data. will use the main SQLite3 engine for all statements (should not to be used normaly. for better speed for most used RESTful operations. override. but complex SQL requests (e. virtual. WhereValue: RawUTF8): boolean.faster than OneFieldValues method.made public since a TSQLRestServerStatic instance may be created stand-alone.is set to TRUE by default to enable faster Direct mode . WhereFieldName.if set to false. which will be used for overriden constructor only) function EngineExecuteAll(const aSQL: RawUTF8): boolean.e. which creates a temporary JSON content mORMot.do nothing method: will return FALSE (aka error) function SearchField(const FieldName. or should be some binary format if aBinaryFile is set to true (this virtual method will just ignore this parameter. without any associated Model/TSQLRestServer . according to its SQL content representation .Synopse mORMot Framework Software Architecture Design 1.in Direct mode. because it will add unnecessary overhead) property Stats: TSQLRestServerStats read fStats. to handle any TSQLVirtualTableJSON static tables (module JSON or BINARY) with direct calls to the storage instance .this method must be implemented to be thread-safe function EngineUpdateField(Table: TSQLRecordClass. const SetFieldName. var ResultID: TIntegerDynArray): boolean.not implemented: always return false .pas unit . SetValue. const aFileName: TFileName = ''.you can set an alternate per-table database engine by using this class .return true on success (i. reading it from a file if necessary .Rev. overload. aServer: TSQLRestServer. Read only access to the Server using this in-memory database property StoredClass: TSQLRecordClass read fStoredClass.you can call the TSQLRestServer. overload. Search for a numerical field value . e.and all its properties are filled from the Items[] values . Read only access to the file name specified by constructor . abstract. if some values have been added to ResultID) . then use UpdateOne() if the changes have to be stored inside the Items[] list . Manual Retrieval of a TSQLRecord field values .returns the ID created on success .calller must always free the returned instance .returns -1 on failure (not UNIQUE field value e. Manual Add of a TSQLRecord .Synopse mORMot Framework Software Architecture Design 1. virtual.Rev.on success. virtual.faster than OneFieldValues method. Read only access to a boolean value set to true if table data was modified property Owner: TSQLRestServer read fOwner.e.18 Date: June 16. FieldValue: Integer. i.this default implementation will call the overloaded SearchField() value after conversion of the FieldValue into RawUTF8 property FileName: TFileName read fFileName write fFileName.pas unit . virtual.18 Page 853 of 1055 . which creates a temporary JSON content . if the supplied aID was incorrect . Read only access to the RTTI properties of the associated record type TSQLRestServerStaticRecordBased = class(TSQLRestServerStatic) Abstract REST server exposing some internal TSQLRecord-based methods function AddOne(Rec: TSQLRecord. 1.) . 2013 function SearchField(const FieldName: RawUTF8.e.return true on success (i.caller can modify these properties. without any associated Model/TSQLRestServer mORMot.method available since a TSQLRestServerStatic instance may be created stand-alone.may be nil if this instance is not associated with a TSQLModel property StoredClassRecordProps: TSQLRecordProperties read fStoredClassRecordProps. ForceID: boolean): integer.g. Read only access to the ORM properties of the associated record type . Read only access to the class defining the record type stored in this REST server property StoredClassProps: TSQLModelRecordProperties read fStoredClassProps. var ResultID: TIntegerDynArray): boolean.StaticDataCreate method to update the file name of an already instancied static table property Modified: boolean read fModified write fModified.g.store the results into the ResultID dynamic array .returns NIL if any error occured. the Rec instance is added to the Values[] list: caller doesn't need to Free it function GetOne(aID: integer): TSQLRecord. abstract.an instance of the associated static class is created . e.ID) . FALSE on any error (e. Manual Update of a TSQLRecord field values . to hash TSQLRestServerStaticInMemory field values constructor Create(aValues: TList. aFieldIndex: integer.method available since a TSQLRestServerStatic instance may be created stand-alone. invalid Rec. i. will apply NormToUpper[] 8 bits uppercase. The corresponding field index in the TSQLRecord mORMot. The corresponding field RTTI property FieldIndex: integer read fField. virtual.g.Rev. aField: TSQLPropInfo.g. If the string comparison shall be case-insensitive property Field: TSQLPropInfo read fProp. FALSE on any error (e. 2013 function UpdateOne(ID: integer.method available since a TSQLRestServerStatic instance may be created stand-alone.used e. and will call overloaded UpdateOne() method function UpdateOne(Rec: TSQLRecord): boolean.will update all properties.g.e. "stored AS_UNIQUE" published property) .aFieldIndex/aField parameters correspond to the indexed field (e. virtual. without any associated Model/TSQLRestServer TListFieldHash = class(TObjectHash) Class able to handle a O(1) hashed-based search of a property in a TList .ID specifies which record is to be updated .pas unit .this default implementation will create a temporary TSQLRecord instance with the supplied Values[].18 Page 854 of 1055 .returns TRUE on success.ID) . const Values: TVarDataDynArray): boolean. invalid Rec. Initialize a hash for a record array field .Synopse mORMot Framework Software Architecture Design 1.will update all properties. without any associated Model/TSQLRestServer . overload.g. including BLOB fields and such . abstract. handling RawUTF8 properties just like the SYSTEMNOCASE collation property CaseInsensitive: boolean read fCaseInsensitive.if CaseInsensitive is TRUE. aCaseInsensitive: boolean). overload. i.Rec.18 Date: June 16.returns TRUE on success. 1. including BLOB fields and such . Manual Update of a TSQLRecord field values from TVarData array . no SQL interpreter is implemented: only valid SQL command is "SELECT Field1.Field2 FROM Table WHERE ID=120.data can be stored and retrieved from a file (JSON format is used by default.made public since a TSQLRestServerStatic instance may be created stand-alone. by using the TSQLRestServer. i.) .especially release all fValue[] instances function AddOne(Rec: TSQLRecord. ForceID: boolean): integer. i. Manual Add of a TSQLRecord .handle only one TSQLRecord by server (it's NOT a true Rest Server) .e. SetValue.handle basic REST commands. ID: integer): boolean. Initialize the server data. override.StaticDataCreate method: it allows an unique access for both SQLite3 and Static databases . if BinaryFile parameter is left to false. without any associated Model/TSQLRestServer mORMot. without any associated Model/TSQLRestServer function EngineUpdateField(Table: TSQLRecordClass.000 rows .". override.our TSQLRestServerStatic database engine is very optimized and is a lot faster than SQLite3 for such queries . aBinaryFile: boolean=false). override.must be registered individualy in a TSQLRestServer to access data from a common client. WhereValue: RawUTF8): boolean. Free used memory .returns -1 on failure (not UNIQUE field value e. if used within a TSQLVirtualTableJSON. you'll be able to handle any kind of SQL statement (even joined SELECT or such) with this memory-stored database . override.but its values remain in RAM.e.g.made public since a TSQLRestServerStatic instance may be created stand-alone. a proprietary compressed binary format can be used instead) if a file name is supplied at creating the TSQLRestServerStaticInMemory instance constructor Create(aClass: TSQLRecordClass.on success.pas unit . const SetFieldName.Synopse mORMot Framework Software Architecture Design 1. 1.data encoding on file is UTF-8 JSON format by default. or should be some binary format if aBinaryFile is set to true destructor Destroy. therefore it is not meant to deal with more than 100.Rev.e a one Table SELECT with one optional "WHERE fieldname = value" statement.18 Page 855 of 1055 . const aFileName: TFileName = ''.store the associated TSQLRecord values in memory .18 Date: June 16. override. aServer: TSQLRestServer. the Rec instance is added to the Values[] list: caller doesn't need to Free it function EngineDelete(Table: TSQLRecordClass. WhereFieldName. i. Overriden method for direct in-memory database engine call . Overriden method for direct in-memory database engine call . reading it from a file if necessary . 2013 TSQLRestServerStaticInMemory = class(TSQLRestServerStaticRecordBased) REST server with direct access to a memory-stored database .returns the ID created on success . override. if the supplied aID was incorrect .the binary content is first checked for consistency. if some values have been added to ResultID) . it won't be able to read a file content with a renamed or modified field type .an instance of the associated static class is created .e. Search for a field value.warning: the field layout should be the same at SaveToBinary call. a 27 KB Dali1.the binary format is a custom compressed format (using our SynLZ fast compression algorithm). which creates a temporary JSON content function TableHasRows(Table: TSQLRecordClass): boolean.g.json content is stored into a 6 KB Dali2. Load the values from binary data .e.method available since a TSQLRestServerStatic instance may be created stand-alone. without any associated Model/TSQLRestServer function IDToIndex(ID: integer): integer.Synopse mORMot Framework Software Architecture Design 1.caller can modify these properties. before loading .store the results into the ResultID dynamic array . Manual Retrieval of a TSQLRecord field values . override. overload.18 Date: June 16. then use UpdateOne() if the changes have to be stored inside the Items[] list .returns NIL if any error occured. for instance. 502 KB People.data file .returns the number of bytes written into Stream function SaveToJSON(Expand: Boolean): RawUTF8.ID should be increasing) function LoadFromBinary(Stream: TStream): boolean. e. override.Rev.g. override. with variable-length record storage . Save the values into JSON data function SearchField(const FieldName. var ResultID: TIntegerDynArray): boolean.pas unit . 1.calller must always free the returned instance .use fast binary search algorithm (since Items[].18 Page 856 of 1055 . i. 2013 function GetOne(aID: integer): TSQLRecord. Save the values into binary data . override.return true on success (i. according to its SQL content representation .data file (this data has a text redundant field content in its FirstName field).return -1 if this ID was not found . FieldValue: RawUTF8. with variable-length record storage: e.faster than OneFieldValues method. Overriden method for direct in-memory database engine call function TableRowCount(Table: TSQLRecordClass): integer. Overriden method for direct in-memory database engine call mORMot.json content is stored into a 92 KB People.will return false if the binary content is invalid function RetrieveBlobFields(Value: TSQLRecord): boolean. Overriden method for direct in-memory database engine call function SaveToBinary(Stream: TStream): integer. Retrieve the index in Items[] of a particular ID .the binary format is a custom compressed format (using our SynLZ fast compression algorithm).and all its properties are filled from the Items[] values . overload.returns TRUE on success. Expand: Boolean). or binary content if BinaryFile property was set to true property BinaryFile: boolean read fBinaryFile write fBinaryFile. including BLOB fields and such . Save the values into JSON data procedure UpdateFile. Read-only access to the number of TSQLRecord values property ExpandedJSON: boolean read fExpandedJSON write fExpandedJSON.this method is called automaticaly when the TSQLRestServerStatic instance is destroyed: should should want to call in in some cases. invalid Rec.g. e. the JSON will be in the custom non-expanded format.e. If set to true.method available since a TSQLRestServerStatic instance may be created stand-alone.18 Date: June 16. i.do nothing if the table content was not modified . file content on disk will expect binary format . FALSE on any error (e. const Values: TVarDataDynArray): boolean. Load the values from JSON data procedure LoadFromJSON(JSONBuffer: PUTF8Char. can set if the format should be expanded or not . i.g.ID specifies which record is to be updated . JSON writing. FALSE on any error (e. Manual Update of a TSQLRecord field values . 2013 function UpdateBlobFields(Value: TSQLRecord): boolean. but can be proprietary property CommitShouldNotUpdateFile: boolean read fCommitShouldNotUpdateFile write fCommitShouldNotUpdateFile. override. overload. without any associated Model/TSQLRestServer procedure LoadFromJSON(const aJSON: RawUTF8).by default.will update all properties.18 Page 857 of 1055 .pas unit .will write JSON content by default. the file is updated on disk . invalid Rec. including BLOB fields and such . override. 1. Load the values from JSON data procedure SaveToJSON(Stream: TStream.g. override.ID) .Rec. in order to force the data to be saved regularly .default format on disk is JSON but can be overriden at constructor call .you can force the JSON to be emitted as an array of objects.will update all properties. without any associated Model/TSQLRestServer function UpdateOne(ID: integer. If file was modified.binary format should be more efficient in term of speed and disk usage.ID) . Overriden method for direct in-memory database engine call function UpdateOne(Rec: TSQLRecord): boolean.e. overload.Rev. to save disk space and time . Manual Update of a TSQLRecord field values from TVarData array .returns TRUE on success. for better human friendliness (reading and modification) mORMot. JSONBufferLen: integer).method available since a TSQLRestServerStatic instance may be created stand-alone.Synopse mORMot Framework Software Architecture Design 1. Set this property to TRUE if you want the COMMIT statement not to update the associated TSQLVirtualTableJSON property Count: integer read GetCount. const aFileName: TFileName=''. Overriden method for direct in-memory database engine call .so it will not handle all SQL requests. virtual. Read-only access to the TSQLRecord values.18 Page 858 of 1055 . override.Rev. but TSQLVirtualTableJSON virtual tables could flush the database content without proper notification .then data persistence will be created using aFileName . override.Synopse mORMot Framework Software Architecture Design 1. Initialize a REST server with a database file .FlushInternalDBCache TSQLRestServerFullMemory = class(TSQLRestServer) A REST server using only in-memory tables .pas unit .all classes of the model will be created as TSQLRestServerStaticInMemory . data will not be persistent destructor Destroy. Call this method when the internal DB content is known to be invalid . it will compile as a TSQLRestServer without complaining for pure abstract methods.by default. override. Read-only access to the ID of a TSQLRecord values property Items[Index: integer]: TSQLRecord read GetItem. 1. if only authentication and CRUD are needed) constructor Create(aModel: TSQLModel. storing the data .this overriden implementation will call Owner. it can be used to host some services if database and ORM needs are basic (e.not implemented: always return false mORMot. all REST/CRUD requests and direct SQL statements are scanned and identified as potentially able to change the internal SQL/JSON cache used at SQLite3 database level. unless you may have unexpected behavior TSQLRestServerStaticInMemoryExternal = class(TSQLRestServerStaticInMemory) REST server with direct access to a memory database.g.this returns directly the item class instance stored in memory: if you change the content. 2013 property ID[Index: integer]: integer read GetID. aBinaryFile: boolean=false. just basic CRUD commands on separated tables .if aFileName is left void (''). and optionally persist the data on disk as JSON or binary files . it will affect the internal data .this server will use TSQLRestServerStaticInMemory instances to handle the data in memory.18 Date: June 16. reintroduce. in order to be consistent with the internal DB cache procedure FlushInternalDBCache. to be used as external table .so for instance DO NOT change the ID values. Write any modification on file (if needed). and release all used memory function EngineExecuteAll(const aSQL: RawUTF8): boolean.at least. aHandleUserAuthentication: boolean=false).this is the kind of in-memory table expected by TSQLVirtualTableJSON. override.all table description (even Unique feature) is retrieved from the Model . override. to host some services on a stand-alone server.pas unit .will return false .this server will use an internal TSQLRestClient instance to handle all ORM operations (i.Model will be used for TSQLRestServerRemoteDB .18 Page 859 of 1055 .e.this overriden method will just return TRUE: in this remote access.caller shall manage its life time function AfterDeleteForceCoherency(Table: TSQLRecordClass. you must create a new TSQLRecord type) procedure LoadFromFile.since it is a server side operation mORMot. as a DMZ for publishing services. with all ORM and data access retrieved from another server: it will allow to easily implement a proxy architecture (for instance. true coherency will be performed on the ORM server side function EngineExecuteAll(const aSQL: RawUTF8): boolean. This method is called internally after any successfull deletion to ensure relational database coherency .do nothing if file name was not assigned property BinaryFile: Boolean read fBinaryFile write fBinaryFile. not implemented . access to objects) . aHandleUserAuthentication: boolean=false).it will use TSQLRestServerStaticInMemory LoadFromJSON/LoadFromBinary SaveToJSON/SaveToBinary methods for optimized storage property FileName: TFileName read fFileName write fFileName. only field adding is available.the supplied TSQLRestClient.this method also create additional fields. virtual.Synopse mORMot Framework Software Architecture Design 1. The file name used for data persistence TSQLRestServerRemoteDB = class(TSQLRestServer) A REST server using a TSQLRestClient for all its ORM process .you must call explicitely this before having called StaticDataCreate() .note that the TSQLRestClient instance won't be freed . Implement Server-Side TSQLRest deletion overriden method for remote database engine call . virtual. or standard JSON . 1. Write any modification into file . reintroduce.18 Date: June 16. Set if the file content is to be compressed binary. Initialize a REST server associated to a given TSQLRestClient instance . Load the content from the specified file name .i.e.it can be used e.g. virtual.the specified TSQLRestClient will be used for all ORM and data process . field renaming or field deleting are not allowed in the FrameWork (in such cases.Rev. 2013 procedure CreateMissingTables(user_version: cardinal=0). aID: integer): boolean. override. if the TSQLRecord definition has been modified. Missing tables are created if they don't exist yet for every TSQLRecord class of the Database Model . but letting ORM process stay out of scope) constructor Create(aRemoteClient: TSQLRestClient.do nothing if file name was not assigned procedure UpdateToFile. return true on success mORMot.pas unit .18 Date: June 16. const Args: array of const): boolean. returns 0 .g.on success. const Args.on success. SendData: boolean. 2013 function ExecuteList(const Tables: array of TSQLRecordClass. returns the new ROWID value. and all '?' chars with Bounds[] (inlining them with :(.return a result table on success. Execute directly a SQL statement . Execute directly a SQL statement with supplied parameters .server must return Status 200/HTML_SUCCESS OK on success function EngineExecute(const SQL: RawUTF8): boolean.will call EngineList() abstract method to retrieve its JSON content property Client: TSQLRestClient read fClient. overload. expecting a list of results . nil on failure .): and auto-quoting strings) . override.server must send on success an header entry with 'Location: ModelRoot/TableName/ID .ID field to use this ID . The remote ORM client used for data persistence TSQLRestClient = class(TSQLRest) A generic REpresentational State Transfer (REST) client . abstract. override. 1. Create a new member (implements REST POST Collection) .) . Bounds: array of const): boolean.Rev.. ForceID: boolean=false): integer. Execute directly a SQL statement with supplied parameters . replacing all '%' chars with Args[] values. override. Delete a member (implements REST DELETE Collection/Member) . on error.if ForceID is true.) function Add(Value: TSQLRecord.if SendData is true.Synopse mORMot Framework Software Architecture Design 1. virtual. URI) remotely implemented (TSQLRestClientURI e.URI is 'ModelRoot/TableName/ID' with DELETE method .is RESTful (i. overload.expect the same format as FormatUTF8() function. ID: integer): boolean.e. Value.expect the same format as FormatUTF8() function. Execute directly a SQL statement.ID is stored to the virtual table function Delete(Table: TSQLRecordClass. const SQL: RawUTF8): TSQLTableJSON.return true on success function EngineExecuteFmt(SQLFormat: PUTF8Char.return true on success function EngineExecuteFmt(SQLFormat: PUTF8Char. content of Value is sent to the server as JSON . client sends the Value. replacing all '%' chars with Args[] values .18 Page 860 of 1055 .is implemented for direct access to a database (TSQLRestClientDB e..g.server must return Status 201/HTML_CREATED on success . overload.if aValue is TSQLRecordFTS3. Value.URI is 'ModelRoot/TableName' with POST method .ID is updated with the new ROWID . you should better use TSQLRest.'Name'.MultiFieldValues() . then retrieve its content.server must return Status 200/HTML_SUCCESS OK on success . const SQLSelect: RawUTF8 = 'RowID'. overload. const SQLWhere: RawUTF8 = ''): TSQLTableJSON.will call the List virtual method internaly function Refresh(aID: integer. false on error .. abstract.e. replacing all '%' chars with Args[] values . Get a member from its ID (implements REST GET Collection/Member) .18 Date: June 16. const SQLSelect: RawUTF8. the WHERE clause can be created with the same format as FormatUTF8() function.for one TClass. const Args.in this version. to release the record mORMot. caller has to call UnLock() method after Value usage. SQLWhereFormat: PUTF8Char.[].URI is 'ModelRoot/TableName/ID' with GET method . the REST method is LOCK and not GET: it tries to lock the corresponding record. ForUpdate: boolean=false): boolean.): in SQLWhere is always a good idea .if ForUpdate is true.MultiFieldValues() function ListFmt(const Tables: array of TSQLRecordClass. Value: TSQLRecord.Synopse mORMot Framework Software Architecture Design 1.. Retrieve a list of members as a TSQLTable (implements REST GET Collection) .optional SQLSelect parameter to change the returned fields as in 'SELECT SQLSelect FROM TableName. Retrieve a list of members as a TSQLTable (implements REST GET Collection) . Bounds: array of const): TSQLTableJSON. const Args: array of const): TSQLTableJSON. const SQLSelect: RawUTF8. overload. the WHERE clause can be created with the same format as FormatUTF8() function.example of use: Table := ListFmt([TSQLRecord]..): in SQLWhereFormat is always a good idea . Retrieve a list of members as a TSQLTable (implements REST GET Collection) . you should better use TSQLRest.'ID=?'.URI is 'ModelRoot/TableName/ID' with GET method . override. SQLWhereFormat: PUTF8Char.using inlined parameters via :(.in this version. .pas unit . and all '?' chars with Bounds[] (inlining them with :(.[aID]). 1.using inlined parameters via :(. replacing all '%' chars with Args[].returns true on server returned 200/HTML_SUCCESS OK success.MultiFieldValues() . you should better use TSQLRest.' .Rev.default SQL statement is 'SELECT ID FROM TableName.' .): and auto-quoting strings) . retrieve the list of all ID of this collection members) .for one TClass...18 Page 861 of 1055 .set Refreshed to true if the content changed function Retrieve(aID: integer.' (i.for one TClass. 2013 function List(const Tables: array of TSQLRecordClass. virtual.will call the List virtual method internaly function ListFmt(const Tables: array of TSQLRecordClass. var Refreshed: boolean): boolean.optional SQLWhere parameter to change the search range or ORDER as in 'SELECT SQLSelect FROM TableName WHERE SQLWhere. Value: TSQLRecord. Get a member from its ID (implements REST GET Collection/Member) .. URI is 'ModelRoot/TableName/ID/BlobFieldName' with PUT method .RTreeMatch(TSQLRecordMapData. Client transaction will use here a pseudo session mORMot. and will call TSQLRecordRTree BlobToCoord and ContainedIn virtual class methods to execute an optimized SQL query . override. MapBox WHERE MapData. Begin a transaction (calls REST BEGIN Member) . const BlobFieldName: RawUTF8.by default.BlobField.:('\uFFF0base64encoded-81. 2013 function RetrieveBlob(Table: TSQLRecordClass.this method expect the blob data to be supplied as a TSQLRawBlob string procedure Commit(SessionID: cardinal=CONST_AUTHENTICATION_NOT_USED).2'):). Client transaction will use here a pseudo session procedure RollBack(SessionID: cardinal=CONST_AUTHENTICATION_NOT_USED).BlobField.by default.ID=MapBox.ResultID). the following statement SELECT MapData.will return all matching DataTable IDs in DataID[] . const DataTableBlobFieldName: RawUTF8. Client transaction will use here a pseudo session function Update(Value: TSQLRecord): boolean.0): AND maxX<=:(-79. aID: integer. override. override.'BlobField'. override. var DataID: TIntegerDynArray): boolean.35.will generate e.36. Abort a transaction (calls REST ABORT Member) .Rev.server must return Status 200/HTML_SUCCESS OK on success . SessionID: cardinal=CONST_AUTHENTICATION_NOT_USED): boolean. Dedicated method used to retrieve matching IDs using a fast R-Tree index .ID AND minX>=:(-81.server must return Status 200/HTML_SUCCESS OK on success . override.0): AND :(maxY<=36.this method retrieve the blob data as a TSQLRawBlob string function RTreeMatch(DataTable: TSQLRecordClass.18 Page 862 of 1055 . when the following Delphi code is executed: aClient.URI is 'ModelRoot/TableName/ID' with PUT method . function TransactionBegin(aTable: TSQLRecordClass. aID: integer.-79.g. End a transaction (calls REST END Member) . Get a blob field content from its record ID and supplied blob field name .implements REST GET member with a supplied member ID and a blob field name . 1.pas unit .server must return Status 200/HTML_SUCCESS OK on success function UpdateBlob(Table: TSQLRecordClass.implements REST PUT member with a supplied member ID and field name . const DataTableBlobField: RawByteString.18 Date: June 16. override.by default. aMapData.Synopse mORMot Framework Software Architecture Design 1.ID From MapData. out BlobData: TSQLRawBlob): boolean. const BlobFieldName: RawUTF8.2): AND MapBox_in(MapData.URI is 'ModelRoot/TableName/ID/BlobFieldName' with GET method . RTreeTable: TSQLRecordRTreeClass.6.a TSQLRecordRTree is associated to a TSQLRecord with a specified BLOB field. Update a blob field from its record ID and supplied blob field name . Update a member (implements REST PUT Collection/Member) .TSQLRecordMapBox.6): AND minY>=:(35. const BlobData: TSQLRawBlob): boolean. 1.2.also unlock all still locked records by this client function BatchAdd(Value: TSQLRecord.returns the corresponding index in the current BATCH sequence.URI are standard Collection/Member implemented as ModelRoot/TableName/ID .ID field to use this ID for adding the record (instead of a database-generated ID) . -1 on error .1.if SendData is true.3 (page 1049).2. This Event is called by Update() to let the client perform the record update (refresh associated report e.pas unit . override. DI-2.Rev. constructor Create(aModel: TSQLModel). even if this property setting is set to TRUE . Is set to TRUE. which setting will spare bandwidth and CPU property OnRecordUpdate: TOnRecordUpdate read fOnRecordUpdate write fOnRecordUpdate.g. Retrieve() will use Blob-related RESTful GET request . 2013 property ForceBlobTransfert: boolean read fForceBlobTransfert write fForceBlobTransfert. Value.i. DI-2. 1. Release memory and close client connection . Add() Update() will use Blob-related RESTful PUT/POST request . this property is set to FALSE.1.2 (page 1048).if Value is TSQLRecordFTS3.1.note that the Refresh method won't handle BLOB fields.1.g.Value class MUST match the TSQLRecordClass used at BatchTransactionBegin. Retrieve the current number of pending transactions in the BATCH sequence . This Event is called by UpdateFromServer() to let the Client adapt to some rows update (for Marked[] e.e.i.e. Create a new member in current BATCH sequence . content of Value is sent to the server as JSON . all BLOB fields are transferred between the Client and the remote Server . SendData: boolean.4 (page 1049). DI-2. Initialize REST client instance destructor Destroy. override.) property OnTableUpdate: TOnTableUpdate read fOnTableUpdate write fOnTableUpdate.2.1.18 Date: June 16. client sends the Value.1 (page 1047).BLOB fields are NEVER transmitted here. even if ForceBlobTransfert=TRUE function BatchCount: integer.Synopse mORMot Framework Software Architecture Design 1.18 Page 863 of 1055 . DI-2.work in BATCH mode: nothing is sent to the server until BatchSend call . or may be of any kind if no class was specified . ForceID: boolean=false): integer.1.) TSQLRestClientURI = class(TSQLRestClient) A generic REpresentational State Transfer (REST) client with URI .handle RESTful commands GET POST PUT DELETE LOCK UNLOCK Used for DI-2.every call to BatchAdd/Update/Delete methods increases this count mORMot.1.by default.if ForceID is true.1 (page 1047).1.ID is stored to the virtual table . Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 function BatchDelete(ID: integer): integer; overload; Delete a member in current BATCH sequence - work in BATCH mode: nothing is sent to the server until BatchSend call - returns the corresponding index in the current BATCH sequence, -1 on error - deleted record class is the TSQLRecordClass used at BatchTransactionBegin() call: it will fail if no class was specified for this BATCH sequence function BatchDelete(Table: TSQLRecordClass; ID: integer): integer; overload; Delete a member in current BATCH sequence - work in BATCH mode: nothing is sent to the server until BatchSend call - returns the corresponding index in the current BATCH sequence, -1 on error - with this overloaded method, the deleted record class is specified: no TSQLRecordClass shall have been set at BatchTransactionBegin() call function BatchSend(var Results: TIntegerDynArray): integer; Execute a BATCH sequence started by BatchStart method - send all pending BatchAdd/Update/Delete statements to the remote server - URI is 'ModelRoot/TableName/0' with POST method - will return the URI Status value, i.e. 200/HTML_SUCCESS OK on success - a dynamic array of integers will be created in Results, containing all ROWDID created for each BatchAdd call, 200 (=HTML_SUCCESS) for all successfull BatchUpdate/BatchDelete, or 0 on error - any error during server-side process MUST be checked against Results[] (the main URI Status is 200 if about communication success, and won't imply that all statements in the BATCH sequence were successfull function BatchStart(aTable: TSQLRecordClass): boolean; Begin a BATCH sequence to speed up huge database change - each call to normal Add/Update/Delete methods will create a Server request, therefore can be slow (e.g. if the remote server has bad ping timing) - start a BATCH sequence using this method, then call BatchAdd() BatchUpdate() or BatchDelete() methods to make some changes to the database - when BatchSend will be called, all the sequence transactions will be sent as one to the remote server, i.e. in one URI request - if BatchAbort is called instead, all pending BatchAdd/Update/Delete transactions will be aborted, i.e. ignored - expect one TSQLRecordClass as parameter, which will be used for the whole sequence (in this case, you can't mix classes in the same BATCH sequence) - if no TSQLRecordClass is supplied, the BATCH sequence will allow any kind of individual record in BatchAdd/BatchUpdate/BatchDelete - return TRUE on sucess, FALSE if aTable is incorrect or a previous BATCH sequence was already initiated - should normally be used inside a Transaction block: there is no automated TransactionBegin..Commit/RollBack generated in the BATCH sequence mORMot.pas unit - Rev. 1.18 Page 864 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 function BatchUpdate(Value: TSQLRecord): integer; Update a member in current BATCH sequence - work in BATCH mode: nothing is sent to the server until BatchSend call - returns the corresponding index in the current BATCH sequence, -1 on error - Value class MUST match the TSQLRecordClass used at BatchTransactionBegin, or may be of any kind if no class was specified - BLOB fields are NEVER transmitted here, even if ForceBlobTransfert=TRUE - if Value has an opened FillPrepare() mapping, only the mapped fields will be updated (and also ID and TModTime fields) - FillPrepareMany() is not handled yet (all simple fields will be updated) function CallBackGet(const aMethodName: RawUTF8; const aParameters: array of const; out aResponse: RawUTF8; aTable: TSQLRecordClass=nil; aID: integer=0; aResponseHead: PRawUTF8=nil): integer; Wrapper to the protected URI method to call a method on the server, using a ModelRoot/[TableName/[ID/]]MethodName RESTful GET request - returns the HTTP error code (e.g. 200/HTML_SUCCESS on success) - this version will use a GET with supplied parameters (which will be encoded with the URL) function CallBackGetResult(const aMethodName: RawUTF8; const aParameters: array of const; aTable: TSQLRecordClass=nil; aID: integer=0): RawUTF8; Wrapper to the protected URI method to call a method on the server, using a ModelRoot/[TableName/[ID/]]MethodName RESTful GET request - returns the UTF-8 decoded JSON result (server must reply with one "result":"value" JSON object) - this version will use a GET with supplied parameters (which will be encoded with the URL) function CallBackPut(const aMethodName, aSentData: RawUTF8; out aResponse: RawUTF8; aTable: TSQLRecordClass=nil; aID: integer=0; aResponseHead: PRawUTF8=nil): integer; Wrapper to the protected URI method to call a method on the server, using a ModelRoot/[TableName/[ID/]]MethodName RESTful PUT request - returns the HTTP error code (e.g. 200/HTML_SUCCESS on success) - this version will use a PUT with the supplied raw UTF-8 data function EngineExecute(const SQL: RawUTF8): boolean; override; Execute directly a SQL statement - URI is 'ModelRoot' with POST method, and SQL statement sent as UTF-8 - server must return Status 200/HTML_SUCCESS OK on success function ExecuteList(const Tables: array of TSQLRecordClass; const SQL: RawUTF8): TSQLTableJSON; override; Execute directly a SQL statement, expecting a list of resutls - URI is 'ModelRoot' with GET method, and SQL statement sent as UTF-8 - return a result table on success, nil on failure function List(const Tables: array of TSQLRecordClass; const SQLSelect: RawUTF8 = 'RowID'; const SQLWhere: RawUTF8 = ''): TSQLTableJSON; override; Retrieve a list of members as a TSQLTable (implements REST GET Collection) - URI is 'ModelRoot/TableName' with GET method - SQLSelect and SQLWhere are encoded as 'select=' and 'where=' URL parameters (using inlined parameters via :(...): in SQLWhere is always a good idea) - server must return Status 200/HTML_SUCCESS OK on success mORMot.pas unit - Rev. 1.18 Page 865 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 function ServerCacheFlush(aTable: TSQLRecordClass=nil; aID: integer=0): boolean; Send a flush command to the remote Server cache - this method will remotely call the Cache.Flush() methods of the server instance, to force cohesion of the data - ServerCacheFlush() with no parameter will flush all stored JSON content - ServerCacheFlush(aTable) will flush the cache for a given table - ServerCacheFlush(aTable,aID) will flush the cache for a given record function ServerInternalState: cardinal; Ask the server for its current internal state revision counter - this counter is incremented every time the database is modified - the returned value is 0 if the database doesn't support this feature - TSQLTable does compare this value with its internal one to check if its content must be updated function ServerTimeStampSynchronize: boolean; You can call this method to call the remote URI root/TimeStamp - this can be an handy way of testing the connection, since this method is always available, even without authentication - returns TRUE if the client time correction has been retrieved - returns FALSE on any connection error - check LastErrorMessage and LastErrorException to find out the exact connection error function ServiceRegister(const aInterfaces: array of PTypeInfo; aInstanceCreation: TServiceInstanceImplementation=sicSingle; const aContractExpected: RawUTF8=''): boolean; overload; virtual; Register one or several Services on the client side via their interfaces - this methods expects a list of interfaces to be registered to the client (e.g. [TypeInfo(IMyInterface)]) - instance implementation pattern will be set by the appropriate parameter - will return true on success, false if registration failed (e.g. if any of the supplied interfaces is not correct or is not available on the server) - that is, server side will be called to check for the availability of each interface - you can specify an optional custom contract for the first interface function ServiceRegister(aInterface: PTypeInfo; aInstanceCreation: TServiceInstanceImplementation=sicSingle; const aContractExpected: RawUTF8=''): TServiceFactory; overload; Register a Service on the client side via its interface - this methods expects one interface to be registered to the client, as Client.ServiceRegister(TypeInfo(IMyInterface),sicShared); - instance implementation pattern will be set by the appropriate parameter - will return the corresponding fake class factory on success, nil if registration failed (e.g. if any of supplied interfaces is not correct or is not available on the server) - that is, server side will be called to check for the availability of each interface - you can specify an optional custom contract for the first interface mORMot.pas unit - Rev. 1.18 Page 866 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 function ServiceRegisterClientDriven(aInterface: PTypeInfo; out Obj; const aContractExpected: RawUTF8=''): boolean; Register and retrieve the sicClientDriven Service instance - will return TRUE on success, filling Obj output variable with the corresponding interface instance - will return FALSE on error function SetUser(const aUserName, aPassword: RawUTF8; aHashedPassword: Boolean=false): boolean; Authenticate an User to the current connected Server - will call the ModelRoot/Auth service, i.e. call TSQLRestServer.Auth() published method to create a session for this user, with our secure TSQLRestServerAuthenticationDefault authentication scheme - returns true on success - calling this method is optional, depending on your user right policy: your Server need to handle authentication - on success, the SessionUser property map the logged user session on the server side - if aHashedPassword is TRUE, the aPassword parameter is expected to contain the already-hashed value, just as stored in PasswordHashHexa (i.e. SHA256('salt'+Value) as in TSQLAuthUser.SetPasswordPlain method) - if SSPIAUTH conditional is defined, and aUserName='', a Windows authentication will be performed via TSQLRestServerAuthenticationSSPI - in this case, aPassword is ignored and table TSQLAuthUser shall contain an entry for the logged Windows user, with the LoginName in form 'DomainName\UserName' - you can directly create the class method ClientSetUser() of a given TSQLRestServerAuthentication inherited class, if neither TSQLRestServerAuthenticationDefault nor TSQLRestServerAuthenticationSSPI match your need function TransactionBegin(aTable: TSQLRecordClass; SessionID: cardinal=1): boolean; override; Begin a transaction (implements REST BEGIN Member) - to be used to speed up some SQL statements like Add/Update/Delete methods above - must be ended with Commit on success - in the current implementation, the aTable parameter is not used yet - must be aborted with Rollback if any SQL statement failed - return true if no transaction is active, false otherwize if Client.TransactionBegin(TSQLRecordPeopleObject) then try //.... modify the database content, raise exceptions on error Client.Commit; except Client.RollBack; // in case of error end; - you can should better use the dedicated TransactionBeginRetry() method in case of Client concurent access mORMot.pas unit - Rev. 1.18 Page 867 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 function TransactionBeginRetry(aTable: TSQLRecordClass; Retries: integer=10): boolean; Begin a transaction (implements REST BEGIN Member) - this version retries a TranslationBegin() to be successfull within a supplied number of times - will retry every 100 ms for "Retries" times (excluding the connection time in this 100 ms time period - default is to retry 10 times, i.e. within 2 second timeout - in the current implementation, the aTable parameter is not used yet - typical usage should be for instance: if Client.TransactionBeginRetry(TSQLRecordPeopleObject,20) then try //.... modify the database content, raise exceptions on error Client.Commit; except Client.RollBack; // in case of error end; function UnLock(Table: TSQLRecordClass; aID: integer): boolean; override; Unlock the corresponding record - URI is 'ModelRoot/TableName/ID' with UNLOCK method - returns true on success function UpdateFromServer(const Data: array of TObject; out Refreshed: boolean; PCurrentRow: PInteger = nil): boolean; Check if the data may have changed of the server for this objects, and update it if possible - only working types are TSQLTableJSON and TSQLRecord descendants - make use of the InternalState function to check the data content revision - return true if Data is updated successfully, or false on any error during data retrieval from server (e.g. if the TSQLRecord has been deleted) - if Data contains only one TSQLTableJSON, PCurrentRow can point to the current selected row of this table, in order to refresh its value - use this method to refresh the client UI, e.g. via a timer function URI(const url, method: RawUTF8; Resp: PRawUTF8=nil; Head: PRawUTF8=nil; SendData: PRawUTF8=nil): Int64Rec; Method calling the remote Server via a RESTful command - calls the InternalURI abstract method, which should be overriden with a local, piped or HTTP/1.1 provider - this method will add sign the url with the appropriate digital signature according to the current SessionUser property - this method will retry the connection in case of authentication failure (i.e. if the session was closed by the remote server, for any reason - mostly a time out) if the OnAuthentificationFailed event handler is set procedure BatchAbort; Abort a BATCH sequence started by BatchStart method - in short, nothing is sent to the remote server, and current BATCH sequence is closed procedure Commit(SessionID: cardinal=CONST_AUTHENTICATION_NOT_USED); override; End a transaction (implements REST END Member) - write all pending SQL statements to the disk mORMot.pas unit - Rev. 1.18 Page 868 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 procedure RollBack(SessionID: cardinal=CONST_AUTHENTICATION_NOT_USED); override; Abort a transaction (implements REST ABORT Member) - restore the previous state of the database, before the call to TransactionBegin property LastErrorCode: integer read fLastErrorCode; Low-level error code, as returned by server - check this value about HTML_* constants - HTML_SUCCESS or HTML_CREATED mean no error - otherwise, check LastErrorMessage property for additional information - this property value will record status codes returned by URI() method property LastErrorException: ExceptClass read fLastErrorException; Low-level exception class, if any - will record any Exception class raised within URI() method - contains nil if URI() execution did not raise any exception (which is the most expected behavior, since server-side errors are trapped into LastErrorCode/LastErrorMessage properties property LastErrorMessage: RawUTF8 read fLastErrorMessage; Low-level error message, as returned by server - this property value will record content returned by URI() method in case of an error, or '' if LastErrorCode is HTML_SUCCESS or HTML_CREATED property MaximumAuthentificationRetry: Integer read fMaximumAuthentificationRetry write fMaximumAuthentificationRetry; Maximum additional retry occurence - defaut is 0, i.e. will retry once - set OnAuthentificationFailed to nil in order to avoid any retry property OnAuthentificationFailed: TOnAuthentificationFailed read fOnAuthentificationFailed write fOnAuthentificationFailed; This Event is called in case of remote authentication failure - client software can ask the user to enter a password and user name - if no event is specified, the URI() method will return directly an HTML_FORBIDDEN "403 Forbidden" error code property OnSetUser: TNotifyEvent read fOnSetUser write fOnSetUser; This Event is called when a user is authenticated - is called always, on each TSQLRestClientURI.SetUser call - you can check the SessionUser property to retrieve the current authenticated user, or nil if authentication failed - could be used to refresh the User Interface layout according to current authenticated user rights property SessionID: cardinal read fSessionID; The current session ID as set after a successfull SetUser() method call - equals 0 (CONST_AUTHENTICATION_SESSION_NOT_STARTED) if the session is not started yet i.e. if SetUser() call failed - equals 1 (CONST_AUTHENTICATION_NOT_USED) if authentication mode is not enabled - i.e. after a fresh Create() without SetUser() call mORMot.pas unit - Rev. 1.18 Page 869 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 property SessionUser: TSQLAuthUser read fSessionUser; The current user as set by SetUser() method - returns nil if no User is currently authenticated - only available fields by default are LogonName and PasswordHashHexa: you can run code similar to the following to fill all needed properties: if fClient.SessionUser<>nil then begin fClient.Retrieve('LogonName=?',[],[fClient.SessionUser.LogonName], fClient.SessionUser); // fill ID, DisplayName, GroupRights fClient.RetrieveBlobFields(fClient.SessionUser); // optional Data end; TSQLRestClientURIDll = class(TSQLRestClientURI) Rest client with remote access to a server through a dll - use only one TURIMapRequest function for the whole communication - the data is stored in Global system memory, and freed by GlobalFree() Used for DI-2.1.1.2.1 (page 1048). constructor Create(aModel: TSQLModel; const DllName: TFileName); reintroduce; overload; Connect to a server contained in a shared library - this dll must contain at least a URIRequest entry - raise an exception if the shared library is not found or invalid Used for DI-2.1.1.2.1 (page 1048). constructor Create(aModel: TSQLModel; aRequest: TURIMapRequest); reintroduce; overload; Connect to a server from a remote function Used for DI-2.1.1.2.1 (page 1048). destructor Destroy; override; Release memory and handles TSQLRestClientURIMessage = class(TSQLRestClientURI) Rest client with remote access to a server through Windows messages - use only one TURIMapRequest function for the whole communication - the data is sent and received by using the standard and fast WM_COPYDATA message - named pipes seems to be somewhat better for bigger messages under XP Used for DI-2.1.1.2.3 (page 1049). mORMot.pas unit - Rev. 1.18 Page 870 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 constructor Create(aModel: TSQLModel; const ServerWindowName, ClientWindowName: string; TimeOutMS: cardinal); reintroduce; overload; Connect to a server from its window name - ServerWindowName is of UnicodeString type since Delphi 2009 (direct use of FindWindow()=FindWindowW() Win32 API) - this version will instanciante and create a Client Window from a Window Name, by using low level Win32 API: therefore, the Forms unit is not needed with this constructor (save some KB) Used for DI-2.1.1.2.3 (page 1049). constructor Create(aModel: TSQLModel; const ServerWindowName: string; ClientWindow: HWND; TimeOutMS: cardinal); reintroduce; overload; Connect to a server from its window name - ServerWindowName is of UnicodeString type since Delphi 2009 (direct use of FindWindow()=FindWindowW() Win32 API) - this version must supply a Client Window handle Used for DI-2.1.1.2.3 (page 1049). destructor Destroy; override; Release the internal Window class created, if any procedure WMCopyData(var Msg : TWMCopyData); message WM_COPYDATA; Event to be trigerred when a WM_COPYDATA message is received from the server - to be called by the corresponding message WM_COPYDATA; method in the client window TSQLRestClientURINamedPipe = class(TSQLRestClientURI) Rest client with remote access to a server through a Named Pipe - named pipe is fast and optimized under Windows - can be accessed localy or remotely Used for DI-2.1.1.2.2 (page 1048). constructor Create(aModel: TSQLModel; const ApplicationName: TFileName); reintroduce; Connect to a server contained in a running application - the server must have been declared by a previous TSQLRestServer.ExportServer(ApplicationName) call with ApplicationName as user-defined server identifier ('DBSERVER' e.g.) - ApplicationName is of UnicodeString type since Delphi 2009 (direct use of Wide Win32 API version) - this server identifier is appended to '\\.\pipe\mORMot_' to obtain the full pipe name to connect to ('\\.\pipe\mORMot__DBSERVER' e.g.) - this server identifier may also contain a remote computer name, and must be fully qualified ('\\ServerName\pipe\ApplicationName' e.g.) - raise an exception if the server is not running or invalid Used for DI-2.1.1.2.2 (page 1048). destructor Destroy; override; Release memory and handles mORMot.pas unit - Rev. 1.18 Page 871 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 TSynValidateRest = class(TSynValidate) Will define a validation to be applied to a TSQLRecord field, using if necessary an associated TSQLRest instance and a TSQLRecord class - a typical usage is to validate a value to be unique in the table (implemented in the TSynValidateUniqueField class) - the optional associated parameters are to be supplied JSON-encoded - ProcessRest and ProcessRec properties will be filled before Process method call by TSQLRecord.Validate() property ProcessRec: TSQLRecord read fProcessRec; The associated TSQLRecord instance - this value is updated by TSQLRecord.Validate with the current TSQLRecord instance to be validated - it can be used in the overriden Process method property ProcessRest: TSQLRest read fProcessRest; The associated TSQLRest instance - this value is updated by TSQLRecord.Validate with the current TSQLRest used for the validation - it can be used in the overriden Process method TSynValidateUniqueField = class(TSynValidateRest) Will define a validation for a TSQLRecord Unique field - it will check that the field value is not void - it will check that the field value is not a duplicate function Process(aFieldIndex: integer; const Value: RawUTF8; var ErrorMsg: string): boolean; override; Perform the unique field validation action to the specified value - duplication value check will use ProcessRest and ProcessRec properties, as set by TSQLRecord.Validate TSQLVirtualTablePreparedConstraint = record A WHERE constraint as set by the TSQLVirtualTable.Prepare() method Column: integer; Column on left-hand side of constraint - The first column of the virtual table is column 0 - The ROWID of the virtual table is column -1 - Hidden columns are counted when determining the column index - if this field contains VIRTUAL_TABLE_IGNORE_COLUMN (-2), TSQLVirtualTable. Prepare() should ignore this entry mORMot.pas unit - Rev. 1.18 Page 872 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 OmitCheck: boolean; If true, the constraint is assumed to be fully handled by the virtual table and is not checked again by SQLite - By default (OmitCheck=false), the SQLite core double checks all constraints on each row of the virtual table that it receives - TSQLVirtualTable.Prepare() can set this property to true Operation: TCompareOperator; Constraint operator - MATCH keyword is parsed into soBeginWith, and should be handled as soBeginWith, soContains or soSoundsLike* according to the effective expression text value ('text*', '%text'...) Value: TVarData; The associated expression - TSQLVirtualTable.Prepare() must set this property VType to <> varEmpty (=0) e.g. to varAny, if an expression is expected at TSQLVirtualTableCursor.Search() call - TSQLVirtualTableCursor.Search() will receive an expression value, to be retrieved e.g. via sqlite3_value_*() functions TSQLVirtualTablePreparedOrderBy = record An ORDER BY clause as set by the TSQLVirtualTable.Prepare() method Column: Integer; Column number - The first column of the virtual table is column 0 - The ROWID of the virtual table is column -1 - Hidden columns are counted when determining the column index. Desc: boolean; True for DESCending order, false for ASCending order. TSQLVirtualTablePrepared = object(TObject) The WHERE and ORDER BY statements as set by TSQLVirtualTable.Prepare - Where[] and OrderBy[] are fixed sized arrays, for fast and easy code EstimatedCost: Double; Estimated cost of using this prepared index - SQLite uses this value to make a choice between several calls to the TSQLVirtualTable.Prepare() method with several expressions OmitOrderBy: boolean; If true, the ORDER BY statement is assumed to be fully handled by the virtual table and is not checked again by SQLite - By default (OmitOrderBy=false), the SQLite core sort all rows of the virtual table that it receives according in order OrderBy: array[0..MAX_SQLFIELDS-1] of TSQLVirtualTablePreparedOrderBy; ORDER BY statement parameters mORMot.pas unit - Rev. 1.18 Page 873 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 OrderByCount: integer; Numver of ORDER BY statement parameters in OrderBy[] Where: array[0..MAX_SQLFIELDS-1] of TSQLVirtualTablePreparedConstraint; WHERE statement parameters, in TSQLVirtualTableCursor.Search() order WhereCount: integer; Number of WHERE statement parameters in Where[] array function IsWhereIDEquals(CalledFromPrepare: Boolean): boolean; Returns TRUE if there is only one ID=? statement in this search function IsWhereOneFieldEquals: boolean; Returns TRUE if there is only one FieldName=? statement in this search TVirtualTableModuleProperties = record Used to store and handle the main specifications of a TSQLVirtualTableModule CursorClass: TSQLVirtualTableCursorClass; The associated cursor class Features: TSQLVirtualTableFeatures; A set of features of a Virtual Table FileExtension: TFileName; Can be used to customize the extension of the filename - the '.' is not to be included RecordClass: TSQLRecordClass; The associated TSQLRecord class - used to retrieve the field structure with all collations StaticClass: TSQLRestServerStaticClass; The associated TSQLRestServerStatic class used for storage - is e.g. TSQLRestServerStaticInMemory for TSQLVirtualTableJSON, TSQLRestServerStaticExternal for TSQLVirtualTableExternal, or nil for TSQLVirtualTableLog TSQLVirtualTableModule = class(TObject) Parent class able to define a Virtual Table module - in order to implement a new Virtual Table type, you'll have to define a so called "Module" to handle the fields and data access and an associated TSQLVirtualTableCursorClass for handling the SELECT statements - for our framework, the SQLite3 unit will inherit from this class to define a TSQLVirtualTableModuleSQLite3 class, which will register the associated virtual table definition into a SQLite3 connection, on the server side - children should override abstract methods in order to implement the association with the database engine itself mORMot.pas unit - Rev. 1.18 Page 874 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 constructor Create(aTableClass: TSQLVirtualTableClass; aServer: TSQLRestServer); virtual; Create the Virtual Table instance according to the supplied class - inherited constructors may register the Virtual Table to the specified database connection function FileName(const aTableName: RawUTF8): TFileName; virtual; Retrieve the file name to be used for a specific Virtual Table - returns by default a file located in the executable folder, with the table name as file name, and module name as extension property CursorClass: TSQLVirtualTableCursorClass read fFeatures.CursorClass; The associated virtual table cursor class property Features: TSQLVirtualTableFeatures read fFeatures.Features; The Virtual Table module features property FileExtension: TFileName read fFeatures.FileExtension; The extension of the filename (without any left '.') property FilePath: TFileName read fFilePath write fFilePath; The full path to be used for the filename - is '' by default, i.e. will use the executable path - you can specify here a custom path, which will be used by the FileName method to retrieve the .json/.data full file property ModuleName: RawUTF8 read fModuleName; The corresponding module name property RecordClass: TSQLRecordClass read fFeatures.RecordClass; The associated TSQLRecord class - is mostly nil, e.g. for TSQLVirtualTableJSON - used to retrieve the field structure for TSQLVirtualTableLog e.g. property Server: TSQLRestServer read fServer; The associated Server instance - may be nil, in case of direct access to the virtual table property StaticClass: TSQLRestServerStaticClass read fFeatures.StaticClass; The associated TSQLRestServerStatic class used for storage - e.g. returns TSQLRestServerStaticInMemory for TSQLVirtualTableJSON, or TSQLRestServerStaticExternal for TSQLVirtualTableExternal, or either nil for TSQLVirtualTableLog property TableClass: TSQLVirtualTableClass read fTableClass; The associated virtual table class mORMot.pas unit - Rev. 1.18 Page 875 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 TSQLVirtualTable = class(TObject) Abstract class able to access a Virtual Table content - override the Prepare/Structure abstract virtual methods for reading access to the virtual table content - you can optionaly override Drop/Delete/Insert/Update/Rename/Transaction virtual methods to allow content writing to the virtual table - the same virtual table mechanism can be used with several database module, with diverse database engines constructor Create(aModule: TSQLVirtualTableModule; const aTableName: RawUTF8; FieldCount: integer; Fields: PPUTF8CharArray); virtual; Create the virtual table access instance - the created instance will be released when the virtual table will be disconnected from the DB connection (e.g. xDisconnect method for SQLite3) - shall raise an exception in case of invalid parameters (e.g. if the supplied module is not associated to a TSQLRestServer instance) - aTableName will be checked against the current aModule.Server.Model to retrieve the corresponding TSQLRecordVirtualTableAutoID class and create any associated Static: TSQLRestServerStatic instance destructor Destroy; override; Release the associated memory, especially the Static instance function Delete(aRowID: Int64): boolean; virtual; Called to delete a virtual table row - should return true on success, false otherwise - does nothing by default, and returns false, i.e. always fails function Drop: boolean; virtual; Called when a DROP TABLE statement is executed against the virtual table - should return true on success, false otherwise - does nothing by default, and returns false, i.e. always fails function Insert(aRowID: Int64; var Values: TVarDataDynArray; out insertedRowID: Int64): boolean; virtual; Called to insert a virtual table row content - the column values are available via some TVarData of type varNull, varInt64, varDouble, varString (mapping a constant PUTF8Char), and varAny (BLOB with size = VLongs[0]) - should return true on success, false otherwise - should return the just created row ID in insertedRowID on success - does nothing by default, and returns false, i.e. always fails class function ModuleName: RawUTF8; Retrieve the corresponding module name - will use the class name, triming any T/TSQL/TSQLVirtual/TSQLVirtualTable* - when the class is instanciated, it will be faster to retrieve the same value via Module.ModuleName mORMot.pas unit - Rev. 1.18 Page 876 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 function Prepare(var Prepared: TSQLVirtualTablePrepared): boolean; virtual; Called to determine the best way to access the virtual table - will prepare the request for TSQLVirtualTableCursor.Search() - in Where[], Expr must be set to not 0 if needed for Search method, and OmitCheck to true if double check is not necessary - OmitOrderBy must be set to true if double sort is not necessary - EstimatedCost should receive the estimated cost - default implementation will let the DB engine perform the search, and prepare for ID=? statement if vtWhereIDPrepared was set function Rename(const NewName: RawUTF8): boolean; virtual; Called to rename the virtual table - by default, returns false, i.e. always fails function Structure: RawUTF8; virtual; Should retrieve the format (the names and datatypes of the columns) of the virtual table, as expected by sqlite3_declare_vtab() - default implementation is to retrieve the structure for the associated Module.RecordClass property (as set by GetTableModuleProperties) or the Static.StoredClass: in both cases, column numbering will follow the TSQLRecord published field order (TSQLRecord.RecordProps.Fields[]) class function StructureFromClass(aClass: TSQLRecordClass; const aTableName: RawUTF8): RawUTF8; A generic method to get a 'CREATE TABLE' structure from a supplied TSQLRecord class - is called e.g. by the Structure method function Transaction(aState: TSQLVirtualTableTransaction; aSavePoint: integer): boolean; virtual; Called to begin a transaction to the virtual table row - do nothing by default, and returns false in case of RollBack/RollBackto - aSavePoint is used for vttSavePoint, vttRelease and vttRollBackTo only - note that if you don't nest your writing within a transaction, SQLite will call vttCommit for each INSERT/UPDATE/DELETE, just like a regular SQLite database - it could make bad written code slow even with Virtual Tables function Update(oldRowID, newRowID: Int64; var Values: TVarDataDynArray): boolean; virtual; Called to update a virtual table row content - the column values are available via some TVarData of type varNull, varInt64, varDouble, varString (mapping a constant PUTF8Char), and varAny (BLOB with size = VLongs[0]) - should return true on success, false otherwise - does nothing by default, and returns false, i.e. always fails class procedure GetTableModuleProperties( var aProperties: TVirtualTableModuleProperties); virtual; abstract; Should return the main specifications of the associated TSQLVirtualTableModule property Module: TSQLVirtualTableModule read fModule; The associated Virtual Table module mORMot.pas unit - Rev. 1.18 Page 877 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 property Static: TSQLRestServerStatic read fStatic; The associated virtual table storage - can be e.g. a TSQLRestServerStaticInMemory for TSQLVirtualTableJSON, or a TSQLRestServerStaticExternal for TSQLVirtualTableExternal, or nil for TSQLVirtualTableLog property TableName: RawUTF8 read fTableName; The name of the Virtual Table, as specified following the TABLE keyword in the CREATE VIRTUAL TABLE statement TSQLVirtualTableCursor = class(TObject) Abstract class able to define a Virtual Table cursor - override the Search/HasData/Column/Next abstract virtual methods to implement the search process constructor Create(aTable: TSQLVirtualTable); virtual; Create the cursor instance - it will be destroyed when by the DB engine (e.g. via xClose in SQLite3) function Column(aColumn: integer; var aResult: TVarData): boolean; virtual; abstract; Called to retrieve a column value of the current data row - handled types in aResult are varNull, varInt64, varDouble, varString (mapping a constant PUTF8Char) and varAny (BLOB with size = VLongs[0]) - if aColumn=-1, should return the row ID as varInt64 into aResult - should return false in case of an error, true on success function HasData: boolean; virtual; abstract; Called after Search() to check if there is data to be retrieved - should return false if reached the end of matching data function Next: boolean; virtual; abstract; Called to go to the next row of matching data - should return false on low-level database error (but true in case of a valid call, even if HasData will return false, i.e. no data match) function Search(const Prepared: TSQLVirtualTablePrepared): boolean; virtual; abstract; Called to begin a search in the virtual table - the TSQLVirtualTablePrepared parameters were set by TSQLVirtualTable.Prepare and will contain both WHERE and ORDER BY statements (retrieved e.g. by x_BestIndex() from a TSQLite3IndexInfo structure) - Prepared will contain all prepared constraints and the corresponding expressions in the Where[].Value field - should move cursor to first row of matching data - should return false on low-level database error (but true in case of a valid call, even if HasData will return false, i.e. no data match) property Table: TSQLVirtualTable read fTable; The associated Virtual Table class instance mORMot.pas unit - Rev. 1.18 Page 878 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 TSQLVirtualTableCursorIndex = class(TSQLVirtualTableCursor) A generic Virtual Table cursor associated to Current/Max index properties function HasData: boolean; override; Called after Search() to check if there is data to be retrieved - will return false if reached the end of matching data, according to the fCurrent/fMax protected properties values function Next: boolean; override; Called to go to the next row of matching data - will return false on low-level database error (but true in case of a valid call, even if HasData will return false, i.e. no data match) - will check the fCurrent/fMax protected properties values function Search(const Prepared: TSQLVirtualTablePrepared): boolean; override; Called to begin a search in the virtual table - this no-op version will mark EOF, i.e. fCurrent=0 and fMax=-1 TSQLVirtualTableCursorJSON = class(TSQLVirtualTableCursorIndex) A Virtual Table cursor for reading a TSQLRestServerStaticInMemory content - this is the cursor class associated to TSQLVirtualTableJSON function Column(aColumn: integer; var aResult: TVarData): boolean; override; Called to retrieve a column value of the current data row - handled types in aResult are varNull, varInt64, varDouble, varString (mapping a constant PUTF8Char) and varAny (BLOB with size = VLongs[0]) - if aColumn=-1, will return the row ID as varInt64 into aResult - will return false in case of an error, true on success function Search(const Prepared: TSQLVirtualTablePrepared): boolean; override; Called to begin a search in the virtual table - the TSQLVirtualTablePrepared parameters were set by TSQLVirtualTable.Prepare and will contain both WHERE and ORDER BY statements (retrieved by x_BestIndex from a TSQLite3IndexInfo structure) - Prepared will contain all prepared constraints and the corresponding expressions in the Where[].Value field - will move cursor to first row of matching data - will return false on low-level database error (but true in case of a valid call, even if HasData will return false, i.e. no data match) - only handled WHERE clause is for "ID = value" - other request will return all records in ID order, and let the database engine handle it mORMot.pas unit - Rev. 1.18 Page 879 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 TSQLVirtualTableJSON = class(TSQLVirtualTable) A TSQLRestServerStaticInMemory-based virtual table using JSON storage - for ORM access, you should use TSQLModel.VirtualTableRegister method to associated this virtual table module to a TSQLRecordVirtualTableAutoID class - transactions are not handled by this module - by default, no data is written on disk: you will need to call explicitly aServer.StaticVirtualTable[aClass].UpdateToFile for file creation or refresh - file extension is set to '.json' function Delete(aRowID: Int64): boolean; override; Called to delete a virtual table row - returns true on success, false otherwise function Drop: boolean; override; Called when a DROP TABLE statement is executed against the virtual table - returns true on success, false otherwise function Insert(aRowID: Int64; var Values: TVarDataDynArray; out insertedRowID: Int64): boolean; override; Called to insert a virtual table row content - the column values are available via some TVarData of type varNull, varInt64, varDouble, varString (mapping a constant PUTF8Char), and varAny (BLOB with size = VLongs[0]) - column order follows the Structure method, i.e. StoredClassRecordProps.Fields[] order - returns true on success, false otherwise - returns the just created row ID in insertedRowID on success - does nothing by default, and returns false, i.e. always fails function Prepare(var Prepared: TSQLVirtualTablePrepared): boolean; override; Called to determine the best way to access the virtual table - will prepare the request for TSQLVirtualTableCursor.Search() - only prepared WHERE statement is for "ID = value" - only prepared ORDER BY statement is for ascending IDs function Update(oldRowID, newRowID: Int64; var Values: TVarDataDynArray): boolean; override; Called to update a virtual table row content - the column values are available via some TVarData of type varNull, varInt64, varDouble, varString (mapping a constant PUTF8Char), and varAny (BLOB with size = VLongs[0]) - column order follows the Structure method, i.e. StoredClassRecordProps.Fields[] order - returns true on success, false otherwise - does nothing by default, and returns false, i.e. always fails class procedure GetTableModuleProperties(var aProperties: TVirtualTableModuleProperties); override; Returns the main specifications of the associated TSQLVirtualTableModule - this is a read/write table, without transaction, associated to the TSQLVirtualTableCursorJSON cursor type, with 'JSON' as module name - no particular class is supplied here, since it will depend on the associated Static instance mORMot.pas unit - Rev. 1.18 Page 880 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 TSQLVirtualTableBinary = class(TSQLVirtualTableJSON) A TSQLRestServerStaticInMemory-based virtual table using Binary storage - for ORM access, you should use TSQLModel.VirtualTableRegister method to associated this virtual table module to a TSQLRecordVirtualTableAutoID class - transactions are not handled by this module - by default, no data is written on disk: you will need to call explicitly aServer.StaticVirtualTable[aClass].UpdateToFile for file creation or refresh - binary format is more efficient in term of speed and disk usage than the JSON format implemented by TSQLVirtualTableJSON - binary format will be set by TSQLVirtualTableJSON.CreateTableInstance - file extension is set to '.data' TSQLVirtualTableLog = class(TSQLVirtualTable) Implements a read/only virtual table able to access a .log file, as created by TSynLog - to be used e.g. by a TSQLRecordLog_Log ('Log_' will identify this 'Log' module) - the .log file name will be specified by the Table Name, to which a '.log' file extension will be appended before loading it from the current directory constructor Create(aModule: TSQLVirtualTableModule; const aTableName: RawUTF8; FieldCount: integer; Fields: PPUTF8CharArray); override; Creates the TSQLVirtualTable according to the supplied parameters - aTableName will be checked against the current aModule.Server.Model to retrieve the corresponding TSQLRecordVirtualTableAutoID class destructor Destroy; override; Release the associated .log file mapping and all internal structures class procedure GetTableModuleProperties( var aProperties: TVirtualTableModuleProperties); override; Returns the main specifications of the associated TSQLVirtualTableModule - this is a read only table, with transaction, associated to the TSQLVirtualTableCursorLog cursor type, with 'Log' as module name, and associated to TSQLRecordLog_Log table field layout TSQLVirtualTableCursorLog = class(TSQLVirtualTableCursorIndex) A Virtual Table cursor for reading a TSynLogFile content - this is the cursor class associated to TSQLVirtualTableLog function Column(aColumn: integer; var aResult: TVarData): boolean; override; Called to retrieve a column value of the current data row function Search(const Prepared: TSQLVirtualTablePrepared): boolean; override; Called to begin a search in the virtual table mORMot.pas unit - Rev. 1.18 Page 881 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 TSQLRecordVirtualTableForcedID = class(TSQLRecordVirtual) Record associated to a Virtual Table implemented in Delphi, with ID forced at INSERT - will use TSQLVirtualTableModule / TSQLVirtualTable / TSQLVirtualTableCursor classes for a generic Virtual table mechanism on the Server side - call Model.VirtualTableRegister() before TSQLRestServer.Create on the Server side (not needed for Client) to associate such a record with a particular Virtual Table module, otherwise an exception will be raised: Model.VirtualTableRegister(TSQLRecordDali1,TSQLVirtualTableJSON); TSQLRecordVirtualTableAutoID = class(TSQLRecordVirtual) Record associated to Virtual Table implemented in Delphi, with ID generated automatically at INSERT - will use TSQLVirtualTableModule / TSQLVirtualTable / TSQLVirtualTableCursor classes for a generic Virtual table mechanism - call Model.VirtualTableRegister() before TSQLRestServer.Create on the Server side (not needed for Client) to associate such a record with a particular Virtual Table module, otherwise an exception will be raised: Model.VirtualTableRegister(TSQLRecordDali1,TSQLVirtualTableJSON); TServiceRunningContext = record Will identify the currently running service on the server side - is the type of the global ServiceContext threadvar Factory: TServiceFactoryServer; The currently running service factory - it can be used within server-side implementation to retrieve the associated TSQLRestServer instance RunningThread: TThread; The thread which launched the request - is set by TSQLRestServer.BeginCurrentThread from multi-thread server handlers - e.g. TSQLite3HttpServer or TSQLRestServerNamedPipeResponse Session: ^TSQLRestServerCallBackParams; The currently runnning context which launched the method - make available e.g. current session or authentication parameters (including e.g. user details via Factory.RestServer.SessionGetUser) - low-level RESTful context is also available in its Call member TSQLLog = class(TSynLog) Logging class with enhanced RTTI - will write TObject/TSQLRecord, enumerations and sets content as JSON - is the default logging family used by the mORMot framework - mORMotDB.pas unit will set SynDBLog := TSQLLog - moRMotSQLite3.pas unit will set SynSQLite3Log := TSQLLog Types implemented in the mORMot unit: mORMot.pas unit - Rev. 1.18 Page 882 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 PClassProp = ^TClassProp; Pointer to TClassProp PServiceMethod = ^TServiceMethod; A pointer to a service provider method - since TInterfaceFactory instances are shared in a global list, we can safely use such pointers in our code to refer to a particular method PSQLRestServerURIParams = ^TSQLRestServerURIParams; Used to map set of parameters for a TSQLRestServer.URI() method RawJSON = type RawUTF8; Interface-based service will transmit this variable content without any serialization - e.g. for efficient and AJAX-ready transmission of TSQLTableJSON result TCallingConvention = ( ccRegister, ccCdecl, ccPascal, ccStdCall, ccSafeCall ); The available methods calling conventions - this is by design only relevant to the x86 model - Win64 has one unique calling convention TCreateTime = type TTimeLog; An Int64-encoded date and time of the record creation - can be used as published property field in TSQLRecord for sftCreateTime - use internally for computation an abstract "year" of 16 months of 32 days of 32 hours of 64 minutes of 64 seconds - same as Iso8601ToSeconds() - type cast any value of TModTime/TCreateTime/TTimeLog with the Iso8601 object below for easy access to its content TFindWhereEqualEvent = procedure(aDest: pointer; aRec: TSQLRecord; aIndex: integer) of object; Event prototype called by FindWhereEqual() method TFloatType = ( ftSingle, ftDouble, ftExtended, ftComp, ftCurr ); Specify floating point (ftFloat) storage size and precision TInterfacedCollectionClass = class of TInterfacedCollection; The class of TInterfacedCollection kind TInterfaceMockSpyCheck = ( chkName, chkNameParams, chkNameParamsResults ); How TInterfaceMockSpy.Verify() shall generate the calls trace TInterfaceStubLogDynArray = array of TInterfaceStubLog; Used to keep track of all stubbed methods calls TInterfaceStubLogLayout = ( wName, wParams, wResults ); Every potential part of TInterfaceStubLog.AddAsText() log entry TInterfaceStubLogLayouts = set of TInterfaceStubLogLayout; Set the output layout of TInterfaceStubLog.AddAsText() log entry TInterfaceStubOption = ( imoLogMethodCallsAndResults, imoFakeInstanceWontReleaseTInterfaceStub, imoRaiseExceptionIfNoRuleDefined, imoReturnErrorIfNoRuleDefined, imoMockFailsWillPassTestCase ); Diverse options available to TInterfaceStub mORMot.pas unit - Rev. 1.18 Page 883 of 1055 Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16, 2013 - by default, method execution stack is not recorded - include imoLogMethodCallsAndResults in the options to track all method calls and the returned values; note that ExpectsTrace() method will set it - by default, TInterfaceStub will be released when the stubed/mocked interface is released include imoFakeInstanceWontReleaseTInterfaceStub in the options to force manual memory handling of TInterfaceStubs - by default, all interfaces will return some default values, unless imoRaiseExceptionIfNoRuleDefined or imoReturnErrorIfNoRuleDefined is included in the options - by default, any TInterfaceMock.Fails() rule execution will notify the TSynTestCase, unless imoMockFailsWillPassTestCase which will let test pass TInterfaceStubOptions = set of TInterfaceStubOption; Set of options available to TInterfaceStub TInterfaceStubRuleKind = ( isUndefined, isExecutesJSON, isRaises, isReturns, isFails ); Diverse types of stubbing / mocking rules - isUndefined is the first, since it will be a ExpectsCount() weak rule which may be overwritten by the other real run-time rules TJSONSerializerCustomReader = function(const aValue: TObject; aFrom: PUTF8Char; var aValid: Boolean): PUTF8Char of object; Method prototype to be used for custom un-serialization of a class - to be used with TJSONSerializer.RegisterCustomSerializer() method - note that the read JSON content is not required to start with '{', as a normal JSON object (you may e.g. read a JSON string for some class) - as a consequence, custom code could explicitely start with "if aFrom^='{'..." - implementation code shall follow function JSONToObject() patterns, i.e. calling low-level GetJSONField() function to decode the JSON content - implementation code shall follow the same exact format for the associated TJSONSerializerCustomWriter callback TJSONSerializerCustomWriter = procedure(const aSerializer: TJSONSerializer; aValue: TObject; aOptions: TTextWriterWriteObjectOptions) of object; Method prototype to be used for custom serialization of a class - to be used with TJSONSerializer.RegisterCustomSerializer() method - note that the generated JSON content is not required to start with '{', as a normal JSON object (you may e.g. write a JSON string for some class) - as a consequence, custom code could explicitely start with Add('{') - implementation code shall follow function TJSONSerializer.WriteObject() patterns, i.e. aSerializer.Add/AddInstanceName/AddJSONEscapeString... - implementation code shall follow the same exact format for the associated TJSONSerializerCustomReader callback TModTime = type TTimeLog; An Int64-encoded date and time of the latest update of a record - can be used as published property field in TSQLRecord for sftModTime - use internally for computation an abstract "year" of 16 months of 32 days of 32 hours of 64 minutes of 64 seconds - same as Iso8601ToSeconds() - type cast any value of TModTime/TCreateTime/TTimeLog with the Iso8601 object below for easy access to its content TNotifyFieldSQLEvent = function(Sender: TSQLRestServer; Event: TSQLEvent; aTable: mORMot.pas unit - Rev. 1.18 Page 884 of 1055 Event called by the TInterfaceStub.see TSQLRestServer.Result shall contain the default JSON array result for this method .use Ctxt.OnUpdateEvent property and InternalUpdateEvent() method .Named[] default properties.Error() to notify the caller for an execution error mORMot. not to synchronize some clients: the framework is designed around a stateless RESTful architecture (like HTTP/1.g.this method will be run when the fake class instance is destroyed (e. const aAffectedFields: TSQLFieldBits): boolean of object.aParams will contain the input parameters.pas unit .g.see TSQLRestServer.should return TRUE if aUserName and aPassword both contain some entered values to be sent for remote secure authentication .to be used only server-side. in order to retry authentication to the server .aClientDrivenID can be set optionally to specify e.method results shall be serialized as JSON in aResult.UpdateFromServer) TNotifySQLEvent = function(Sender: TSQLRestServer.18 Date: June 16.OnBlobUpdateEvent property and InternalUpdateEvent() method . Used by TSQLRestClientURI. Used to define how to trigger Events on record update .g. false if an error occured (but action must continue) . aResult. and ignore aResult content . if aInstanceCreation is sicClientDriven.1). aPassword: string): boolean of object. 1.returns true on success. var aUserName.URI() to let the client ask for an User name and password. Event: TSQLEvent. to notify the server than the client life time just finished) TOnFakeInstanceInvoke = function (const aMethod: TServiceMethod. an URI-level session TOnInterfaceStubExecuteJSON = procedure(Ctxt: TOnInterfaceStubExecuteParamsJSON)of object.by default Ctxt. as P := pointer(Ctxt.returns true on success.Params).Rev.CreateFakeInstance() to run a method . not to synchronize some clients: the framework is designed around a stateless RESTful architecture (like HTTP/1. encoded as a JSON array . Event called when destroying a TInterfaceFactory.shall return TRUE on success. the result shall use this record to set HTTP custom content and headers. aClientDrivenID: PCardinal.aMethod will specify which method is to be executed .1). const aParams: RawUTF8.you can call Ctxt. Used to define how to trigger Events on record field update . aTable: TSQLRecordClass. Event used by TInterfaceFactory. . with a corresponding explanation in aErrorMsg . aServiceCustomAnswer: PServiceCustomAnswer): boolean of object. if aServiceCustomAnswer is not nil.CreateFakeInstance() .Returns([GetNextItemDouble(P)-GetNextItemDouble(P)]).18 Page 885 of 1055 .Synopse mORMot Framework Software Architecture Design 1.should return FALSE if the user pressed cancel or the number of Retry reached a defined limit TOnFakeInstanceDestroy = procedure(aClientDrivenID: cardinal) of object. Ctxt. or FALSE in case of failure. in which clients ask the server for refresh (see TSQLRestClientURI. aErrorMsg: PRawUTF8.UpdateFromServer) TOnAuthentificationFailed = function(Retry: integer. aID: integer. e. 2013 TSQLRecordClass.Executes() fluent method for JSON process . false if an error occured (but action must continue) .to be used only server-side. aID: integer): boolean of object. in which clients ask the server for refresh (see TSQLRestClientURI. var Data: RawByteString). Used by TSQLRestClientURI. Server-side service provider uses this to store its internal instances . TSQLPropInfoRecord content will be stored as sftBlobCustom. mORMot.pas unit . sicPerUser. Optional event handler used by TSQLPropInfoRecord to handle textual storage . otUWord. specify such a callback event to allow storage as UTF-8 textual field and use a sftUTF8Custom kind of column . 1.e.use TSQLRest. Possible call parameters for TOnTableUpdate Event TOrdType = ( otSByte. tusChanged. sicPerGroup. otSWord.note: Int64 is stored as its own TTypeKind. pfAddress. pfOut. pfResult ). sicPerSession. since TRecordReference depends on it to store the Table type in its highest bits TServiceFactoryServerInstanceDynArray = array of TServiceFactoryServerInstance. not as tkInteger TParamFlag = ( pfVar.UpdateFromServer() to let the client perform the rows update (for Marked[] e. specify such a callback event to allow storage as UTF-8 textual field and use a sftUTF8Custom kind of column .Synopse mORMot Framework Software Architecture Design 1. DataLen: integer. State: TOnTableUpdateState) of object. pfConst.Rev. otUByte. tusNoChange ). sicClientDriven. var Text: RawUTF8). Optional event handler used by TSQLPropInfoRecord to handle textual storage .stored as an 32 bits unsigned integer (i.event implementation shall convert data/datalen binary value into Text TOnTableUpdate = procedure(aTable: TSQLTableJSON.by default.) TOnTableUpdateState = ( tusPrepare.Update() to let the client perform the record update (refresh associated report e.18 Date: June 16.) TOnSQLPropInfoRecord2Data = procedure(Text: PUTF8Char.type cast any value of TRecordReference with the RecordRef object below for easy access to its content . otSLong. Specify ordinal (tkInteger and tkEnumeration) storage size and sign .event implementaiton shall convert Text into Data binary value TOnSQLPropInfoRecord2Text = procedure(Data: pointer. 2013 TOnRecordUpdate = procedure(Value: TSQLRecord) of object. pfReference. A set of kind of method parameters TRecordReference = type PtrUInt. sicPerThread ).by default. sicShared.18 Page 886 of 1055 . The available kind of method parameters TParamFlags = set of TParamFlag.don't change associated TSQLModel tables order. sicPerSession.Retrieve(Reference) to get a record value . a pointer=TObject) . TSQLPropInfoRecord content will be stored as sftBlobCustom. A reference to another record in any table in the database Model . sicPerUser or sicPerGroup mode TServiceInstanceImplementation = ( sicSingle. pfArray.g. otULong ).g. Used by TSQLRestClientURI.used by TServiceFactoryServer in sicClientDriven. Describe a service provider method arguments TServiceMethodDynArray = array of TServiceMethod. for better response time and CPU use (this is the technical reason why service implementation methods have to handle multi-threading safety carefully. optFreeInMainThread ). smdVar. smvEnum. service methods are called within the thread which received them. smvCurrency.optFreeInMainThread will force the _Release/Destroy method to be run in the main thread: setting this option for any method will affect the whole service class .ServiceRegister method . smdOut. Describe a service provider methods TServiceMethodOption = ( optExecInMainThread.g. Handled kind of parameters for a service provider method mORMot. this is the default setting for TSQLRestServer. for performance reasons TServiceMethodValueDirection = ( smdConst.e.sicShared: one object instance is used for all incoming calls and is not recycled subsequent to the calls . TSQLite3HttpServer or TSQLRestServerNamedPipeResponse).smdResult is used for a function method. smvRecord.sicClientDriven: one object instance will be created in synchronization with the client-side lifetime of the corresponding interface: when the interface will be released on client. Handled kind of parameters direction for a service provider method . the sicPerUser and sicPerGroup implementation should be thread-safe . smvInt64.it may be usefull instead of sicShared mode if the service process expects some per-heavy thread initialization.sicSingle: one object instance is created per call . smdResult ). Possible service provider method options. for instance TServiceMethodArgumentDynArray = array of TServiceMethodArgument. sicPerUser and sicPerGroup modes will maintain one object instance per running session / user / group (only working if RESTful authentication is enabled) . smvBoolean. about logging or execution TServiceMethodOptions = set of TServiceMethodOption.18 Page 887 of 1055 . smvDateTime. smvWideString. 2013 The possible Server-side instance implementation patterns for Services .g.the implementation should be thread-safe on the server side .is not set by default.on the Client-side. e. and will be available through our JSON-serialized remote access: smdVar and smdOut kind of parameters will be returned within the "result": JSON array . with sicClientDriven behavior if necessary) .sicPerThread will maintain one object instance per calling thread . 1.it can be used e.since it may be shared among users or groups. each instance will be handled depending on the server side implementation (i.g. OUT directions can be applied to arguments. smvDouble.Synopse mORMot Framework Software Architecture Design 1. by using TRTLCriticalSection mutex on purpose) . Set of per-method execution options for a service provider .IN.g.Rev. smvInteger.this is the most expensive way of implementing the service.each interface-based service will be implemented by a corresponding class instance on the server: this parameter is used to define how class instances are created and managed . IN/OUT. smvString.pas unit . smvObject. smvRawJSON. smvCardinal. e. but is safe for simple workflows (like a one-type call). on multi-thread server instances (e. if your implementation rely heavily on COM servers . to handle the returned value TServiceMethodValueType = ( smvNone.a numerical identifier will be transmitted for all JSON requests .18 Date: June 16. smvRawUTF8. smvDynArray ).sicPerSession. smvSelf. it will be released on the server side .by default. smvSet.Synchronize() call .optExecInMainThread will force the method to be called within a RunningThread. ..] (one benefit of using URI is that it will be more secured in our RESTful authentication scheme: each method and even client driven session will be signed properly) . smvvSelf.) {"method":"Add".g. smvvString. for a sicClientDriven mode service: POST /root/ComplexNumber (... POST /root/Calculator (. after registration via a TTextWriter.30] in this case."params":[1. actmarkOlderThanSixMonths.records will be serialized as Base64 string...LoadFromJSON / TTextWriter. but provide some enhanced types handled by JSONToObject/ObjectToJSON functions (smvObject) or TDynArray.18 Page 888 of 1055 .Add: POST /root/Calculator.2]} or."id":1234} TSQLAction = ( actNoAction. or as true JSON objects.. without serialization TServiceMethodValueTypes = set of TServiceMethodValueType.if rmJSON_RPC is used.we do not handle all kind of Delphi variables. smvvWideString. The routing mode of the service remote request . the sent content will be a JSON array of [parameters. 1.) [1.AddDynArrayJSON methods (smvDynArray) . will use an URI-based layout (rmREST).by default.Method[/ClientDrivenID] e. actUnmarkAll.Add/1234 (.. actMark. with our RecordSave/RecordLoad low-level format by default.18 Date: June 16.2] or. then the method name will be inlined with parameters. smvv64.pas unit .Rev.. for a sicClientDriven mode service: POST /root/ComplexNumber. actmarkAllEntries. rmJSON_RPC ).) [20. the URI will define the interface. smvvObject.RegisterCustomJSONSerializer call . as /Model/Interface. 2013 .reference-counted variables will have their own storage . smvvRawUTF8. Handled kind of parameters internal variables . actmarkOlderThanOneYear."params":[20. smvvDynArray ).. actmarkOlderThanOneDay.Synopse mORMot Framework Software Architecture Design 1. Set of parameters for a service provider method TServiceMethodValueVar = ( smvvNone.Add (.smvVariant kind of parameter will be handled as a special smvvRecord TServiceRoutingMode = ( rmREST.smvRawJSON will transmit the raw JSON content. smvvRecord. actmarkInverse ).all non referenced-counted variables are stored within some 64 bit content . mORMot. actmarkOlderThanOneMonth. e. in which the service will be identified within the URI.g. Standard actions for User Interface generation TSQLActions = set of TSQLAction.) {"method":"Add". for ICalculator. actmarkOlderThanOneWeek.30]. inline parameter . and actions can be authorized via overriding the TSQLRest. in case the session is not closed gracefully TSQLCheckTableName = ( ctnNoCheck. 1.ComputeFieldsBeforeWrite virtual method TSQLFieldTables = set of 0. A set of potential actions to be executed from the server . with XMLHTTPRequest.18 Page 889 of 1055 . sftBlobCustom.GetJSONValues methods and SimpleFieldsBits[] array (in this case.. reUrlEncodedDelete. since deletion is global for all fields) . seDelete. sftBlob. Set of available SQL field property types TSQLListLayout = ( llLeft.some Events can be trigerred via TSQLRestServer.g. soDelete is never used. soDelete ). for a GET (to be used e.OnUpdateEvent is called BEFORE deletion. Defines the way the TDrawGrid is displayed by User Interface generation TSQLOccasion = ( soSelect. you may have to set the SessionTimeOut to a small value. reUrlEncodedSQL. sftUTF8Text. sftFloat.is used also by TSQLRecord. sftDateTime. sftCreateTime ). Used to defined the CRUD associated SQL statement of a command . sftMany.reService will indicate the right to execute the interface-based JSON-RPC service implementation . Used to define the triggered Event types for TNotifySQLEvent . sftAnsiText. Used to store bit set for all available Tables in a Database Model TSQLFieldType = ( sftUnknown. encoded as sql=.UpdateFromServer) . / a fixed array of SQL field property types TSQLFieldTypes = set of TSQLFieldType. soUpdate. sftObject.reUrlEncodedSQL will indicate the right to execute a SQL query encoded at the URI level.pas unit . sftEnumerate. and AFTER insertion or update.reUrlEncodedDelete will indicate the right to delete items using a WHERE clause for DELETE verb at /root/TableName?WhereClause . ctnMustExist. reOneSessionPerUser)..reOneSessionPerUser will force that only one session may be created for one user. in which clients ask the server for refresh (see TSQLRestClientURI..Rev. sftUTF8Custom. even if connection comes from the same IP: in this case. by TSQLRecord.reSQL will indicate the right to execute any POST SQL statement (not only SELECT statements) . llClient. sftRecord. sftTimeLog.used e. seUpdateBlob ). sftBoolean.g. reService. 2013 Set of standard actions for User Interface generation TSQLAllowRemoteExecute = set of ( reSQL. sftSet. llUp.OnUpdateEvent when a Table is modified. soInsert. as managed with the database driver TSQLFieldTypeArray = array[0. sftBlobDynArray.. it should be used only server-side. sftCurrency. sftInteger..RecordCanBeUpdated method . The possible options for handling table names TSQLEvent = ( seAdd. not to synchronize some clients: the framework is designed around a stateless RESTful architecture (like HTTP/1. ctnTrimExisting ).MAX_SQLFIELDS] of TSQLFieldType.also used for cache content notification mORMot. llLeftUp ). sftModTime.18 Date: June 16. The available types for any SQL field property. seUpdate.MAX_SQLTABLES-1.1). which forced SentData='' by definition). sftID.Synopse mORMot Framework Software Architecture Design 1. ExpectsCount() methods TSQLQueryOperators = set of TSQLQueryOperator.EnumIndex)+64 TSQLQueryOperator = ( qoNone. Set of ORM attributes for a TSQLPropInfo definition TSQLPropInfoClass = class of TSQLPropInfo. but a typecast of a prepared TSynSoundEx object instance (i. qoLessThanOrEqualTo.18 Date: June 16. pointer(@SoundEx)) by the caller . qoSoundsLikeSpanish ). Set of UI Query comparison operators TSQLRawBlob = type RawByteString.Operator is ord(TSQLQueryOperator) by default (i.QueryAddCustom() method) . returning true indicates that this custom query is available for this table .qoEqualTo to qoGreaterThanOrEqualTo apply to all field kind (work with either numeric either UTF-8 values) .pas unit . qoSoundsLikeEnglish.18 Page 890 of 1055 . or is a custom enumeration index for custom queries (see TSQLQueryCustom.Synopse mORMot Framework Software Architecture Design 1. the event is called with FieldType := TSQLFieldType(TSQLQueryCustom. qoContains. qoEqualToWithCase. used to mark or unmark some lines in a UI Grid or for TInterfaceStub. qoBeginWith. qoNotEqualTo. and make the comparison using the phonetic algorithm corresponding to a language family . Value: PUTF8Char. Type of a TSQLPropInfo class TSQLPropInfoDynArray = array of TSQLPropInfo. aID: integer. for class function TSQLRest. Type of a TSQLPropInfoRTTI class TSQLQueryEvent = function(aTable: TSQLRecordClass. qoSoundsLike* operators expect the Reference not to be a PUTF8Char. qoLessThan. qoGreaterThanOrEqualTo.for custom query (from TSQLQueryCustom below). A String used to store the BLOB content mORMot. Used to defined a set of CRUD associated SQL statement of a command TSQLPropInfoAttribute = ( aIsUnique ). User Interface Query action evaluation function prototype . Operator: integer. 1. and TSQLRest.these operators are e. Dynamic array of ORM fields information for published properties TSQLPropInfoRTTIClass = class of TSQLPropInfoRTTI. UI Query comparison operators .e.QueryIsTrue).for default Operator as ord(TSQLQueryOperator).e. ORM attributes for a TSQLPropInfo definition TSQLPropInfoAttributes = set of TSQLPropInfoAttribute. FieldType: TSQLFieldType.for default Operator as ord(TSQLQueryOperator). qoSoundsLikeFrench. qoGreaterThan. the event must handle a special first call with Value=nil to select if this custom Operator/Query is available for the specified aTable: in this case.EnumIndex below.g. qoNotEqualToWithCase. qoEqualTo.qoEqualToWithCase to qoSoundsLikeSpanish handle the field as UTF-8 text.for custom query (from TSQLQueryCustom below). Reference: PUTF8Char): boolean of object. 2013 TSQLOccasions = set of TSQLOccasion. qoContains and qoBeginWith expect the Reference to be already uppercase .Rev. similar to the DataSnap mORMot.equals RawByteString for byte storage. jkDestFields.this mechanism is able to handle some custom Client/Server request. the BLOB fields are not retrieved or updated with raw TSQLRest. or the fields specified by aCustomFieldsCSV (the Dest table name will be added: e.* and DestTable. because they will be always the same for a same SourceID. rRTree.DestGetJoinedTable() method call .Two) . DestTable.a plain TSQLRecord class can be defined as rCustomForcedID (e.Two) . and a TSQLRecordVirtualTable*ID with rCustomForcedID/rCustomAutoID . This kind of record array can be used for direct coordinates storage TSQLRecordVirtualKind = ( rSQLite3.One. PivotTable.g.g. will retrieve PivotTable.Retrieve() method. that is "Lazy loading" is enabled by default for blobs. for aCustomFieldsCSV='One. or the fields specified by aCustomFieldsCSV (the Pivot table name will be added: e. for TSQLRecordMany) after registration for an external DB via a call to VirtualTableExternalRegister() from SQLite3DB unit TSQLRestCacheEntryValueDynArray = array of TSQLRestCacheEntryValue.18 Page 891 of 1055 .ID . will retrieve DestTable.One.jkPivotFields will retrieve PivotTable. TSQLRecordFTS4 with vFTS4. jkPivotID. max: double. to force no implicit charset conversion. 1.ForceBlobTransfert property is TRUE.ID and PivotTable.* simple fields. unless TSQLRestClientURI.Two'. A dynamic array used to store the TSQLRecord classes in a Database Model TSQLRecordManyJoinKind = ( jkDestID. thatever the codepage of the resulting string is .jkDestID and jkPivotID will retrieve only DestTable.Source fields are not available. stores all tables values TSQLRestServerAuthenticationClass = class of TSQLRestServerAuthentication.18 Date: June 16.* simple fields.TSQLRecordFTS3 will be associated with vFTS3.* simple fields.g. The kind of fields to be available in a Table resulting of a TSQLRecordMany. rCustomForcedID. For TSQLRestCache.Two'.pas unit .jkPivotAndDestAllFields for PivotTable.by default.Two') TSQLRecordTreeCoords = array[0. jkPivotFields. 2013 .One. if used to define such a published property . rCustomAutoID ).g. and they should be available from the TSQLRecord which hold the TSQLRecordMany instance .Synopse mORMot Framework Software Architecture Design 1.. rFTS3. so use RetrieveBlob() methods for handling BLOB fields TSQLRecordClass = class of TSQLRecord.RTREE_MAX_DIMENSION-1] of packed record min. rFTS4. 'PivotTable. DestTable.Rev. jkPivotAndDestFields ). for aCustomFieldsCSV='One. any native SQlite3 table as vSQLite3. Class-reference type (metaclass) of TSQLRecord TSQLRecordClassDynArray = array of TSQLRecordClass. TSQLRecordRTree with vRTree. The kind of SQlite3 (virtual) table . Used to define an authentication scheme by its implementation class TSQLRestServerCallBack = procedure(var Ctxt: TSQLRestServerCallBackParams) of object. Method prototype which must be used to implement the Server-Side ModelRoot/[TableName/ID/]MethodName RESTful GET/PUT request of the Framework .jkDestFields will retrieve DestTable.will identify a sftBlob field type. or will retrieve the specified aCustomFieldsCSV fields (with the table name associated: e. end. URI receive a request for ModelRoot/MethodName or ModelRoot/TableName/ID/MethodName.when TSQLRestServer.b: Extended.Session* will identify to the authentication session of the remote client (CONST_AUTHENTICATION_NOT_USED=1 if authentication mode is not enabled or CONST_AUTHENTICATION_SESSION_NOT_STARTED=0 if the session not started yet) .when TSQLRestServer. Ctxt. GET/POST/PUT. // same as: Ctxt.URI receive a request for ModelRoot/TableName/ID/MethodName.Parameters. end. but in a KISS way.Error('Missing Parameter').'SORT.Method will indicate the used HTTP verb (e. and each parameter can be retrieved with a loop like this: if not UrlDecodeNeedParameters(Ctxt.b..Parameters.Parameters.just add a published method of this type to any TSQLRestServer descendant .URI when the method returns .Parameters<>nil do begin UrlDecodeExtended(Ctxt.Results([]) method to set a JSON response object with one "result" field name or Ctxt.if process failed. begin if UrlDecodeNeedParameters(Ctxt. implementation shall call Ctxt.Returns(JSONEncode(['result'.Ctxt. UrlDecodeExtended(Ctxt.Synopse mORMot Framework Software Architecture Design 1.Call is set with low-level incoming and outgoing data from client (e.a+b]).18 Date: June 16.Success will return HTML_SUCCESS) .Returns([]) with a JSON object described in Name/Value pairs. end.Returns(['result'. var a. 2013 technology. .Parameters<>nil do begin UrlDecodeValue(Ctxt.Ctxt.) .a typical implementation may be: procedure TSQLRestServerTest. implementation shall call overloaded Ctxt. end else Ctxt.'COUNT='. Ctxt.'A='.Call. with its field ID set.if process succeeded. the just created instance will be freed by TSQLRestServer. mORMot.Parameters. and no data is expected to be returned to the caller. use Ctxt. note that the only set field is ID: other fields of aRecord are not set. 1. it will check for a published method in its self instance named MethodName which MUST be of TSQLRestServerCallBack type (not checked neither at compile time neither at runtime: beware!) and call it to handle the request .when TSQLRestServer.for ModelRoot/TableName/ID/MethodName. it calls the corresponding published method with aRecord pointing to a just created instance of the corresponding class. it calls the corresponding published method with aRecord set to nil . // same as: Ctxt.'B='. implementation shall call Ctxt.code may use SessionGetUser() protected method to retrieve the user details . end.Parameters.g.Ctxt. it's fully integrated in the Client/Server architecture of our framework . if the returned value is not JSON_CONTENT_TYPE. but must secificaly be retrieved on purpose [email protected]+b])).Ctxt.Returns() and its optional CustomHeader parameter can specify a custom header like TEXT_CONTENT_TYPE_HEADER .Parameters).if process succeeded.e.'SORT='.Error() method to set the corresponding error message and error code number .InBody contain POST/PUT data message) .Rev.aCountInteger.important warning: the method implementation MUST be thread-safe . while Ctxt.'A.18 Page 892 of 1055 .aSortString).Parameters).B') then begin while Ctxt.Sum(var Ctxt: TSQLRestServerCallBackParams).a).Results([a+b]).Parameters values are set from incoming URI.Success() method with the expected status (i. UrlDecodeValueInteger(Ctxt. just Ctxt.COUNT') then exit.URI receive a request for ModelRoot/MethodName.pas unit .@Ctxt. TSQLURIMethod = ( mNone. 2013 . see also TSQLModel. and named (by convention) as MethodName. either TSQLRecord (if to be called as ModelRoot/TableName/MethodName[/ID]) a custom public or protected method. A set of features of a Virtual Table TSQLVirtualTableTransaction = ( vttBegin.Sum(aClient: TSQLRestClientURI.Client-Side can be implemented as you wish. mGET. vttRelease. vttRelease. tkLString. vttSync.returns in result. headers in Head^ .getURICallBack and JSONDecode function function TSQLRecordPeople. tkSet.err). vttCommit. tkArray. end.Rev. thanks to the cdecl calling convention) . method. By convention. TSQLRestClientURI has dedicated methods like CallBackGetResult. vttRollBackTo vtWhereIDPrepared if the ID=? WHERE statement TSQLVirtualTableCursor. vttRollBack.CallBackGetResult('sum'.NET. Available type families for Delphi 6 up to XE values TURIMapRequest = function(url.['a'. var err: integer. 1. tkRecord. b: double): double. mSTATE ). mABORT. mDELETE. The available transaction levels TSynFilterOrValidateClass = class of TSynFilterOrValidate.use PUTF8Char instead of string: no need to share a memory manager. tkClass.a. tkWChar. vttRollBack .Hi the server database internal status . vttSync. tkFloat. mLOCK. vttSavePoint. tkInt64. The available THTTP methods transmitted between client and server TSQLVirtualTableFeature = ( vtWrite.18 Page 893 of 1055 . mPUT. tkInterface.vtWrite is to be set if the table is not Read/Only .you can specify some POST/PUT data in SendData (leave as nil otherwize) . cdecl. vttRollBackTo ). mEND. mPOST. calling TSQLRestClientURI. SendData: PUTF8Char.Search() will be handled in TSQLVirtualTableFeatures = set of TSQLVirtualTableFeature. vtWhereIDPrepared ). vtSavePoint.b]). begin val(aClient. tkString. tkDynArray ).18 Date: June 16.URL with the appropriate parameters. tkWString.Lo the HTTP STATUS integer error or success code . tkChar. The possible features of a Virtual Table . and CallBackPut.pas unit . tkMethod. a.'b'. and can be used with any language (even C or . Class-refrence type (metaclass) for a TSynFilter or a TSynValidate TTypeKind = ( tkUnknown.vtSavePoint if handles vttSavePoint. mBEGIN. vttCommit. allocate and store the resulting JSON body into Resp^.result. tkVariant. tkInteger. it could be appropriate to define in either TSQLRestServer (if to be called as ModelRoot/MethodName).use a GlobalFree() function to release memory for Resp and Head responses Constants implemented in the mORMot unit: mORMot. tkEnumeration. CallBackGet.Synopse mORMot Framework Software Architecture Design 1.on success. Resp.returns in result. Function prototype for remotly calling a TSQLRestServer . vtTransaction. Head: PPUTF8Char): Int64Rec.vtTransaction if handles vttBegin. mUNLOCK. Synopse mORMot Framework Software Architecture Design 1. mORMot.18 Date: June 16. The used TAuthSession. alllmighty over all fields ALL_FIELDS: TSQLFieldBits = [0. Special TSQLFieldBits value containing all field bits set to 1 AS_UNIQUE = false. HTML Status Code for "Bad Request" HTML_CREATED = 201.this constant will set AllowRemoteExecute field to true . Supervisor Table access right. 1.high(TSQLFieldType)] [sftUnknown. HTML Status Code for "Internal Server Error" HTML_SUCCESS = 200. allmighty over all Tables . Used as "stored AS_UNIQUE" published property definition in TSQLRecord CONST_AUTHENTICATION_NOT_USED = 1.. sftMany]. for direct local access right HTML_BADREQUEST = 400.e. i.i. HTML Status Code for "Success" HTML_TIMEOUT = 408.i. HTML Status Code for "Not Found" HTML_NOTIMPLEMENTED = 501.HandleAuthentication equals FALSE CONST_AUTHENTICATION_SESSION_NOT_STARTED = 0. 2013 ALL_ACCESS_RIGHTS = [0.e. i.reService.e. HTML Status Code for "Not Implemented" HTML_NOTMODIFIED = 304.reUrlEncodedDelete]. if the session handling is still in its handshaking phase COPIABLE_FIELDS: TSQLFieldTypes = [low(TSQLFieldType)..is used by default only TSQLRestClientDB. HTML Status Code for "Forbidden" HTML_NOTALLOWED = 405. HTML Status Code for "Created" HTML_FORBIDDEN = 403. PUT: ALL_ACCESS_RIGHTS. GET: ALL_ACCESS_RIGHTS.Rev. HTML Status Code for "Not Modified" HTML_SERVERERROR = 500. DELETE: ALL_ACCESS_RIGHTS).IDCardinal value if the session not started yet . Kind of fields which can be copied from one TSQLRecord instance to another FULL_ACCESS_RIGHTS: TSQLAccessRights = (AllowRemoteExecute: [reSQL..MAX_SQLTABLES-1]. if TSQLRest.URI() method.e.pas unit .18 Page 894 of 1055 . HTML Status Code for "Method Not Allowed" HTML_NOTFOUND = 404.IDCardinal value if authentication mode is not set .MAX_SQLFIELDS-1]. Supervisor Database access right. The used TAuthSession. POST: ALL_ACCESS_RIGHTS. 1. POST: ALL_ACCESS_RIGHTS.com/RADStudio/en/Classes_and_Objects#Published_Members .18 Date: June 16. allmighty over all Tables TEXT_FIELDS: TSQLFieldTypes = [sftAnsiText.512 seems big enough on practice MAX_SQLTABLES = 256. sftMany]. rCustomForcedID]. If a TSQLVirtualTablePreparedConstraint. as expected by TSQLAccessRights or such) NOT_SIMPLE_FIELDS: TSQLFieldTypes = [sftUnknown. If the TSQLRecordVirtual table kind is not an embedded type .code is somewhat faster and easier with a fixed cache size .Rev. SendTotalRowsCountFmt: nil). update or adding PAGINGPARAMETERS_YAHOO: TSQLRestServerURIPagingParameters = ( Sort: 'SORT='.g. in Synopse.Synopse mORMot Framework Software Architecture Design 1. sftDateTime. Dir: 'DIR='.18 Page 895 of 1055 . DELETE: ALL_ACCESS_RIGHTS). rFTS4]. rFTS4. GET: ALL_ACCESS_RIGHTS. rRTree. 2013 HTML Status Code for "Request Time-out" HTML_UNAVAILABLE = 503.you should not change it to a value lower than expected in an existing database (e. If a TSQLVirtualTablePreparedConstraint. e.pas unit . rCustomAutoID].can be set for a TSQLRecord after a VirtualTableExternalRegister call IS_FTS = [rFTS3.those values are the one expected by YUI components RTREE_MAX_DIMENSION = 5. The default URI parameters for query paging . sftUTF8Text.embarcadero.g. Kind of fields which will contain TEXT content when converted to JSON VIRTUAL_TABLE_IGNORE_COLUMN = -2. sftObject ]. Where: 'WHERE='. There is no RTTI generated for them: so it won't work :( see http://docwiki. HTML Status Code for "Service Unavailable" INSERT_WITH_ID = [rFTS3.Column points to the RowID mORMot. PUT: ALL_ACCESS_RIGHTS.Column is to be ignored VIRTUAL_TABLE_ROWID_COLUMN = -1. Maximum handled dimension for TSQLRecordRTree . Supervisor Database access right. sftBlob.this constant is used internaly to optimize memory usage in the generated asm code . If the TSQLRecordVirtual table kind expects the ID to be set on INSERT IS_CUSTOM_VIRTUAL = [rCustomForcedID. Results: 'RESULTS='.inc maximum number of Tables in a Database Model . i. Maximum number of the locked record in a Table (used in TSQLLocks) . Select: 'SELECT='. StartIndex: 'STARTINDEX='.this value is the one used by SQLite3 R-Tree virtual table SUPERVISOR_ACCESS_RIGHTS: TSQLAccessRights = (AllowRemoteExecute: [reService.should be defined globaly.e. Kind of fields not retrieved during normal query. If the TSQLRecordVirtual table kind is a FTS3/FTS4 virtual table MAX_SQLLOCKS = 512.reUrlEncodedDelete]. used for User Interface generation . 2013 WM_TIMER_REFRESH_REPORT = 2.RefreshClickHandled Functions or procedures implemented in the mORMot unit: Functions or procedures Description Page Base64MagicToBlob Convert a Base64-encoded content into binary hexadecimal ready for SQL 898 BlobToBytes Create a TBytes from TEXT-encoded blob data 898 BlobToStream Create a memory stream from TEXT-encoded blob data 899 BlobToTSQLRawBlob Fill a TSQLRawBlob from TEXT-encoded blob data 899 ClassFieldIndex Retreive a Field property index from a Property Name 899 ClassFieldProp Retrieve a Field property RTTI information from a Property Name 899 ClassFieldPropWithPar ents Retrieve a Field property RTTI information from a Property Name 899 ClassFieldPropWithPar entsFromUTF8 Retrieve a Field property RTTI information from a Property Name 899 ClassInstanceCreate Create an instance of the given class from its registered class name 899 ClassInstanceCreate Create an instance of the given class 899 CopyCollection Copy two TCollection instances 899 CopyObject Copy object properties 899 CurrentServiceContext Wrapper function to retrieve the global ServiceContext threadvar value 900 GetEnumCaption Retrieve the ready to be displayed text of an enumeration 900 GetEnumNameTrimed Get the corresponding enumeration name. 1.is handled in TSQLRibbon. Timer identifier which indicates we must refresh the Report content . and is handled in TSQLRibbon.AutoRefresh property.18 Page 896 of 1055 .pas unit . without the first lowercase chars (otDone -> 'Done') 900 GetJSONObjectAsSQL Decode JSON fields object into an UTF-8 encoded SQL-ready statement 900 GetJSONObjectAsSQL Decode JSON fields object into an UTF-8 encoded SQL-ready statement 900 GetObjectComponent Retrieve an object's component from its property name and class 900 InternalClassProp Retrieve the class property RTTI information for a specific class 901 mORMot.18 Date: June 16.Synopse mORMot Framework Software Architecture Design 1.is associated with the TSQLRibbonTabParameters.RefreshClickHandled WM_TIMER_REFRESH_SCREEN = 1.used for User Interface generation .Rev. Timer identifier which indicates we must refresh the current Page . . 1..) 901 IsNotAjaxJSON Returns TRUE if the JSON content is in expanded format 901 JSONFileToObject Fill the object properties from a JSON file content 901 JSONGetObject Retrieve a JSON '{"Name":Value.. to be used for circular references 903 SetWeakZero {$ifdef HASINLINE}inline.Rev.woStoreClassName]).pas unit . 2013 Functions or procedures Description Page InternalMethodInfo Retrieve a method RTTI information for a specific class 901 isBlobHex Return true if the TEXT is encoded as SQLite3 BLOB literals (X'53514C697465' e.{$endif} raise compilation Internal Error C2170 assign a Weak interface reference. as saved by ObjectToJSON(.18 Page 897 of 1055 . 901 JSONToObject Read an object properties.}' object 901 JSONIgnoreFieldName Go to the end of a field name in a JSON '"FieldName":Value' pair 901 JSONIgnoreFieldValue Go to the end of a value in a JSON '"FieldName":Value.Synopse mORMot Framework Software Architecture Design 1.' pair 901 JSONIgnoreObject Go to the end of a JSON '{"Name":Value.. as saved by ObjectToJSON function 902 ObjectFromInterface Low-level function to retrieve the class instance implementing a given interface 902 ObjectToJSON Will serialize any TObject into its UTF-8 JSON representation 902 ObjectToJSONFile Persist a class instance into a JSON file 902 ReadObject Read an object properties.... as saved by TINIWriter. which will be ZEROed (set to nil) when the corresponding object will be released 904 SQLGetOrder Get the order table name from a SQL statement 904 StatusCodeToErrorMsg Convert any HTML_* constant to a short English text 904 TSQLRawBlobToBlob Creates a TEXT-encoded version of blob data from a TSQLRawBlob 904 mORMot..}' object 901 JSONToNewObject Create a new object instance. as saved by TINIWriter..g.WriteObject() method 903 RecordReference Create a TRecordReference with the corresponding parameters 903 RecordRefToID Convert a dynamic array of TRecordReference into its corresponding IDs 903 SetDefaultValuesObjec t Set any default integer or enumerates (including boolean) published properties values for an object 903 SetWeak Assign a Weak interface reference.18 Date: June 16.WriteObject() method 903 ReadObject Read an object properties. from a JSON content 904 URIRequest This function can be exported from a DLL to remotely access to a TSQLRestServer 904 UrlDecodeObject Decode a specified parameter compatible with URI encoding into its original object contents 905 UrlEncode Encode supplied parameters to be compatible with URI encoding 905 UTF8CompareBoolean Special comparaison function for sorting sftBoolean UTF-8 encoded values in the SQLite3 database or JSON content 905 UTF8CompareCurr64 Special comparaison function for sorting sftCurrency UTF-8 encoded values in the SQLite3 database or JSON content 905 UTF8CompareDouble Special comparaison function for sorting sftFloat UTF-8 encoded values in the SQLite3 database or JSON content 905 UTF8CompareInt64 Special comparaison function for sorting sftInteger or sftTimeLog / sftModTime / sftCreateTime UTF-8 encoded values in the SQLite3 database or JSON content 905 UTF8CompareISO8601 Special comparaison function for sorting sftDateTime UTF-8 encoded values in the SQLite3 database or JSON content 905 UTF8CompareRecord Special comparaison function for sorting ftRecord (TRecordReference/RecordRef) UTF-8 encoded values in the SQLite3 database or JSON content 905 UTF8CompareUInt32 Special comparaison function for sorting sftEnumerate.g. Convert a Base64-encoded content into binary hexadecimal ready for SQL .g.returns e. 2013 Functions or procedures Description Page TSQLRawBlobToBlob Creates a TEXT-encoded version of blob data from a memory data 904 UnJSONFirstField Get the FIRST field value of the FIRST row.18 Date: June 16. 1.WriteObject() method 906 WriteObject Write an object properties.pas unit .Synopse mORMot Framework Software Architecture Design 1.) or or Base-64 encoded content ('\uFFF0base64encodedbinary') or plain TEXT mORMot.Rev. X'53514C697465' function BlobToBytes(P: PUTF8Char): TBytes. sftSet or sftID UTF-8 encoded values in the SQLite3 database or JSON content 905 UTF8ContentType Guess the content type of an UTF-8 encoded field value. as saved by TINIWriter. as used in TSQLTable.WriteObject() method 906 procedure Base64MagicToBlob(Base64: PUTF8Char.18 Page 898 of 1055 . var result: RawUTF8).blob data can be encoded as SQLite3 BLOB literals (X'53514C697465' e.Get() 906 WriteObject Write an object properties. as saved by TINIWriter. Create a TBytes from TEXT-encoded blob data . TCollection items can be copied also.the class shall have been registered via TJSONSerializer.g.) or or Base-64 encoded content ('\uFFF0base64encodedbinary') or plain TEXT function ClassFieldIndex(ClassType: TClass. so is to be preferred to aClass. 2013 function BlobToStream(P: PUTF8Char): TStream. PropName: PUTF8Char): PPropInfo. Retrieve a Field property RTTI information from a Property Name function ClassFieldPropWithParents(aClassType: TClass.Synopse mORMot Framework Software Architecture Design 1.RegisterClassForJSON() or via the standard RegisterClass() function of Classes.18 Date: June 16. Copy two TCollection instances .pas unit . const PropName: shortstring): integer.will handle the custom virtual constructors of TSQLRecord or TCollection classes as expected. Dest: TCollection).) or or Base-64 encoded content ('\uFFF0base64encodedbinary') or plain TEXT .18 Page 899 of 1055 .will call CopyObject() in loop to repopulate the Dest collection procedure CopyObject(aFrom. these are not class instances.g.Rev. Create a memory stream from TEXT-encoded blob data .pas unit . aTo: TObject). Retreive a Field property index from a Property Name function ClassFieldProp(ClassType: TClass.Create procedure CopyCollection(Source. so only the integer value is copied). const PropName: shortstring): PPropInfo.this special version also search into parent properties (default is only current) function ClassFieldPropWithParentsFromUTF8(aClassType: TClass.copy only Integer. if they are of the same exact class . that is for regular Delphi classes mORMot.blob data can be encoded as SQLite3 BLOB literals (X'53514C697465' e.the caller must free the stream instance after use function BlobToTSQLRawBlob(P: PUTF8Char): TSQLRawBlob. so is to be preferred to aClass. Fill a TSQLRawBlob from TEXT-encoded blob data . Create an instance of the given class from its registered class name . Retrieve a Field property RTTI information from a Property Name .will handle the custom virtual constructors of TSQLRecord or TCollection classes as expected. 1. Int64. enumerates (including boolean).object properties instances are created in aTo if the objects are not TSQLRecord children (in this case.blob data can be encoded as SQLite3 BLOB literals (X'53514C697465' e.this special version also search into parent properties (default is only current) function ClassInstanceCreate(aClass: TClass): TObject. but INTEGER reference to records. object properties and (Ansi/Wide/Unicode)String properties (excluding shortstring) . Retrieve a Field property RTTI information from a Property Name . overload. overload. Create an instance of the given class . Copy object properties .Create function ClassInstanceCreate(const aClassName: RawUTF8): TObject. const PropName: shortstring): PPropInfo. so take care that it is an unique string . function GetObjectComponent(Obj: TPersistent. 2013 function CurrentServiceContext: TServiceRunningContext. const ComponentName: shortstring.2 (page 1049). for faster process . RowID: Integer=0. InlinedParams: boolean.. Fields[] contains the column names and expects "VAL1".escape SQL strings.returns 'COL1="VAL1".P contains the next object start or nil on unexpected end of input .returns '(COL1. Retrieve an object's component from its property name and class . ReplaceRowIDWithID: Boolean=false): RawUTF8. 1. COL2=:(VAL2):' . ComponentClass: TClass): pointer.returns 'COL1="VAL1".} pairs . const Fields: TRawUTF8DynArray... InlinedParams: boolean.usefull to set User Interface component. ' inside a string is stored as '') .to be used when accessing the value from a package. Retrieve the ready to be displayed text of an enumeration . ReplaceRowIDWithID: Boolean=false): RawUTF8.Rev. overload.otherwize.Synopse mORMot Framework Software Architecture Design 1. to circumvent a Delphi RTL/compiler restriction (bug?) function GetEnumCaption(aTypeInfo: PTypeInfo. use GetEnumCaption() to retrieve the enumeration display text function GetJSONObjectAsSQL(JSON: RawUTF8. VAL2)' otherwize (INSERT format) .aIndex will be converted to the matching ordinal value (byte or word) . stopping at '}' or ']' . Decode JSON fields object into an UTF-8 encoded SQL-ready statement .if RowID is set. COL2) VALUES ("VAL1". without the first lowercase chars (otDone -> 'Done') . const aIndex): RawUTF8.expect JSON expanded object as "COL1"="VAL1". VAL2)' otherwize (INSERT format) . RowID: Integer=0.if InlinedParams is set. function GetJSONObjectAsSQL(var P: PUTF8Char.pas unit . Update.aIndex will be converted to the matching ordinal value (byte or word) function GetEnumNameTrimed(aTypeInfo: PTypeInfo.if Fields is void. Get the corresponding enumeration name.returns '(COL1.18 Page 900 of 1055 . will create prepared parameters like 'COL1=:("VAL1"):. COL2=VAL2' if UPDATE is true (UPDATE SET format) . mORMot.e.will "uncamel" then translate into a generic VCL string . will create prepared parameters like 'COL2=:(VAL2):' . COL2=VAL2' if UPDATE is true (UPDATE SET format) . in P^ . according to the official SQLite3 documentation (i. Wrapper function to retrieve the global ServiceContext threadvar value .. COL2) VALUES ("VAL1". Decode JSON fields object into an UTF-8 encoded SQL-ready statement ."VAL2".this function decodes in the P^ buffer memory itself (no memory allocation or copy). Update.1.1.if InlinedParams is set.make its own temporary copy of JSON data before calling GetJSONObjectAsSQL() above .18 Date: June 16.g. expects expanded "COL1"="VAL1" pairs in P^. a RowID column will be added within the returned content Used for DI-2.this will return the code-based English text. const aIndex): string. a RowID column will be added within the returned content Used for DI-2.if RowID is set.2 (page 1049). e. overload. var ObjectInstance.. TObjectListItemClass: TClass=nil): boolean.] . Go to the end of a JSON '{"Name":Value.. 2013 function InternalClassProp(ClassType: TClass): PClassProp. as plain [{"ID":10.Synopse mORMot Framework Software Architecture Design 1.. Returns TRUE if the JSON content is in expanded format . Retrieve a JSON '{"Name":Value. at least. Go to the end of a field name in a JSON '"FieldName":Value' pair .or.returns the position after the expected ending '}' delimiter function JSONToNewObject(var From: PUTF8Char...' or '}' delimiter function JSONIgnoreObject(P: PUTF8Char): PUTF8Char.RegisterClass() function call mORMot. Retrieve the class property RTTI information for a specific class function InternalMethodInfo(aClassType: TClass... by a Classes.returns the position of the expected ending '.i..' pair .if ExtractID is set. Retrieve a method RTTI information for a specific class function isBlobHex(P: PUTF8Char): boolean.}' . either '{"ClassName":"TMyClass".e. Return true if the TEXT is encoded as SQLite3 BLOB literals (X'53514C697465' e.) function IsNotAjaxJSON(P: PUTF8Char): Boolean..returns the UTF-8 encoded JSON object.18 Date: June 16.woStoreClassName option shall have been used at ObjectToJSON() call . const aMethodName: ShortString): PMethodInfo. Create a new object instance.returns nil if P was not formatted as expected ."FirstName".and the corresponding class shall have been previously registered by TJSONSerializer.Rev. Fill the object properties from a JSON file content . it will contain the "ID":203 field value. including first '{' and last '}' .}' object . Go to the end of a value in a JSON '"FieldName":Value.18 Page 901 of 1055 .woStoreClassName]).ObjectInstance must be an existing TObject instance ..returns nil if P was not formatted as expected ..JSON input should be either 'null'.}' object .i. var Valid: boolean): TObject."LastName":"Smith"}."LastName".returns nil if P was not formatted as expected .returns the position of Value function JSONIgnoreFieldValue(P: PUTF8Char): PUTF8Char.this function will call RemoveCommentsFromJSON() before process function JSONGetObject(var P: PUTF8Char. 1... ."values":["ID". not as '{"fieldCount":3."FirstName":"John".pas unit ..']} function JSONFileToObject(const JSONFile: TFileName. ExtractID: PInteger. and this field won't be included in thre resulting UTF-8 encoded JSON object (will expect this "ID" property to be the FIRST in the "Name":Value pairs function JSONIgnoreFieldName(P: PUTF8Char): PUTF8Char.P is nil in return in case of an invalid object . as saved by ObjectToJSON(.g. in order to retrieve the class type from it name . var EndOfObject: AnsiChar): RawUTF8...e..RegisterClassForJSON(). but including WideString and UnicodeString under Delphi 2009+) .you can add some custom (un)serializers for ANY Delphi class.g. will call FreeAndNil(Value) . Options: TTextWriterWriteObjectOptions=[woDontStoreDefault]): RawUTF8. TStrings.RegisterCustomSerializer() class method .nested properties are serialized as nested JSON objects . 1. via the TJSONSerializer.g. var Valid: boolean.RegisterClassForJSON() (or Classes.set Valid=TRUE on success.you can add some custom serializers for ANY Delphi class. Valid=FALSE on error.Add is missing). string. but also with TInterfaceFactory.won't handle TObjectList (even if ObjectToJSON is able to serialize them) since has now way of knowing the object type to add (TCollection. From: PUTF8Char. on any unknown property name) . const JSONFile: TFileName. floating point. TObjectListItemClass: TClass=nil): PUTF8Char. or 2.this will work with interfaces stubs generated by the compiler.caller should explicitely perform a SetDefaultValuesObject(Value) if the default values are expected to be set before JSON parsing function ObjectFromInterface(const aValue: IInterface): TObject.serialize as JSON the published integer. and provide a TObjectList object.any TCollection property will also be serialized as JSON arrays . and the main function will point in From at the syntax error place (e. TDateTime (stored as ISO 8601 text).pas unit .will clear any previous TCollection objects.Synopse mORMot Framework Software Architecture Design 1. set.will write also the properties published in the parent classes .18 Page 902 of 1055 . and string properties (excluding ShortString. enumerate (including boolean).18 Date: June 16. boolean) properties of the object (and its parents) . Low-level function to retrieve the class instance implementing a given interface .e. variant. via the TJSONSerializer. Int64.TList won't be handled since it may leak memory when calling TList. TDateTime.WriteObject() method procedure ObjectToJSONFile(Value: TObject.g. Read an object properties. woStoreClassName option has been used at ObjectToJSON() call and the corresponding classes have been previously registered by TJSONSerializer. as saved by ObjectToJSON function .RegisterCustomSerializer() class method . Will serialize any TObject into its UTF-8 JSON representation .Rev.ObjectInstance must be an existing TObject instance . variant and enumerate (e. TCollection. Int64. 2013 function JSONToObject(var ObjectInstance.Clear .won't handle shortstring properties . Persist a class instance into a JSON file mORMot.handle Integer.the data inside From^ is modified (unescaped and transformed): don't call JSONToObject(pointer(JSONRawUTF8)) but makes a temporary copy of the JSONRawUTF8 text before calling this function . you set the TObjectListItemClass property as expected. if From='null'.the enumerates properties are stored with their integer index value . unless: 1. Options: TTextWriterWriteObjectOptions=[woHumanReadable]). floating point values. TRawUTF8List.CreateFakeInstance kind of classes function ObjectToJSON(Value: TObject.call internaly TJSONSerializer. and convert any null JSON basic type into nil .RegisterClass) . 1.for integers.Synopse mORMot Framework Software Architecture Design 1.this version doesn't handle embedded objects function RecordReference(Model: TSQLModel. enumerates (including boolean). Assign a Weak interface reference.i.WriteObject() method . to be used for circular references .Field := aValue will increment the internal reference count of the implementation object: when underlying objects reference each other via interfaces (e. floating point values and (Ansi/Wide/Unicode)String properties (excluding shortstring) . variant and (Ansi/Wide/Unicode)String properties (excluding shortstring) . as saved by TINIWriter.g. if no value is stored in From (or From is ''). the default value from the property definition is set procedure ReadObject(Value: TObject. Read an object properties. if no value is stored in FromContent.by default setting aInterface.reset only the published properties of the current class level (do NOT reset the properties content published in the parent classes) procedure SetWeak(aInterfaceField: PIInterface. enumerates (including boolean).ClassName] . const SubCompName: RawUTF8='').read only the published properties of the current class level (do NOT read the properties content published in the parent classes) .Rev. aTable: TSQLRecordClass. const aValue: IInterface). overload.for integers and enumerates. what causes the reference count to never reach zero. as saved by TINIWriter. the default value is set .to avoid this issue.e. Int64. Int64. Convert a dynamic array of TRecordReference into its corresponding IDs procedure SetDefaultValuesObject(Value: TObject). overload. floating point.18 Page 903 of 1055 . use this procedure instead mORMot."From" must point to the [section] containing the object properties . therefore resulting in memory links .e. 2013 procedure ReadObject(Value: TObject. From: PUTF8Char. Read an object properties. Create a TRecordReference with the corresponding parameters procedure RecordRefToID(var aArray: TPtrUIntDynArray). Set any default integer or enumerates (including boolean) published properties values for an object .read only the published properties of the current class level (do NOT read the properties content published in the parent classes) . only Integer.i. const SubCompName: RawUTF8=''). const FromContent: RawUTF8.this version gets the appropriate section from [Value. only Integer.WriteObject() method . as parent and children).pas unit . aID: integer): TRecordReference.18 Date: June 16. Creates a TEXT-encoded version of blob data from a TSQLRawBlob .g.g. Get the order table name from a SQL statement .1 (page 1048). calling the previous method afterward (so will work even with custom FreeInstance implementations) .ExportServer to assign a server to this function . Head: PPUTF8Char): Int64Rec. but will avoid any GPF. it will assign the unused vmtAutoTable VMT entry trick (just like TSQLRecord.pas unit . 2013 procedure SetWeakZero(aObject: TObject.1.1.TEXT will be encoded as SQLite3 BLOB literals (X'53514C697465' e. which will be ZEROed (set to nil) when the corresponding object will be released .thread-safe implementation.{$endif} raise compilation Internal Error C2170 assign a Weak interface reference. using a per-class fast lock function SQLGetOrder(const SQL: RawUTF8): RawUTF8.) function TSQLRawBlobToBlob(const RawBlob: TSQLRawBlob): RawUTF8.memory for Resp and Head are allocated with GlobalAlloc(): client must release this pointers with GlobalFree() after having retrieved their content .ExportServer has been assigned . Convert any HTML_* constant to a short English text function TSQLRawBlobToBlob(RawBlob: pointer. This function can be exported from a DLL to remotely access to a TSQLRestServer .return 501 HTML_NOTIMPLEMENTED if no TSQLRestServer.2. RawBlobLength: integer): RawUTF8.) function UnJSONFirstField(var P: PUTF8Char): RawUTF8.TEXT will be encoded as SQLite3 BLOB literals (X'53514C697465' e.this function is bit slower than SetWeak.g. Get the FIRST field value of the FIRST row.1.for faster possible retrieval. {$ifdef HASINLINE}inline. 1. Resp.note that it will be compatible also with interfaces implemented via TSQLRecord children .same as TSQLRawBlob. usefull to get an ID without converting a JSON content into a TSQLTableJSON Used for DI-2. aObjectInterfaceField: PIInterface. from a JSON content . var result: RawUTF8).18 Date: June 16. Creates a TEXT-encoded version of blob data from a memory data .simply use TSQLRestClientURIDll to access to an exported URIRequest() function Used for DI-2. function URIRequest(url.RecordProps) . by maintaining a list of per-instance weak interface field reference. overload. and hook the FreeInstance virtual method in order to reset any reference to nil: FreeInstance will be overriden for this given class VMT only (to avoid unnecessary slowdown of other classes).e.return the word following any 'ORDER BY' statement . method.use TSQLRestServer.18 Page 904 of 1055 .Rev. mORMot. const aValue: IInterface).2 (page 1049). overload. SendData: PUTF8Char. cdecl.return 'RowID' if none found procedure StatusCodeToErrorMsg(Code: integer. but with direct memory access via a pointer/byte size pair .Synopse mORMot Framework Software Architecture Design 1. P2: PUTF8Char): PtrInt. Value is not modified.P2: PUTF8Char): PtrInt.TObject serialization into UTF-8 will be processed by the ObjectToJSON() function function UTF8CompareBoolean(P1.P2: PUTF8Char): PtrInt. 1.Synopse mORMot Framework Software Architecture Design 1. as Name. url := UrlEncodeFull(['select'. or any TObject (standard UrlEncode() will only handle . Special comparaison function for sorting sftInteger or sftTimeLog / sftModTime / sftCreateTime UTF-8 encoded values in the SQLite3 database or JSON content function UTF8CompareISO8601(P1.'offset'.@Next ) will return Next^='where=.' and P=20.. Special comparaison function for sorting sftDateTime UTF-8 encoded values in the SQLite3 database or JSON content function UTF8CompareRecord(P1. Decode a specified parameter compatible with URI encoding into its original object contents . Special comparaison function for sorting ftRecord (TRecordReference/RecordRef) UTF-8 encoded values in the SQLite3 database or JSON content function UTF8CompareUInt32(P1. and result is TRUE function UrlEncode(const NameValuePairs: array of const): RawUTF8.pas unit .45&where=LastName%3D%27M%C3%B4net%27'.ObjectInstance must be an existing TObject instance . sftSet or sftID UTF-8 encoded values in the SQLite3 database or JSON content mORMot.45 .'*'. Encode supplied parameters to be compatible with URI encoding . 2013 function UrlDecodeObject(U.aObject]).P. Special comparaison function for sorting sftCurrency UTF-8 encoded values in the SQLite3 database or JSON content function UTF8CompareDouble(P1.18 Date: June 16. integer or extended. Value is modified with the supplied content. Special comparaison function for sorting sftEnumerate. Next: PPUTF8Char=nil): boolean.23. overload.18 Page 905 of 1055 .'where'. Special comparaison function for sorting sftFloat UTF-8 encoded values in the SQLite3 database or JSON content function UTF8CompareInt64(P1.P2: PUTF8Char): PtrInt. e. .g.if Upper is found.'ID=12'.'PRICE='.Value pairs.'object'.P2: PUTF8Char): PtrInt. and result is FALSE ..parameters must be supplied two by two.parameters can be either textual.P2: PUTF8Char): PtrInt.will call internaly JSONToObject() function to unserialize its content UrlDecodeExtended('price=20. Upper: PUTF8Char.P2: PUTF8Char): PtrInt. Special comparaison function for sorting sftBoolean UTF-8 encoded values in the SQLite3 database or JSON content function UTF8CompareCurr64(P1. var ObjectInstance.if Upper is not found.Rev. value is always written.Synopse mORMot Framework Software Architecture Design 1.Get() . if the value matches the default value. as saved by TINIWriter. with no section .since P is PUTF8Char.sftFloat is returned for any floating point value. allowing to retrieve the current execution context .when accessed from a package. as used in TSQLTable.write only the published properties of the current class level (do NOT write the properties content published in the parent classes) .when used.its content is reset to zero out of the scope of a method execution . const Section: RawUTF8. var IniContent: RawUTF8. TSQLLog class is used for logging for all our ORM related functions . sftID. only Integer. 2013 function UTF8ContentType(P: PUTF8Char): TSQLFieldType.is set by TServiceFactoryServer.return the properties as text Name=Values pairs.for integers. as saved by TINIWriter.pas unit . 1. it is not added to the result Variables implemented in the mORMot unit: ServiceContext: TServiceRunningContext.18 Date: June 16.18 Page 906 of 1055 . string type is sftUTF8Text only . floating point values and (Ansi/Wide/Unicode)String properties (excluding shortstring) . even if matches the default value function WriteObject(Value: TObject): RawUTF8.WriteObject() method .write only the published properties of the current class level (do NOT write the properties content published in the parent classes) . to circumvent a Delphi RTL/compiler restriction (bug?) SQLite3Log: TSynLogClass = TSQLLog. guess its type from its value characters .e.Rev. only Integer.for integers.i. Write an object properties.this global variable can be used to customize it mORMot. a local copy or a PServiceRunningContext pointer should better be created. return sftUnknown .e. This thread-specific variable will be set with the currently running service context (on the server side) . sftBoolean or sftModTime / sftCreateTime / sftTimeLog type procedure WriteObject(Value: TObject.) or with '\uFFF0' magic code . overload.i.direct update of INI-like content .sftBlob is returned if the field is encoded as SQLite3 BLOB literals (X'53514C697465' e. enumerates (including boolean).g. Write an object properties. even if it was declared as sftCurrency type . use function CurrentServiceContext() instead. Guess the content type of an UTF-8 encoded field value.WriteObject() method . since accessing a threadvar has a non negligible performance cost . overload.if P if nil or 'null'.ExecuteMethod() just before calling the implementation method of a service. even if it was declared as sftEnumerate. floating point values and (Ansi/Wide/Unicode)String properties (excluding shortstring) . enumerates (including boolean). const SubCompName: RawUTF8='').otherwize. Int64.sftInteger is returned for any INTEGER stored value. Int64. sftRecord. sftSet. Rev. If this variable is TRUE.18 Page 907 of 1055 . the URIRequest() function won't use Win32 API GlobalAlloc() function.1. 2013 USEFASTMM4ALLOC: boolean = false. mORMot. but fastest native Getmem() .Synopse mORMot Framework Software Architecture Design 1.1 (page 1048).can be also usefull for debugg Used for DI-2.2.pas unit .1. 1.18 Date: June 16. 18 Date: June 16.for JOINed SQL statements.this unit is a part of the freeware Synopse mORMot framework.this unit is a part of the freeware Synopse framework. using the external SQL database connection.Synopse mORMot Framework Software Architecture Design 1. version 1. the external database is also defined as a SQLite3 virtual table. licensed under a MPL/GPL/LGPL tri-license. licensed under a MPL/GPL/LGPL tri-license. licensed under a MPL/GPL/LGPL tri-license.this unit is a part of the freeware Synopse mORMot framework.18 Page 908 of 1055 .18 325 SynDB Abstract database direct access classes . mORMotDB. and prepared statements .URI for faster RESTful direct access . version 1.18 509 TSQLRestServerStatic TSQLRestServerStaticExternal TSQLVirtualTable TSQLVirtualTableExternal TSQLVirtualTableCursor TSQLVirtualTableCursorExternal mORMotDB class hierarchy Objects implemented in the mORMotDB unit: Objects Description Page TSQLRestServerStaticE xternal REST server with direct access to a SynDB-based external database 908 TSQLVirtualTableCurso rExternal A Virtual Table cursor for reading a TSQLDBStatement content 910 TSQLVirtualTableExter nal A SynDB-based virtual table for accessing any external database 911 TSQLRestServerStaticExternal = class(TSQLRestServerStatic) REST server with direct access to a SynDB-based external database . 2013 23. 1.handle all REST commands. licensed under a MPL/GPL/LGPL tri-license.this unit is a part of the freeware Synopse mORMot framework.26.pas unit Purpose: Virtual Tables for external DB access for mORMot .is used by TSQLRestServer.pas unit . version 1. version 1. via the TSQLVirtualTableExternal[Cursor] classes mORMotDB.18 Units used in the mORMotDB unit: Unit Name Description Page mORMot Common ORM and SOA classes for mORMot .18 715 SynCommons Common functions used by most Synopse projects .Rev. const FieldNames: array of RawUTF8. Update a field value of the external database class function ExternalRecordProperties(aClass: TSQLRecordClass.e. override. i. FieldValue: Integer.ExternalDatabase property to create the connection . var ResultID: TIntegerDynArray): boolean. Overriden method for direct external database engine call mORMotDB.store the results into the ResultID dynamic array function TableHasRows(Table: TSQLRecordClass): boolean.StaticVirtualTable[] and will return nil if not a TSQLRestServerStaticExternal function RetrieveBlobFields(Value: TSQLRecord): boolean. according to its SQL content representation .Synopse mORMot Framework Software Architecture Design 1.pas unit . ID: integer): boolean. Overriden method for direct external database engine call function SearchField(const FieldName: RawUTF8.RecordProps. override. if some values have been added to ResultID) .all filename/binary parameters are ignored here. including any database schema prefix function CreateSQLMultiIndex(Table: TSQLRecordClass.e.18 Date: June 16. Delete a row. calling the external engine with SQL . aServer: TSQLRestServer): TSQLDBConnectionProperties.RecordProps. var ResultID: TIntegerDynArray): boolean.return true on success (i. Search for a field value. override. Unique: boolean. without any associated Model/TSQLRestServer function EngineExecuteAll(const aSQL: RawUTF8): boolean.store the results into the ResultID dynamic array function SearchField(const FieldName. overload. FieldValue: RawUTF8.g. since it will rely on the RecordProps. override. const aFileName: TFileName = ''. override. if some values have been added to ResultID) . const SetFieldName.ExternalTableName will retrieve the real full table name. 2013 constructor Create(aClass: TSQLRecordClass. 1. SetValue.just map aServer. e.made public since a TSQLRestServerStatic instance may be created stand-alone. override.return true on success (i. Overriden method for direct external SQL database engine thread-safe process . overload. aServer: TSQLRestServer.it will convert all inlined parameters (like :(1234): into bound parameters) function EngineUpdateField(Table: TSQLRecordClass.ExternalDatabase will map the associated TSQLDBConnectionProperties .18 Page 909 of 1055 .this method will in fact call the SQLAddIndex method. aBinaryFile: boolean=false). override. Search for a numerical field value . Retrieve the external database connection associated to a TSQLRecord .Rev. IndexName: RawUTF8=''): boolean. override. WhereFieldName.in practice. Initialize the remote database connection . Create one index for all specific FieldNames at once .e. if the index is not already existing function EngineDelete(Table: TSQLRecordClass. just call the global VirtualTableExternalRegister() procedure . WhereValue: RawUTF8): boolean.this method will in fact call only one (first) statement . override. i.must be ended with Commit on success . 2013 function TableRowCount(Table: TSQLRecordClass): integer. Abort a transaction (implements REST ABORT Member) .Synopse mORMot Framework Software Architecture Design 1. End a transaction (implements REST END Member) .return true if no transaction is active. any INSERT will compute the new ID from an internal variable . override.18 Date: June 16.18 Page 910 of 1055 . before the call to TransactionBegin property EngineAddUseSelectMaxID: Boolean read fEngineUseSelectMaxID write fEngineUseSelectMaxID.this is the cursor class associated to TSQLVirtualTableExternal function Column(aColumn: integer.you can set EngineAddUseSelectMaxID=true to execute a slower 'select max(ID) from TableName' SQL statement property Properties: TSQLDBConnectionProperties read fProperties.this method shall be called directly. override.must be aborted with Rollback if any SQL statement failed . The associated external database connection TSQLVirtualTableCursorExternal = class(TSQLVirtualTableCursor) A Virtual Table cursor for reading a TSQLDBStatement content .e.if aColumn=VIRTUAL_TABLE_ROWID_COLUMN(-1). varInt64. call TSQLDBConnectionPropertiesThreadSafe. true on success mORMotDB. This method is called by TSQLRestServer.EndCurrentThread method just before a thread is finished to ensure that the associated external DB connection will be released for this thread .will return false in case of an error. override. Called to retrieve a column value of the current data row . override. unless external IDs can be created outside this engine .pas unit . varDouble.to be used to speed up some SQL statements like Insert/Update/Delete . By default. varString (mapping a constant PUTF8Char) and varAny (BLOB with size = VLongs[0]) .handled types in aResult are varNull.this overriden implementation will clean thread-specific connections. nor from the main thread procedure RollBack(SessionID: cardinal=1). Overriden method for direct external database engine call function TransactionBegin(aTable: TSQLRecordClass. override. will return the row ID as varInt64 into aResult . false otherwize function UpdateBlobFields(Value: TSQLRecord): boolean. SessionID: cardinal=1): boolean. var aResult: TVarData): boolean. override. Begin a transaction (implements REST BEGIN Member) . Overriden method for direct external database engine call procedure Commit(SessionID: cardinal=1). 1.restore the previous state of the database.EndCurrentThread method .it is very fast and reliable.Rev. override.write all pending SQL statements to the external database procedure EndCurrentThread(Sender: TObject). 18 Date: June 16.18 Page 911 of 1055 .Rev.e. override. you should use VirtualTableExternalRegister method to associated this virtual table module to any TSQLRecord class . even if HasData will return false. override.returns true on success.Prepared will contain all prepared constraints and the corresponding expressions in the Where[]. i. then execute it. no data match) function Search(const Prepared: TSQLVirtualTablePrepared): boolean.column order follows the Structure method. override.Synopse mORMot Framework Software Architecture Design 1.will create the internal fStatement from a SQL query. varDouble.returns true on success. varInt64.Value field . no data match) .pas unit .Fields[] order .for ORM access.will return false on low-level database error (but true in case of a valid call. override.e.Prepare and will contain both WHERE and ORDER BY statements (retrieved by x_BestIndex from a TSQLite3IndexInfo structure) .should return false on low-level database error (but true in case of a valid call.returns true on success. out insertedRowID: Int64): boolean.all WHERE and ORDER BY clauses are able to be translated into a plain SQL statement calling the external DB engine . StoredClassProps. bind the parameters. Called to go to the next row of matching data .the TSQLVirtualTablePrepared parameters were set by TSQLVirtualTable. according to the external database function Delete(aRowID: Int64): boolean. Called to delete a virtual table row . var Values: TVarDataDynArray. Called to insert a virtual table row content . ready to be accessed via HasData/Next TSQLVirtualTableExternal = class(TSQLVirtualTable) A SynDB-based virtual table for accessing any external database . even if HasData will return false. Called after Search() to check if there is data to be retrieved . override. varString (mapping a constant PUTF8Char). override. 2013 function HasData: boolean. i. 1. false otherwise function Drop: boolean.transactions are handled by this module. false otherwise . and varAny (BLOB with size = VLongs[0]) .returns the just created row ID in insertedRowID on success mORMotDB. false otherwise function Insert(aRowID: Int64.should return false if reached the end of matching data function Next: boolean. i. creating a SQL query .will move cursor to first row of matching data .e. Called to begin a search in the virtual table. Called when a DROP TABLE statement is executed against the virtual table .the column values are available via some TVarData of type varNull. override. varDouble.column order follows the Structure method.Synopse mORMot Framework Software Architecture Design 1. and OmitCheck always set to true since double check is not necessary .ColumnIndexed is set (i.fFields[]. varString (mapping a constant PUTF8Char). if column has an index) function Update(oldRowID. ORDER BY . override.will prepare the request for TSQLVirtualTableCursor.OmitOrderBy will be set to true since double sort is not necessary . Returns the main specifications of the associated TSQLVirtualTableModule . varInt64.Search() .." statement . and varAny (BLOB with size = VLongs[0]) .this is a read/write table.18 Date: June 16. since it will depend on the associated Static TSQLRestServerStaticExternal instance Functions or procedures implemented in the mORMotDB unit: Functions or procedures Description Page VirtualTableExternalR egister Register on the Server-side an external database for an ORM class 913 VirtualTableExternalR egisterAll Register all tables of the model to be external 913 mORMotDB..EstimatedCost will receive the estimated cost.Rev. 2013 function Prepare(var Prepared: TSQLVirtualTablePrepared): boolean. Called to determine the best way to access the virtual table . WHERE . Expr must be set to not 0 if needed for Search method. using a standard SQL "SELECT * FROM .returns true on success. with lowest value if fStatic. var Values: TVarDataDynArray): boolean.e. with 'External' as module name and TSQLRestServerStaticExternal as the related static class . Called to update a virtual table row content .e.pas unit . override. newRowID: Int64.Fields[] order . associated to the TSQLVirtualTableCursorExternal cursor type.no particular class is supplied here.this overriden method will let the external DB engine perform the search. StoredClassProps. without transaction (yet).18 Page 912 of 1055 ..the column values are available via some TVarData of type varNull. i.in Where[]. false otherwise class procedure GetTableModuleProperties(var aProperties: TVirtualTableModuleProperties). 1. Model := TSQLModel.'AdventureWorks2008R2'.Create (the server-side ORM must know if the database is to be managed as internal or external) .typical usage is therefore for instance: Props := TOleDBMSSQLConnectionProperties. 1.'').'root'). unless they are explicitely declared as external via VirtualTableExternalRegister: this function can be used to register all tables to be handled by an external DBs .Create() will reset all supplied classes to be defined as non virtual (i.18 Date: June 16. Server := TSQLRestServerDB.''.Synopse mORMot Framework Software Architecture Design 1.RecordProps.pas unit .this function (and the whole unit) is NOT to be used on the client-side . depending on the customer's expectations (or license) function VirtualTableExternalRegisterAll(aModel: TSQLModel. TSQLAuthUser and TSQLAuthGroup tables will be handled via the external DB.the supplied aExternalDB parameter is stored within aClass.e.18 Page 913 of 1055 . so the instance must stay alive until all database access to this external table is finished (e.VirtualTableRegister method).db').by default.note that TSQLModel.Create(aModel.this function shall be called BEFORE TSQLRestServer. aExternalDB: TSQLDBConnectionProperties.true) .Create (the server-side ORM must know if the database is to be managed as internal or external) .\SQLEXPRESS'.TSQLCustomer.the TSQLDBConnectionProperties instance should be shared by all classes.'application. even if the class does not inherit from TSQLRecordVirtualTableAutoID (it can be any plain TSQLRecord or TSQLRecordMany sub-class for instance) .will associate the supplied class with a TSQLVirtualTableExternal module (calling aModel. 2013 function VirtualTableExternalRegister(aModel: TSQLModel.server-side may omit a call to VirtualTableExternalRegister() if the need of an internal database is expected: it will allow custom database configuration at runtime. const aExternalTableName: RawUTF8): boolean.by default. 'Customer' for 'TSQLCustomer') . could be provided here (SQLTableName will be used internaly as table name when called via the associated SQLite3 Virtual Table) . but you can avoid it for speed when handling session and security mORMotDB. DoNotCacheUserGroupTables: boolean=false): boolean. use a private/protected property) .if no table name is specified ('').Props.the full table name. aExternalDB: TSQLDBConnectionProperties.'Sales. Register all tables of the model to be external . Register on the Server-side an external database for an ORM class . all tables are handled by the SQLite3 engine.Rev. will use SQLTableName (e. aClass: TSQLRecordClass. Kind=rSQLite3) . VirtualTableExternalRegister(Model.the TSQLDBConnectionProperties instance should be shared by all classes.g. and released globaly when the ORM is no longer needed .Create('. and released globaly when the ORM is no longer needed .Customer').this function shall be called BEFORE TSQLRestServer. as expected by the external database.this function (and the whole unit) is NOT to be used on the client-side .Create([TSQLCustomer].g. 'libfcgi.A nil-terminated array of strings. version 1.Rev. Defines the state of a FastCGI stream .18 Units used in the mORMotFastCgiServer unit: Unit Name Description Page mORMot Common ORM and SOA classes for mORMot . licensed under a MPL/GPL/LGPL tri-license.so. version 1.pas unit Purpose: FastCGI HTTP/1. Useful FCGX_Request flag .27. Name of the dll we use to import all FastCGI low-level functions from .18 715 SynCommons Common functions used by most Synopse projects . 2013 23.this unit is a part of the freeware Synopse mORMot framework. licensed under a MPL/GPL/LGPL tri-license. Calling Sequence FastCGI error code FCGX_PARAMS_ERROR = -4. licensed under a MPL/GPL/LGPL tri-license. Unsupported Version FastCGI error code Functions or procedures implemented in the mORMotFastCgiServer unit: mORMotFastCgiServer.dll'.Synopse mORMot Framework Software Architecture Design 1. Parameters related FastCGI error code FCGX_PROTOCOL_ERROR = -3.this unit is a part of the freeware Synopse mORMot framework.1 Server implementation for mORMot .this unit is a part of the freeware Synopse mORMot framework. version 1.18 325 Types implemented in the mORMotFastCgiServer unit: FCGX_ParamArrayType = PPAnsiChar. An environment (as defined by environ(7)) .pas unit . each string having the form name=value PFCGX_Stream = pointer.18 Page 914 of 1055 .The state of a stream is private and should only be accessed as an 'opaque' pointer Constants implemented in the mORMotFastCgiServer unit: dllname = 'libfcgi.0' is Ubuntu/Debian Linux standard library name: check your distribution FCGI_FAIL_ACCEPT_ON_INTR = 1.Setting FCGI_FAIL_ACCEPT_ON_INTR prevents FCGX_Accept() from restarting upon being interrupted FCGX_CALL_SEQ_ERROR = -5. 1.18 Date: June 16. Protocol related FastCGI error code FCGX_UNSUPPORTED_VERSION = -2. mORMotFastCgiServer. envp: FCGX_ParamArrayType): PAnsiChar.see @http://hoohoo. Accept a new request (NOT multi-thread safe) . cdecl. 2013 Functions or procedures Description Page FCGX_Accept Accept a new request (NOT multi-thread safe) 915 FCGX_GetLine Read a line from the server socket 915 FCGX_GetParam Obtain value of FCGI parameter in environment 915 FCGX_GetStr Read some data from the server socket 915 FCGX_IsCGI Returns TRUE if this process appears to be a CGI process 916 FCGX_PutStr Write some data to the server socket 916 mORMotFastCGIMainProc Publishes a HTTP/1.18 Page 915 of 1055 . NULL if name not present in the environment envp . to the result of calling FCGX_GetParam). output. var params: FCGX_ParamArrayType): integer. _out.html for a Environment Variables list function FCGX_GetStr(str: PAnsiChar.edu/cgi/env.DO NOT retain pointers to the envp array or any strings contained in it (e.return 0 for successful call. . . using FASTCGI 916 function FCGX_Accept(var _in. external dllname. external dllname. Read a line from the server socket .Stops before n-1 bytes have been read if '\n' or EOF is read. stream: PFCGX_Stream): integer.Reads up to n-1 consecutive bytes from the input stream into the character array str. cdecl.illinois.ncsa. external dllname. . the end of input has been reached mORMotFastCgiServer. Read some data from the server socket . *out.reads up to n consecutive bytes from the input stream into the character array str. cdecl. n: integer. cdecl. and error streams and assigns them to *in. Performs no interpretation of the input bytes.g. 1. . Obtain value of FCGI parameter in environment .Rev.Synopse mORMot Framework Software Architecture Design 1.returns the value bound to name.caller must not mutate the result or retain it past the end of this request . If result is smaller than n.returns NULL if EOF is the first thing read from the input stream function FCGX_GetParam(const name: PAnsiChar. _err: PFCGX_Stream.1 RESTFUL JSON mORMot Server. stream: PFCGX_Stream): PAnsiChar. n: integer. external dllname.18 Date: June 16.The terminating '\n' is copied to str. stores a '\0' terminator.Finishes the request accepted by (and frees any storage allocated by) the previous call to FCGX_Accept. Creates a parameters data structure to be accessed via getenv(3) (if assigned to environ) or by FCGX_GetParam and assigns it to *envp. -1 for error . since these will be freed by the next call to FCGX_Finish or FCGX_Accept function FCGX_GetLine(str: PAnsiChar. and *err respectively.pas unit . . Creates input.returns number of bytes read. After copying the last byte into str. 1. stream: PFCGX_Stream): integer.call this procedure in your main block of your program: it is up to the HTTP server to implement the request handling mORMotFastCgiServer.18 Date: June 16.caller should raise an exception in such case function FCGX_PutStr(str: PAnsiChar. you should not use the FastCGI implementation .performs no interpretation of the output bytes. Write some data to the server socket . cdecl. but a normal CGI process . . n: integer.in such case. 2013 function FCGX_IsCGI: boolean. EOF (-1) if an error occurred procedure mORMotFastCGIMainProc(Server: TSQLRestServer). external dllname. cdecl. Publishes a HTTP/1.18 Page 916 of 1055 .returns the number of bytes written (n) for normal return. .pas unit .Synopse mORMot Framework Software Architecture Design 1. external dllname.Rev.will raise an exception if the executable was not used as a FastCGI process.writes n consecutive bytes from the character array str into the output stream. using FASTCGI . Returns TRUE if this process appears to be a CGI process .1 RESTFUL JSON mORMot Server. 1 RESTFUL JSON Client class using WinHTTP API 919 mORMotHttpClient.18 479 SynLZ SynLZ Compression routines . version 1.1 protocol 1049 Units used in the mORMotHttpClient unit: Unit Name Description Page mORMot Common ORM and SOA classes for mORMot .this unit is a part of the freeware Synopse framework.18 325 SynCrtSock Classes implementing HTTP/1.pas unit Purpose: HTTP/1.1 RESTFUL JSON Client classes for mORMot . version 1. licensed under a MPL/GPL/LGPL tri-license.1.licensed under a MPL/GPL/LGPL tri-license.Synopse mORMot Framework Software Architecture Design 1.1. 2013 23.5 engine version) . version 1. mORMotHttpClient. licensed under a MPL/GPL/LGPL tri-license.18 The mORMotHttpClient unit is quoted in the following items: SWRS # DI-2. 1.4 Description Page HTTP/1.this unit is a part of the freeware Synopse mORMot framework.pas unit . version 1.1 RESTFUL JSON mORMot Client class 918 TSQLHttpClientWinGene ric HTTP/1.this unit is a part of the freeware Synopse mORMot framework.18 707 TSQLHttpClientWinSock TSQLRestClientURI TSQLHttpClientGeneric TSQLHttpClientWinINet TSQLHttpClientWinGeneric TSQLHttpClientWinHTTP mORMotHttpClient class hierarchy Objects implemented in the mORMotHttpClient unit: Objects Description Page TSQLHttpClientGeneric Generic HTTP/1.18 Date: June 16. version 1.this unit is a part of the freeware Synopse mORMot framework.2.2. version 1. licensed under a MPL/GPL/LGPL tri-license.28.this unit is a part of the freeware Synopse mORMot framework.18 715 SynCommons Common functions used by most Synopse projects . licensed under a MPL/GPL/LGPL tri-license.18 584 SynZip Low-level access to ZLib compression (1. licensed under a MPL/GPL/LGPL tri-license.1 client and server protocol .Rev.1 RESTFUL JSON mORMot Client abstract class using either WinINet either TWinHTTP API 918 TSQLHttpClientWinHTTP HTTP/1.18 Page 917 of 1055 . 1 RESTFUL JSON mORMot Client class using SynCrtSock / WinSock .18 Page 918 of 1055 .e. property KeepAliveMS: cardinal read fKeepAliveMS write SetKeepAliveMS. or both.1 RESTFUL JSON mORMot Client class property Compression: TSQLHttpCompressions read fCompression write SetCompression. reintroduce. The compression algorithms usable with this client . 20 seconds TSQLHttpClientWinSock = class(TSQLHttpClientGeneric) HTTP/1. but has been found out to be slower over a network . i. 2013 Objects Description Page TSQLHttpClientWinINet HTTP/1.1 RESTFUL JSON mORMot Client abstract class using either WinINet either TWinHTTP API . aModel: TSQLModel. 1. Internal class instance used for the connection .for a Delphi client. aPort: AnsiString.will return either a TWinINet. either a TWinHTTP class instance mORMotHttpClient.will give the best performance on a local computer. and aProxyByPass an optional semicolon delimited list of host names or IP addresses. Connect to TSQLHttpServer on aServer:aPort property Socket: THttpClientSocket read fSocket.e. aPort: AnsiString.18 Date: June 16. aHttps: boolean=false.1 compatible client TSQLHttpClientWinGeneric = class(TSQLHttpClientGeneric) HTTP/1.pas unit . const aProxyByPass: AnsiString='').optional aProxyName may contain the name of the proxy server to use.Rev. const aProxyName: AnsiString=''. The time (in milliseconds) to keep the connection alive with the TSQLHttpServer .1 RESTFUL JSON mORMot Client class using SynCrtSock / WinSock 918 TSQLHttpClientGeneric = class(TSQLRestClientURI) Generic HTTP/1. no compression . reintroduce. Connect to TSQLHttpServer on aServer:aPort .not to be called directly. aModel: TSQLModel).default is 20000.is not able to use secure HTTPS protocol constructor Create(const aServer. Internal HTTP/1.Synopse mORMot Framework Software Architecture Design 1.default is []. that should not be routed through the proxy property WinAPI: TWinHttpAPI read fWinAPI. but via TSQLHttpClientWinINet or (even better) TSQLHttpClientWinHTTP overriden classes constructor Create(const aServer.1 RESTFUL JSON mORMot Client class using WinINet API 919 TSQLHttpClientWinSock HTTP/1. i. is implemented by creating a TWinHTTP internal class instance Types implemented in the mORMotHttpClient unit: TSQLHttpClient = TSQLHttpClientWinHTTP. and display some error messages or authentification dialog on screen .18 Date: June 16.4 (page 1049). The default WinHTTP proxy configuration is set by either proxycfg. but not standard: use hcSynLZ for Delphi clients.Rev.1 RESTFUL JSON default mORMot Client class .1 RESTFUL JSON mORMot Client class using WinINet API .you can optionaly specify manual Proxy settings at constructor level .this class is 15/20 times slower than TSQLHttpClient using SynCrtSock on a local machine.is implemented by creating a TWinINet internal class instance TSQLHttpClientWinHTTP = class(TSQLHttpClientWinGeneric) HTTP/1.SynLZ is faster then Deflate.18 Page 919 of 1055 . but was found to be faster throughout local networks .it will retrieve by default the Internet Explorer proxy settings.by design.by design. Available compression algorithms for transmission .exe on Windows Vista and Windows Server 2008 or later. hcDeflate ).with hcSynLZ.under Windows. for instance. TSQLHttpCompression = ( hcSynLZ.exe on Windows XP and Windows Server 2003 or earlier.so it seems to be used in your client programs: TSQLHttpClient will therefore map to this class . maps the TSQLHttpClientWinHTTP class Used for DI-2. call netsh or proxycfg bits from %SystemRoot%\SysWOW64 folder explicitely) . the WinHTTP API can be used from a service or a server . 1. but hcDeflate for AJAX or any HTTP clients . HTTP/1.has a common behavior as THttpClientSocket() but seems to be faster over a network and is able to retrieve the current proxy settings (if available) and handle secure HTTPS connection . the 440 KB JSON for TTestClientServerAccess. either netsh.this class is able to connect via the secure HTTPS protocol . Set of available compressions schemes mORMotHttpClient.1.1. the WinINet API should not be used from a service . is 25 % slower TSQLHttpCompressions = set of TSQLHttpCompression. hcDeflate with its level set to 1 (fastest)._TSQLHttpClient is compressed into 106 KB with no speed penalty (it's even a bit faster) whereas deflate. to configure applications using the 32 bit WinHttp settings.you can optionaly specify manual Proxy settings at constructor level .Synopse mORMot Framework Software Architecture Design 1.2.pas unit . 2013 TSQLHttpClientWinINet = class(TSQLHttpClientWinGeneric) HTTP/1. you can run "proxycfg -u" or "netsh winhttp import proxy source=ie" to use the current user's proxy settings for Internet Explorer (under 64 bit Vista/Seven.1 RESTFUL JSON Client class using WinHTTP API .WinHTTP does not share directly any proxy settings with Internet Explorer. licensed under a MPL/GPL/LGPL tri-license.18 707 TObject TSQLHttpServer mORMotHttpServer class hierarchy Objects implemented in the mORMotHttpServer unit: Objects Description Page TSQLHttpServer HTTP/1. 1.1.18 Page 920 of 1055 .licensed under a MPL/GPL/LGPL tri-license. version 1.this unit is a part of the freeware Synopse framework.Rev. version 1.pas unit . version 1. licensed under a MPL/GPL/LGPL tri-license.this unit is a part of the freeware Synopse mORMot framework.1 client and server protocol . licensed under a MPL/GPL/LGPL tri-license.18 The mORMotHttpServer unit is quoted in the following items: SWRS # DI-2. version 1.1.1 RESTFUL JSON mORMot Server class 921 mORMotHttpServer.this unit is a part of the freeware Synopse mORMot framework.pas unit Purpose: HTTP/1. mORMotHttpServer.this unit is a part of the freeware Synopse mORMot framework.29. licensed under a MPL/GPL/LGPL tri-license. version 1.2. version 1.18 479 SynLZ SynLZ Compression routines .18 584 SynZip Low-level access to ZLib compression (1.1 protocol 1049 Units used in the mORMotHttpServer unit: Unit Name Description Page mORMot Common ORM and SOA classes for mORMot .Synopse mORMot Framework Software Architecture Design 1. 2013 23.2.5 engine version) .4 Description Page HTTP/1.this unit is a part of the freeware Synopse mORMot framework.18 325 SynCrtSock Classes implementing HTTP/1.1 RESTFUL JSON Server classes for mORMot .18 Date: June 16. licensed under a MPL/GPL/LGPL tri-license.18 715 SynCommons Common functions used by most Synopse projects . ServerThreadPoolCount: Integer=32).raise a EHttpServer exception if binding failed . it will use a pure Delphi THttpServer instance. mORMotHttpServer.Root value. binded and listening on a TCP port to HTTP JSON requests . as expected by the WinSock API . aRestAccessRights: PSQLAccessRights=nil.4 (page 1049). a solution is to call the THttpApiServer. constructor Create(const aPort: AnsiString.the ServerThreadPoolCount parameter will set the number of threads to be initialized to handle incoming connections (default is 32. maximum is 256) Used for DI-2.for a true AJAX server. which may be sufficient for most cases.port is an AnsiString.but you need to have administrator rights under Vista or Seven: if http. aHttpServerKind: TSQLHttpServerOptions=useHttpApi.Synopse mORMot Framework Software Architecture Design 1. it should work OK under XP or WS 2K3 .your code may contain: DBServer.sys fails to initialize.aDomainName is the URLprefix to be used for HttpAddUrl API call: it could be either a fully qualified case-insensitive domain name an IPv4 or IPv6 literal string. const aDomainName: AnsiString='+'.1.this server is multi-threaded and not blocking . '*' will accept the request when no other listening hostnames match the request for that port) . binded and listening on a TCP port to HTTP JSON requests . aHttpServerKind: TSQLHttpServerOptions=useHttpApi. reintroduce.by default. Used for DI-2. or a wildcard ('+' will bound to all domain names for the specified port.18 Page 921 of 1055 .specify one or more TSQLRestServer server class to be used: each class must have an unique Model.2.pas unit .4 (page 1049). or using the standard Sockets library (useHttpSocket) .AddUrlAuthorize class method during program setup for the desired port. const aDomainName: AnsiString='+'. in order to allow it for every user .18 Date: June 16. overload. aServer: TSQLRestServer.Rev.NoAJAXJSON := false.aDomainName is the URLprefix to be used for HttpAddUrl API call Used for DI-2. Create a Server Thread. as expected by the WinSock API .1.e.1. overload. 2013 TSQLHttpServer = class(TObject) HTTP/1. ServerThreadPoolCount: Integer=32).sys kernel-mode server (i. optionally registering the URI (useHttpApiRegisteringURI) if needed.1.aHttpServerKind defines how the HTTP server itself will be implemented: it will use by default optimized useHttpApi kernel-based http. expanded data is prefered . reintroduce.2.this parameter is ignored by the TSQLHttpApiServer instance . constructor Create(const aPort: AnsiString. const aServers: array of TSQLRestServer.will first try to use fastest http. Create a Server Thread.specify one TSQLRestServer server class to be used .raise a EHttpServer exception if binding failed .2. to identify which TSQLRestServer instance must handle a particular request from its URI .4 (page 1049).1.1 RESTFUL JSON mORMot Server class . the PSQLAccessRights will be set to nil .sys server.1.port is an AnsiString. 1. create a THttpApiServer instance).just create it and it will serve SQL statements as UTF-8 JSON . 2. Write-only access to all internal servers access right .can be set e.Root value. internal mORMot server and HTTP handlers function AddServer(aServer: TSQLRestServer.g.can be used to override the default HTTP_DEFAULT_ACCESS_RIGHTS setting property DBServerCount: integer read GetDBServerCount.2.an optional aRestAccessRights parameter is available to override the default HTTP_DEFAULT_ACCESS_RIGHTS access right setting . Try to register another TSQLRestServer instance to the HTTP server .each TSQLRestServer class must have an unique Model.1.each TSQLRestServer class must have an unique Model. override. false on error (e. Read-only access to all internal servers Used for DI-2.18 Date: June 16.g.or specify an URI to be allowed as origin (e. 2013 destructor Destroy. Read-only access to the number of registered internal servers property HttpServer: THttpServerGeneric read fHttpServer. function RemoveServer(aServer: TSQLRestServer): boolean. The associated running HTTP server instance .1.g. and does not check the incoming "Origin: " header value property DBServer[Index: integer]: TSQLRestServer read GetDBServer. 1. to identify which instance must handle a particular request from its URI .1. Un-register a TSQLRestServer from the HTTP server . Set this property to TRUE if the server must only respond to request of MIME type APPLICATION/JSON .Root value.Rev.return true on success. to identify which instance must handle a particular request from its URI .4 (page 1049).org/en-US/docs/HTTP/Access_control_CORS . Enable cross-origin resource sharing (CORS) for proper AJAX process .but you shall better rely on the authentication feature included in the framework .g. duplicated Root value) Used for DI-2.pas unit .Synopse mORMot Framework Software Architecture Design 1.18 Page 922 of 1055 .see @https://developer.mozilla.current implementation is pretty basic. Release all memory. in order to allow direct view of JSON from any browser Types implemented in the mORMotHttpServer unit: mORMotHttpServer.return true on success. property DBServerAccessRight[Index: integer]: PSQLAccessRights write SetDBServerAccessRight.example') . specified server not found) property AccessControlAllowOrigin: RawUTF8 read fAccessControlAllowOrigin write SetAccessControlAllowOrigin.the default is false. aRestAccessRights: PSQLAccessRights=nil): boolean. either THttpServer property OnlyJSONRequests: boolean read fOnlyJSONRequests write fOnlyJSONRequests. to '*' to allow requests from any sites .1.4 (page 1049). 'http://foo.either THttpApiServer. false on error (e. AddUrlAuthorize('root'.you would need to register the URI by hand. useHttpSocket ). via code similar to this one: THttpApiServer. during setup) .SYS server (THttpApiServer) .will need Administrator execution rights at least one time (e.useHttpSocket will use the standard Sockets library (e. 1. WinSock) . then use kernel-mode HTTP.it will trigger the Windows firewall popup UAC window at first run Constants implemented in the mORMotHttpServer unit: HTTP_DEFAULT_ACCESS_RIGHTS: PSQLAccessRights = @SUPERVISOR_ACCESS_RIGHTS. similar to IIS/WCF security policy as specified by Microsoft) .Rev.18 Date: June 16. The default access rights used by the HTTP server if none is specified mORMotHttpServer. 2013 TSQLHttpServerOptions = ( useHttpApi.useHttpApiRegisteringURI will first registry the given URI.SYS server (THttpApiServer) with an already registered URI (default way.pas unit .useHttpApi to use kernel-mode HTTP.false.g. useHttpApiRegisteringURI. in the Setup program. Available running options for TSQLHttpServer.Create() constructor .'+')) .18 Page 923 of 1055 .'888'.g. e.g.Synopse mORMot Framework Software Architecture Design 1. licensed under a MPL/GPL/LGPL tri-license.18 Date: June 16.3.msg.g.18 715 SynCommons Common functions used by most Synopse projects .) 926 TLanguage = object(TObject) A common record to identify a language Used for DI-2. 1. CharSet: integer.3 (page 1054).3 Description Page Automated i18n 1054 Units used in the mORMoti18n unit: Unit Name Description Page mORMot Common ORM and SOA classes for mORMot . licensed under a MPL/GPL/LGPL tri-license.Synopse mORMot Framework Software Architecture Design 1.this unit is a part of the freeware Synopse mORMot framework. version 1.3.18 325 TLanguageFile TObject TLanguage mORMoti18n class hierarchy Objects implemented in the mORMoti18n unit: Objects Description Page TLanguage A common record to identify a language 924 TLanguageFile Class to load and handle translation files (fr.Rev. version 1. de.msg. The corresponding Char Set CodePage: cardinal.1.18 Page 924 of 1055 .pas unit .18 The mORMoti18n unit is quoted in the following items: SWRS # DI-2.pas unit Purpose: Internationalization (i18n) routines and classes for mORMot . 2013 23. licensed under a MPL/GPL/LGPL tri-license. The corresponding Code Page mORMoti18n.this unit is a part of the freeware Synopse mORMot framework. mORMoti18n.msg. e.this unit is a part of the freeware Synopse mORMot framework..1. ja. version 1.30. The corresponding Windows LCID function Abr: RawByteString. 2013 Index: TLanguages. using current UI language . UnicodeString for Delphi 2009 and up procedure Fill(Language: TLanguages). LANGUAGE_NONE before first SetLanguageLocal() LCID: cardinal.).g.g.Synopse mORMot Framework Software Architecture Design 1. Returns fully qualified language name ('Hebrew' e. 1.Rev. i.e.18 Date: June 16. Returns two-chars long language abreviation ('HE' e.return "string" type.) function Name: string. Initializes all TLanguage object fields for a specific language mORMoti18n. As in LanguageAbr[index].pas unit .18 Page 925 of 1055 . . Each user is able to select its own preferred translation. 6. translator must be aware of some important characters.txt original file.Some other sections appears before the [Messages] part. 4.This standard .Unicode characters (Chinese or Japanese) can be used. and does apply to windows as they are displayed on screen.g.1.msg text file contains all the program resources translated into any language. By default. The numeric value is a hash (i. %d will be replaced by a numerical value before display.) and all text between < and > must NOT be modified. Extract all english message into a . de. this default translation may be customized: in such cases.) . Language: TLanguage. by calling the ExtractAllResources() procedure in the main program 1. 2013 TLanguageFile = class(TObject) Class to load and handle translation files (fr. FR. containing the original English messages 2. . e. but the NumericValue must remain the same. . .The most important part of this file is the [Messages] section.msg.msg for Russian). like the Windows notepad) 3. . the whole NumericValue=Text pair must be contained in an unique line.18 Page 926 of 1055 .In order to add a new language.18 Date: June 16. the original text (never used. the text is replaced by a _ with a numerical value pointing to a text inside the [Messages] section.Synopse mORMot Framework Software Architecture Design 1. . At the end of every line. and appears in exactly the same place inside the translated text: 1. By adding this . the steps are to be performed: 0. %s will be replaced by a textual value before display. which must NOT be modified. to see in real time its modifications: he/she just has to restart the PC software to reload the updated translations. some HTML code may appear (e.In the "Text" part.msg as file extension (e. and . only put there for translator convenience) was added.g. Save this new file.msg for French or RU. unique identifier) of the Text. the "Text" part of these pairs must be translated. Use the latest . ja. even if it is huge.g. but is also used some other times as a delimiter between sentences. with the ISO two chars corresponding to the new language as file name.msg. Identify the current language mORMoti18n.3 (page 1054). 5. To make a new translation. the PC User software will automatically find and use it to translate the User Interface on the fly. 6. 5. ~ indicates a LF (line feed) character. Used for DI-2. 2. The translator can perform the steps 3 to 5 more than once. sometimes is a comma inside a sentence.. . some Unicode characters may be used 4. <br><font color="clnavy">.exe folder..pas unit . On some rare occasion. but a real text editor. | indicates a CR (carriage return) character.Rev. the exact new text to be displayed can be used instead of the _1928321 part.txt ansi file.3. no line feed or word wrap is to be used inside the "Text" part.e. 3. 1.msg file into the PhD. Open this file into a text editor (not Microsoft Word. Translate the English text into a new language. which contain all the text to be displayed in NumericValue=Text pairs.msg. 2013 constructor Create(aLanguageLocale: TLanguages).3 (page 1054).3 (page 1054).by default. overload. overload.1. Convert a date into a ready to be displayed text on the screen Used for DI-2.3. overload.3.1. Convert the supplied boolean constant into ready to be displayed text . overload.pas unit . Convert a date into a ready to be displayed text on the screen Used for DI-2. overload. constructor Create(const aFileName: TFileName.1. Convert a date and time into a ready to be displayed text on the screen Used for DI-2.Rev.3 (page 1054). overload. overload.1.returns the text as generic string type.3 (page 1054). aLanguageLocale: TLanguages).1.1. function DateToText(const Time: TTimeLog): string. returns 'No' for false.3 (page 1054).1. Specify a text file containing the translation messages for a language Used for DI-2.msg translation text file from the current exe directory Used for DI-2. function DateToText(const ISO: Iso8601): string.18 Date: June 16. function DateTimeToText(const ISO: Iso8601): string. Load corresponding *. Convert a date and time into a ready to be displayed text on the screen Used for DI-2. 1.18 Page 927 of 1055 .3.3. overload. destructor Destroy. override.Synopse mORMot Framework Software Architecture Design 1. Free translation tables memory function BooleanToString(Value: boolean): string. and 'Yes' for true .3. mORMoti18n. ready to be used in the VCL function DateTimeToText(const DateTime: TDateTime): string.3 (page 1054).1.3.3. function DateToText(const DateTime: TDateTime): string.3 (page 1054). Convert a date into a ready to be displayed text on the screen Used for DI-2.3. function DateTimeToText(const Time: TTimeLog): string.3 (page 1054). Convert a date and time into a ready to be displayed text on the screen Used for DI-2. the value of the main property (mostly 'Name') of the referenced record .3 (page 1054). overload.msg file before any [Section] function TimeToText(const DateTime: TDateTime): string.returns the text as generic string type.will convert any sftUTF8Text/sftAnsiText into ready to be displayed text . Client: TSQLRest): string. overload. or into UnicodeString for Delphi 2009 and up procedure Translate(var English: string). 1.must be called once with english captions .1. UnicodeString for Delphi 2009 and up) Used for DI-2.1. Convert a time into a ready to be displayed text on the screen Used for DI-2.Rev.3.will convert any sftRecord to 'Table Name: Record Name' .will convert any sftID to 'Record Name'.3 (page 1054). Translate an English string into a localized string . Convert a time into a ready to be displayed text on the screen Used for DI-2. sftDateTime or sftTimeLog/sftModTime/sftCreateTime into the corresponding text.will convert a sftSet property value to a list of all set enumerates. Types implemented in the mORMoti18n unit: TCompareFunction = function(const S1. mORMoti18n.1.will convert any sftInteger/sftFloat/sftCurrency into its textual value . Translate the english captions of a TForm into the current UI language .3.call automaticaly if conditional USEFORMCREATEHOOK is defined procedure LoadFromFile(const aFileName: TFileName). sftEnumerate.3 (page 1054).3. Fill translation tables from text file containing the translation messages . stored in the .expect parameter as generic VCL string (i. overload.e. Convert a time into a ready to be displayed text on the screen Used for DI-2. procedure FormTranslateOne(aForm: TComponent). i. function TimeToText(const Time: TTimeLog): string.handle on the fly UTF-8 and UNICODE decode into the corresponding ANSI CHARSET. Instance: TSQLRecord. separated by #13#10 .will convert any sftBoolean.English is case-sensitive (same as standard gettext) . depending on the current language .pas unit .e.Synopse mORMot Framework Software Architecture Design 1.3. 2013 function PropToString(Prop: TSQLPropInfo.18 Page 928 of 1055 .will ignore sftBlob field .1. function TimeToText(const ISO: Iso8601): string.3 (page 1054). Read a parameter. S2: AnsiString): Integer.translations are stored in Messages[] and Text properties .18 Date: June 16. Convert a TSQLRecord published property value into ready to be displayed text . ready to be used in the VCL function ReadParam(const ParamName: RawUTF8): string. 2.'bo'. lngMalgash.'mk'. lngArmenian. 13. 'sl'.'es'. 47.'fr'. 35.'gr'. 45. lngRussian.'hu'.'ie'. lngArabic. 52. 44. 22.'am'.'id'. lngCroatian. lngCatalan.'ru'. lngAramaic. change this value to your company's name. 19. lngTahitian.'da'. lngPolish. 55. lngGerman. To sort in alphabetic order : LanguageAbr[TLanguages(LanguageAlpha[lng])] .'de'.18 Page Page 929 of 1055 . lngIndonesian. lngHungarian. lngCoptic.'pt'. 53.'sk'.'ca'. 2013 Function prototype for comparing two Ansi strings . lngBulgarian. US English Windows LCID. lngAlbanian.'cu'. lngMacedonian. lngSlovak. used as reference for all other translation.'ro'.'fa'. 37.'hy'. lngIcelandic. 9. 'en'. 30.'cs'. 46. total count is 60 . lngJapanese. 31.'ty'.'is'. 40. Languages handled by this mORMoti18n unit . lngGaelic. lngRomanian. lngCzech.'sr'.'pl'. lngPortuguese.'lt'. 34. 5. 49.'ar'. lngPashtol ). 42. 23. 36.'hr'.).'et'.'co'. lngBosnian. lngFinnish.'ja'. 56. lngSwedish. lngDari.'cp'. Arabic) may need specific language pack installed on western/latin version of windows . 16. lngFarsi. the key is HKEY_CURRENT_USER\Software\[RegistryCompanyName]i18n\programname Functions or procedures implemented in the mORMoti18n unit: Functions or procedures Description mORMoti18n. standard international settings RegistryCompanyName = ''. 20. 'it'. lngDutch. lngEstonian.'sq'. Chinese. lngSlovenian.recreate these table with ModifiedLanguageAbr if LanguageAbr[] changed LANGUAGE_NONE = TLanguages(255). 33. 'th'. lngKorean.'lv'. 25. lngSanskrit. 43. 26. lngTibetan. lngCorsican.'sy'.18 Date: June 16. 50. lngLituanian. Language is read from registry once at startup: the sub-entry used to store the i18n settings in the registry. 18. 51).e. lngThai. lngOccitan. 41. 12.'bs'. with a trailing backslash ('WorldCompany\' e.'fi'. 29.'oc'. 0. 54. 10.'cy'. 57.include all languages known by WinXP SP2 without some unicode-only very rare languages.pas unit . 11. lngSpanish.'vi'. lngGreek. lngFrench.'ko'. 24. 8. and included into executable (no EN. lngEnglish. lngLatvian.'sv'.'uk'.'bg'. 14.'ap'). 21. 4. lngUkrainian. 38.Rev. i. 1.'sa'. lngTurkish. lngDanish. 27. ISO 639-1 compatible abbreviations (not to be translated): LanguageAlpha: packed array[TLanguages] of byte = (3. lngBelarusian. lngIrish. 58.'zh'. 6.msg file will never be loaded) Constants implemented in the mORMoti18n unit: LanguageAbr: packed array[TLanguages] of RawByteString = ('he'. lngVietnamese. lngWelsh.'nl'. 32.'tr'. 17.'ad'. lngSerbian. lngLatin. lngInterlingue. Value stored into a TLanguages enumerate to mark no language selected yet LCID_US = $0409. 15. lngSyriac. lngSlavic.lngEnglish is the default language of the executable.'mg'.some languages (Japanase. 7. 48. lngChinese.used for comparison within the current selected language TLanguages = ( lngHebrew.'no'.'ga'.Synopse mORMot Framework Software Architecture Design 1. lngNorwegian.'la'.'be'. lngItalian. 1.g.'gd'. 39. 59. 28. the TLanguageFile. (for Delphi 2 to 2007) or with the new Unicode VCL (for Delphi 2009 and up) .e. with no || nor $$[$[$]] 931 i18nAddLanguageCombo Add combo-box items. for all available languages on disk 931 i18nAddLanguageMenu Add sub-menu items to the Menu.before Delphi 2009. e. 932 LanguageName Return the language text.Synopse mORMot Framework Software Architecture Design 1. 932 LanguageAbrToIndex LanguageAbrToIndex('GR')=1.18 Date: June 16. for all available languages on disk 931 i18nAddLanguageItems Add strings items.pas unit .Rev. CurrentAnsiConvert) mORMoti18n.g. for all available languages on disk 931 i18nLanguageToRegistr y Save the default language to the registry 931 i18nRegistryToLanguag e Get the default language from the registry 931 Iso2S Convert a custom date/time into a VCL-ready string 931 LanguageAbrToIndex LanguageAbrToIndex('GR')=1.LoadFromFile() method is able to display any Unicode message into the 8 bit standard Delphi VCL. 1.18 Page 930 of 1055 . ready to be displayed (after translation if necessary) 932 LanguageToLCID Convert a i18n language index into a Windows LCID 932 LCIDToLanguage Convert a Windows LCID into a i18n language 932 LoadResString Our hooked procedure for reading a string resource 932 S2U Convert any generic VCL Text into an UTF-8 encoded String 932 U2S Convert an UTF-8 encoded text into a VCL-ready string 932 _ Translate the 'English' term into current language 932 function AnyTextFileToString(const FileName: TFileName): string. 2013 Functions or procedures Description Page AnyTextFileToString Get text File contents (even Unicode or UTF8) and convert it into a Charset-compatible AnsiString (for Delphi 7) or an UnicodeString (for Delphi 2009 and up) according to any BOM marker at the beginning of the file 930 DateTimeToIso Generic US/English date/time to VCL text conversion 931 GetText Translate the 'Text' term into current language. the current string code page is used (i. e.g.by use of this function. Get text File contents (even Unicode or UTF8) and convert it into a Charset-compatible AnsiString (for Delphi 7) or an UnicodeString (for Delphi 2009 and up) according to any BOM marker at the beginning of the file . e. 2013 function DateTimeToIso(const DateTime: TDateTime.language will be changed at next startup . UnicodeString for Delphi 2009 and up function i18nRegistryToLanguage: TLanguages.DateTimeToText/DateToText/TimeToText procedure GetText(var Text: string). DateOnly: boolean): string.pas points to this procedure .DateTimeToText method function LanguageAbrToIndex(const value: RawUTF8): TLanguages. Add strings items.return a message ready to be displayed on the screen .uses internaly i18nAddLanguageItems() function above .current language is selected by default .if MsgPath is not set.new items are added to List: Strings[] will contain a caption text. Add sub-menu items to the Menu. Get the default language from the registry function Iso2S(Iso: TTimeLog): string. Add combo-box items. Save the default language to the registry .all created MenuItem.OnClick event will launch Language.LanguageClick to change the current language in the registry function i18nLanguageToRegistry(const Language: TLanguages): string. direct use of LoadResStringTranslate() is better in apps .LanguageClick to change the current language in the registry function i18nAddLanguageItems(MsgPath: TFileName.it will search in MsgPath for all *. 1.18 Page 931 of 1055 . i.return LANGUAGE_NONE if not found mORMoti18n. List: TStrings): integer. for all available languages on disk .e.current language is checked . ready to be displayed.Items[] procedure i18nAddLanguageMenu(const MsgPath: TFileName. LanguageAbrToIndex('GR')=1. and PtrInt(Objects[]) will be the corresponding language ID .not to be used in your programs: it's just here to allow inlining of TLanguageFile.the OnClick event will launch Language. Generic US/English date/time to VCL text conversion .uses internaly i18nAddLanguageItems() function above . Convert a custom date/time into a VCL-ready string .18 Date: June 16. e.Synopse mORMot Framework Software Architecture Design 1.this function must be assigned to i18nDateText global var of mORMot. Combo: TComboBox).pas unit .return the current language index in List.wrapper to Language. Menu: TMenuItem). Translate the 'Text' term into current language.therefore. the current executable directory will be used for searching . UnicodeString for Delphi 2009 and up procedure i18nAddLanguageCombo(const MsgPath: TFileName. i.g. for all available languages on disk . with no || nor $$[$[$]] .return "string" type.Rev.msg available . .pas unit . for all available languages on disk .LoadResStringTranslate of our customized system.expect "string" type. overload. LanguageName(lngEnglish)='English' . ready to be displayed (after translation if necessary) . Translate the 'English' term into current language . LoadResStringTranslate() Used for DI-2. CodePage: CODEPAGE_US.18 Date: June 16. Convert a Windows LCID into a i18n language function LoadResString(ResStringRec: PResStringRec): string.UTF8ToString() Used for DI-2.call interenaly GetText() procedure. Our hooked procedure for reading a string resource . Variables implemented in the mORMoti18n unit: CurrentLanguage: TLanguage = ( Index: LANGUAGE_NONE. 1.return LANGUAGE_NONE if not found function LanguageName(aLanguage: TLanguages): string. Convert an UTF-8 encoded text into a VCL-ready string .3. The global Language used by the User Interface. Convert a i18n language index into a Windows LCID function LCIDToLanguage(LCID: integer): TLanguages.18 Page 932 of 1055 . as updated by the last SetCurrentLanguage() call i18nCompareStr: TCompareFunction = nil.e.Synopse mORMot Framework Software Architecture Design 1. e. i. Convert any generic VCL Text into an UTF-8 encoded String .3. Return the language text.StringToUTF8() Used for DI-2.3 (page 1054). function U2S(const Text: RawUTF8): string. i.can be used for MBCS strings (with such code pages.pas unit is replaced by this one . Use this function to compare string with case sensitivity for the UI .e. overload. it will use windows slow but accurate API) mORMoti18n.3 (page 1054).1.e. CharSet: DEFAULT_CHARSET.return "string" type.pas unit .g.Rev.3. UnicodeString for Delphi 2009 and up function S2U(const Text: string): RawUTF8.1. UnicodeString for Delphi 2009 and up function LanguageToLCID(Language: TLanguages): integer.g.same as SynCommons. function _(const English: WinAnsiString): string. 2013 function LanguageAbrToIndex(p: pAnsiChar): TLanguages.e.3 (page 1054). .this function add caching and on the fly translation (if LoadResStringTranslate is defined in mORMot.pas unit) .1.you should use resourcestring instead of this function .the default one in System. LCID: LCID_US ). LanguageAbrToIndex('GR')=1.same as SynCommons. i.use current language for comparison .use "string" type. used for translation .Rev.can NOT be used for MBCS strings (with such code pages. Global variable set by SetCurrentLanguage(). according to the current language . 1. according to the current language .use this object.18 Date: June 16. it will use windows slow but accurate API) i18nToLower: TNormTable. True if this program is running on Windows Vista (tm) . to retrieve current UI settings OnTranslateComponent: function(C: TComponent): boolean of object = nil.18 Page 933 of 1055 .Synopse mORMot Framework Software Architecture Design 1. and its Language property.can NOT be used for MBCS strings (with such code pages. A table used for fast conversion to uppercase. A table used for fast conversion to lowercase. according to the current language .use current language for comparison . according to the current language . 2013 i18nCompareText: TCompareFunction = nil. or false if the translation must be done by the framework mORMoti18n.pas unit . you should use windows slow but accurate API) i18nToLowerByte: TNormTableByte absolute i18nToLower. Use this function to compare string with no case sensitivity for the UI .can be used for MBCS strings (with such code pages. you should use windows slow but accurate API) i18nToUpper: TNormTable.can NOT be used for MBCS strings (with such code pages.the method implementing this event must return true if the translation was handled.used to customize on the fly any TTreeView component. to meet Vista and Seven expectations Language: TLanguageFile = nil. Global event to be assigned for component translation override .can NOT be used for MBCS strings (with such code pages. you should use windows slow but accurate API) i18nToUpperByte: TNormTableByte absolute i18nToUpper. you should use windows slow but accurate API) isVista: boolean = false. A table used for fast conversion to uppercase. A table used for fast conversion to lowercase. this unit is a part of the freeware Synopse framework. version 1.31. licensed under a MPL/GPL/LGPL tri-license. version 1.this unit is a part of the freeware Synopse framework.18 584 SynPdf PDF file generation .this unit is a part of the freeware Synopse mORMot framework.adds GIF.allows Antialiased rending of any EMF file using GDI+ .this unit is a part of the freeware Synopse framework. with full preview and export as PDF or TXT files.Rev. mORMotReport.pas unit . version 1.pas unit Purpose: Reporting unit .2 A reporting feature.licensed under a MPL/GPL/LGPL tri-license.3. 2013 23.make available most useful GDI+ drawing methods . licensed under a MPL/GPL/LGPL tri-license. PNG and JPG pictures read/write support as standard TGraphic .18 325 SynGdiPlus GDI+ library API access . licensed under a MPL/GPL/LGPL tri-license. TIF. shall be integrated 1054 Units used in the mORMotReport unit: Unit Name Description Page SynCommons Common functions used by most Synopse projects .18 600 THeaderFooter TObject TGDIPagereference TGDIPageContent TPaintBox TPagePaintBox TScrollBox TGDIPages mORMotReport class hierarchy Objects implemented in the mORMotReport unit: mORMotReport. version 1.18 Date: June 16.Synopse mORMot Framework Software Architecture Design 1. 1.18 The mORMotReport unit is quoted in the following items: SWRS # Description Page DI-2. version 1.18 576 SynLZ SynLZ Compression routines . licensed under a MPL/GPL/LGPL tri-license.18 Page 934 of 1055 . Graphical coordinates of the hot zone . The associated page number (starting at 1) Preview: TRect.pas unit . the TRect will describe the hot region . as used by SaveLayout/RestoreSavedLayout methods THeaderFooter = class(TObject) Internal format of the header or footer text constructor Create(Report: TGDIPages. Initialize the header or footer parameters with current report state TColRec = record Internal format of a text column TPagePaintBox = class(TPaintBox) Hack the TPaintBox to allow custom background erase TGDIPagereference = class(TObject) Internal structure used to store bookmarks or links Page: Integer.Rev. const aText: SynUnicode=''. Bottom: integer). Initialize the structure with the current page mORMotReport. Top. IsText: boolean=false). doubleline: boolean.for Outline. Coordinates on screen of the hot zone Rect: TRect. 2013 Objects Description Page TColRec Internal format of a text column 935 TGDIPageContent Contains one page 936 TGDIPagereference Internal structure used to store bookmarks or links 935 TGDIPages Report class for generating documents from code 936 THeaderFooter Internal format of the header or footer text 935 TPagePaintBox Hack the TPaintBox to allow custom background erase 935 TSavedState A report layout state. Top is the Y position . 1.18 Page 935 of 1055 . Left.for links.Synopse mORMot Framework Software Architecture Design 1.for bookmarks. Right. Top is the Y position and Bottom the outline tree level constructor Create(PageNumber: integer.18 Date: June 16. as used by SaveLayout/RestoreSavedLayout methods 935 TSavedState = record A report layout state. and direct pdf export .3.so this property is set to true by default for proper display on screen .used for the preview caption form .pas unit . If true.Synopse mORMot Framework Software Architecture Design 1. internal text drawing will use a font-fallback mechanism for characters not existing within the current font (just as with GDI) .we found out that GDI+ 1. If true. for underlined fonts . drawing will NOT to use native GDI+ 1. Caption: string.data is drawn in memory.18 Page 936 of 1055 . The physical page size Text: string. of course ForceInternalAntiAliasedFontFallBack: boolean. they displayed or printed as desired .1 was not as good as our internal conversion function written in Delphi. Compute the coordinates on screen into Preview TGDIPageContent = object(TObject) Contains one page MarginPx: TRect. If true.2 (page 1054).used for the printing document name ForceCopyTextAsWholeContent: boolean. 2013 procedure ToPreview(Pages: TGDIPages).handle bookmark. outlines and links inside the document .g. Text equivalent of the page TGDIPages = class(TScrollBox) Report class for generating documents from code . e.ForceUseDrawString property mORMotReport.18 Date: June 16.allow preview and printing.Rev. but could be set to TRUE to force enabling TGDIPlusFull. the headers are copied only once to the text ForceInternalAntiAliased: boolean.will only be used if ForceNoAntiAliased is false. 1.1 conversion . The title of the report . Non printable offset of the page SizePx: TPoint.page coordinates are in mm's Used for DI-2.is disabled by default. Margin of the page MetaFileCompressed: RawByteString. SynLZ-compressed content of the page OffsetPx: TPoint. default handling (i.this may be slow on old computers.18 Date: June 16. If true. aYPosition: integer=0): Boolean. 2013 ForceNoAntiAliased: boolean. releasing all used memory function AddBookMark(const aBookmarkName: string. Create a bookmark entry at the current position of the current page .not usefull.default handling (i. should have been fixed . Customize left aligned text conversion from Ansi . Event trigerred when the ReportPopupMenu is displayed . leave this field nil) is to add Page naviguation . If true the preview will not use GDI+ library to draw anti-aliaised graphics . <= or >=) PopupMenuClass: TPopupMenuClass.if set to true. virtual.18 Page 937 of 1055 .e. since slows the printing a lot and makes huge memory usage GroupsMustBeOnSamePage: boolean. override.you can override this method for adding items to the ReportPopupMenu OnStringToUnicode: TOnStringToUnicodeEvent. Creates the reporting component destructor Destroy. so caller can disable it on demand ForcePrintAsBitmap: boolean. the PrintPages() method will use a temporary bitmap for printing . the groups will be forced to be placed on the same page (this was the original default "Pages" component behavior.pas unit .Synopse mORMot Framework Software Architecture Design 1. the current Y position will be used mORMotReport. in order to force some character customization (e.to be used before Delphi 2009/2010/XE only. but this is not usual in page composition.if set to false.you can override this method for handling additionnal items to the menu . the groups will force a page feed if there is not enough place for 20 lines on the current page (default behavior) OnPopupMenuClick: TNotifyEvent. The bitmap used to draw the page constructor Create(AOwner: TComponent).Rev. Event trigerred when a ReportPopupMenu item is selected .g. leave this field nil) is for Page navigation . so is disabled by default in TGDIPages) . true on success .e.the Tag component of the custom TMenuItem should be 0 or greater than Report pages count: use 1000 as a start for custom TMenuItem.return false if this bookmark name was already existing. User can customize this class to create an advanced popup menu instance PreviewSurfaceBitmap: TBitmap. Finalize the component.some printer device drivers have problems with printing metafiles which contains other metafiles.if aYPosition is not 0.Tag values OnPopupMenuPopup: TNotifyEvent. Set group page fill method . override. 1. default OnClick event is to go to page set by the Tag property function PrinterPxToMmX(px: integer): integer. Convert a mm Y position into pixel canvas units function NewPopupMenuItem(const aCaption: string. Go to the specified bookmark .uses internal PDF code.returns CurrentYPos if no group is in use function ExportPDF(aPdfFileName: TFileName. Create a meta file and its associated canvas for displaying a picture . 1. Export the current report as PDF in a specified stream . specified in mm function HasSpaceForLines(Count: integer): boolean.used mostly internaly to add page browsing . virtual. Export the current report as PDF file .18 Page 938 of 1055 .you must release manually both Objects after usage function CurrentGroupPosStart: integer.Used to check if there's sufficient vertical space remaining on the page for the specified number of lines based on the current Y position function MmToPrinter(const R: TRect): TRect. ShowErrorOnScreen: boolean. a file name can be set function ExportPDFStream(aDest: TStream): boolean.uses internal PDF code.in this case. Add an item to the popup menu . Convert a mm X position into pixel canvas units function MmToPrinterPxY(mm: integer): integer. from Synopse PDF engine (handle bookmarks.in this case. from Synopse PDF engine (handle bookmarks. outline and twin bitmaps) . Retrieve the attributes of a specified column function GotoBookmark(const aBookmarkName: string): Boolean. Returns true if there is enough space in the current Report for Count lines . 2013 function CreatePictureMetaFile(Width. SubMenu: TMenuItem=nil. outline and twin bitmaps) . Convert a pixel canvas X position into mm mORMotReport. out MetaCanvas: TCanvas): TMetaFile. Height: integer.Synopse mORMot Framework Software Architecture Design 1. Tag: integer=0. Returns true if there is enough space in the current Report for a vertical size. ImageIndex: integer=-1): TMenuItem.18 Date: June 16. Convert a rect of mm into pixel canvas units function MmToPrinterPxX(mm: integer): integer. a file name can be set function GetColumnInfo(index: integer): TColRec. Distance (in mm's) from the top of the page to the top of the current group . LaunchAfter: boolean=true): boolean.returns true if the bookmark name was existing and reached function HasSpaceFor(mm: integer): boolean. OnClick: TNotifyEvent=nil.Rev.pas unit . if a column need to be right aligned or currency aligned. with the current font formating . then all pages are printed . WithBottomGrayLine: boolean. Convert a rect of pixel canvas units into mm function PrintPages(PrintFrom. PrintTo: integer): boolean.18 Page 939 of 1055 . Register a column. Convert a pixel canvas Y position into mm function PrinterToMM(const R: TRect): TRect. but corresponding alignment is set to right .call this method once with all columns text as CSV procedure AddColumns(const PercentWidth: array of integer.Rev.18 Date: June 16. Adds either a single line or a double line (drawn between the left & right page margins) to the page header mORMotReport.if PrintFrom=-1 or PrintTo=-1.if PrintFrom=0 and PrintTo=0.you can call this method several times in order to have diverse font formats across the column headers procedure AddColumnHeadersFromCSV(var CSV: PWideChar. Return the width of the specified text. Register some column headers. 2013 function PrinterPxToMmY(px: integer): integer.negative widths are converted into absolute values. bold: boolean). with proper alignment procedure AddColumnHeaders(const headers: array of SynUnicode. align: TColAlign=caLeft).Column headers will appear just above the first text output in columns on each page . Register same alignement columns. with the current font formating . in mm function TitleFlags: integer. RowLineHeight: integer=0). BoldFont: boolean=false. Adds either a single line or a double line (drawn between the left & right page margins) to the page footer procedure AddLineToHeader(doubleline: boolean). align: TColAlign. use SetColumnAlign() method below . Get the formating flags associated to a Title procedure AddColumn(left.Synopse mORMot Framework Software Architecture Design 1. Register some column headers. with percentage of page column width . BoldFont: boolean=false. WithBottomGrayLine: boolean=false.individual column may be printed in bold with SetColumnBold() method procedure AddLineToFooter(doubleline: boolean). but can be of any value .sum of all percent width should be 100.pas unit . then a printer dialog is displayed function TextWidth(const Text: SynUnicode): integer. 1. flags: integer=0). RowLineHeight: integer=0. right: integer. Print the selected pages to the default printer of Printer unit .Column headers will appear just above the first text output in columns on each page . Create an outline entry at the current position of the current page . Clear the current Report document procedure ClearColumnHeaders. aPageNumber: integer=0).pas unit . Adds text using to current font and alignment to the page header procedure AddTextToHeaderAt(const s: SynUnicode. will put the text at the current right margin procedure AppendRichEdit(RichEditHandle: HWnd). XPos: integer). Adds text using to current font and alignment to the page footer procedure AddTextToFooterAt(const s: SynUnicode. Begin a Report document .if XPos=-1. 2013 procedure AddLink(const aBookmarkName: string.if aYPosition is not 0.BeginGroup-EndGroup text blocks can't be nested procedure Clear. virtual. you have to set its MaxLength property as expected (this is a limitation of the VCL. aLevel: Integer. Adds text to the page header at the specified horizontal position and using to current font. 1. Create a link entry at the specified coordinates of the current page . the current Y position will be used procedure AddPagesToFooterAt(const PageText: string. will put the text at the current right margin procedure AddTextToHeader(const s: SynUnicode). aYPosition: integer=0. in the desired language . Adds text to the page footer at the specified horizontal position and using to current font. aRect: TRect.the bookmark name is not checked by this method: a bookmark can be linked before being marked in the document procedure AddOutline(const aTitle: string.if XPos=-1. XPos: integer).if XPos=-1. .18 Page 940 of 1055 . XPos: integer).No Line feed will be triggered: this method doesn't increment the YPos.coordinates are specified in mm . aPageNumber: integer=0). Will add the current 'Page n/n' text at the specified position . Clear the Headers associated to the Columns mORMotReport. Append a Rich Edit content to the current report . so can be used to add multiple text on the same line . Begin a Group: stops the contents from being split across pages .Rev. virtual.PageText must be of format 'Page %d/%d'.note that if you want the TRichEdit component to handle more than 64 KB of RTF content. will put the text at the current right margin procedure AddTextToFooter(const s: SynUnicode).18 Date: June 16. not of this method) procedure BeginDoc. .Synopse mORMot Framework Software Architecture Design 1. virtual. No Line feed will be triggered.Every report must start with BeginDoc and end with EndDoc procedure BeginGroup. Draw a filled square box at the given coordinates procedure DrawDashedLine. overload.Usually column headers are drawn once per page just above the first column. SolidHead: boolean).bottom: integer).18 Page 941 of 1055 .top. HeadSize: integer. const Legend: string='').18 Date: June 16. ColumnHeadersNeeded is useful where columns of text have been separated by a number of lines of non-columned text procedure DrawAngledTextAt(const s: SynUnicode. Draw one line of text. Draw a square box at the given coordinates procedure DrawBoxFilled(left. Angle: integer). with a specified Angle and X Position procedure DrawArrow(Point1. go to next page . bWidth: integer. Clear all already predefined Headers procedure ColumnHeadersNeeded.bottom: integer.Synopse mORMot Framework Software Architecture Design 1. 2013 procedure ClearColumns. Draw a Dashed Line between the left & right margins mORMotReport.bLeft (in mm) is calculated in reference to the LeftMargin position .Rev. Erase all columns and the associated headers procedure ClearFooters.then the current Y position is updated .if bLeft is maxInt. Stretch draws a bitmap image at the specified page coordinates in mm's procedure DrawBMP(bmp: TBitmap. ColumnHeadersNeeded will force column headers to be drawn again just prior to printing the next row of columned text . the bitmap is centered to the page width . Draw an Arrow procedure DrawBMP(rec: TRect. overload.top.right. Color: TColor). XPos. Clear all already predefined Footers procedure ClearHeaders. Add the bitmap at the specified X position . Point2: TPoint.right. 1.bitmap is stretched (keeping aspect ratio) for the resulting width to match the bWidth parameter (in mm) procedure DrawBox(left. bmp: TBitmap).pas unit . bLeft.if there is not enough place to draw the bitmap. either simple or double. the bitmap is centered to the page width .e.18 Page 942 of 1055 . Draw one line of text. between the left & right margins procedure DrawLinesInCurrencyCols(doublelines: boolean).if bLeft is maxInt. Stretch draws a metafile image at the specified page coordinates in mm's procedure DrawText(const s: string). split across every columns . to highlight errors) procedure DrawTextAt(s: SynUnicode. Draw some text. Draw some text as a paragraph.then the current Y position is updated .this method use format() like parameterss procedure DrawTextU(const s: RawUTF8). with the current alignment . BackgroundColor: TColor=clNone). #13) procedure DrawTextAcrossCols(const StringArray: array of SynUnicode.Synopse mORMot Framework Software Architecture Design 1. with the current alignment .Rev.18 Date: June 16.pas unit . BackgroundColor: TColor=clNone). const Args: array of const).e.i.e. Draw some UTF-8 text as a paragraph.bitmap is stretched (keeping aspect ratio) for the resulting width to match the bWidth parameter (in mm) procedure DrawLine(doubleline: boolean=false). bWidth: integer.this method does all word-wrapping and formating if necessary .i. Draw (double if specified) lines at the bottom of all currency columns procedure DrawMeta(rec: TRect.g. clRed or clNavy or clBlack). the row is printed on white with this background color (e. XPos: integer. Draw some text as a paragraph. bLeft. 2013 procedure DrawGraphic(graph: TGraphic. clRed or clNavy or clBlack).g. const aLink: string=''. split across every columns .handle only TBitmap and TMetafile kind of TGraphic . Draw some text.if there is not enough place to draw the bitmap.if BackgroundColor is not clNone (i. const Legend: SynUnicode=''). Draw a Line. Add the graphic (bitmap or metafile) at the specified X position . meta: TMetafile). go to next page .if BackgroundColor is not clNone (i.this method handle multiple paragraphs inside s (separated by newlines . 1. with the current alignment . #13) mORMotReport.e.this method does all word-wrapping and formating if necessary .this method handle multiple paragraphs inside s (separated by newlines . the row is printed on white with this background color (e. to highlight errors) procedure DrawTextAcrossColsFromCSV(var CSV: PWideChar.bLeft (in mm) is calculated in reference to the LeftMargin position . with the current alignment procedure DrawTextFmt(const s: string.this method expect the text to be separated by commas . CheckPageNumber: boolean=false). pas unit . OutlineLevel: Integer=0. Jump to next page. with the current alignment . Draw some Unicode text as a paragraph.e.18 Date: June 16.this method handle multiple paragraphs inside s (separated by newlines .Increments the current Y Position the equivalent of 'count' lines relative to the current font height and line spacing procedure NewPage(ForceEndGroup: boolean=false). Jump some half line space between paragraphs . 1. override. End a previously defined Group .BeginGroup-EndGroup text blocks can't be nested procedure GotoPosition(aPage: integer. a bookmark is created at this position . 2013 procedure DrawTextW(const s: SynUnicode). const aLink: string='').Rev.Increments the current Y Position the equivalent of a single line relative to the current font height and line spacing procedure NewLines(count: integer). force a page break procedure NewPageIfAnyContent. DrawBottomLine: boolean=false. a link to the specified bookmark name (in aLink) is made procedure EndDoc. End the Report document . but only if some content is pending mORMotReport.the outline level can be specified. if UseOutline property is enabled . Customized invalidate procedure NewHalfLine.if aBookmark is set. aYPos: integer).Every report must start with BeginDoc and end with EndDoc procedure EndGroup.used e. const aBookmark: string=''. Draw some text as a paragraph title .this method does all word-wrapping and formating if necessary . Jump some line space between paragraphs . i.if aLink is set.e.Synopse mORMot Framework Software Architecture Design 1.18 Page 943 of 1055 .Increments the current Y Position the equivalent of an half single line relative to the current font height and line spacing procedure NewLine.g. Jump some line space between paragraphs . Go to the specified Y position on a given page . #13) procedure DrawTitle(const s: SynUnicode.i. by GotoBookmark() method procedure Invalidate. Jump to next page. Synopse mORMot Framework Software Architecture Design 1. 1.g.18 Date: June 16. they will be the exact Tabs positions procedure ShowPreviewForm.will then force a page break by a call to NewPage(true) method . SaveLayout/RestoreSavedLayout methods property Canvas: TMetaFileCanvas read fCanvas. Change the page layout for the upcoming page . overload.can change the default non-printable printer margin if nonPrintable*>=0 procedure PopupMenuItemClick(Sender: TObject).will then force a page break by a call to NewPage(true) method . 2013 procedure NewPageLayout(paperSize: TGdiPagePaperSize. Show a form with the preview. orientation: TPrinterOrientation=poPortrait.if one value is provided.if more than one value are provided. Set the Tabs stops on every line .18 Page 944 of 1055 . Retrieve the current Column count mORMotReport. overload. nonPrintableWidthMM: integer=-1.Rev. nonPrintableHeightMM: integer=-1). procedure SetTabStops(const tabs: array of integer). Change the page layout for the upcoming page . Individually set column bold state . Save the current font and alignment procedure SetColumnAlign(index: integer.can change the default margin if margin*>=0 . sizeHeightMM: integer. Individually set column alignment .usefull after habing used AddColumns([]) method e. it will set the Tabs as every multiple of it . DrawTitle.this will be used by DrawText[At]. procedure SetColumnBold(index: integer). nonPrintableWidthMM: integer=-1.can change the default non-printable printer margin if nonPrintable*>=0 procedure NewPageLayout(sizeWidthMM. virtual.The Canvas property should be rarely needed property ColumnCount: integer read GetColumnCount. nonPrintableHeightMM: integer=-1). Specifies the reading order (bidirectional mode) of the box . virtual.g. This is the main popup menu item click event procedure RestoreSavedLayout.can change the default margin if margin*>=0 . Can be used to draw directly using GDI commands .usefull after habing used AddColumns([]) method e. DrawTextAcrossCols. allowing the user to browse pages and print the report property BiDiMode: TBiDiMode read fBiDiMode write fBiDiMode. align: TColAlign). Restore last saved font and alignment procedure SaveLayout. AddTextToHeader/Footer[At].only bdLeftToRight and bdRightToLeft are handled .pas unit . the resulting PDF file content will be bigger in size (e.default value is 'Arial Unicode MS'.80/90 is a good ration if you want to have a nice PDF to see on screen .Rev. this doesn't affect vectorial (i. This property can force saving all bitmaps as JPEG in exported PDF . Optional Author name used during Export to PDF property ExportPDFBackground: TGraphic read fExportPDFBackground write fExportPDFBackground. and free it after the pdf is generated property ExportPDFEmbeddedTTF: boolean read fExportPDFEmbeddedTTF write fExportPDFEmbeddedTTF. meaning that the JPEG compression is not forced. Distance (in mm's) from the top of the page to the top of the next line property ExportPDFA1: Boolean read fExportPDFA1 write fExportPDFA1.if not set. this property is set to 0 by the constructor of this class.g.18 Page 945 of 1055 .Synopse mORMot Framework Software Architecture Design 1. the used True Type fonts will be embedded to the exported PDF . for publishing PDF over the internet .in this case. use this for printing) . and the engine will use the native resolution of the bitmap .by default. emf) pictures property ExportPDFKeywords: string read fExportPDFKeywords write fExportPDFKeywords. Optional Keywords name used during Export to PDF property ExportPDFSubject: string read fExportPDFSubject write fExportPDFSubject.used only if UseFontFallBack is TRUE . to save disk space and produce tiny PDF property ExportPDFFontFallBackName: string read fExportPDFFontFallBackName write fExportPDFFontFallBackName. If set to TRUE.note that no private copy of the TGraphic instance is made: the caller has to manage it. Set the font name to be used for missing characters in exported PDF document . the exported PDF is made compatible with PDF/A-1 requirements property ExportPDFApplication: string read fExportPDFApplication write fExportPDFApplication.pas unit .e.of course. An optional background image.g. to be exported on every pdf page . Optional Subject text used during Export to PDF mORMotReport. global Application.not set by default. If set to TRUE. 1. Optional application name used during Export to PDF .60 is the prefered way e. 2013 property CurrentYPos: integer read GetYPos write SetYPos.18 Date: June 16.Title will be used property ExportPDFAuthor: string read fExportPDFAuthor write fExportPDFAuthor. if existing property ExportPDFForceJPEGCompression: integer read fForceJPEGCompression write fForceJPEGCompression. usefull for Hebrew.wikipedia. Arabic and some Asiatic languages handling . Size of the left margin relative to its corresponding edge in mm's property LineHeight: integer read GetLineHeightMm.18 Date: June 16. lsOneAndHalf or lsDouble property NegsToParenthesesInCurrCols: boolean read fNegsToParenthesesInCurrCols write fNegsToParenthesesInCurrCols. Accounting standard layout for caCurrency columns: . Get current line height (mm) property LineSpacing: TLineSpacing read fLineSpacing write fLineSpacing.i. for faster content generation property ForceScreenResolution: boolean read fForceScreenResolution write fForceScreenResolution.default value is TRUE property ExportPDFUseUniscribe: boolean read fExportPDFUseUniscribe write fExportPDFUseUniscribe. http://en.Synopse mORMot Framework Software Architecture Design 1. Event triggered when each column was drawn mORMotReport. True if any header as been drawn.org/wiki/Income_statement) .set to FALSE by default. Left justification hang indentation property HeaderDone: boolean read fHeaderDone.g.using parentheses instead of negative numbers is used in financial statement reporting (see e.g.e.Rev.18 Page 946 of 1055 . 1. Set if the exporting PDF engine must use the Windows Uniscribe API to render Ordering and/or Shaping of the text .pas unit . that is if something is to be printed property LeftMargin: integer read GetLeftMargin write SetLeftMargin. when the EndDoc method has just been called property OnEndColumnHeader: TNotifyEvent read fEndColumnHeader write fEndColumnHeader. for Chinese text) .align numbers on digits. Event triggered whenever the report document generation is done . Line spacing: can be lsSingle.convert all negative sign into parentheses . If set to true. 2013 property ExportPDFUseFontFallBack: boolean read fExportPDFUseFontFallBack write fExportPDFUseFontFallBack.will use the font specified by FontFallBackName property to add any Unicode glyph not existing in the currently selected font . not parentheses property OnDocumentProduced: TNotifyEvent read fOnDocumentProducedEvent write fOnDocumentProducedEvent. we reduce the precision for better screen display property HangIndent: integer read fHangIndent write fHangIndent. Used to define if the exported PDF document will handle "font fallback" for characters not existing in the current font: it will avoid rendering block/square symbols instead of the correct characters (e. numerotation begin with Pages[0] for page 1 . Event triggered whenever the preview page is zoomed in or out property Orientation: TPrinterOrientation read GetOrientation write SetOrientation. for X and Y directions mORMotReport. 1. Event triggered when each footer was drawn property OnEndPageHeader: TNotifyEvent read fEndPageHeader write fEndPageHeader. Event triggered when each new footer is about to be drawn property OnStartPageHeader: TNotifyEvent read fStartPageHeader write fStartPageHeader. Access to all pages content . Event triggered whenever the current preview page is changed property OnStartColumnHeader: TNotifyEvent read fStartColumnHeader write fStartColumnHeader. in mm's property PrinterName: string read fCurrentPrinter. Number of pixel per inch.18 Page 947 of 1055 . Event triggered when each new page is created property OnPreviewPageChanged: TNotifyEvent read fPreviewPageChangedEvent write fPreviewPageChangedEvent. Event triggered when each new header is about to be drawn property OnZoomChanged: TZoomChangedEvent read fZoomChangedEvent write fZoomChangedEvent. Get the current selected paper size. 2013 property OnEndPageFooter: TNotifyEvent read fEndPageFooter write fEndPageFooter. The name of the current selected printer property PrinterPxPerInch: TPoint read fPrinterPxPerInch. Event triggered when each new column is about to be drawn property OnStartPageFooter: TNotifyEvent read fStartPageFooter write fStartPageFooter.the Pages[] property should be rarely needed property PaperSize: TSize read GetPaperSize. Event triggered when each header was drawn property OnNewPage: TNewPageEvent read fStartNewPage write fStartNewPage. The paper orientation property Page: integer read fCurrPreviewPage write SetPage.please note that the first page is 1 (not 0) property PageCount: integer read GetPageCount. Size of each margin relative to its corresponding edge in mm's property Pages: TGDIPageContentDynArray read fPages.Rev.Synopse mORMot Framework Software Architecture Design 1. Total number of pages property PageMargins: TRect read GetPageMargins write SetPageMargins.pas unit .18 Date: June 16. The index of the previewed page . zsPercent.18 Date: June 16. The current page number.18 Page 948 of 1055 .this is enabled by default property VirtualPageNum: integer read fVirtualPageNum write fVirtualPageNum. psLetter. i.Page is used during preview. psLegal ).you can use PAGE_WIDTH and PAGE_FIT constants to force the corresponding zooming mode (similar to ZoomStatus property setter) . Word wrap (caLeft) left-aligned columns into multiple lines .g. during text adding . Used to store all pages of the report TGdiPagePaperSize = ( psA4. its content is wrapped to the next line . Text line spacing TNewPageEvent = procedure(Sender: TObject. caCurrency ).if the text contains some #13/#10 characters. psA3. during text adding property UseOutlines: boolean read fUseOutlines write fUseOutlines. not before ShowPreviewForm method call property ZoomStatus: TZoomStatus read fZoomStatus write SetZoomStatus.Rev. 2013 property RightMarginPos: integer read GetRightMarginPos. lsDouble ). Event trigerred when a new page is added TOnStringToUnicodeEvent = function(const Text: SynUnicode): SynUnicode of object. lsOneAndHalf.set this property will work only when the report is already shown in preview mode. Text column alignment TGDIPageContentDynArray = array of TGDIPageContent. psA5. for PDF generation . If set. Available known paper size for NewPageLayout() method TLineSpacing = ( lsSingle.e. not before ShowPreviewForm method call Types implemented in the mORMotReport unit: TColAlign = ( caLeft. 1. Position of the right margin. after text adding property WordWrapLeftCols: boolean read fWordWrapLeftCols write fWordWrapLeftCols. it will be splitted into individual lines . The current Zoom procedure.used e. The current Zoom value. caRight.if the text is wider than the column width. according to the zoom status .set this property will define the Zoom at PAGE_WIDTH or PAGE_FIT special constant. if needed . zsPageFit or zsPageWidth . The current Text Alignment. caCenter.pas unit . in mm property TextAlign: TTextAlign read fAlign write SetTextAlign.this is disabled by default property Zoom: integer read fZoom write SetZoom. any DrawTitle() call will create an Outline entry . PageNumber: integer) of object.Synopse mORMot Framework Software Architecture Design 1. Event trigerred to allow custom unicode character display on the screen mORMotReport.set this property will work only when the report is already shown in preview mode. zsPercent is used with a zoom percentage (e.g. Fontstyle bits 10-12 FORMAT_DEFAULT = $0.. This constant can be used to be replaced by the page number in the middle of any text PAGE_FIT = -2. Minimum gray border with around preview page PAGENUMBER = '<<pagenumber>>'.Synopse mORMot Framework Software Architecture Design 1. '>=' can be converted to the one unicode equivalent) TReportPopupMenu = ( rNone. rPreviousPage. mORMotReport. TEXT FORMAT FLAGS.called for all text. Event trigerred when the Zoom was changed TZoomStatus = ( zsPercent. rNextPage. taCenter. TGdiPages. taJustified ). DrawTextAt XPos 16-30 bits (max value = ~64000) GRAY_MARGIN = 10. whatever the alignment is .pas unit . Zoom: integer. rBookmarks. Alignment bits 8-9 FORMAT_BOLD = $400. rPageAsText.'. rClose ). taRight. max = 255 FORMAT_UNDEFINED = $2000.Zoom property value for "Page fit" layout during preview PAGE_WIDTH = -1. Text paragraph alignment TZoomChangedEvent = procedure(Sender: TObject. ZoomStatus: TZoomStatus) of object. 100% or 50%) . 2013 . zsPageWidth ). rExportPDF.Rev. Undefined bit 13 FORMAT_XPOS_MASK = $FFFF0000..18 Page 949 of 1055 . Available zoom mode . rPrint. Fontsize bits 0-7 . Line flags bits 14-15 FORMAT_SIZE_MASK = $FF. rGotoPage.18 Date: June 16. The available menu items TTextAlign = ( taLeft.zsPageFit fits the page to the report .g. zsPageFit. rZoom. 1.Text content can be modified by this event handler to customize some characters (e. FORMAT_SINGLELINE = $8000.zsPageWidth zooms the page to fit the report width on screen Constants implemented in the mORMotReport unit: FORMAT_ALIGN_MASK = $300. 18 Date: June 16.Synopse mORMot Framework Software Architecture Design 1. 1.pas unit . 2013 TGdiPages.Rev.18 Page 950 of 1055 .Zoom property value for "Page width" layout during preview mORMotReport. version 1.this unit is a part of the freeware Synopse framework. MD5.make available most useful GDI+ drawing methods .this unit is a part of the freeware Synopse mORMot framework. mORMotSelfTests.this unit is a part of the freeware Synopse framework.allows Antialiased rending of any EMF file using GDI+ . TIF.Synopse mORMot Framework Software Architecture Design 1. SHA1.18 497 SynDB Abstract database direct access classes . licensed under a MPL/GPL/LGPL tri-license.18 325 SynCrtSock Classes implementing HTTP/1.licensed under a MPL/GPL/LGPL tri-license. version 1. version 1.x library direct access classes to be used with our SynDB architecture . licensed under a MPL/GPL/LGPL tri-license. version 1. licensed under a MPL/GPL/LGPL tri-license. version 1.this unit is a part of the freeware Synopse mORMot framework. version 1. licensed under a MPL/GPL/LGPL tri-license. licensed under a MPL/GPL/LGPL tri-license.optimized for speed (tuned assembler and VIA PADLOCK optional support) .18 Page 951 of 1055 . version 1.32.18 584 SynLZO Fast LZO Compression routines .18 564 SynGdiPlus GDI+ library API access . version 1.18 Date: June 16.18 557 SynDBSQLite3 SQLite3 direct access classes to be used with our SynDB architecture .this unit is a part of the freeware Synopse mORMot framework.this unit is a part of the freeware Synopse framework.18 553 SynDBOracle Oracle DB direct access classes (via OCI) . version 1.pas unit . XOR.13 586 mORMotSelfTests.implements AES.this unit is a part of the freeware Synopse mORMot framework. version 1.adds GIF.1 client and server protocol . PNG and JPG pictures read/write support as standard TGraphic .18 576 SynLZ SynLZ Compression routines . licensed under a MPL/GPL/LGPL tri-license. ADLER32. 2013 23. SHA256 algorithms .this unit is a part of the freeware Synopse framework.licensed under a MPL/GPL/LGPL tri-license. version 1.Rev. licensed under a MPL/GPL/LGPL tri-license.pas unit Purpose: Automated tests for common units of the Synopse mORMot Framework .18 Units used in the mORMotSelfTests unit: Unit Name Description Page SynCommons Common functions used by most Synopse projects . licensed under a MPL/GPL/LGPL tri-license. 1.18 509 SynDBODBC ODBC 3.this unit is a part of the freeware Synopse mORMot framework.18 479 SynCrypto Fast cryptographic routines (hashing and cypher) . licensed under a MPL/GPL/LGPL tri-license. version 1. version 1. licensed under a MPL/GPL/LGPL tri-license. licensed under a MPL/GPL/LGPL tri-license.this unit is a part of the freeware Synopse framework. 1.18 642 SynZip Low-level access to ZLib compression (1. 2013 Unit Name Description Page SynOleDB Fast OleDB direct access classes . version 1. version 1.18 Date: June 16.this procedure will create a console. licensed under a MPL/GPL/LGPL tri-license. licensed under a MPL/GPL/LGPL tri-license.18 707 Functions or procedures implemented in the mORMotSelfTests unit: Functions or procedures Description SQLite3ConsoleTests Page 952 procedure SQLite3ConsoleTests.2.5 engine version) .18 587 SynPdf PDF file generation .Rev.this unit is a part of the freeware Synopse framework.Synopse mORMot Framework Software Architecture Design 1.pas unit . then run all available tests mORMotSelfTests.this unit is a part of the freeware Synopse framework. This is the main entry point of the tests .this unit is a part of the freeware Synopse mORMot framework.18 600 SynSelfTests Automated tests for common units of the Synopse mORMot Framework .18 Page 952 of 1055 . resume. stop.) an existing service . licensed under a MPL/GPL/LGPL tri-license.18 Date: June 16.Rev. version 1.Synopse mORMot Framework Software Architecture Design 1. use the TService class mORmotService.. version 1.18 715 SynCommons Common functions used by most Synopse projects ..to provide the service itself. licensed under a MPL/GPL/LGPL tri-license.) an existing service 953 TServiceController = class(TObject) TServiceControler class is intended to create a new service instance or to maintain (that is start. pause. mORmotService. version 1. 1. pause. resume. licensed under a MPL/GPL/LGPL tri-license.18 Page 953 of 1055 .33.pas unit ..this unit is a part of the freeware Synopse mORMot framework. 2013 23.this unit is a part of the freeware Synopse mORMot framework.this unit is a part of the freeware Synopse mORMot framework..18 Units used in the mORmotService unit: Unit Name Description Page mORMot Common ORM and SOA classes for mORMot .18 325 TServiceController TObject TService mORmotService class hierarchy Objects implemented in the mORmotService unit: Objects Description Page TService TService is the class used to implement a service provided by an application 956 TServiceController TServiceControler class is intended to create a new service instance or to maintain (that is start. stop.pas unit Purpose: Win NT Service managment classes for mORMot . .DesiredAccess .DisplayName . ServiceType: DWORD = SERVICE_WIN32_OWN_PROCESS or SERVICE_INTERACTIVE_PROCESS. 1.Start method).18 Date: June 16.set it to empty string if local computer is the target. If the service type is SERVICE_KERNEL_DRIVER or SERVICE_FILE_SYSTEM_DRIVER.Dependances .18 Page 954 of 1055 .set it to empty string if the default database is supposed ('ServicesActive').name of a service.Name .an order group name (unnecessary) . which specifies a Win32 service that runs in its own process). ". const Username: string = ''. . If '' is specified.DatabaseName . this parameter is ignored. SERVICE_CHANGE_CONFIG. SERVICE_KERNEL_DRIVER. SERVICE_INTERROGATE. SERVICE_INTERACTIVE_PROCESS (default value.pas unit .one of following: SERVICE_ERROR_IGNORE. SERVICE_ERROR_SEVERE. 2013 constructor CreateNewService(const TargetComputer. Name. Services of type SERVICE_WIN32_SHARE_PROCESS are not allowed to specify an account other than LocalSystem. . SERVICE_SYSTEM_START. Or. which enables a Win32 service process to interact with the desktop) . SERVICE_AUTO_START (which specifies a device driver or service started by the service control manager automatically during system startup).display name of a service. For service type SERVICE_WIN32_OWN_PROCESS. SERVICE_ERROR_NORMAL (default value.Password .\Username" can be specified. ErrorControl: DWORD = SERVICE_ERROR_NORMAL).a password for login name.string containing a list with names of services.a combination of following flags: SERVICE_ALL_ACCESS (default value).TargetComputer . that is the TServiceController. SERVICE_QUERY_STATUS. const Dependances: string = ''. SERVICE_USER_DEFINED_CONTROL .OrderGroup . the service will be logged on as the 'LocalSystem' account. SERVICE_ENUMERATE_DEPENDENTS. . . SERVICE_DEMAND_START (default value.StartType . Expected Parameters (strings are unicode-ready since Delphi 2009): . the account name in the form of "DomainName\Username". entire list should be separated with #0#0.a set of following flags: SERVICE_WIN32_OWN_PROCESS (default value. which must start before (every name should be separated with #0. SERVICE_FILE_SYSTEM_DRIVER. the Password parameter must be empty too. DesiredAccess: DWORD = SERVICE_ALL_ACCESS. Creates a new service and allows to control it and/or its configuration. .Username . which specifies a service started by a service control manager when a process calls the StartService function. If the account belongs to the built-in domain.one of following values: SERVICE_BOOT_START. SERVICE_PAUSE_CONTINUE. by which the startup program logs the error and displays a message but continues the startup operation). SERVICE_STOP. const OrderGroup: string = ''. const Password: string = ''. SERVICE_WIN32_SHARE_PROCESS.Path . Path: string.a path to binary (executable) of the service created. DisplayName.Rev.ErrorControl .login name. an empty string can be passed if there are no dependances). . StartType: DWORD = SERVICE_DEMAND_START. SERVICE_ERROR_CRITICAL mORmotService. in which case.Synopse mORMot Framework Software Architecture Design 1. . SERVICE_START. SERVICE_DISABLED .ServiceType . SERVICE_QUERY_CONFIG. DatabaseName. DataBaseName.its value is 0 if something failed in any Create*() method property SCHandle: THandle read FSCHandle. Release memory and handles function Delete: boolean. close the Service function Pause: boolean.name of a service. 1. override. SERVICE_ENUMERATE_DEPENDENTS. either AnsiString (for FPC and old Delphi compiler). SERVICE_QUERY_STATUS.TargetComputer . . . Requests the service to update immediately its current status information to the service control manager function Resume: boolean. i. DesiredAccess: DWORD = SERVICE_ALL_ACCESS). Retrive the Current state of the service property Status: TServiceStatus read GetStatus.18 Page 955 of 1055 .Rev. . Removes service from the system.DatabaseName . Starts the execution of a service with some specified arguments .pas unit . SERVICE_INTERROGATE. Requests the service to pause function Refresh: boolean.Name .DesiredAccess . SERVICE_CHANGE_CONFIG.18 Date: June 16. SERVICE_STOP. SERVICE_PAUSE_CONTINUE.set it to empty string if local computer is the target. Name: String. Requests the service to stop property Handle: THandle read FHandle.a combination of following flags: SERVICE_ALL_ACCESS. Opens an existing service. SERVICE_START. Parameters (strings are unicode-ready since Delphi 2009): .this version expect PChar pointers. Retrieve the Current status of the service mORmotService. Handle of service opened or created . Requests the paused service to resume function Shutdown: boolean. in order to control it or its configuration from your application. SERVICE_USER_DEFINED_CONTROL destructor Destroy. either UnicodeString (till Delphi 2009) function Stop: boolean. Handle of SC manager property State: TServiceState read GetState.Synopse mORMot Framework Software Architecture Design 1. 2013 constructor CreateOpenService(const TargetComputer. Request the service to shutdown .this function always return false function Start(const Args: array of PChar): boolean.e.set it to empty string if the default database is supposed ('ServicesActive'). SERVICE_QUERY_CONFIG. create a local TServiceController with the current executable file. Reports new status to the system procedure DoCtrlHandle(Code: DWORD).uses a local TServiceController with the current Service Name procedure Start.Rev. Stops the service . Callback handler for Windows Service Controller . Removes the service from database .pas unit .the service is added to the internal registered services .uses a local TServiceController with the current Service Name property ArgCount: Integer read GetArgCount. in which the Service should implement its run procedure Remove. then auto generated handler calls DoCtrlHandle mORmotService.if handler is not set. This is the main method.and report the service status to the system (via ReportStatus method) procedure Execute. Number of arguments passed to the service by the service controler property Args[Idx: Integer]: String read GetArgs. Installs the service in the database . aDisplayName: String).main application must call the global ServicesRun procedure to actually start the services .caller must free the TService instance when it's no longer used destructor Destroy.Synopse mORMot Framework Software Architecture Design 1. virtual. Free memory and release handles function Install(const Params: string=''): boolean. Starts the service . reintroduce. dwWait: DWORD): BOOL. virtual.return true on success . virtual. 2013 TService = class(TObject) TService is the class used to implement a service provided by an application constructor Create(const aServiceName. override. with the supplied command line parameters function ReportStatus(dwState. Creates the service . List of arguments passed to the service by the service controler property ControlHandler: TServiceCtrlHandler read GetCtrlHandler write SetCtrlHandler.18 Page 956 of 1055 .it will call OnControl/OnStop/OnPause/OnResume/OnShutdown events . 1.18 Date: June 16. from the OS point of view . This method is the main service entrance.uses a local TServiceController with the current Service Name procedure Stop. dwExitCode. Custom event trigerred when the service is resumed property OnShutdown: TServiceEvent read fOnShutdown write fOnShutdown. Type of service property StartType: DWORD read fStartType write fStartType. stdcall. in the Execute method) property OnStop: TServiceEvent read fOnStop write fOnStop. or use ReportStatus method (better) Types implemented in the mORmotService unit: TServiceControlEvent = procedure(Sender: TService. Custom event trigerred when the service receive an Interrogate property OnPause: TServiceEvent read fOnPause write fOnPause. Event triggered for Control handler TServiceCtrlHandler = procedure(CtrlCode: DWORD). Name of the service. Whether service is installed in DataBase .Rev.launched in the main service thread (i. Type of start of service property Status: TServiceStatus read fStatusRec write SetStatus.18 Date: June 16. Custom event trigerred when the service is stopped property ServiceName: String read fSName. Custom event trigerred when the service is shut down property OnStart: TServiceEvent read fOnStart write fOnStart.uses a local TServiceController to check if the current Service Name exists property OnControl: TServiceControlEvent read fOnControl write fOnControl. Any data You wish to associate with the service object property DisplayName: String read fDName write fDName. assign another value to this record. Custom event trigerred when a Control Code is received from Windows property OnExecute: TServiceEvent read fOnExecute write fOnExecute. 2013 property Data: DWORD read FData write FData.18 Page 957 of 1055 . mORmotService. Display name of the service property Installed: boolean read GetInstalled. Current service status .Synopse mORMot Framework Software Architecture Design 1.pas unit . Must be unique property ServiceType: DWORD read fServiceType write fServiceType. 1. Custom Execute event . in the Execute method) property OnInterrogate: TServiceEvent read fOnInterrogate write fOnInterrogate. Start event is executed before the main service thread (i. Custom event trigerred when the service is paused property OnResume: TServiceEvent read fOnResume write fOnResume.e. Code: DWORD) of object.To report new status to the system.e. ssPausing. The internal list of Services handled by this unit . ssStopping.the registered list of service provided by the aplication is sent to the operating system function ServiceStateText(State: TServiceState): string. ssStarting.pas unit . 2013 Callback procedure for Windows Service Controller TServiceEvent = procedure(Sender: TService) of object. ssResuming. ssPaused.18 Date: June 16.Rev. 1.Synopse mORMot Framework Software Architecture Design 1. ssErrorRetrievingState ). Launch the registered Services execution .then run the global ServicesRun procedure . Return the ready to be displayed text of a TServiceState value Variables implemented in the mORmotService unit: Services: TList = nil. and they will be added/registered to this list . All possible states of the service Functions or procedures implemented in the mORmotService unit: Functions or procedures Description Page CurrentStateToService State Convert the Control Code retrieved from Windows into a service state enumeration item 958 ServicesRun Launch the registered Services execution 958 ServiceStateText Return the ready to be displayed text of a TServiceState value 958 function CurrentStateToServiceState(CurrentState: DWORD): TServiceState. Convert the Control Code retrieved from Windows into a service state enumeration item procedure ServicesRun. ssStopped.every TService instance is to be freed by the main application. Event triggered to implement the Service functionality TServiceState = ( ssNotInstalled. ssRunning.18 Page 958 of 1055 .not to be accessed directly: create TService instances. when it's no more used mORmotService. version 1. version 1. licensed under a MPL/GPL/LGPL tri-license.Synopse mORMot Framework Software Architecture Design 1.1 The SQLite3 engine shall be embedded to the framework 1052 Units used in the mORMotSQLite3 unit: Unit Name Description Page mORMot Common ORM and SOA classes for mORMot .pas unit . version 1.this unit is a part of the freeware Synopse mORMot framework.18 The mORMotSQLite3 unit is quoted in the following items: SWRS # Description Page DI-2.18 325 SynSQLite3 SQLite3 Database engine direct access . version 1.18 Page 959 of 1055 . and get result in memory 960 mORMotSQLite3. 1.2. licensed under a MPL/GPL/LGPL tri-license.this unit is a part of the freeware Synopse mORMot framework.18 707 TSQLRestClientURI TSQLRestClientDB TSQLRestServer TSQLRestServerDB TSQLTableJSON TSQLTableDB TSQLVirtualTableModule TSQLVirtualTableModuleSQLite3 TSQLVirtualTableModuleServerDB mORMotSQLite3 class hierarchy Objects implemented in the mORMotSQLite3 unit: Objects Description Page TSQLRestClientDB REST client with direct access to a SQLite3 database 962 TSQLRestServerDB REST server with direct access to a SQLite3 database 960 TSQLTableDB Execute a SQL statement in the local SQLite3 database engine.Rev.18 Date: June 16. licensed under a MPL/GPL/LGPL tri-license.34.18 715 SynCommons Common functions used by most Synopse projects .5 engine version) . mORMotSQLite3.18 647 SynZip Low-level access to ZLib compression (1.this unit is a part of the freeware Synopse mORMot framework. licensed under a MPL/GPL/LGPL tri-license. licensed under a MPL/GPL/LGPL tri-license.2.this unit is a part of the freeware Synopse mORMot framework. 2013 23. version 1.pas unit Purpose: SQLite3 embedded Database engine used as the mORMot SQL kernel .this unit is a part of the freeware Synopse framework. virtual. const aPassword: RawUTF8='').18 Date: June 16.it will then call the other overloaded constructor to initialize the server destructor Destroy. and init TSQLTable fields . Expand: boolean). Initialize a REST server with a database . and get result in memory . aHandleUserAuthentication: boolean=false). const Tables: array of TSQLRecordClass. 1. Execute a SQL statement. 2013 Objects Description Page TSQLVirtualTableModul eServerDB Define a Virtual Table module for a TSQLRestServerDB SQLite3 engine 964 TSQLVirtualTableModul eSQLite3 Define a Virtual Table module for a stand-alone SQLite3 engine 963 TSQLTableDB = class(TSQLTableJSON) Execute a SQL statement in the local SQLite3 database engine. aDB: TSQLDataBase.if specified.caching is handled at TSQLDatabase level .SQL statements for record retrieval from ID are prepared for speed Used for DI-2. reintroduce.Synopse mORMot Framework Software Architecture Design 1. aHandleUserAuthentication: boolean=false. not the wal file during run) .the BLOB data is converted into TEXT: you have to retrieve it with a special request explicitely (note that JSON format returns BLOB data) .uses a TSQLTableJSON internaly: faster than sqlite3_get_table() (less memory allocation/fragmentation) and allows efficient caching constructor Create(aDB: TSQLDatabase.pas unit .any needed TSQLVirtualTable class should have been already registered via the RegisterVirtualTableModule() method constructor Create(aModel: TSQLModel. and free it on Destroy . the password will be used to cypher this file on disk (the main SQLite3 database file is encrypted. and allows efficient caching .FieldCount=0 if no result is returned . override. Initialize a REST server with a database.18 Page 960 of 1055 .will raise an ESQLException on any error TSQLRestServerDB = class(TSQLRestServer) REST server with direct access to a SQLite3 database .1 (page 1052).2. by specifying its filename .Rev. Close database and free used memory mORMotSQLite3. const aDBFileName: TFileName. and uses less memory . overload.uses a TSQLTableJSON internaly: all currency is transformed to its floating point TEXT representation. overload. it's retrieved from its cached value: our JSON parsing is a lot faster than SQLite3 engine itself.all DATA (even the BLOB fields) is converted into UTF-8 TEXT .TSQLRestServerDB will initialize a owned TSQLDataBase.if the SQL statement is in the DB cache. constructor Create(aModel: TSQLModel. const aSQL: RawUTF8. then reopened function RetrieveBlobFields(Value: TSQLRecord): boolean.return true if no transaction is active.write all pending SQL statements to the disk mORMotSQLite3. Begin a transaction (implements REST BEGIN Member) .to be used to speed up some SQL statements like Insert/Update/Delete . VACCUUMed.gz compressed file . then reopened function RestoreGZ(const BackupFileName: TFileName): boolean.18 Date: June 16.must be aborted with Rollback if any SQL statement failed . override.Synopse mORMot Framework Software Architecture Design 1. source DB file is replaced by the supplied content. copied. Backup of the opened Database into a . End a transaction (implements REST END Member) . override.18 Page 961 of 1055 .database is closed.this method doesn't use the experimental SQLite Online Backup API (which restart the backup process on any write: so no good performance could be achieved on a working database: this method uses a faster lock + copy approach) .Rev. which is very fast. 1. SessionID: cardinal=1): boolean. Backup of the opened Database into an external stream (e. false otherwize function UpdateBlobFields(Value: TSQLRecord): boolean. source DB file is replaced by the supplied content. from a .default compression level is 2. in one SQL statement procedure Commit(SessionID: cardinal=1). VACCUUMed.database is closed. then reopened function BackupGZ(const DestFileName: TFileName. and good enough for a database file content: you may change it into the default 6 level function EngineExecuteAll(const aSQL: RawUTF8): boolean. a file. compressed into .database is closed. then reopened .it will update all BLOB fields at once. override. override.gz compressed file . CompressionLevel: integer=2): boolean. Overriden method for direct SQLite3 database engine call .must be ended with Commit on success . in one SQL statement function TransactionBegin(aTable: TSQLRecordClass. Restore a database content on the fly . Overriden method for direct SQLite3 database engine call .g. 2013 function Backup(Dest: TStream): boolean.gz file. override.pas unit . compressed or not) . Restore a database content on the fly.it will retrieve all BLOB fields at once. Overriden method for direct SQLite3 database engine call function Restore(const ContentToRestore: RawByteString): boolean.database is closed. if the TSQLRecord definition has been modified. overload. virtual.pas unit .18 Page 962 of 1055 .restore the previous state of the database.1 (page 1052).g. 2013 procedure CreateMissingTables(user_version: cardinal=0).18 Date: June 16. before the call to TransactionBegin property DB: TSQLDataBase read fDB.CacheFlush method procedure InitializeEngine.RegisterSQLFunction() procedure RollBack(SessionID: cardinal=1).you must call explicitely this before having called StaticDataCreate() . 1. you must create a new TSQLRecord type) procedure FlushInternalDBCache. but will access directly to the server mORMotSQLite3. Call this method when the internal DB content is known to be invalid . Initialize the associated DB connection .all table description (even Unique feature) is retrieved from the Model .this method also create additional fields.you can override this method to call e.this overriden implementation will call TSQLDataBase.DBOpen .a hidden TSQLRestServerDB server is created and called internaly Used for DI-2. all REST/CRUD requests and direct SQL statements are scanned and identified as potentially able to change the internal SQL/JSON cache used at SQLite3 database level. Missing tables are created if they don't exist yet for every TSQLRecord class of the Database Model . Abort a transaction (implements REST ABORT Member) .2.will register all *_in() functions for available TSQLRecordRTree . DB.g.Synopse mORMot Framework Software Architecture Design 1. override. TSQLRestServerStaticExternal classes defined in SQLite3DB) could flush the database content without proper notification .called by Create and on Backup/Restore just after DB. for an existing TSQLRestServerDB .Rev.by default.will register all modules for available TSQLRecordVirtualTable*ID with already registered modules via RegisterVirtualTableModule() . but some virtual tables (e.the client TSQLModel will be cloned from the server's one . reintroduce. Initialize the class. constructor Create(aRunningServer: TSQLRestServerDB). only field adding is available. override.the TSQLRestServerDB and TSQLDatabase instances won't be managed by the client. Associated database TSQLRestClientDB = class(TSQLRestClientURI) REST client with direct access to a SQLite3 database . field renaming or field deleting are not allowed in the FrameWork (in such cases. override. Retrieve the file name to be used for a specific Virtual Table . aServerClass: TSQLRestServerDBClass. from a SQLite3 filename specified .an internal TSQLDataBase will be created internaly and freed on Destroy . not the wal file during run) constructor Create(aClientModel.aServerClass could be TSQLRestServerDB by default . which is very fast property DB: TSQLDataBase read getDB. without any URI() call. aServerModel: TSQLModel.18 Page 963 of 1055 . aServerModel: TSQLModel. overload.this overriden method call directly the database to get its result. const SQLSelect: RawUTF8 = 'ID'.Synopse mORMot Framework Software Architecture Design 1. Same as above.if specified. override. const SQLWhere: RawUTF8 = ''): TSQLTableJSON. override. 2013 constructor Create(aClientModel. Release the server function List(const Tables: array of TSQLRecordClass. reintroduce. and creates an internal TSQLRestServerDB to internaly answer to the REST queries .overriden method returning a file located in the DB file folder. override. Retrieve a list of members as a TSQLTable (implements REST GET Collection) . and '' if the main DB was created as ':memory:' (so no file should be written) .it's not needed to free this instance: it will be destroyed by the SQLite3 engine together with the DB connection function FileName(const aTableName: RawUTF8): TFileName.of course. even if the DB is created as ':memory:' mORMotSQLite3. 1. if a custom FilePath property value is specified. aDB: TSQLDataBase. it will be used.other TSQLRestClientDB methods use URI() function and JSON conversion of only one record properties values. the password will be used to cypher this file on disk (the main SQLite3 database file is encrypted. overload. const aDBFileName: TFileName.pas unit . aHandleUserAuthentication: boolean=false). reintroduce.Rev. Initializes the class. aServerClass: TSQLRestServerDBClass.18 Date: June 16. Associated database property Server: TSQLRestServerDB read fServer.aServerClass could be TSQLRestServerDB by default destructor Destroy. but with use of DB JSON cache if available . Associated Server TSQLVirtualTableModuleSQLite3 = class(TSQLVirtualTableModule) Define a Virtual Table module for a stand-alone SQLite3 engine . const aPassword: RawUTF8=''). aHandleUserAuthentication: boolean=false. will raise EBusinessLayerException if aDB is incorrect.returns the created TSQLVirtualTableModule instance (which will be a TSQLVirtualTableModuleSQLite3 instance in fact) .will call sqlite3_check() to raise the corresponding ESQLite3Exception .18 Date: June 16. Clean class instance memory .will raise an exception of failure mORMotSQLite3.in case of success (no exception).. Register the Virtual Table to the database connection of a TSQLRestServerDB server . an excepton will be raised destructor Destroy.Synopse mORMot Framework Software Architecture Design 1. but in case of error (an exception is raised).pas unit . aServer: TSQLRestServer). 2013 procedure Attach(aDB: TSQLDataBase).g. Initialize the module for a given DB connection .Rev.internally set fModule and call sqlite3_create_module_v2(fModule) .except and free the TSQLVirtualTableModuleSQLite3 instance property DB: TSQLDataBase read fDB. e. Initialize a Virtual Table Module for a specified database .in case of an error. or SetDB() has already been called for this module .to be used for low-level access to a virtual module.when using our ORM. it is up to the caller to intercept it via a try. The associated SQLite3 database connection TSQLVirtualTableModuleServerDB = class(TSQLVirtualTableModuleSQLite3) Define a Virtual Table module for a TSQLRestServerDB SQLite3 engine constructor Create(aClass: TSQLVirtualTableClass. aDatabase: TSQLDataBase): TSQLVirtualTableModule. with TSQLVirtualTableLog . override. you should call TSQLModel.especially the link to TSQLRestServerDB Functions or procedures implemented in the mORMotSQLite3 unit: Functions or procedures Description Page RegisterVirtualTableM odule Initialize a Virtual Table Module for a specified database 964 VarDataFromValue Set a SQLite3 value into a TVarData 965 VarDataToContext Set a TVarData into a SQlite3 result context 965 function RegisterVirtualTableModule(aModule: TSQLVirtualTableClass. override.18 Page 964 of 1055 . 1. the SQLite3 engine will release the module by itself.VirtualTableRegister() instead to associate a TSQLRecordVirtual class to a module . only a way of data sharing e.g.only handle varNull.will call the corresponding sqlite3_value_*() function to retrieve the data with the less overhead (e.18 Page 965 of 1055 . and varAny (BLOB with size = VLongs[0]) types in TVarData . 1. Set a TVarData into a SQlite3 result context . Set a SQLite3 value into a TVarData . memory allocation or copy) as possible function VarDataToContext(Context: TSQLite3FunctionContext. const Res: TVarData): boolean.Column method . var Res: TVarData).Synopse mORMot Framework Software Architecture Design 1. varDouble.will call the corresponding sqlite3_result_*() function and return true. varInt64. and varAny (BLOB with size = VLongs[0]) types in TVarData . for the TSQLVirtualTableCursor.Insert or Update methods .g.only handle varNull.Rev.therefore it's not a true Variant typecast. varInt64. or will return false if the TVarData type is not handled mORMotSQLite3. varString (mapping a constant PUTF8Char). 2013 procedure VarDataFromValue(Value: TSQLite3Value. varString (mapping a constant PUTF8Char).g. only a way of data sharing e.pas unit .18 Date: June 16. for the TSQLVirtualTable.therefore it's not a true Variant typecast. varDouble. this unit is a part of the freeware Synopse framework. licensed under a MPL/GPL/LGPL tri-license.18 934 mORMotUI Grid to display database content for mORMot .1. version 1.18 700 mORMotToolBar.this unit is a part of the freeware Synopse mORMot framework.18 576 SynTaskDialog Implement TaskDialog window (native on Vista/Seven.18 993 SynCommons Common functions used by most Synopse projects .this unit is a part of the freeware mORMot framework.18 Page 966 of 1055 . version 1.adds GIF.18 715 mORMoti18n Internationalization (i18n) routines and classes for mORMot .this unit is a part of the freeware Synopse framework. licensed under a MPL/GPL/LGPL tri-license. version 1.make available most useful GDI+ drawing methods .18 325 SynGdiPlus GDI+ library API access .18 The mORMotToolBar unit is quoted in the following items: SWRS # Description Page DI-2.this unit is a part of the freeware Synopse mORMot framework. version 1. licensed under a MPL/GPL/LGPL tri-license.2 RTTI generated Toolbars 1054 Units used in the mORMotToolBar unit: Unit Name Description Page mORMot Common ORM and SOA classes for mORMot .pas unit . 2013 23.this unit is a part of the freeware Synopse mORMot framework.18 924 mORMotReport Reporting unit .18 Date: June 16. emulated on XP) .35.pas unit Purpose: ORM-driven Office 2007 Toolbar for mORMot . version 1.3. PNG and JPG pictures read/write support as standard TGraphic .this unit is a part of the freeware Synopse mORMot framework. licensed under a MPL/GPL/LGPL tri-license.1 Database Grid Display 1053 DI-2. version 1.Synopse mORMot Framework Software Architecture Design 1.1. version 1.18 980 mORMotUILogin Some common User Interface functions and dialogs for mORMot . licensed under a MPL/GPL/LGPL tri-license. licensed under a MPL/GPL/LGPL tri-license.this unit is a part of the freeware Synopse mORMot framework. licensed under a MPL/GPL/LGPL tri-license.this unit is a part of the freeware Synopse mORMot framework. TIF.3.allows Antialiased rending of any EMF file using GDI+ . 1. version 1. licensed under a MPL/GPL/LGPL tri-license. version 1. mORMotToolBar. licensed under a MPL/GPL/LGPL tri-license.Rev. 18 Page 967 of 1055 . used for handling toolbar buttons of actions to be performed on a TSQLRecordClass list 969 TSQLRibbon Store some variables common to all pages. for the whole ribbon 974 TSQLRibbonTab Store the UI elements and data. 1.Synopse mORMot Framework Software Architecture Design 1. which will contain some toolbars for a TSQLRecord class 968 TSynPager The ribbon pager. version 1.2. 2013 Unit Name Description Page SynZip Low-level access to ZLib compression (1. corresponding to one action 968 mORMotToolBar.18 Date: June 16.5 engine version) . one per each Table 972 TSynPage A Ribbon page.pas unit . i. according to an enumeration of actions 972 TSQLLister A hidden component. licensed under a MPL/GPL/LGPL tri-license.18 707 TComponent TSQLLister TSQLRibbonTab TSQLRibbon TObject TSQLCustomToolBar TFreeShortCut TPageControl TSynPager TTabSheet TSynPage TToolBar TSynToolBar TToolButton TSynToolButton mORMotToolBar class hierarchy Objects implemented in the mORMotToolBar unit: Objects Description Page TFreeShortCut A simple object to get one char shortcuts from caption value 968 TSQLCustomToolBar Create one or more toolbars in a ribbon page. which will contain one page per TSQLRecord class 969 TSynToolBar A toolbar on a Ribbon page 968 TSynToolButton A button on the Ribbon toolbars.e.Rev.this unit is a part of the freeware Synopse framework. from 'A' to 'Z' function FindFreeShortCut(const aCaption: string): string. ActionHints: string. from a Caption: try every character of aCaption.18 Date: June 16.18 Page 968 of 1055 . Display drop down menu TSynToolBar = class(TToolBar) A toolbar on a Ribbon page function CreateToolButton(ButtonClick: TNotifyEvent. 2013 TFreeShortCut = object(TObject) A simple object to get one char shortcuts from caption value Values: TFreeShortCutSet. 1. ButtonWidth: integer. const ActionName. which will contain some toolbars for a TSQLRecord class function CreateToolBar(AddToList: boolean=true): TSynToolBar. Attempt to create free shortcut of one char length. corresponding to one action constructor Create(aOwner: TComponent).then call TSynToolBar. iAction.e. Images: TCustomImageList): TSynToolButton.it will create the captions under the toolbars . from left to right .Synopse mORMot Framework Software Architecture Design 1. Number of TSynToolBar in the page list property ToolBars[aIndex: integer]: TSynToolBar read GetToolBar.Rev.Images procedure DoDropDown.can be call multiple times. Add a TSynToolBar to the page list . Bit set for already used short cut. Access to the TSynToolBar list of this page mORMotToolBar. override.CreateToolButton to add some buttons procedure ToolBarCreated. var ShortCutUsed: TFreeShortCut.returns '' if no shortcut calculation was possible TSynToolButton = class(TToolButton) A button on the Ribbon toolbars. Create a button on the toolbar TSynPage = class(TTabSheet) A Ribbon page. ImageListFirstIndex: integer. This class will have AutoSize set to true function Images: TCustomImageList. i. TToolBar(Owner). when a toolbar has been added and filled will all its buttons property ToolBarCount: integer read GetToolBarCount. Call this event when all toolbars have been created .pas unit . The associated image list. Publish this property. e. mORMotToolBar. used for handling toolbar buttons of actions to be performed on a TSQLRecordClass list Used for DI-2.pas unit . i. overload. caption and buttons property TopPanel: TPanel read fTopPanel. TabIndexEnd: integer. The label on TopMostPanel.2 (page 1054). which will contain one page per TSQLRecord class function AddPage(const aCaption: string): integer.e. so that FormNoCaption method can be called later function TabGroupsAdd(TabIndexStart. const aCaption: string): TLabel.Rev.18 Page 969 of 1055 .NoCaption property HelpButton: TSynToolButton read GetHelpButton.Pages property property TopMostPanel: TPanel read fTopMostPanel. containing groups.1 (page 1053). the TSynForm(Owner). The panel containing this TSynPager TSQLLister = class(TComponent) A hidden component. caption and min/max/close buttons. The panel added above the pager. Mimic TTabSheet. to close a tab by a double click property Pages[aIndex: Integer]: TSynPage read GetSynPage.g. 1. NoTabVisible: boolean=false): TSynPager.3. Create the ribbon pager on a form . The help button to be available on the ribbon property OnDblClick.3.18 Date: June 16.Synopse mORMot Framework Software Architecture Design 1. Force OnChange event to be triggered property Caption: TLabel read GetCaption. Add a page instance class function CreatePager(aOwner: TCustomForm.1. 2013 TSynPager = class(TPageControl) The ribbon pager. overload. DI-2. Hide TSynForm caption bar and put caption and buttons at groups right property ActivePageIndex: integer read GetActivePageIndex write SetActivePageIndex.reserve some above space for groups.1. Create a group label starting for the given page indexes procedure FormNoCaption. Create a new page with the specified caption function AddPage(aPage: TSynPage): integer. aOnButtonClick is called with a specified action if a button is clicked. reintroduce. aOnValueText: TValueTextEvent.1.pas unit . Initialize the lister for a specified Client and Class .a single page is used for a list of records. Find associate popup Menu item for an action class function FindPage(aOwner: TSynPager. aHideDisabledButtons: boolean=false. aClass: TSQLRecordClass. Same as above. a default one is created retrieving a list of records with aGridSelect about the aClass Table from aClient. overload.aImageList16: TImageList.Rev. aHeaderCheckboxSelectsInsteadOfSort: boolean).the TSynPage tag property contains integer(aClass) mORMotToolBar.1. with the ID column hidden (no TSQLTableToGrid will be created if aGridSelect is '') . const CustomCaption: string.18 Date: June 16. 2013 constructor Create(aOwner: TComponent. aOnValueText: TValueTextEvent. Add a page (if not already) for a corresponding TSQLRecordClass .18 Page 970 of 1055 . aTable: TSQLTable. aOnButtonClick: TSQLListerEvent.aImageList16: TImageList.a single page can share multiple toolbars . aImageList32. aIDColumnHide: boolean. const aGridSelect: RawUTF8= '*'. Retrieve the page index from a TSQLRecordClass . aClass: TSQLRecordClass. but with a specified TSQLTable Used for DI-2. reintroduce.1 (page 1053). aClass: TSQLRecordClass): integer. or '' if not existing class function AddPage(aOwner: TSynPager. aPager: TSynPager.SQLTableName) or taken directly from CustomCaption if a value is specified (with translation if CustomCaptionTranslate is set) function FindButton(ActionIndex: integer): TSynToolButton. aGrid: TDrawGrid.Synopse mORMot Framework Software Architecture Design 1. aPager: TSynPager. specified by their unique class . aOnButtonClick: TSQLListerEvent. aClient: TSQLRestClientURI.1 (page 1053).the possible actions are retrieved from the Client TSQLModel . aHeaderCheckboxSelectsInsteadOfSort: Boolean=false).3. Find associate Button for an action function FindMenuItem(ActionIndex: integer): TMenuItem. 1.if aGrid has no associated TSQLTableToGrid. aIDColumnHide: boolean. constructor Create(aOwner: TComponent. CustomCaptionTranslate: boolean): TSynPage. aGrid: TDrawGrid. aImageList32. function ActionHint(const Action): string. Retrieve a ready to be displayed hint for a specified action . or with ActionValue=0 each time a row is selected Used for DI-2.returns the Hint caption of the corresponding button.both TImagelist will be used to display some images in Action buttons (32 pixels wide) and Popup Menu (16 pixels wide) .the TSynPage caption is expanded and translated from aClass with LoadResStringTranslate(aClass. aHideDisabledButtons. overload.3. aClass: TSQLRecordClass.the TSynPage tag property will contain integer(aClass) . aClient: TSQLRestClientURI. Create a sub menu item to both button and menu item for an action . and add it to a menu function SetToolBar(const aToolBarName: string. Tag: integer=0. The Popup Menu.18 Page 971 of 1055 .with respect to the Toolbar theming property ActionHints: string read fActionHints write fActionHints.if aCaption is ''. itemEnabled: boolean=true): TMenuItem. TImagelist used to display some images in Action buttons property ImageList32: TImageList read fImageList32.Model.SetActions(TypeInfo(. Can be used by any TSQLTableToGrid .. TImagelist used to display some images in Action buttons property Menu: TSynPopupMenu read fMenu. State: TGridDrawState).must be set before SetToolBar() method call . Add or update a ToolBar with a specific actions set . itemEnabled: boolean=true). The associated Page on the Office 2007 menu property RecordClass: TSQLRecordClass read fClass. OnClick: TNotifyEvent. Rect: TRect.aActions must point to a set of enumerates. displayed with the Grid property Page: TSynPage read fPage. the status of its Action buttons is enabled or disabled according to the actions set . The associated record class mORMotToolBar. as defined by Client.first call once this procedure to create the toolbar buttons. ActionIndex: integer. ImageIndex: integer=-1.Synopse mORMot Framework Software Architecture Design 1.Rev.if the ToolBar is already existing. The associated Grid display property ImageList16: TImageList read fImageList16. 2013 function NewMenuItem(Menu: TPopupMenu.one action (starting with actMark) each line property Client: TSQLRestClient read fClient. const aActions.pas unit . const aCaption: string. The associated Client property Grid: TDrawGrid read fGrid. ACol.a single page can share multiple toolbars.)) . Create a menu item. then call it again to update the enable/disable status of the buttons procedure CreateSubMenuItem(const aCaption: string. erase any previous menu procedure OnDrawCellBackground(Sender: TObject.18 Date: June 16. The Hints captions to be displayed on the screen . ActionIsNotButton: pointer): TSynToolBar.to draw marked rows with a highlighted color . ImageIndex: integer=-1. 1. ARow: Longint. OnClick: TNotifyEvent=nil. which caption name must be identical between calls for geniune buttons . SubMenu: TMenuItem=nil. CurrentRecord: TSQLRecord.Rev.SetToolBar() .call with aCaption void to clear the menu first .1. const aActionHints: string. aImageList: TImageList. The associated TSQLTableToGrid hidden component TSQLCustomToolBar = object(TObject) Create one or more toolbars in a ribbon page.to be used for custom forms (e. a new page is created and added to this TSynPager.1. with appropriate bits set for its buttons function CreateSubMenuItem(aButtonIndex: integer.18 Date: June 16.18 Page 972 of 1055 .3. 2013 property ReportDetailedIndex: integer read fReportDetailedIndex.if aToolbarOrPage is a TSynPage descendant. aTag: integer=0): TMenuItem.2 (page 1054). The frame containing associated Details.if aToolbarOrPage is a TCustomForm.Synopse mORMot Framework Software Architecture Design 1. aOnClick: TNotifyEvent.then call it for every menu entry procedure Init(aToolbarOrPage: TControl.use a similar layout and logic as TSQLLister. TSQLRibbonTab = class(TObject) Store the UI elements and data. Set to to a "Details" level.3.g. aImageListFirstIndex: integer=0).pas unit .3. 1. and used for toolbars adding . const aCaption: string. The frame containing associated the List.set to the Action index which is currently available property TableToGrid: TSQLTableToGrid read fTableToGrid. aEnum: PTypeInfo. preview or edit) or to add some custom buttons to a previously created one by TSQLLister. Create a popup menu item for a button .simply set the associated objects via the Init() method. the toolbar is added to this specified Page Used for DI-2.2 (page 1054). one per each Table Used for DI-2. left side of the Page FrameRight: TFrame. A current record value FrameLeft: TFrame. ActionsBits: pointer=nil. Call this method for every toobar. according to an enumeration of actions .SetToolBar() method above . this form will became a . function AddToolBar(const ToolBarName: string.2 (page 1054). Call this method first to initialize the ribbon . right side to the list mORMotToolBar.if aToolbarOrPage is a TSynPager descendant. according to the bsCheck button pushed .1. then call AddToolBar() for every toolbar which need to be created Used for DI-2. aButtonClick: TNotifyEvent. ButtonWidth: integer=60): TSynToolBar. ActionIsNotButton: pointer.aImageList16: TImageList. To provide the List with data from Client ViewToolBar: TSynToolBar. override. const aTabParameters: TSQLRibbonTabParameters.populate this page with available Toolbars . To associate Class.populate all Toolbars with action Buttons destructor Destroy. Ribbon and Toolbars Page: TSynBodyPage. Body: TSynBodyPager. Client: TSQLRestClientURI. Associated TSQLRecord index in database Model TableToGrid: TSQLTableToGrid.NoReport is false Tab: TSynPage. Create all the UI elements for a specific Table/Class .18 Date: June 16.Rev.exists if aTabParameters. ViewToolbarIndex: integer. aOnValueText: TValueTextEvent. 1.pas unit . Release associated memory mORMotToolBar. Allows List resizing List: TDrawGrid. to display the page . Associated table list Lister: TSQLLister. Actions. Associate Tab in the Ribbon Table: TSQLRecordClass.Synopse mORMot Framework Software Architecture Design 1. The "View" toolbar on the associated Ribbon Tab constructor Create(ToolBar: TSynPager. SetAction: TSQLRibbonSetActionEvent. Associated TSQLRecord TableIndex: integer. ActionsHintCaption: string. const ActionsTBCaptionCSV. var aPagesShortCuts: TFreeShortCut. 2013 FrameSplit: TSplitter. The associated Report. Associated Tab settings used to create this Ribbon Tab Report: TGDIPages. aUserRights: TSQLFieldBits. Associate Client Body Page Parameters: PSQLRibbonTabParameters. aHeaderCheckboxSelectsInsteadOfSort: boolean). aOnActionClick: TSQLListerEvent. aHideDisabledButtons.18 Page 973 of 1055 .Layout is not llClient. aImageList32.create a new page for this Table/Class . and if aTabParameters. ParamsEnum: PTypeInfo.return 101 if "Apply to Marked" was choosen . Retrieve the current selected ID of the grid .caller must supply an array of boolean pointers to reflect the checked state of every popup menu item entry procedure ReportClick(Sender: TObject). aTitle: string. ARow: integer.e. i. ParamsEnabled: pointer. Ask the User where to perform an Action .18 Page 974 of 1055 . Page: array of TSQLRibbonTab. OnClick: TNotifyEvent).2 (page 1054). and a custom enumeration type together with its (bit-oriented) values for the current Ribbon Tab . 1. for the whole ribbon Used for DI-2. Client: TSQLRest.18 Date: June 16. ForUpdate: boolean=false): boolean. 2013 function AskForAction(const ActionCaption.return 100 if "Apply to Selected" was choosen .3. const Values: array of PBoolean).return any other value if Cancel or No was choosen function Retrieve(Client: TSQLRestClient.returns 0 if no row is selected property ReportPopupParamsEnabled: pointer read FReportPopupParamsEnabled. The pages array ShortCuts: TFreeShortCut. Store the keyboard shortcuts for the whole ribbon mORMotToolBar. Trigerred when a report popup menu item is clicked property CurrentID: integer read GetCurrentID. Add the report options to the specified menu procedure CustomReportPopupMenu(OnClick: TNotifyEvent.this method expect two standard handlers.Rev. Retrieve CurrentRecord from server procedure AddReportPopupMenuOptions(Menu: TPopupMenu.Synopse mORMot Framework Software Architecture Design 1. Used to customize the popup menu of the associated Report . ReturnMarkedIfSomeMarked: boolean): integer. DontAskIfOneRow. Pointers to every popup meu items data TSQLRibbon = class(TObject) Store some variables common to all pages.pas unit .1. Pointer to the set of available popup menu parameters for this report property ReportPopupValues: TPBooleanDynArray read FReportPopupValues. aImageList32.2 (page 1054). or even worse marketing's know-how . TabParameters: PSQLRibbonTabParameters.useful to customize the Ribbon layout. OnCaptionName: TOnCaptionName=nil. CSVFieldNames: PUTF8Char=nil. if automatic generation from RTTI don't fit exactly your needs. all main fields are displayed. aHideDisabledButtons: boolean. aActionIndex: integer): TSynToolButton. WithTitle: Boolean.3.pdf) and plain text (. 2013 constructor Create(Owner: TCustomForm.retrieve the main Caption of this record (e.by default. const ActionHint: string.most parameters are sent back to the SQLRibbonTab.returns TRUE if deletion was successful. Generic method which delete either the current selected entry.Rev.display the save dialog before . but caller can specify custom field names as Comma-Separated-Values . OpenAfterCreation: boolean=true): TFileName. const ActionsTBCaptionCSV.returns nil if no page is currently selected mORMotToolBar. Retrieve the reference of a given button of the ribbon . const ActionHint: string): Boolean. aUserRights: TSQLFieldBits. Release associated memory function AddToReport(aReport: TGDIPages. const GroupCSV: string. ColWidthValue: integer=60): string. TabParametersSize: integer.if BackgroundPictureResourceNameCSV is set. aOnActionClick: TSQLListerEvent. aOnValueText: TValueTextEvent. ViewToolbarIndex: integer.called by SetButtonHint method function GetActivePage: TSQLRibbonTab. reintroduce.by default.this constructor must be called in the Owner. ActionsHintCaption: string. either all marked entries .g. the report is created by using the CreateReport method function FindButton(aTable: TSQLRecordClass. or FALSE if any error occured function ExportRecord(aTable: TSQLRecordClass. CSVFieldNameToHide: PUTF8Char=nil.) .18 Page 975 of 1055 . overload. Client: TSQLRestClientURI. Generic method which export the supplied record . aRecord: TSQLRecord. const BackgroundPictureResourceNameCSV: string=''.pas unit . the "Name" field value) function DeleteMarkedEntries(aTable: TSQLRecordClass. ToolBar: TSynPager.aImageList16: TImageList. aHeaderCheckboxSelectsInsteadOfSort: boolean=false). or '' if any error occured .Create constructor . virtual.18 Date: June 16. PagesCount: integer. RefreshActionIndex. the corresponding background pictures will be extracted from resources and displayed behind the ribbon toolbar. 1. override.Synopse mORMot Framework Software Architecture Design 1. destructor Destroy. ActionIsNotButton: pointer. SetAction: TSQLRibbonSetActionEvent. Retrieve the current TSQLRibbonTab instance on the screen .1.returns the exported file name if export was successful. according to the group Used for DI-2. Initialize the Pages properties for this ribbon . aID: integer. ColWidthName: Integer=40.only two formats are available here: Acrobat (. Add the specified fields content to the report .OnCreate handler (not in OnShow) .txt) . Body: TSynBodyPager. Make a specified record available to the UI . overload. ActionToPerform: integer=0).18 Page 976 of 1055 . Handle a ribbon button press . out Tab: TSQLRibbonTab): boolean. Retrieve the TSQLRibbonTabParameters associated to a Ribbon tab. virtual. overload. Table: TSQLTable.returns TRUE if a Refresh command has been processed (caller should exit) and a refresh timer command has been set .returns nil if the specified table is not valid function MarkedEntriesToReport(aTable: TSQLRecordClass. const ColWidths: array of integer.EditFieldNameToHideCSV value procedure GotoRecord(aRecord: TSQLRecord. Make a specified record available to the UI . the corresponding action is launched mORMotToolBar.Rev. the corresponding action is launched procedure GotoRecord(aTable: TSQLRecordClass.the report must be created from the Page[aPageIndex]. Add the specified database Table Content to the report .returns FALSE if the caller must handle the action procedure AddToReport(aReport: TGDIPages. Resize the lists according to the body size procedure CreateReport(aPageIndex: Integer).select tab and record index . ActionValue: integer. their values are caculated from the Table content columns procedure BodyResize(Sender: TObject).18 Date: June 16. Get the the TSQLRibbonTabParameters associated to a Ribbon tab. AlreadyBegan: boolean=false). overload.Synopse mORMot Framework Software Architecture Design 1.select tab and record index . aReport: TGDIPages. overload. 1. overload.returns nil if the specified page index is not valid function GetParameter(aTable: TSQLRecordClass): PSQLRibbonTabParameters. from its table .pas unit .this default method create a report with the content of all fields. Generic method which print the all marked entries of the supplied table function RefreshClickHandled(Sender: TObject. from its index . Create a report for the specified page index . aRep: TGDIPages=nil): TGDIPages. aID: integer. overload.if ActionToPerform is set. aID: integer.if ColWidths are not specified (that is set to []).CurrentRecord record content . const ColWidths: array of integer). RecordClass: TSQLRecordClass.if ActionToPerform is set.call the CreateReport virtual method procedure CreateReport(aTable: TSQLRecordClass.returns -1 if this page was not found function GetParameter(aPageIndex: Integer): PSQLRibbonTabParameters. ActionToPerform: integer=0). Retrieve the index of a given Pages[] . overload. 2013 function GetPage(aRecordClass: TSQLRecordClass): integer. Create a report for the specified page index . except those listed in the corrresponding TSQLRibbonTabParameters. Used to store the options status TSQLListerEvent = procedure(Sender: TObject. This event is called when a button is pressed TSQLRibbonSetActionEvent = function(TabIndex.e. Refresh the specified page content . records list and report) on the Form property Client: TSQLRestClientURI read fClient write fClient.will refresh the screen as necessary property Body: TSynBodyPager read fBody. 2013 procedure Refresh(aTable: TSQLRecordClass=nil). Event used to customize screen text of property names TPBooleanDynArray = array of PBoolean.will free GDI resources and unneeded memory procedure WMRefreshTimer(var Msg: TWMTimer).will test the button is available (avoid any GPF error) procedure ToolBarChange(Sender: TObject). var A): string of object. The main Pager component used to display the main data (i. ToolbarIndex: integer. Must be called by the main form to handle any WM_TIMER message . The associated Client connection property Form: TCustomForm read fForm.Rev. aActionIndex: integer.18 Date: June 16. 1. The Toolbar component used to display the Ribbon on the Form Types implemented in the mORMotToolBar unit: TFreeShortCutSet = set of ord('A'). Index: integer=-1): string of object.ord('Z').calls internaly RefreshClickHandled method procedure SetButtonHint(aTable: TSQLRecordClass. const aHint: string).Synopse mORMot Framework Software Architecture Design 1.18 Page 977 of 1055 . The associated Form on scren property ReportAutoFocus: boolean read fReportAutoFocus write fReportAutoFocus. Obj: TObject=nil. Customize the Hint property of any button . Used to mark which shortcut keys have already been affected TOnCaptionName = function(const Action: RawUTF8. Trigger this event when a page changed on screen . with TestEnabled=false mORMotToolBar. the right-sided report is focused instead of the left-sided records list property ToolBar: TSynPager read fToolBar. TestEnabled: boolean. const RecordClass: TSQLRecordClass. This event provide the action values for a specified toolbar . refresh the current page content .pas unit .first call is to test the action presence.. ActionValue: integer) of object.by default. If set to TRUE. Retrieve the ready to be displayed text of the given property mORMotToolBar. 2013 .18 Date: June 16. Obj: TObject=nil. 1. Icon: HIcon): integer. with TestEnabled=true . or '' TSynBodyPage = TSynPage.pas unit . Index: integer=-1): string. should return any customized toolbar caption name.this form will have a button in the TaskBar .Synopse mORMot Framework Software Architecture Design 1.jpg file embedded as a resource to the executable 979 LoadImageListFromBitm ap Load TImageList bitmaps from a TBitmap 979 LoadImageListFromEmbe ddedZip Load TImageList bitmaps from an .return the newly created index in the image list . A popup menu to be displayed Functions or procedures implemented in the mORMotToolBar unit: Functions or procedures Description Page AddIconToImageList Add an Icon to the supplied TImageList 978 CaptionName Retrieve the ready to be displayed text of the given property 978 CreateReportWithIcons Create a report containing all icons for a given action enumeration 979 ImageListStretch Fill a TImageList from the content of another TImageList 979 LoadBitmapFromResourc e Load a bitmap from a .the HIcon handle is destroyed before returning function CaptionName(OnCaptionName: TOnCaptionName.second call is to test the action enable/disable state.zip archive embedded as a ZIP resource 979 NewDrawCellBackground Draw the cell of a TDrawGrid according to the current Theming of TabAppearance 979 function AddIconToImageList(ImgList: TCustomImageList.Rev. Add an Icon to the supplied TImageList .18 Page 978 of 1055 .a special call is made with ToolBarIndex=-1. in which A should be filled with the marking actions . const Action: RawUTF8. Body page used to display the list and the report on the client screen TSynBodyPager = TSynPager.png/.this form will hide the default Delphi application virtual form TSynPopupMenu = TPopupMenu. Body pager used to display the list and the report on the client screen TSynForm = TVistaForm.in all cases. A Vista-enabled TForm descendant . Load TImageList bitmaps from an . 1. Draw the cell of a TDrawGrid according to the current Theming of TabAppearance mORMotToolBar.jpg file embedded as a resource to the executable procedure LoadImageListFromBitmap(ImgList: TCustomImageList.Rev. ARow: Integer. Rect: TRect. BkColor: TColor=clSilver). for marketing or User Interface review purposes procedure ImageListStretch(ImgListSource.stretching use GDI+ so is smooth enough for popup menu display function LoadBitmapFromResource(const ResName: string): TBitmap. ImgListDest: TImageList. ImgList: TImageList. 2013 procedure CreateReportWithIcons(ParamsEnum: PTypeInfo. StartIndexAt: integer).warning Bmp content can be modified: it could be converted from multi-line (e. Create a report containing all icons for a given action enumeration . Hints: string. Load TImageList bitmaps from a TBitmap .Synopse mORMot Framework Software Architecture Design 1. Bmp: TBitmap).zip archive embedded as a ZIP resource procedure NewDrawCellBackground(Sender: TObject.g.18 Date: June 16. const ZipName: TFileName).18 Page 979 of 1055 .g. Fill a TImageList from the content of another TImageList . Marked: boolean). IDE export format) into one-line (as expected by TImageList.pas unit .AddMasked) procedure LoadImageListFromEmbeddedZip(ImgList: TCustomImageList. State: TGridDrawState.png/. const Title.useful e. Load a bitmap from a . ACol. this unit is a part of the freeware Synopse mORMot framework. licensed under a MPL/GPL/LGPL tri-license.18 Date: June 16.18 924 SynCommons Common functions used by most Synopse projects .18 715 mORMoti18n Internationalization (i18n) routines and classes for mORMot .pas unit Purpose: Grid to display database content for mORMot .1 Description Page Database Grid Display 1053 Units used in the mORMotUI unit: Unit Name Description Page mORMot Common ORM and SOA classes for mORMot .3.this unit is a part of the freeware mORMot framework. version 1.18 The mORMotUI unit is quoted in the following items: SWRS # DI-2. used for displaying a TSQLTable in a TDrawGrid 982 mORMotUI. 1. 2013 23.36.this unit is a part of the freeware Synopse mORMot framework.1. mORMotUI. licensed under a MPL/GPL/LGPL tri-license. licensed under a MPL/GPL/LGPL tri-license.18 Page 980 of 1055 .this unit is a part of the freeware Synopse mORMot framework.18 325 Exception ESynLabeledEdit TComponent TSQLTableToGrid TForm TVistaForm THintWindow THintWindowDelayed TLabeledEdit TSynLabeledEdit mORMotUI class hierarchy Objects implemented in the mORMotUI unit: Objects Description Page ESynLabeledEdit Exception class raised by TSynIntegerLabeledEdit 986 THintWindowDelayed A THintWindow descendant. version 1. version 1. version 1. licensed under a MPL/GPL/LGPL tri-license.Synopse mORMot Framework Software Architecture Design 1. with an internal delay to auto-hide 981 TSQLTableToGrid A hidden component.Rev.pas unit . FontColor: TColor. Unicode ready procedure ShowDelayedString(const Text: string.you can specify a time interval for the popup window to be hidden .Y.Time is the maximum text display delay.18 Page 981 of 1055 . Displays the appropriate Hint Text at a position relative to a control .if string is AnsiString (i. AData: Pointer): TRect. override.ShowHint) . AlignLeft: boolean=false).this component expects UTF-8 encoded text. and displays it as Unicode constructor Create(aOwner: TComponent). overload.Text is decoded from Ansi to Unicode (using the current i18n code page) before display . Initializes the component destructor Destroy.Synopse mORMot Framework Software Architecture Design 1. in milliseconds property Col: integer read fCol. overload.Text is decoded from UTF-8 to Unicode before display . 2013 Objects Description Page TSynLabeledEdit TLabeledEdit with optional boundaries check of a Variant value 986 TVistaForm Vista-enabled TForm descendant 987 THintWindowDelayed = class(THintWindow) A THintWindow descendant. override.Time: integer. AlignLeft: boolean=false). reintroduce.pas unit .Time is the maximum text display delay.Time: integer. AlignLeft: boolean=false). X.Text is decoded from UTF-8 to Unicode before display .Y. in milliseconds procedure ShowDelayedUTF8(const Text: RawUTF8.Time is the maximum text display delay. X. The column number when the hint is displayed mORMotUI.Time: integer. overload. Releases component resources and memory function CalcHintRect(MaxWidth: Integer. Overriden method.Y. Displays the appropriate Hint Text at a specified screen position . in milliseconds procedure ShowDelayedUTF8(const Text: RawUTF8. Origin: TControl. const AHint: RawUTF8. FontColor: TColor. AlignLeft: boolean=false). Origin: TControl. FontColor: TColor.Y. FontColor: TColor. with an internal delay to auto-hide . Displays the appropriate Hint Text at a specified screen position . in milliseconds procedure ShowDelayedString(const Text: string.Rev. Text is decoded into Unicode (using the current i18n code page) before display .Time: integer.Time is the maximum text display delay.this component can be used directly with the hint text to be displayed (companion to the controls Hint properties and Application. X.e.18 Date: June 16. X. for Delphi 2 to 2007). 1. overload. Displays the appropriate Hint Text at a position relative to a control . Rev. constructor Create(aOwner: TDrawGrid.Table) to initiate the association .18 Page 982 of 1055 . override. reintroduce.free the associated TSQLTable and its memory content . incremental key lookup. the Client is not used to retrieve the data.) . as VCL text . aClient: TSQLRestClientURI).will be called by any future TSQLTableToGrid. destructor Destroy. hide ID .return true if Table data has been successfully retrieved from Client and if data was refreshed because changed since last time . sftTimeLog.if ForceRefresh is TRUE. field sort. Client: TObject): string.1.Create(Grid. Force refresh paint of Grid from Table data .Synopse mORMot Framework Software Architecture Design 1.Create() association .18 Date: June 16. column size. 0 on error (no ID field e.pas unit . sftRecord and all other properties .usefull even if ID column was hidden with IDColumnHide mORMotUI. for sftEnumerate.will reset the Grid overriden events to avoid GPF function ExpandRowAsString(Row: integer. The row number when the hint is displayed TSQLTableToGrid = class(TComponent) A hidden component.just call TSQLTableToGrid. 1.handle unicode. Release the hidden object .will be called by the parent Grid when it is destroyed .1 (page 1053). Get the ID of the first selected row. Fill a TDrawGrid with the results contained in a TSQLTable Used for DI-2.3.Ctrl + click on a cell to display its full unicode content Used for DI-2.uses OnValueText property Event if defined by caller class function From(Grid: TDrawGrid): TSQLTableToGrid.g. aTable: TSQLTable. Read-only access to a particular row values.Create() will be overriden .the Table will be released when no longer necessary .Model is one TSQLModel instance (used to display TRecordReference) . Retrieve the associated TSQLTableToGrid from a specific TDrawGrid function GetMarkedBits: pointer.3. used for displaying a TSQLTable in a TDrawGrid . 2013 property Row: integer read fRow.any former association by TSQLTableToGrid. ready to be displayed via the VCL after translation. Retrieve the Marked[] bits array function Refresh(ForceRefresh: Boolean=false): boolean.1 (page 1053).1.returns the text as generic string. which must be already refreshed before this call function SelectedID: integer. var Key: Word. X. Y: Integer).warning: it's up to the caller to Free the created instance after use (you should e. Button: TMouseButton. Called by the owner TDrawGrid to draw a Cell from the TSQLTable data . X.used for LEFT/RIGHT ARROW column order change procedure DrawGridKeyPress(Sender: TObject. . State: TGridDrawState). ARow: Integer.Rev.check if the first (fixed) row is clicked: then change sort order .used for incremental key lookup procedure DrawGridMouseDown(Sender: TObject. Called by the owner TDrawGrid when the user presses a key . Button: TMouseButton. nil on error .Free... Rect: TRect.SelectedRecordCreate. embedd the process in a try. ARow: Longint. Y: Integer).record type is retrieved via Table. var CanSelect: Boolean). Shift: TShiftState. var Key: Char). Called by the owner TDrawGrid when the user presses a key . finally Rec.the first row (fixed) is drawn as field name (centered bold text with sorting order displayed with a triangular arrow) procedure DrawGridKeyDown(Sender: TObject. X.pas unit . Shift: TShiftState. ACol.18 Date: June 16. 1.usefull even if ID column was hidden with IDColumnHide procedure AfterRefresh(aID: integer). Retrieve the record content of the first selected row.finally block): Rec := Grid. If the ID column is available. Called by the owner TDrawGrid when a Cell is clicked by the mouse . Shift: TShiftState). Y: Integer). 2013 function SelectedRecordCreate: TSQLRecord. hides it from the grid mORMotUI.Ctrl + click to display its full unicode content (see HintText to customize it) procedure DrawGridMouseMove(Sender: TObject.QueryTables[0] (if defined) .the cell is drawn using direct Win32 Unicode API .g.current Row will be set back to aID . Called by the owner TDrawGrid when the mouse is over a Cell procedure DrawGridMouseUp(Sender: TObject. end. ACol. Called by the owner TDrawGrid when a Cell is selected procedure IDColumnHide. Shift: TShiftState.18 Page 983 of 1055 . Called by the owner TDrawGrid when the mouse is unclicked over a Cell procedure DrawGridSelectCell(Sender: TObject. Call this procedure after a refresh of the data . if Rec<>nil then try DoSomethingWith(Rec).called internal by Refresh function above procedure DrawCell(Sender: TObject.Synopse mORMot Framework Software Architecture Design 1. will set some uniform width. Toggle the sort order of a specified column procedure SortForce(ACol: integer.supply a string with every character value is proportionate to the corresponding column width .if ACol=-1. Set columns number which must be aligned to non default left layout . ready to be used with the VCL for all Delphi compiler versions procedure SortChange(ACol: integer). const aCustomFormat: string).e. 1. Set column alignment for a given type . aMarkAllowed: boolean). in current sort mORMotUI.Rev. Display a popup Hint window at a specified Cell position . ARow. UnicodeString for Delphi 2009/2010.18 Page 984 of 1055 . Used by TSQLRestClientURI.a faster overload to Aligned[] property procedure SetCustomFormatByType(aFieldType: TSQLFieldType. FontColor: TColor=clBlack). then the Marked[] rows are shown first.18 Date: June 16.if aMarkAllowed is set.From(DrawGrid). Force the mean of characters length for every field .if the character is lowercase. Call this procedure to automaticaly resize the TDrawString columns . Set a custom format for all columns of a given type . Time: integer. i.UpdateFromServer() to let the client perform the rows update (for Marked[]) procedure PageChanged. Perform the corresponding Mark/Unmark[All] Action procedure ShowHintString(const Text: string. 2013 procedure OnTableUpdate(State: TOnTableUpdateState). for example procedure Resize(Sender: TObject).expect generic string Text. Set a specified column for sorting . ACol. the column is set as centered . ARow: integer=-1). a first checkbox column is added. aAlign: TSQLTableToGridAlign). .Synopse mORMot Framework Software Architecture Design 1. aAlign: TSQLTableToGridAlign). left aligned procedure SetMark(aAction: TSQLAction).Resize(). Ascending: boolean.g.only support the field types and formats handled by CustomFormat[] property procedure SetFieldFixedWidth(aColumnWidth: integer). for reflecting and updating the Marked[] field values e. procedure SetAligned(const aCols: array of cardinal.a faster overload to CustomFormat[] property .if Lengths=''. You can call this method when the list is no more on the screen . in pixels procedure SetFieldLengthMean(const Lengths: RawUTF8.pas unit .it will hide any pending popup Hint windows.a faster overload to Aligned[] property procedure SetAlignedByType(aFieldType: TSQLFieldType. Force all columns to have a specified width.can be used as TSQLTableToGrid. the field index which can be used for Marked actions .if no item is marked. Associated Client used to retrieved the Table data property CurrentFieldOrder: integer read fCurrentFieldOrder. True if only one entry is in Marked[]. Set individual column custom format .pas unit . Current field number used for current table sorting property CustomFormat[aCol: cardinal]: string read GetCustomFormat write SetCustomFormat. 2013 property Aligned[aCol: cardinal]: TSQLTableToGridAlign read GetAlign write SetAlign. Format() or FormatFloat()/FormatCurrency() mask for sftFloat or sftCurrency.Rev. 1. True if Marked[] is available (add checkboxes at the left side of every row) property MarkAvailable: boolean read GetMarkAvailable. Retrieves if a row was previously marked .equals -1 if not such field exists property FieldTitleTruncatedNotShownAsHint: boolean read fTruncAsHint write fTruncAsHint. Returns the number of item marked or selected .18 Date: June 16. Set to TRUE to let the header check box select/unselect all rows instead of sorting them .may be more conventional use of this header check box property Hint: THintWindowDelayed read fHint. sftCreateTime) property DrawGrid: TDrawGrid read GetDrawGrid.as handled by TSQLTable.18 Page 985 of 1055 . and it is the current one property MarkedTotalCount: integer read GetMarkedTotalCount.just typecast the Owner as TDrawGrid property FieldIndexTimeLogForMark: integer read GetFieldIndexTimeLogForMark. Set individual column alignment property Client: TSQLRestClientURI read fClient. i. sftTimeLog. Associated TDrawGrid .ExpandAsString() method. sftModTime.first data row index is 1 property MarkedIsOnlyCurrrent: boolean read GetMarkedIsOnlyCurrrent. it return 0 even if a row is currently selected mORMotUI.Synopse mORMot Framework Software Architecture Design 1. or FormatDateTime() mask for sftDateTime.e. Set to FALSE to display the column title as hint when truncated on screen property HeaderCheckboxSelectsInsteadOfSort: boolean read fHeaderCheckboxSelectsInsteadOfSort write fHeaderCheckboxSelectsInsteadOfSort.i. sftDateTime.e. True if any Marked[] is checked property Marked[RowIndex: integer]: boolean read GetMarked write SetMarked. Retrieves the index of the sftTimeLog first field . Used to display some hint text property MarkAllowed: boolean read fMarkAllowed. override. Lowest allowed Variant value mORMotUI. 1. Associated TSQLTable to be displayed ESynLabeledEdit = class(Exception) Exception class raised by TSynIntegerLabeledEdit TSynLabeledEdit = class(TLabeledEdit) TLabeledEdit with optional boundaries check of a Variant value RaiseExceptionOnError: boolean. The kind of value which is currently edited by this TSynLabeledEdit property MaxValue: Variant read FMaxValue write FMaxValue. Highest allowed Variant value property MinValue: Variant read FMinValue write FMinValue. Some additional popup hint to be displayed .Rev. 2013 property OnDrawCellBackground: TDrawCellEvent read fOnDrawCellBackground write fOnDrawCellBackground.18 Page 986 of 1055 . Value: #' . the allowed range is displayed: 'Min. reintroduce. when the Value property is read constructor Create(AOwner: TComponent). Override this event to customize the Ctrl+Mouse click popup text property OnRightClickCell: TRightClickCellEvent read fOnRightClickCell write fOnRightClickCell.Synopse mORMot Framework Software Architecture Design 1. Override this event to customize the Mouse right click on a data cell property OnSelectCell: TSelectCellEvent read fOnSelectCell write fOnSelectCell. Convert the entered Variant value into a textual representation function ValidateValue: boolean.18 Date: June 16.you can specify here some additional text to be displayed when the mouse is hover the component property Kind: TSynLabeledEditKind read fKind write fKind default sleInteger. GetValue() will raise an ESynVariantLabeledEdit exception on any Variant value range error.by default. Override this event to customize the text display in the table property Table: TSQLTable read fTable. Assign an event here to customize the background drawing of a cell property OnHintText: THintTextEvent read fOnHintText write fOnHintText. Max. Return TRUE if the entered value is inside the boundaries property AdditionalHint: string read FAdditionalHint write FAdditionalHint.pas unit . Override this event to customize the Mouse click on a data cell property OnValueText: TValueTextEvent read fOnValueText write fOnValueText. Value: #. Create the component instance function ToString(NumberOfDigits: integer): string. If true. The TLabel instance created on NoCaptionPanel to replace the Caption bar property NoCaptionPanel: TPanel read fNoCaption. Diverse kind of values which may be edited by a TSynLabeledEdit TValueTextEvent = function(Sender: TSQLTable. Call this method to hide the Caption bar and replace it with a TPanel property NoCaptionLabel: TLabel read fNoCaptionLabel.it will also raise a ESynVariantLabeledEdit exception if RaiseExceptionOnError is set to TRUE (equals FALSE by default) TVistaForm = class(TForm) Vista-enabled TForm descendant .if the cell at FiieldIndex/RowIndex is to have a custom content. Kind of event used to change some text on the fly for grid display . Kind of event used to change some text on the fly for popup hint . 1. Kind of event used to display a menu on a cell right click TSQLTableToGridAlign = ( alLeft.this form will hide the default Delphi application virtual form . Set to TRUE if MinValue/MaxValue properties must be checked when reading Value property property Value: Variant read GetValue write SetValue. var Text: string): boolean of object.18 Date: June 16. if RangeChecking is set . The entered value . The available alignments of a TSQLTableToGrid cell TSynLabeledEditKind = ( sleInteger.getting this property will check for in range according to the current MinValue/MaxValue boundaries.it will sound a beep in case of any out of range .if RangeChecking is not set. sleInt64. sleDouble ). The TPanel instance replacing the Caption bar Types implemented in the mORMotUI unit: THintTextEvent = function(Sender: TSQLTable.this form will have a button in the TaskBar . shall set the Text variable content mORMotUI. UnicodeString for Delphi 2009/2010. UnicodeString for Delphi 2009/2010. i.e. alRight ). aLabelLeft: integer).e. i. alCenter. FieldIndex.expect generic string Text.Synopse mORMot Framework Software Architecture Design 1. FieldIndex. could return a NULL variant for no data . sleCurrency.pas unit . ACol.Rev. MouseX. RowIndex: Integer.this form can be with no caption bar using SetNoCaption method procedure SetNoCaption(aTopMostPanel: TPanel.18 Page 987 of 1055 . ready to be used with the VCL for all Delphi compiler versions TRightClickCellEvent = procedure(Sender: TSQLTable.expect generic string Text. ready to be used with the VCL for all Delphi compiler versions . ARow. 2013 property RangeChecking: boolean read fRangeChecking write fRangeChecking. MouseY: Integer) of object. RowIndex: Integer. var Text: string): boolean of object. ApplicationPathAndExe: string). Vista and Seven . Vista and Seven . const RunMinimized: Boolean = false): TFileName.return the .Synopse mORMot Framework Software Architecture Design 1.e.lnk file name (i. PortNumber: cardinal).18 Page 988 of 1055 .lnk') mORMotUI. standard font smoothing is forced. Create an Icon . IconFilename: TFileName. WorkingDir. Parameters.works on Windows WP.under Windows 2000.works on Windows XP. Allow an application to access the network through the Windows firewall . const IconIndex: Integer.if returns FALSE. 1.Rev.caller process must have the administrator rights (this is the case for a setup program) procedure ClearTypeEnable. from its ID 989 HideAppFormTaskBarBut ton Low level VCL routine in order to hide the application from Windows task bar 989 IsClearTypeEnabled Test if the ClearType is enabled for font display 989 Register Register the TSynIntegerLabeledEdit component in the IDE toolbar 989 procedure AddApplicationToFirewall(const EntryName. Path. Name+'.Cells[] with the supplied data 989 GetShellFolderPath Get the corresponding windows folder.18 Date: June 16. Open a firewall port on the current computer . the default content will be displayed Functions or procedures implemented in the mORMotUI unit: Functions or procedures Description Page AddApplicationToFirew all Allow an application to access the network through the Windows firewall 988 AddPortToFirewall Open a firewall port on the current computer 988 ClearTypeEnable Enable the ClearType font display 988 CreateAnIcon Create an Icon 988 DrawCheckBox Draw a CheckBox in the Canvas Handle of the Wwindow hWnd. in the middle of the Rect coordinates 989 FillStringGrid Fill TStringGrid. since Clear Type was introduced with XP function CreateAnIcon (const Name. Description. Enable the ClearType font display .pas unit . 2013 and return TRUE .caller process must have the administrator rights (this is the case for a setup program) procedure AddPortToFirewall(const EntryName: string. use theming under XP. 1. in the middle of the Rect coordinates . and handle the header properly (using the current mORMoti18n.Cells[] with the supplied data .the Client optional parameter will be used to display any RecordRef column . Fill TStringGrid. if any) . you don't have to register anything unless you define your own forms including those components mORMotUI. Register the TSynIntegerLabeledEdit component in the IDE toolbar . Low level VCL routine in order to hide the application from Windows task bar .18 Page 989 of 1055 . Dest: TStringGrid. const Rect: TRect.pas unit .Synopse mORMot Framework Software Architecture Design 1.ClearType is a software technology that improves the readability of text on liquid crystal display (LCD) monitors procedure Register. but will work on a non standard TDrawGrid component .18 Date: June 16. from its ID procedure HideAppFormTaskBarButton. and not from the Delphi IDE. Handle: HDC. Checked: boolean). 2013 procedure DrawCheckBox(hWnd: THandle.it will display date & time and enumerates as plain text.CreateParams() function IsClearTypeEnabled: boolean. Draw a CheckBox in the Canvas Handle of the Wwindow hWnd. Get the corresponding windows folder. Test if the ClearType is enabled for font display .not necessary for the mORMot framework to run: since all User Interface is created from code.all data will be stored within the TStringGrid: you can safely release the Source data after having called this procedure function GetShellFolderPath(const FolderID: Integer): string.pas language settings.Rev. Client: TSQLRest=nil).don't use it directly: it's called by TVistaForm.will be slower than the TSQLTableToGrid method. Vista and Seven procedure FillStringGrid(Source: TSQLTable. 18 966 mORMotUI Grid to display database content for mORMot . licensed under a MPL/GPL/LGPL tri-license.18 325 SynTaskDialog Implement TaskDialog window (native on Vista/Seven. licensed under a MPL/GPL/LGPL tri-license.18 993 SynCommons Common functions used by most Synopse projects . 1. version 1. version 1.18 924 mORMotToolBar ORM-driven Office 2007 Toolbar for mORMot .pas unit Purpose: Record edition dialog. licensed under a MPL/GPL/LGPL tri-license.Synopse mORMot Framework Software Architecture Design 1.18 Page 990 of 1055 .this unit is a part of the freeware Synopse mORMot framework. version 1.this unit is a part of the freeware Synopse mORMot framework.this unit is a part of the freeware Synopse mORMot framework. mORMotUIEdit. version 1.Rev. licensed under a MPL/GPL/LGPL tri-license. version 1.18 Date: June 16.18 Units used in the mORMotUIEdit unit: Unit Name Description Page mORMot Common ORM and SOA classes for mORMot . licensed under a MPL/GPL/LGPL tri-license. 2013 23. licensed under a MPL/GPL/LGPL tri-license.18 700 TVistaForm TRTTIForm TRecordEditForm mORMotUIEdit class hierarchy Objects implemented in the mORMotUIEdit unit: Objects Description Page TRecordEditForm Record edition dialog.18 715 mORMoti18n Internationalization (i18n) routines and classes for mORMot .this unit is a part of the freeware Synopse mORMot framework. version 1. version 1.37. version 1.this unit is a part of the freeware Synopse mORMot framework.18 980 mORMotUILogin Some common User Interface functions and dialogs for mORMot . licensed under a MPL/GPL/LGPL tri-license.this unit is a part of the freeware Synopse mORMot framework. used to edit record content with mORMot . used by both TRecordEditForm and TOptionsForm 991 mORMotUIEdit. licensed under a MPL/GPL/LGPL tri-license.pas unit .this unit is a part of the freeware mORMot framework. emulated on XP) .this unit is a part of the freeware Synopse mORMot framework. used to edit record content on the screen 991 TRTTIForm A common ancestor. this event is also triggerred once at the creation of the Option window. used by both TRecordEditForm and TOptionsForm OnCaptionName: TOnCaptionName. all the User Interface (fields. This event is used to customize the input components creation . with Prop=nil.can be used to disabled the component if user don't have the right to modify its value.18 Page 991 of 1055 . and something not nil if the object is to be ignored (same as a runtime-level _Name object) . OnComponentCreate at least.the window content is taken from the RTTI of the supplied record.caller must initialize some events.. for TOptionsForm . with Obj=Prop=nil and Parent=TOptionsForm: the event must call method Parent.components creation is fully customizable by some events mORMotUIEdit.this event is triggered once for every object.this is the only mandatory event of this component.Synopse mORMot Framework Software Architecture Design 1. in order to supply the objects to be added on the form .triggered when the component has been created . etc. This event is used to customize screen text of property names OnComponentCreate: TOnComponentCreate.. but he/she will still be able to view it TRecordEditForm = class(TRTTIForm) Record edition dialog.) is created from the class definition using RTTI: published properties are displayed as editing components .this event is not mandatory for TRecordEditForm (you can call its SetRecord method directly) OnComponentCreated: TOnComponentCreated.pas unit .18 Date: June 16. This event is used to customize the input components after creation .Rev.AddEditors() / Parent.SetRecord() to add fields to the Option (this is not mandatory to the Record Edit window) . and should return nil if the object is to be added to the dialog. used to edit record content on the screen . 1. 2013 TRTTIForm = class(TVistaForm) A common ancestor. 1.editor parameters are taken from the optional Ribbon parameter. and its EditFieldHints/EditExpandFieldHints/EditFieldNameWidth properties . which is separated from the UI (better multi-tier architecture) mORMotUIEdit.to be used by OnComponentCreate(nil. Parent: TWinControl): TWinControl of object. via a popup message for instance . Comp: TWinControl) of object. 2013 procedure SetRecord(aClient: TSQLRestClient. Prop: TSQLPropInfo. Prop: TSQLPropInfo): boolean of object.is checked when the user press the "Save" Button .if returns false.properties which name starts by '_' are not added to the UI window .18 Date: June 16.create field on the window for all published properties of the supplied TSQLRecord instance . but only exists in memory). Event used to customize the input component after creation TOnComponentValidate = function(EditControl: TWinControl. FALSE if the content is to be modified . FieldHints: string=''.nil. but you can specify a CSV list in the optional CSVFieldNames parameter .user can customize the component creation by setting the OnComponentCreate / OnComponentCreated events .if Ribbon is nil.it's up to the handler to inform the user that this field is not correct. aRecord: TSQLRecord. aCaption: string=''). FieldHints may contain the hints to be displayed on screen (useful if your record is not stored in any TSQLRestClient. The associated Record to be edited Types implemented in the mORMotUIEdit unit: TOnComponentCreate = function(Obj: TObject. FieldNamesWidth: integer=0. Ribbon: TSQLRibbon=nil. Event called to check if the content of a field on form is correct .pas unit . Event used for the window creation TOnComponentCreated = procedure(Obj: TObject. component is focused and window is not closed property Rec: TSQLRecord read fRec.by default.must return TRUE if the specified field is correct. used to access remote data property OnComponentValidate: TOnComponentValidate read fOnComponentValidate write fOnComponentValidate.Rev. all published fields are displayed. Prop: TSQLPropInfo.the supplied aRecord instance must be available during all the dialog window modal apparition on screen . CSVFieldNames: PUTF8Char=nil.AddFilterOrValidate() mechanism.Synopse mORMot Framework Software Architecture Design 1. Event used for individual field validation .you should better use the TSQLRecord. The associated database Client.18 Page 992 of 1055 . you can set FieldNamesWidth by hand in this case property Client: TSQLRestClient read fClient.EditForm) in order to populate the object tree of this Form . Create the corresponding components on the dialog for editing a Record . 1. mORMotUILogin.18 700 TForm TLoginForm mORMotUILogin class hierarchy Objects implemented in the mORMotUILogin unit: Objects Description Page TLoginForm Form used to Log User and enter its password 993 TLoginForm = class(TForm) Form used to Log User and enter its password class function Login(const aTitle.pas unit Purpose: Some common User Interface functions and dialogs for mORMot . PNG and JPG pictures read/write support as standard TGraphic . licensed under a MPL/GPL/LGPL tri-license. licensed under a MPL/GPL/LGPL tri-license.18 980 SynCommons Common functions used by most Synopse projects . version 1.adds GIF. aPassWord: string. version 1. licensed under a MPL/GPL/LGPL tri-license. aText: string. licensed under a MPL/GPL/LGPL tri-license.18 325 SynGdiPlus GDI+ library API access . var aUserName.allows Antialiased rending of any EMF file using GDI+ . emulated on XP) .18 576 SynTaskDialog Implement TaskDialog window (native on Vista/Seven.pas unit .this unit is a part of the freeware Synopse mORMot framework.this unit is a part of the freeware Synopse mORMot framework.this unit is a part of the freeware mORMot framework.this unit is a part of the freeware Synopse mORMot framework. version 1. licensed under a MPL/GPL/LGPL tri-license.make available most useful GDI+ drawing methods .this unit is a part of the freeware Synopse framework.38.Rev. 2013 23. version 1. AllowUserNameChange: boolean.this unit is a part of the freeware Synopse mORMot framework. licensed under a MPL/GPL/LGPL tri-license. version 1. Display the Login dialog window mORMotUILogin.18 Units used in the mORMotUILogin unit: Unit Name Description Page mORMot Common ORM and SOA classes for mORMot .Synopse mORMot Framework Software Architecture Design 1.18 Page 993 of 1055 . TIF. const CSVComboValues: string): boolean.18 Date: June 16.18 715 mORMotUI Grid to display database content for mORMot . version 1. using a Vista-Style dialog box 996 function Choose(const aTitle.Rev. 1. Ask the User to choose between some Commands .18 Page 994 of 1055 . starting numerotation at 100 mORMotUILogin. const Commands: array of string.return the selected command index. aContent. aText: string. Display the password dialog window Functions or procedures implemented in the mORMotUILogin unit: Functions or procedures Description Page Choose Ask the User to choose between some Commands 994 Choose Ask the User to choose between some Commands 994 CreateTempForm Popup a temporary form with a message over all forms 995 EnsureSingleInstance Ensure that the program is launched once 995 HtmlEscape Convert an error message into html compatible equivalency 995 InputBox Ask the User to enter some string value 995 InputQuery Ask the User to enter some string value 995 InputSelect Ask the User to select one item from an array of strings 995 InputSelectEnum Ask the User to select one enumerate item 995 SetStyle Set the style for a form and a its buttons 995 ShowException Show an error dialog box.pas unit .18 Date: June 16. with the corresponding Client-Side information 995 ShowMessage Show an (error) message. corresponding to a specified exception 995 ShowLastClientError Show an error dialog box. then commands) function Choose(const aTitle. 2013 class function PassWord(const aTitle. overload. aFooter: string. overload.return the selected command index.this overloaded function expect the Content and the Commands to be supplied as CSV string (Content as first CSV. starting numerotation at 100 . Ask the User to choose between some Commands . using a Vista-Style dialog box 996 YesNo Ask the User to choose Yes or No [and Cancel]. var aPassWord: string): boolean. aFooterIcon: TTaskDialogFooterIcon=tfiInformation): integer.Synopse mORMot Framework Software Architecture Design 1. using a Vista-Style dialog box 996 ShowMessage Show an (error) message. aCSVContent: string): integer. const ContextMessage: string=''. Ask the User to enter some string value .CreateForm(TMainForm.retrieve last error message from Client. APrompt.. Ask the User to enter some string value .the main project .e. ADefault: string. AItemsText. will mask the prompt with '*' chars (e.18 Page 995 of 1055 .18 Date: June 16. CommonButtons: TCommonButtons=[cbOk]): integer. APrompt: string.g. -1 if Cancel button was pressed function InputSelectEnum(const ACaption. ASelectedText: string): integer. function HtmlEscape(const Msg: string): string. ScreenCursorHourGlass: boolean=false. Popup a temporary form with a message over all forms procedure EnsureSingleInstance. QueryMasked: boolean=false): Boolean.if QueryMasked=TRUE. const ContextMessage: string=''): integer. will mask the prompt with '*' chars (e.if QueryMasked=TRUE. var Value: string. Calibri if available function ShowException(E: Exception. aCaptionColor: integer=clNavy.dpr source file must contain: begin Application. APrompt. APrompt: string. Set the style for a form and a its buttons . MainForm). aCaptionSize: integer=12): TForm. Show an error dialog box. EnsureSingleInstance..GetCaption() to retrieve the text to be displayed .set the Default Font for all components. // program is launched once Application. var Index): boolean. CommonButtons: TCommonButtons=[cbOk].Rev. Ensure that the program is launched once . corresponding to a specified exception function ShowLastClientError(Client: TSQLRestClientURI.g. Ask the User to select one item from an array of strings . 1. Ask the User to select one enumerate item .allow to display < > & correctly function InputBox(const ACaption. for entering a password) function InputQuery(const ACaption.pas unit .Index must be an instance of this enumeration type (internaly mapped to a PByte) procedure SetStyle(Form: TComponent). with the corresponding Client-Side information .. for entering a password) function InputSelect(const ACaption.use internally TEnumType. EnumTypeInfo: PTypeInfo. .Synopse mORMot Framework Software Architecture Design 1. aPanelReference: PTPanel=nil. Show an error dialog box. QueryMasked: boolean=false): string.LastError* values mORMotUILogin. 2013 function CreateTempForm(const aCaption: string. i.Initialize. Convert an error message into html compatible equivalency .return the selected index. Inst: string. 2013 procedure ShowMessage(const Msg: string.pas unit . Error: boolean=false). overload. using a Vista-Style dialog box procedure ShowMessage(const Msg.Rev. const aConfirm: string =''. withCancel: boolean=true.18 Page 996 of 1055 . using a Vista-Style dialog box function YesNo(const aQuestion: string. Error: boolean=false). Show an (error) message. 1.Synopse mORMot Framework Software Architecture Design 1. Ask the User to choose Yes or No [and Cancel]. using a Vista-Style dialog box mORMotUILogin. Show an (error) message. Warning: boolean=false): integer.18 Date: June 16. overload. pas unit Purpose: General Options setting dialog for mORmot . 1. licensed under a MPL/GPL/LGPL tri-license.this unit is a part of the freeware Synopse mORMot framework.this unit is a part of the freeware Synopse mORMot framework. licensed under a MPL/GPL/LGPL tri-license. licensed under a MPL/GPL/LGPL tri-license. licensed under a MPL/GPL/LGPL tri-license. licensed under a MPL/GPL/LGPL tri-license.this unit is a part of the freeware Synopse mORMot framework. version 1. version 1. licensed under a MPL/GPL/LGPL tri-license.18 966 mORMotUI Grid to display database content for mORMot . 2013 23.18 Units used in the mORMotUIOptions unit: Unit Name Description Page mORMot Common ORM and SOA classes for mORMot .18 Date: June 16.18 700 TRTTIForm TOptionsForm mORMotUIOptions class hierarchy Objects implemented in the mORMotUIOptions unit: Objects Description Page TOptionsForm Options setting dialog 998 mORMotUIOptions.this unit is a part of the freeware Synopse mORMot framework.18 325 SynTaskDialog Implement TaskDialog window (native on Vista/Seven. licensed under a MPL/GPL/LGPL tri-license. emulated on XP) .this unit is a part of the freeware Synopse mORMot framework.this unit is a part of the freeware Synopse mORMot framework. version 1.18 993 SynCommons Common functions used by most Synopse projects .this unit is a part of the freeware Synopse mORMot framework. version 1.18 715 mORMoti18n Internationalization (i18n) routines and classes for mORMot .39.18 Page 997 of 1055 . version 1. version 1. licensed under a MPL/GPL/LGPL tri-license.Synopse mORMot Framework Software Architecture Design 1. mORMotUIOptions.18 980 mORMotUIEdit Record edition dialog.this unit is a part of the freeware mORMot framework. version 1. licensed under a MPL/GPL/LGPL tri-license.18 990 mORMotUILogin Some common User Interface functions and dialogs for mORMot . version 1.this unit is a part of the freeware Synopse mORMot framework.pas unit .Rev. version 1. used to edit record content with mORMot .18 924 mORMotToolBar ORM-driven Office 2007 Toolbar for mORMot . Creator may define this property to force a particular node to be selected at form showing function AddEditors(Node: TTreeNode.components creation is fully customizable by some events SelectedNodeObjectOnShow: TObject. and published properties are displayed as editing components .Synopse mORMot Framework Software Architecture Design 1. aActionsBits: pointer. OnComponentCreate at least.properties which name starts by '_' are not added to the UI window . in order to supply the objects to be added on the form . Obj: TObject). const aActionHints: string. const aTitle: string=''): TTreeNode.18 Date: June 16.OptionsForm) in order to populate the object tree of this Form . aProp: PPropInfo.to be used by OnComponentCreate(nil. Obj: TObject. its bits indicates the Buttons to appear in the list mORMotUIOptions.aActionHints is a multi line value containing the Hint captions for all available Actions . 2013 TOptionsForm = class(TRTTIForm) Options setting dialog . aEnum: PTypeInfo. const aCustomCaption: string=''.pas unit .the settings parameters are taken from the RTTI of supplied objects: all the user interface is created from the code definition of classes.if aActionsBits is not nil.published properties of parents of Obj are also added procedure AddToolbars(Scroll: TScrollBox.published textual properties may be defined as generic RawUTF8 or as generic string (with some possible encoding issue prior to Delphi 2009) .caller must initialize some events.nil. 1.Rev. Create corresponding checkboxes lists for a given action toolbar . a visual tree node will reflect the properties recursion. Create corresponding nodes and components for updating Obj .18 Page 998 of 1055 .aEnum points to the Action RTTI . const aToolbarName: string. 18 993 SynCommons Common functions used by most Synopse projects . licensed under a MPL/GPL/LGPL tri-license. version 1. version 1.40.pas unit .18 700 TVistaForm TQueryForm mORMotUIQuery class hierarchy Objects implemented in the mORMotUIQuery unit: Objects Description Page TQueryForm This Form perform simple Visual queries to a Grid 1000 mORMotUIQuery. emulated on XP) .pas unit Purpose: Form handling queries to a User Interface Grid for mORMot . version 1.this unit is a part of the freeware mORMot framework.this unit is a part of the freeware Synopse mORMot framework.18 Units used in the mORMotUIQuery unit: Unit Name Description Page mORMot Common ORM and SOA classes for mORMot . version 1. licensed under a MPL/GPL/LGPL tri-license.18 715 mORMoti18n Internationalization (i18n) routines and classes for mORMot .this unit is a part of the freeware Synopse mORMot framework. licensed under a MPL/GPL/LGPL tri-license. version 1. version 1. licensed under a MPL/GPL/LGPL tri-license.Synopse mORMot Framework Software Architecture Design 1.18 Page 999 of 1055 .18 325 SynTaskDialog Implement TaskDialog window (native on Vista/Seven.Rev. 1.18 924 mORMotUI Grid to display database content for mORMot .this unit is a part of the freeware Synopse mORMot framework.18 980 mORMotUILogin Some common User Interface functions and dialogs for mORMot . licensed under a MPL/GPL/LGPL tri-license. mORMotUIQuery. licensed under a MPL/GPL/LGPL tri-license. version 1.18 Date: June 16.this unit is a part of the freeware Synopse mORMot framework.this unit is a part of the freeware Synopse mORMot framework. licensed under a MPL/GPL/LGPL tri-license. 2013 23.this unit is a part of the freeware Synopse mORMot framework. aTableToGrid: TSQLTableToGrid). by the TSQLRest. 2013 TQueryForm = class(TVistaForm) This Form perform simple Visual queries to a Grid .like . to add some custom field search (e.pas unit . but can demand some bandwith for custom field search (since data has to be retrieved from the server to search within) constructor Create(aOwner: TComponent.Rev.QueryAddCustom() method. Create the window instance . reintroduce.18 Date: June 16.use TSQLQueryCustom records previously registered to the TSQLRest class.caller must have used TSQLRest.mark or unmark items.INI-like section entries) . if necessary mORMotUIQuery. to search into fields not available on the grid.in practice. or some data embedded inside a field .all parameters (especially TSQLRest instance to use for custom search) are retrieved via the supplied TSQLTableToGrid .18 Page 1000 of 1055 .g. the query is very fast (immediate for standard fields and parameters).QueryIsTrue() method for standard fields and parameters .QueryAddCustom() method to register some custom queries. depending of the input of the User on this form . 1.use TSQLRest.Synopse mORMot Framework Software Architecture Design 1. for better speed with Delphi older than Delphi 2009 Update 3.18 Date: June 16. version 1.jgknet.de/blog/bugfix-units/midas-speed-fix-12 mORmotVCL. mORmotVCL.for better speed with Delphi older than Delphi 2009 Update 3. licensed under a MPL/GPL/LGPL tri-license.with non-Unicode version of Delphi.this unit is a part of the freeware Synopse mORMot framework. aClient: TSQLRest=nil . created from the supplied TSQLTable content (a more optimized version may appear later) . Convert a JSON result into a VCL DataSet . if needed .this unit is a part of the freeware Synopse framework. you can set aForceWideString to force the use of WideString fields instead of AnsiString. 1. licensed under a MPL/GPL/LGPL tri-license. UnicodeString will be used .with Unicode version of Delphi (2009+).18 325 Functions or procedures implemented in the mORmotVCL unit: Functions or procedures Description Page JSONToDataSet Convert a JSON result into a VCL DataSet 1001 TSQLTableToDataSet Convert a TSQLTable result into a VCL DataSet 1001 function JSONToDataSet(aOwner: TComponent.current implementation will return a TClientDataSet instance. aForceWideString: boolean=false): TDataSet.de/blog/bugfix-units/midas-speed-fix-12 function TSQLTableToDataSet(aOwner: TComponent.this unit is a part of the freeware Synopse mORMot framework. created from the supplied TSQLTable content (a more optimized version may appear later) . it is recommended to use http://andy. if needed .with non-Unicode version of Delphi. const aJSON: RawUTF8. it is recommended to use http://andy.jgknet.18 Units used in the mORmotVCL unit: Unit Name Description Page mORMot Common ORM and SOA classes for mORMot . version 1. aTable: TSQLTable. you can set aForceWideString to force the use of WideString fields instead of AnsiString.41.18 715 SynCommons Common functions used by most Synopse projects .pas unit Purpose: DB VCL dataset using TSQLTable/TSQLTableJSON data access . Convert a TSQLTable result into a VCL DataSet . aForceWideString: boolean=false): TDataSet. aClient: TSQLRest=nil . licensed under a MPL/GPL/LGPL tri-license. 2013 23. version 1.Synopse mORMot Framework Software Architecture Design 1.pas unit .current implementation will return a TClientDataSet instance.18 Page 1001 of 1055 .Rev. version 1. version 1.18 549 ESQLDBDataset ESQLDBBDE TSQLDBConnectionThreadSafe TSQLDBBDEConnection TSQLDBDatasetConnectionProperties TSQLDBBDEConnectionProperties TSQLDBDatasetStatement TSQLDBBDEStatement SynDBBDE class hierarchy Objects implemented in the SynDBBDE unit: Objects Description Page ESQLDBBDE Exception type associated to the direct BDE connection 1002 TSQLDBBDEConnection Implements a direct connection via the BDE access layer 1003 TSQLDBBDEConnectionPr operties Implement properties shared by BDE connections 1003 TSQLDBBDEStatement Implements a statement via a BDE connection 1004 ESQLDBBDE = class(ESQLDBDataset) Exception type associated to the direct BDE connection SynDBBDE. 2013 23. licensed under a MPL/GPL/LGPL tri-license.pas unit Purpose: BDE access classes for SynDB units .18 509 SynDBDataset DB.18 Page 1002 of 1055 . version 1.this unit is a part of the freeware Synopse framework.pas unit .18 325 SynDB Abstract database direct access classes .this unit is a part of the freeware Synopse framework.Synopse mORMot Framework Software Architecture Design 1.42. licensed under a MPL/GPL/LGPL tri-license. SynDBBDE.Rev.18 Date: June 16. licensed under a MPL/GPL/LGPL tri-license.18 Units used in the SynDBBDE unit: Unit Name Description Page SynCommons Common functions used by most Synopse projects .this unit is a part of the freeware Synopse framework. version 1.this unit is a part of the freeware Synopse mORMot framework. 1. licensed under a MPL/GPL/LGPL tri-license.pas TDataset-based direct access classes (abstract TQuery-like) . override. override. Begin a Transaction for this connection property Database: TDatabase read fDatabase. Initialize the properties to connect to the BDE engine .StartTransaction method must have been called before procedure Connect. Create a new connection . Create a new statement instance procedure Commit. override.pas unit .caller is responsible of freeing this instance . override. 1. override. Release memory and connection function IsConnected: boolean.this overriden method will create an TSQLDBBDEConnection instance TSQLDBBDEConnection = class(TSQLDBConnectionThreadSafe) Implements a direct connection via the BDE access layer constructor Create(aProperties: TSQLDBConnectionProperties).Rev. override. override.StartTransaction method must have been called before procedure StartTransaction. 2013 TSQLDBBDEConnectionProperties = class(TSQLDBDatasetConnectionProperties) Implement properties shared by BDE connections constructor Create(const aServerName. Access to the associated BDE connection instance SynDBBDE. override. aDatabaseName. override. Connect to the specified BDE server . override.18 Date: June 16. Return TRUE if Connect has been already successfully called function NewStatement: TSQLDBStatement. Discard changes of a Transaction for this connection .should raise an ESQLDBBDE on error procedure Rollback.aServerName shall contain the BDE Alias name . override.should raise an ESQLDBBDE on error procedure Disconnect. Prepare a connection to a specified BDE database server destructor Destroy. aUserID.Synopse mORMot Framework Software Architecture Design 1. Commit changes of a Transaction for this connection .18 Page 1003 of 1055 . Stop connection to the specified BDE database server .aDatabaseName is ignored function NewConnection: TSQLDBConnection. aPassWord: RawUTF8). 18 Page 1004 of 1055 . as retrieved at BDE connection creation property DBMSName: RawUTF8 read fDBMSName. The remote DBMS type.Synopse mORMot Framework Software Architecture Design 1. 1. The remote DBMS name.pas unit .Rev.18 Date: June 16. 2013 property DBMS: TSQLDBDefinition read fDBMS. as retrieved at BDE connection creation TSQLDBBDEStatement = class(TSQLDBDatasetStatement) Implements a statement via a BDE connection SynDBBDE. SynDBFireDAC.this unit is a part of the freeware Synopse framework.18 325 SynDB Abstract database direct access classes .18 Units used in the SynDBFireDAC unit: Unit Name Description Page SynCommons Common functions used by most Synopse projects . 2013 23. licensed under a MPL/GPL/LGPL tri-license.this unit is a part of the freeware Synopse framework.Rev.this unit is a part of the freeware Synopse framework.pas unit .Synopse mORMot Framework Software Architecture Design 1.pas TDataset-based direct access classes (abstract TQuery-like) . licensed under a MPL/GPL/LGPL tri-license.18 549 ESQLDBDataset ESQLDBFireDAC TSQLDBConnectionThreadSafe TSQLDBFireDACConnection TSQLDBDatasetConnectionProperties TSQLDBFireDACConnectionProperties TSQLDBDatasetStatementAbstract TSQLDBFireDACStatement SynDBFireDAC class hierarchy Objects implemented in the SynDBFireDAC unit: Objects Description Page ESQLDBFireDAC Exception type associated to FireDAC/AnyDAC database access 1005 TSQLDBFireDACConnecti on access TSQLDBFireDACConnecti onProperties connection properties definition using FireDAC/AnyDAC database access TSQLDBFireDACStatemen t implements a direct connection via FireDAC/AnyDAC database implements a statement via a FireDAC connection 1006 1006 1007 ESQLDBFireDAC = class(ESQLDBDataset) Exception type associated to FireDAC/AnyDAC database access SynDBFireDAC. 1.pas unit Purpose: FireDAC/AnyDAC-based classes for SynDB units .18 509 SynDBDataset DB.18 Date: June 16.18 Page 1005 of 1055 . version 1.this unit is a part of the freeware Synopse mORMot framework.43. licensed under a MPL/GPL/LGPL tri-license. licensed under a MPL/GPL/LGPL tri-license. version 1. version 1. version 1. aUserID.0.0.db3'.g.this overriden method will use FireDAC metadata to retrieve the information property Parameters: TStringList read fFireDACOptions. uADPhysMSAcc.1\SQLEXPRESS'. Get all table names . Create('MySQL?Server=127. override.':memory:'.'User'.g.this overriden method will use FireDAC metadata to retrieve the information procedure GetTableNames(var Tables: TRawUTF8DynArray). override.Port=3306'.0. Create('SQLite'.'TNSNAME'. 2013 TSQLDBFireDACConnectionProperties = class(TSQLDBDatasetConnectionProperties) connection properties definition using FireDAC/AnyDAC database access constructor Create(const aServerName. DatabaseName.Synopse mORMot Framework Software Architecture Design 1.'').0.'User'.'Password').by default.'Password').note that you need to link the FireDAC driver by including the expected uADPhys*.'MyDB'. e. Release internal structures function NewConnection: TSQLDBConnection. Create('Ora?CharacterSet=cl8mswin1251'. 'Ora'.0.pas unit into a uses clause of your application.'Password').1.'Password').0. Create('IB'. ServerName.aDatabaseName shall contain the database server name . Create('IB?CreateDatabase=Yes'. and some optional parameters (e. override. uADPhysMySQL. e.''). Create a new connection . UserID and Password are set by the Create() constructor according to the underlying FireDAC driver . Initialize the properties to connect via FireDAC/AnyDAC database access . aPassWord: RawUTF8). uADPhysSQLite.'c:\data\access.'127.this overriden method will create an TSQLDBFireDACConnection instance procedure GetFields(const aTableName: RawUTF8. Create('MSSQL?Server=127.IB'.IB'.''. var Fields: TSQLDBColumnDefineDynArray).'TNSNAME'. uADPhysOracle.18 Date: June 16.'C:\ib\ADDEMO_IB2007.0.1:C:\ib\ADDEMO_IB2007.mdb'.' . Create('MSAcc'.'c:\data\myapp.'User'.'User'. Retrieve the column/field layout of a specified table .aServerName shall contain the FireDAC provider DriverID.''. 1.'127.you can add some additional options here TSQLDBFireDACConnection = class(TSQLDBConnectionThreadSafe) implements a direct connection via FireDAC/AnyDAC database access SynDBFireDAC. uADPhysMSSQL.IB'.'Northwind'.0.'User'. aDatabaseName.''. Create('IB?Server=my_host/3055'.'User'.Rev.1:C:\ib\ADDEMO_IB2007. override.'Password'). after a '?' and separated by '. Allow to set the options specific to a FireDAC driver .'Password').caller is responsible of freeing this instance .'').'User'. .18 Page 1006 of 1055 .g. or uADPhysIB destructor Destroy. Create('SQLite'.'Password').pas unit . remote server name if needed). override.for instance: Create('Ora'. . override.parameters marked as ? will be bound later. before ExecutePrepared call . Create a new statement instance procedure Commit.'IB'.should raise an ESQLDBFireDAC on error procedure Disconnect. overload.StartTransaction method must have been called before procedure Connect.'SQLite'.this specific version will handle the FireDAC specific parameter classes . override. FireDAC DriverID values corresponding to SynDB recognized SQL engines SynDBFireDAC. Discard changes of a Transaction for this connection .''). Prepare an UTF-8 encoded SQL statement . ExpectResults: boolean = false).'MSAcc'. override.high(TSQLDBDefinition)] of RawUTF8 = ( 'Ora'.if ExpectResults is TRUE. override. then Step() and Column*() methods are available to retrieve the data rows . override. 1. Access to the associated FireDAC connection instance TSQLDBFireDACStatement = class(TSQLDBDatasetStatementAbstract) implements a statement via a FireDAC connection .18 Date: June 16.it will also handle Array DML commands. if possible procedure Prepare(const aSQL: RawUTF8.Rev. override. Commit changes of a Transaction for this connection .StartTransaction method must have been called before procedure StartTransaction.raise an ESQLDBFireDAC on any error Constants implemented in the SynDBFireDAC unit: FIREDAC_PROVIDER: array[dOracle.pas unit .Synopse mORMot Framework Software Architecture Design 1. Begin a Transaction for this connection property Database: TADConnection read fDatabase. Return TRUE if Connect has been already successfully called function NewStatement: TSQLDBStatement.should raise an ESQLDBFireDAC on error procedure Rollback. override. Release memory and connection function IsConnected: boolean. Stop connection to the specified database server using FireDAC . Prepare a connection for a specified FireDAC/AnyDAC database access destructor Destroy. 2013 constructor Create(aProperties: TSQLDBConnectionProperties). Connect to the specified database server using FireDAC .'MSSQL'.18 Page 1007 of 1055 . override.'MySQL'. override. override. this unit is a part of the freeware Synopse mORMot framework.18 325 SynDB Abstract database direct access classes .18 Page 1008 of 1055 . version 1.pas unit Purpose: NexusDB 3. licensed under a MPL/GPL/LGPL tri-license.44.18 549 ESQLDBDataset ESQLDBNexusDB TSQLDBConnectionThreadSafe TSQLDBNexusDBConnection TSQLDBDatasetConnectionProperties TSQLDBNexusDBConnectionProperties TSQLDBDatasetStatement TSQLDBNexusDBStatement SynDBNexusDB class hierarchy Objects implemented in the SynDBNexusDB unit: Objects Description Page ESQLDBNexusDB Exception type associated to the direct NexusDB connection 1008 TSQLDBNexusDBConnecti on Implements a direct connection to the native NexusDB database 1009 TSQLDBNexusDBConnecti onProperties Implement properties shared by native NexusDB connections 1009 TSQLDBNexusDBStatemen t Implements a statement via the native NexusDB connection 1010 ESQLDBNexusDB = class(ESQLDBDataset) Exception type associated to the direct NexusDB connection SynDBNexusDB. 1.pas TDataset-based direct access classes (abstract TQuery-like) . licensed under a MPL/GPL/LGPL tri-license.this unit is a part of the freeware Synopse framework. 2013 23. version 1.pas unit .18 Date: June 16.this unit is a part of the freeware Synopse framework.Synopse mORMot Framework Software Architecture Design 1. SynDBNexusDB. version 1.18 509 SynDBDataset DB. licensed under a MPL/GPL/LGPL tri-license. licensed under a MPL/GPL/LGPL tri-license.this unit is a part of the freeware Synopse framework.Rev.18 Units used in the SynDBNexusDB unit: Unit Name Description Page SynCommons Common functions used by most Synopse projects .x direct access classes (embedded engine only) . version 1. 2013 TSQLDBNexusDBConnectionProperties = class(TSQLDBDatasetConnectionProperties) Implement properties shared by native NexusDB connections . aDatabaseName. virtual. virtual.this overriden method will initialize the protocol to be used as stated by aServerName i.this overriden method will create an TSQLDBNexusDBConnection instance property Protocol: TNXProtocol read fProtocol. Create a new connection .pas unit .if protocol is nxpFolder then aDatabaseName will contain the path to the folder to be used .feedback needed! constructor Create(const aServerName.if protocol is other then nxpFolder than aServerName will contain the server to connect to and aDatabaseName will contains the alias of the database .caller is responsible of freeing this instance . Release memory and connection function IsConnected: boolean.43 . virtual. nxpTCIP://11. override. 1.Rev.18 Page 1009 of 1055 . Delete the database folder .18 Date: June 16. Create the database folder (if not existing) function DatabaseExists: boolean.just test if the corresponding folder exists function DeleteDatabase: boolean. aUserID.including all its files .34. override. override. Initialize the properties to connect to the NexusDB engine . Prepare a connection to a specified NexusDB database server destructor Destroy.e.note that only the embedded engine is implemented by now .Synopse mORMot Framework Software Architecture Design 1. override.Default protocol is nxpFolder . aPassWord: RawUTF8). override. The transport protocol used to connect to the NexusDB engine TSQLDBNexusDBConnection = class(TSQLDBConnectionThreadSafe) Implements a direct connection to the native NexusDB database constructor Create(aProperties: TSQLDBConnectionProperties).Possible aServerName formats: <protocol>://<servername>/<alias> <protocol>://servername '' (aDatabaseName will be overwritten by this alias) (aDatabaseName will contain alias) (aDatabaseName contains path to nxpFOLDER database) function CreateDatabase: boolean. Determine if database exists . Return TRUE if Connect has been already successfully called SynDBNexusDB.23.so to be used carefully! function NewConnection: TSQLDBConnection. StartTransaction method must have been called before procedure StartTransaction. nxpCOM. Access to the associated NexusDB connection instance property ServerEngine: TnxBaseServerEngine read fServerEngine write SetServerEngine.nxpTCPIP: TCP/IP transport. override.Rev. override. 1. indicated by nxmem:// . Discard changes of a Transaction for this connection . 2013 function NewStatement: TSQLDBStatement. nxpMEM.nxpMEM: direct memory transport. Stop connection to the specified NexusDB database server . override. Set aServerName to this value to create an in-memory table . override.do not use this constant. nxpPIPE. indicated by nxbfisch:// Constants implemented in the SynDBNexusDB unit: NEXUSDB_INMEMORY = '#INMEM'.nxpFOLDER: default protocol.Synopse mORMot Framework Software Architecture Design 1.18 Page 1010 of 1055 .pas unit . since it was not working as expected yet Functions or procedures implemented in the SynDBNexusDB unit: SynDBNexusDB. Available communication protocols used by NexusDB between client and server .nxpPIPE: Windows Named Pipe transport. Commit changes of a Transaction for this connection . nxpFOLDER. accessing NexusDB database in a Windows Folder .nxpBFISH: BlowFish transport. indicated by nxtcp:// .should raise an ESQLDBNexusDB on error procedure Rollback.should raise an ESQLDBNexusDB on error procedure Disconnect.18 Date: June 16. Associated NexusDB server engine TSQLDBNexusDBStatement = class(TSQLDBDatasetStatement) Implements a statement via the native NexusDB connection Types implemented in the SynDBNexusDB unit: TNXProtocol = ( nxpUnknown. indicated by nxpipe:// . Connect to the specified NexusDB server . override. nxpBFISH ).StartTransaction method must have been called before procedure Connect. override. Begin a Transaction for this connection property Database: TnxDatabase read fDatabase. nxpTCPIP. Create a new statement instance procedure Commit. Determine NexusDB transport protocol (TNXProtocol) to be used.initialize it.aServerName will contain the URL to the Server if the protocol is not nxpFOLDER function NexusEmbeddedEngine: TnxServerEngine. out aAlias: RawUTF8): TNXProtocol. 1. Release any internal NexusDB embedded engine .pas unit .Rev. based on protocol indicator in connection string 1011 NexusEmbeddedEngine Return the internal NexusDB embedded engine 1011 function DropNexusEmbeddedEngine: TnxServerEngine. 2013 Functions or procedures Description Page DropNexusEmbeddedEngi ne Release any internal NexusDB embedded engine 1011 GetNXProtocol Determine NexusDB transport protocol (TNXProtocol) to be used. Return the internal NexusDB embedded engine . if was not already the case SynDBNexusDB.18 Date: June 16.returns nil on success. out aServerName: RawUTF8. .Synopse mORMot Framework Software Architecture Design 1. or PtrInt(-1) if was not initialized function GetNXProtocol(const aConnectionString: RawUTF8.18 Page 1011 of 1055 .if no protocol specifier is included in the connectionstring then nxpFOLDER is assumed. based on protocol indicator in connection string . this unit is a part of the freeware Synopse mORMot framework.18 Units used in the SynDBUniDAC unit: Unit Name Description Page SynCommons Common functions used by most Synopse projects .pas unit . licensed under a MPL/GPL/LGPL tri-license.Rev.pas TDataset-based direct access classes (abstract TQuery-like) .this unit is a part of the freeware Synopse framework.18 325 SynDB Abstract database direct access classes . licensed under a MPL/GPL/LGPL tri-license. version 1. licensed under a MPL/GPL/LGPL tri-license.18 509 SynDBDataset DB.18 Date: June 16.45.this unit is a part of the freeware Synopse framework.18 Page 1012 of 1055 .pas unit Purpose: UniDAC-based classes for SynDB units . licensed under a MPL/GPL/LGPL tri-license.Synopse mORMot Framework Software Architecture Design 1. SynDBUniDAC.this unit is a part of the freeware Synopse framework. 1. version 1. version 1.18 549 ESQLDBDataset ESQLDBUniDAC TSQLDBConnectionThreadSafe TSQLDBUniDACConnection TSQLDBDatasetConnectionProperties TSQLDBUniDACConnectionProperties TSQLDBDatasetStatement TSQLDBUniDACStatement SynDBUniDAC class hierarchy Objects implemented in the SynDBUniDAC unit: Objects Description Page ESQLDBUniDAC Exception type associated to UniDAC database access 1012 TSQLDBUniDACConnectio n TSQLDBUniDACConnectio nProperties TSQLDBUniDACStatement implements a direct connection via UniDAC database access 1014 connection properties definition using UniDAC database 1013 implements a statement via a UniDAC connection 1014 access ESQLDBUniDAC = class(ESQLDBDataset) Exception type associated to UniDAC database access SynDBUniDAC. version 1. 2013 23. aServerName shall contain the UniDAC provider name. override. const aLibraryLocation: TFileName=''. aDatabaseName.this overriden method will use UniDAC metadata to retrieve the information procedure GetTableNames(var Tables: TRawUTF8DynArray).for instance. which will be added to the internal SpecificOptions[] .URI(dOracle.caller is responsible of freeing this instance . to be completed on the left side with the executable path .you can use the TSQLDBUniDACConnectionProperties. 2013 TSQLDBUniDACConnectionProperties = class(TSQLDBDatasetConnectionProperties) connection properties definition using UniDAC database access constructor Create(const aServerName. Allow to set the options specific to a UniDAC driver . 'databasefilename'.TSQLDBDefinition enumeration. override.'Firebird\fbembed. override.Rev. e. Release internal structures function NewConnection: TSQLDBConnection. aPassWord: RawUTF8). override.dll'). PropsFirebird := TSQLDBUniDACConnectionProperties.aDatabaseName shall contain the database server name destructor Destroy. Initialize the properties to connect via UniDAC database access . aLibraryLocationAppendExePath: boolean=true): RawUTF8.possible use may be: PropsOracle := TSQLDBUniDACConnectionProperties. Compute the UniDAC URI from a given database engine . var Fields: TSQLDBColumnDefineDynArray).pas unit . SynDBUniDAC. aUserID. Get all table names .SpecificOptions. Create a new connection . you can set for both SQLite3 and Firebird/Interbase: Props.''.URI(dFirebird.').Values['ClientLibrary'] := ClientDllName.this overriden method will use UniDAC metadata to retrieve the information property SpecificOptions: TStringList read fSpecificOptions. 'tnsname'.'user'. Retrieve the column/field layout of a specified table .18 Date: June 16.this overriden method will create an TSQLDBUniDACConnection instance class function URI(aServer: TSQLDBDefinition. and optionally set some options.'oci64\oci. procedure GetFields(const aTableName: RawUTF8. 'Oracle' .g.URI() to retrieve the provider name from its SynDB. 1.18 Page 1013 of 1055 .pass').Create( TSQLDBUniDACConnectionProperties.Create( TSQLDBUniDACConnectionProperties.dll'). override.Synopse mORMot Framework Software Architecture Design 1.you can set an optional full path to the client library name. override.18 Page 1014 of 1055 .'Access'. override. Commit changes of a Transaction for this connection .Rev.'NexusDB').'InterBase'. Stop connection to the specified database server using UniDAC . override.. Prepare a connection for a specified UniDAC database access destructor Destroy. override. Create a new statement instance procedure Commit. Release memory and connection function IsConnected: boolean. override.should raise an ESQLDBUniDAC on error procedure Rollback.'SQL Server'. 1.Synopse mORMot Framework Software Architecture Design 1. override. override. Begin a Transaction for this connection property Database: TUniConnection read fDatabase. override. Access to the associated UniDAC connection instance TSQLDBUniDACStatement = class(TSQLDBDatasetStatement) implements a statement via a UniDAC connection Constants implemented in the SynDBUniDAC unit: UNIDAC_PROVIDER: array[dOracle. override.StartTransaction method must have been called before procedure Connect.'MySQL'. Connect to the specified database server using UniDAC .18 Date: June 16. Discard changes of a Transaction for this connection . 2013 TSQLDBUniDACConnection = class(TSQLDBConnectionThreadSafe) implements a direct connection via UniDAC database access constructor Create(aProperties: TSQLDBConnectionProperties).should raise an ESQLDBUniDAC on error procedure Disconnect.'SQLite'.high(TSQLDBDefinition)] of RawUTF8 = ( 'Oracle'. Return TRUE if Connect has been already successfully called function NewStatement: TSQLDBStatement.pas unit . UniDAC provider names corresponding to SynDB recognized SQL engines SynDBUniDAC.StartTransaction method must have been called before procedure StartTransaction. 18 Page 1015 of 1055 . This unit is shared by both client and server sides. SynFile application Adopt a mORMot This sample application is a simple database tool which stores text content and files into the database.see Object-relational mapping (page 65).only Delphi code. No external configuration files to write . a TSQLModel class SAD . in order to introduce the reader to some main aspects of the Framework: . This document will follow the application architecture and implementation.1. . the database tables are defined as regular Delphi classes.Synopse mORMot Framework Software Architecture Design 1. General architecture According to the Multi-tier architecture.Rev. Nice and easy. There is an Audit Trail table for tracking the changes made to the database. Classes are translated to database tables.Database design .18 Date: June 16. 1. like a true ORM framework. 2013 24. Safe records are stored using AES-256/SHA-256 encryption. i. See FileTables.e. some units will define the three layers of the SynFile application: Database Model First. with a shared data model.Main SynFile Demo . 24.pas unit.General architecture . in both clear and "safe" manner. .User Interface generation. Published properties of these classes are translated to table fields. We hope this part of the Software Architecture Design (SAD) document would be able to be a reliable guideline for using our framework for your own projects.see Multi-tier architecture (page 61). and a service named "Event" to easily populate the Audit Trail from the Client side. 1.ActionClick. The last FileEdit.Main SynFile Demo . which implements an automated Audit Trail.18 Page 1016 of 1055 . dynamically from the database model and some constant values and enumeration types (thanks to Delphi RTTI) as defined in FileTables. which will be used to describe the software UI. The client side is defined in another class. See FileClient. and add a BLOB data field containing these thumbnails.pas unit is just the form used for editing the data. The reports use GDI+ for anti-aliased drawing. which is able to communicate with the server. can be zoomed and saved as pdf or text files. and fill/update/delete/add the database content playing with classes instances. It also uses our SynGdiPlus. describing all ORM tables/classes. It contains also internal event descriptions. which defines also the classes/tables). using our SynCrypto.pas unit to create thumbnails of any picture (emf+jpg+tif+gif+bmp) of data inserted in the database. triggered when a button is pressed. even if they use their own RESTful GET/PUT dedicated URI (they are not JSON encoded.pas unit is implementing all TSQLRecord child classes. able to create the database tables. See FileServer.dfm file. and actions. and the ForceBlobTransfert := true line in TFileClient. The following class hierarchy was designed: SAD .2. thanks to its ORM orientation.pas unit. to save bandwidth and maintain the RESTful model). Presentation Layer The main form of the Client is void. It's main method is TMainForm. You'll discover how the ORM plays its role here: you change the data.Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16.pas unit.see Object-relational mapping (page 65). All the User Interface is created by the framework. if you open its FileMain. 2013 instance. which will handle the actions. just like changing any class instance properties. You'll see that BLOB fields are handled just like other fields. using the ORM aspect of the framework . It also performs the encryption of "safe memo" and "safe data" records. 24.pas unit.pas unit (the first one. It's also used to call the Audit Trail related service. Create method. Database design The FileTables. Business Logic The server side is defined in a dedicated class. and create the reports.Rev. The framework handles it for you. but transmitted as raw data. Memo. and each corresponding database field layout of each registered class: TSQLMemo = class(TSQLFile) SAD . Here follows the Delphi code written. Name. Picture. It's called "abstract". fCreated: TTimeLog.Rev. trimming the left 'TSQL' characters). fKeyWords: RawUTF8. TSQLMemo. end. because it's purpose is not to contain data. 1. KeyWords) are taken from the TSQLFile abstract parent class. It was used to defined the properties only once. The TSQLRecordSigned class type just defines some Signature and SignatureTime additional properties.Synopse mORMot Framework Software Architecture Design 1. TSQLSafeMemo. The database itself will define TSQLAuditTrail. and TSQLSafeData classes. fModified: TTimeLog. without the need of writing the private variables nor the getter/setter for children classes. doesn't it? The only fact to be noticed is that it does not inherit from a TPersistent class. Modified. property Modified: TTimeLog read fModified write fModified. Data. but as a class with no "real" database table associated. SafeMemo and SafeData tables in the SQlite3 database (the table names are extract from the class name. Only TSQLAuditTrail won't inherit from this parent class. Sounds like a regular Delphi class. 2013 TSQLSafeMemo TSQLSafeData TSQLData TSQLMemo TSQLFile TSQLAuditTrail TSQLRecordSigned TSQLRecord SynFile TSQLRecord classes hierarchy Most common published properties (i. property Created: TTimeLog read fCreated write fCreated. but just some information.Main SynFile Demo . Here is this common ancestor type declaration: TSQLFile = class(TSQLRecordSigned) public fName: RawUTF8. but from a TSQLRecord class. property KeyWords: RawUTF8 read fKeyWords write fKeyWords. Created. They will be stored as AuditTrail. TSQLData.e. which is the parent object type to be used for our ORM.18 Date: June 16. not in the current Delphi OOP terms. published property Name: RawUTF8 read fName write fName.18 Page 1017 of 1055 . which will be used here for handling digital signing of records. fPicture: TSQLRawBlob. property Picture: TSQLRawBlob read fPicture write fPicture. ID : integer Data : TSQLRawBlob Created : TTimeLog KeyWords : RawUTF8 Modified : TTimeLog Name : RawUTF8 Picture : TSQLRawBlob Signature : RawUTF8 SignatureTime: TTimeLog SafeMemo Record Layout TSQLSafeData = class(TSQLData).18 Date: June 16. published property Content: RawUTF8 read fContent write fContent. 2013 public fContent: RawUTF8. end. published property Data: TSQLRawBlob read fData write fData. end. ID : integer Content : RawUTF8 Created : TTimeLog KeyWords : RawUTF8 Modified : TTimeLog Name : RawUTF8 Picture : TSQLRawBlob Signature : RawUTF8 SignatureTime: TTimeLog Memo Record Layout TSQLData = class(TSQLFile) public fData: TSQLRawBlob.18 Page 1018 of 1055 .Rev. 1.Main SynFile Demo . ID : integer Data : TSQLRawBlob Created : TTimeLog KeyWords : RawUTF8 Modified : TTimeLog Name : RawUTF8 Picture : TSQLRawBlob Signature : RawUTF8 SignatureTime: TTimeLog Data Record Layout TSQLSafeMemo = class(TSQLData).Synopse mORMot Framework Software Architecture Design 1. SAD . This special type (mapped as an INTEGER field in the database) is able to define a "one to many" relationship with ANY other record of the database model. Since they were declared as class(TSQLData). RecordReference(Model) method in order to get the value corresponding to an existing SAD . but also the table index as registered at TSQLModel creation. 2013 ID : integer Data : TSQLRawBlob Created : TTimeLog KeyWords : RawUTF8 Modified : TTimeLog Name : RawUTF8 Picture : TSQLRawBlob Signature : RawUTF8 SignatureTime: TTimeLog SafeData Record Layout You can see that TSQLSafeMemo and TSQLSafeData are just a direct sub-class of TSQLData to create "SafeMemo" and "SafeData" tables with the exact same fields as the "Data" table. Then the latest class is not inheriting from TSQLFile.Main SynFile Demo . Retrieve(AssociatedRecord) to get the corresponding record instance. you should define a property with the corresponding TSQLRecord sub-type (for instance.Synopse mORMot Framework Software Architecture Design 1. . fAssociatedRecord: TRecordReference. . In order to access this AssociatedRecord property content.If you want to create a "one to many" relationship with a particular table. holding the RowID value of the associated record (and this field content will be filled with pointer(RowID) and not with a real TSQLSafeData instance). fTime: TTimeLog. they are some new class type. property Status: TFileEvent read fStatus write fStatus. define the property as AssociatedData: TSQLSafeData.18 Page 1019 of 1055 .Rev.) . ID : integer AssociatedRecord : TRecordReference Status : TFileEvent StatusMessage : RawUTF8 Time : TTimeLog AuditTrail Record Layout The AssociatedRecord property was defined as TRecordReference. property StatusMessage: RawUTF8 read fStatusMessage write fStatusMessage. end. 1. You could also use the TSQLRecord.in this case.18 Date: June 16. you could use either TSQLRest. property AssociatedRecord: TRecordReference read fAssociatedRecord write fAssociatedRecord. if you want to link to a particular SafeData row.Using a TRecordReference type will not link to a particular table. and is used only as a log of all actions performed using SynFile: TSQLAuditTrail = class(TSQLRecord) protected fStatusMessage: RawUTF8. fStatus: TFileEvent. but any table of the database model: it will store in its associated INTEGER database field not only the RowID of the record. because it does not contain any user data. this will create an INTEGER field in the database. published property Time: TTimeLog read fTime write fTime. or typecast it to RecordRef(AssociatedRecord) to easily retrieve or set the associated table and RowID. which can be linked to actions and custom status. You can select which set of components are used. But for producing easily applications. It is able to generated a Ribbon-based application. To this list could be added an integrated event feature. .the framework expect a common database model to be shared between client and server. hint texts.Synopse mORMot Framework Software Architecture Design 1. . 24.pas unit. using the mORMotUIEdit. which is able to create custom graphs from the application source code it parsed. Just note for the moment that it will register the TSQLAuditTrail. TSQLSafeMemo. .How generic automated edition.1. A common function has been defined in the FileTables. User Interface generation You could of course design your own User Interface without our framework.pas unit.see Model-View-Controller (page 60) .Native VCL components.g. We'll see later its implementation.3.g.Proprietary TMS components. The order of the registration of those classes will be used for the AssociatedRecord: TRecordReference field of TSQLAuditTrail . 1.Which actions should be associated with each table. reporting etc. as such: function CreateFileModel(Owner: TSQLRest): TSQLModel.globally to your project (i. TSQLData.Rev. According to the MVC model . in which each table is available via a Ribbon tab. 2013 TSQLRecord instance.see REST (page 191) . TSQLMemo. the framework provides a mechanism based on both ORM description and RTTI compiler-generated information in order to create most User Interface by code. without providing any explicit database content conversion mechanism. For instance. Note that all above graphs were created directly from the SynProject.g.see Enhanced logging (page 78). is to be generated.).How the User Interface should be customized (e.3.please do not make confusion between this user-level logging and technical-level logging using TSynLog and TSQLLog classes and "families" . and some actions performed to it. in the SAD . So it's mandatory to NOT change this order in any future modification of the database schema. by defining . a TSQLMemo record will be identified with a table index of 1 in the RecordReference encoded value.since such a feature is not yet integrated to our provided source code. and TSQLSafeData classes as part of the database model..e.. So the framework would need to know: .Main SynFile Demo . grid layout on screen. . 24. this is perfectly feasible to use only the ORM part of it. in the SynFile TSQLAuditTrail table) .18 Date: June 16. Rendering The current implementation of the framework User Interface generation handles two kind of rendering: .Which tables must be displayed. it should be needed to develop AJAX applications using its RESTful model . That is. to provide a centralized handling of user-level loging (as used e.e.18 Page 1020 of 1055 . TSynToolButton. TSynPage.18 Date: June 16. but will have a very diverse layout.microsoft. Here is the screen content.. 1.com/en-us/library/cc872782. 2013 Project/Options/Conditionals menu) .aspx.microsoft. Vista and Seven. the TSynForm. For instance. If you use TMS ribbon. TSynToolBar. XP. using the TMS components: SAD .Main SynFile Demo . and will display a "ribbon" very close to the official Office 2007/2010 version. TSynPopupMenu. If you use the generic components as defined in mORMotToolBar (i. The Office UI licensing program was designed by Microsoft for software developers who wish to implement the Office UI as a software component and/or incorporate the Office UI into their own applications.18 Page 1021 of 1055 . the USETMSPACK conditional will do all the magic for you. The TMS components will have the same rendering whatever the Windows it's running on. please take a look at those official guidelines: http://msdn.Synopse mORMot Framework Software Architecture Design 1. The native VCL components will use native Windows API components. If it is not set (which is by default). TSynBodyPager and TSynBodyPage classes) and SynTaskDialog (for TSynButton) in your own code. The "ribbon" as generated with VCL components has most functionalities than the Office 2007/2010 ribbon.aspx.Rev.com/en-us/office/aa973809. Here are some PROs and CONs about both solutions: Criteria VCL TMS Rendering Basic Sophisticated OS version Variant Constant Ribbon look Unusual Office-like Preview button & Shortcuts None by default Available Extra Price None High GPL ready Yes No Office UI Licensing N/A Required EXE size Smaller Bigger It's worth saying that the choice of one or other component set could be changed on request.the USETMSPACK conditional. it will use VCL components.e. TSynPager. the resulting screen will be diverse if the application is run under Windows 2000.see at http://msdn. it does not require any more acceptance of the Office UI License terms .. If you want to design your user interface using a Office 2007/2010 ribbon look. So the look and feel of the application will vary depending on the Windows version it is running on. Synopse mORMot Framework Software Architecture Design 1.Main SynFile Demo . 1.18 Page 1022 of 1055 .Rev. available from Delphi 6 up to XE4: User Interface generated using VCL components SAD .18 Date: June 16. 2013 User Interface generated using TMS components And here is the same application compiled using only VCL components. if necessary. Translate method. 24. FieldWidth: 'IddId'.Main SynFile Demo . RTTI and "uncamelcasing" will be used to display this list as regular text. "Refresh".Synopse mORMot Framework Software Architecture Design 1. ORM Registration The User Interface generation will be made by creating an array of objects inheriting from the TSQLRibbonTabParameters type. feServerShutdown. was also defined. Enumeration types A list of available actions should be defined. FieldWidth: 'gIZ'. "Import". "Query". faImport. faExport. feRecordModified. the following list will generate a set of available buttons on the User Interface. "Sign".faMark. SAD . feRecordCreated. faDelete. faUnmarkAll. "Extract" and "Settings".. "Edit". Firstly. Select: 'Time.4] of TFileRibbonTabParameters = ( (Table: TSQLAuditTrail. Actions: DEF_ACTIONS). Layout: llClient.faRefresh. Its action-driven design won't make it easy to interface with the event-driven design of our User Interface handling.Rev. See both above screen-shots to guess how the button captions match the enumeration names . end.faPrintPreview. feRecordDigitallySigned. associating TFileRibbonTabParameters = object(TSQLRibbonTabParameters) /// the SynFile actions Actions: TFileActions. "Export".2.Status. and we have to confess that this component has rather bad reputation (at least in the Delphi 2009 version). User Interface generated using VCL components (page 1022) and User Interface generated using VCL components (page 1022). 2013 We did not use yet the Ribbon component as was introduced in Delphi 2009. feRecordDeleted. faPrintPreview. Then a constant array of such objects is defined: const FileTabs: array[0. faQuery.3. faCopy. Feel free to adapt our Open Source code to use it .18 Page 1023 of 1055 . faCreate. "Unmark all". Some events reflect the change made to the database rows (like feRecordModified). it could be translated on-the-fly from English into the current desired language. "Copy".3.StatusMessage'. Actions: [faDelete. Group: GROUP_CLEAR. Thanks to the Delphi RTTI. faSign.e.faQuery.18 Date: June 16. named "Mark".faSettings]). 1. (Table: TSQLMemo. but we don't have time nor necessity to do it by ourself. ShowID: true. faRefresh.i. "Print preview". as an enumeration type: TFileAction = ( faNoAction. A list of events.pas unit (responsible of application i18n) and the TLanguageFile.3. faMark.we'll be very pleased to release a new version supporting it. 24. In the grid and the reports. faEdit. "Create". a custom object type is defined. Select: DEF_SELECT. before display on screen or report creation. faExtract. faSettings ). Thanks to the mORMoti18n. "Delete". feRecordExported ). Group: GROUP_MAIN. feServerStarted.faUnmarkAll. feRecordImported. and "Un Camel Casing". and translated to the current language. ReverseOrder: true. like "Record digitally signed". or generic application status (like feServerStarted): TFileEvent = ( feUnknownState. as used for the TSQLAuditTrail table. For each table. A custom CSV list of fields should be set to detail which database columns must be displayed on the grids and the reports. By default. AlreadyBegan: boolean=false).Allow preview (with anti-aliased drawing via GDI+) and printing. aID: integer.pdf file. titles and such). Note that this array definition uses some previously defined individual constants (like DEF_SELECT. Select: DEF_SELECT. P: TSQLRibbonTab. and could make code maintenance easier later on.lowercase character will center the field data. 1. Group: GROUP_CLEAR. The reporting engine in the framework is implemented via the TGDIPages class. the available actions are also set.18 Page 1024 of 1055 .4. override. (Table: TSQLSafeData. Actions: DEF_ACTIONS_DATA)). aReport: TGDIPages.Data is drawn in memory. . (Table: TSQLSafeMemo. columns. Pic: TBitmap.3. DEF_ACTIONS_DATA or GROUP_SAFE. var Rec: TSQLFile. Actions: DEF_ACTIONS_DATA). Select: DEF_SELECT. BeginDoc. The grid column widths are defined as a FieldWidth string in which each displayed field length mean is set with one char per field (A=first Select column. . in the Select property. FieldWidth: 'IddId'. PC: PChar.Rev. end.CreateReport(aTable: TSQLRecordClass.Handle bookmark.18 Date: June 16. Select: DEF_SELECT.pas: /// class used to create the User interface TFileRibbon = class(TSQLRibbon) public /// overridden method used customize the report content procedure CreateReport(aTable: TSQLRecordClass. Each ribbon tab could contain one or more TSQLRecord table: the Group property is set to identify on which ribbon group it should be shown.Synopse mORMot Framework Software Architecture Design 1.Z=26th column) . This is a good practice. The Table property will map the ORM class to the User Interface ribbon tab. begin with aReport do begin // initialize report Clear. Actions: DEF_ACTIONS). the CreateReport method of TSQLRibbon will write all editable fields value to the content.txt or . defined in the mORMotReport. they displayed or printed as desired. Report generation The following CreateReport method is overridden in FileClient. aID: integer. but you can have access to a TCanvas property which allows any possible content generation via standard VCL methods. SAD . outlines and links inside the document. . FieldWidth: 'IddId'. and will be used to create the possible buttons to be shown on the ribbon toolbars (enabling or disabling a button is to be done at runtime).High-level reporting methods are available (implementing tables.pas: . Group: GROUP_SAFE. . 2013 (Table: TSQLData.Main SynFile Demo . AlreadyBegan: boolean=false).Direct export as . FieldWidth: 'IddId'. The method is overridden by the following code: procedure TFileRibbon. aReport: TGDIPages. s: string. Group: GROUP_SAFE. 24. CurentRecord. then restore the default settings.Iso2S(Rec. end.Size := 10.18 Date: June 16. RestoreSavedLayout.Rev. NewLine. Caption := U2S(Rec.Synopse mORMot Framework Software Architecture Design 1. // write global header at the beginning of the report DrawTitle(P. and the report caption is set via the record Name field.fCreated<>0 then DrawTextAcrossCols([sCreated.fName).Main SynFile Demo . // default handler exit.SignatureTime<>0 then begin PC := Pointer(Format(sSignedN.fKeyWords='' then s := sNone else begin s := U2S(Rec.fModified)]). if Rec.Size := 9.CurrentRecord. Page footer are set by using two methods: .Iso2S(Rec.$C0C0FF). end. ExportPDFKeywords := s.AddTextToFooterAt to add some custom text at a given position (here the right margin. Report header is written using the following methods: SAD . AddTextToFooterAt('SynFile http://synopse. and BeginDoc method is called to start creating the internal canvas and band positioning.Free. if not aTable. after having changed the text alignment into right-aligned).true).CaptionName+' : '+Caption.InheritsFrom(TSQLFile) then P := nil else P := GetActivePage.Width div 3). Pic := LoadFromRawByteString(Rec. 1.info . Font.CurrentRecord). The report is cleared.[Rec. if Rec.18 Page 1025 of 1055 . 2013 Font.0. and parameters are checked against expected values. end. TextAlign := taRight.Iso2S(Rec.LeftMargin).SignedBy. AddPagesToFooterAt(sPageN. if Rec.AddPagesToFooterAt to add the current page number at a given position (here the left margin). DrawTextAcrossCols([sKeyWords. end.fPicture).'+Caption. if Rec. AddColumns([6.fCreated)]). // prepare page footer SaveLayout.fModified<>0 then DrawTextAcrossCols([sModified.fKeyWords). DrawTextAcrossColsFromCSV(PC. Then the current viewed record is retrieved from GetActivePage.SignatureTime)])). finally Pic.40]).Pic.s]). Note that SaveLayout/RestoreSavedLayout methods are used to modify temporary the current font and paragraph settings for printing the footer. if Pic<>nil then try DrawBMP(Pic.Table. Rec := TSQLFile(P. NewHalfLine.ID<>aID) or (P. The font size is set. .RightMarginPos). SetColumnBold(0).Table<>aTable) then begin inherited. if (P=nil) or (P. .GetMimeContentType is used to retrieve the exact type of the data stored in this record. with a black line below it (second parameter to true) . as such: resourcestring sCreated = 'Created'.[U2S(KB(Length(Data)))]). as defined in mORMoti18n. ExportPDFForceJPEGCompression := 80.true).Content) else if Rec. // write report content DrawTitle(sContent. the font is set to 'Courier New' so that it will be displayed with fixed width. which content is loaded using the generic LoadFromRawByteString function implemented in SynGdiPlus.pdf on request.DrawText. and that the header bitmap should be compressed as JPEG before writing to the file (in order to produce a small sized .InheritsFrom(TSQLSafeMemo) then DrawText(sSafeMemoContent) else if Rec.NewHalfLine and NewLine will leave some vertical gap between two paragraphs. Font. . SaveLayout. DrawText(sDataContent).pas. end.this title will be added to the report global outline.fName))). Then the report content is appended.InheritsFrom(TSQLSafeData) then s := U2S(GetMimeContentType(Pointer(Data). s := PictureName(TSynPicture. . sContent = 'Content'. SAD . if Rec.InheritsFrom(TSQLData) then with TSQLData(Rec) do begin DrawTextU(Rec. You perhaps did notice that textual constant were defined as resourcestring. . sModified = 'Modified'.Name := 'Courier New'.pdf). sKeyWords = 'KeyWords'. with the current alignment .Length(Data).AddColumns. we want to notify that SynFile generated those files.IsPicture(TFileName(Rec.DrawBMP will draw a bitmap to the report. according to the record class type: .TFileName(Rec. NewHalfLine. 2013 .U2S and Iso2S function.[s]) else if not Rec. end.DrawTextAcrossCols and DrawTextAcrossColsFromCSV will fill a table row according to the text specified.DrawTitle to add a title to the report.Main SynFile Demo . . DrawTextFmt(sSizeN. if s<>'' then DrawTextFmt(sContentTypeN.18 Page 1026 of 1055 . with parameters set as percentages. // set custom report parameters ExportPDFApplication := 'SynFile http://synopse.in this case. 1. DrawTextU and DrawTextFmt are able to add a paragraph of text to the report. if s<>'' then s := format(sPictureN. RestoreSavedLayout. Those ExportPDFApplication and ExportPDFForceJPEGCompression properties (together with the ExportPDFKeywords are able to customize how the report will be exported into a . .pas. and will be exported as such in . will initialize a table with the first column content defined as bold (SetColumnBold(0)).18 Date: June 16.InheritsFrom(TSQLMemo) then DrawTextU(TSQLMemo(Rec). end.fName))).fName).pdf file. are used for conversion of some text or TTimeLog into a text formated with the current language settings (i18n). one string per column.Rev. In our case.Synopse mORMot Framework Software Architecture Design 1.[s]).info'. via its ExtractAllResources function.'. a corresponding .Rev.18 Date: June 16. and create a reference text file.'.5.'#13+ 'Please click on the "Edit" button to show its content. Creating a report from code does make sense in an ORM. sSignedN = 'Signed. 2013 sNone = 'None'. Since we have most useful data at hand as Delphi classes. from enumerations or class properties names).pas unit is able to extract all textual resource from the executable. The mORMoti18n. Creating the reference file In order to begin a translation task. and even captions generated from RTTI . For instance. A list of all used textual elements will be retrieved then hashed into an unique numerical value. and a few lines of code is able to produce complex reports. e. the mORMoti18n.Internationalization (i18n) is the process of designing a software application so that it can be adapted to various languages.3.3. SAD . sContentTypeN = 'Content Type: %s'.g. sPageN = 'Page %d / %d'.1. The unit extends this to visual forms. an end-user) is able to add a new language.Synopse mORMot Framework Software Architecture Design 1.pas unit.g. It will in fact: . Our framework handles both features. and create a reference text file to be translated into any handled language.msg file is to be supplied in the executable folder. sDataContent = 'Please click on the "Extract" button to get its content. starting from another . 24.msg text file in the executable folder matching the expected locale definition. via the mORMoti18n.Main SynFile Demo . unified layout.Extract all captions generated from RTTI (e. Application i18n and L10n In computing.5. sSafeMemoContent = 'This memo is password protected.Extract all resourcestring text. 24. even a non developer (e. sPictureN = '%s Picture'. code can be shared among all kind of reports. it will search for FR.Localization (L10n) is the process of adapting internationalized software for a specific region or language by adding locale-specific components and translating text. for dates display. sSizeN = 'Size: %s'. The unit expects all textual content (both resourcestring and RTTI derived captions) to be correct English text.pas unit is able to parse all those resourcestring from a running executable. . 1.msg. We just saw above how resourcestring defined in the source code are retrieved from the executable and can be translated on the fly. . nor the executable is to be rebuild to add a new language. And since this file is indeed a plain textual file. internationalization and localization (also spelled internationalisation and localisation) are means of adapting computer software to different languages. Neither the source code. with enhanced rendering.msg for translation into French. regional differences and technical requirements of a target market: .see RTTI (page 129). associated with their numerical hash value. containing all English sentences and words to be translated. When a specific locale is set for the application.By %s on %s'. direct internationalization and export capabilities. the unit will search for a .g.18 Page 1027 of 1055 . In order to translate all the user interface. for the framework main demo: procedure TMainForm. Running once the executable will create a SynFile. 1.Caption=_3731019706 KeyWords [TLoginForm] Label1. 2013 . For instance.Main SynFile Demo . all enumerations to be translated [TypeInfo(TFileEvent). but only extract all resources from the executable.Model].TypeInfo(TFileAction). and create per-form sections.ToolBar.TypeInfo(TPreviewAction)]. and all needed English caption text will be extracted. Then the ExtractAllResources global procedure is to be called somewhere in the code. end.messages text file in the SynFile.Caption=_2817614158 Name KeyWords.SynFile 940170664=Content 3153227598=None 3708724895=Page %d / %d 2767358349=Size: %s SAD .Rev. allowing a custom translation of displayed captions or hints. The Close method is then called.pas. here is how this is implemented in FileMain. {$endif} Ribbon. globally to the whole application (a full rebuild is necessary after having added or suppressed this conditional from the Project / Options / Folders-Conditionals IDE field). since we don't want to use the application itself. The TFileEvent and TFileAction enumerations RTTI information is supplied. containing all English text: [TEditForm] Name.[]). // then some class instances (including the TSQLModel will handle all TSQLRecord) [Client.18 Date: June 16. // some custom classes or captions [].Extract all embedded dfm resources. together with the current TSQLModel instance.Synopse mORMot Framework Software Architecture Design 1.EditLabel.18 Page 1028 of 1055 .EditLabel.ActivePageIndex := 1. This creation step needs a compilation of the executable with the EXTRACTALLRESOURCES conditional defined. begin {$ifdef EXTRACTALLRESOURCES} ExtractAllResources( // first.exe folder.SynFile [Messages] 2784453965=Memo 2751226180=Data 744738530=Safe memo 895337940=Safe data 2817614158=Name 1741937413=&User name: 4235002365=&Password: 16479868= Synopse mORMot demo . Close. {$else} //i18nLanguageToRegistry(lngFrench). All TSQLRecord classes (and therefore properties) will be scanned.Caption=_1741937413 Label2.FormShow(Sender: TObject).Caption=_4235002365 [TMainForm] Caption=_16479868 &User name: &Password: Synopse mORMot demo . in order to reflect a specific use of the generic text on the screen. the default numerical values will be used.. if you set in FileMain. as NumericalKey=EnglishText pairs..By %s on %s (. 388288630=Signed. 1.|Please click on the "Edit" button to show its content.Create constructor.3. and replacing line feeds (#13) by the special | character (a line feed is not expected on a one-line-per-pair file layout). 24. i. 24. 2013 4281038646=Content Type: %s 2584741026=This memo is password protected. Note that if no _NumericalKey is specified. This is usual for instance for hint values.pas.Main SynFile Demo . Language selection User Interface language can be specified at execution.2.5. each application form has its own section (e. it contains all English extracted texts. As requested.FR file. [TEditForm].3.Caption will use the text identified by 1741937413 in the [Messages] section). 3011148197=Choisissez "Extraire" pour enregistrer le contenu.FormShow(Sender: TObject). but it will also allow easier translation of all forms. The underline character before the numerical key is used to refers to this value.. For instance.5. [TMainForm]).Synopse mORMot Framework Software Architecture Design 1. it will use the registry to set the language. specified by a numerical key (for instance Label1.. proposing some default translation. In fact. Note that the special characters %s %d .e.18 Date: June 16. | markup was preserved: only the plain English text has been translated to the corresponding French. Name.SynFile 940170664=Contenu 3153227598=Vide 3708724895=Page %d / %d 2767358349=Taille: %s 4281038646=Type de contenu: %s 2584741026=Le contenu de ce memo est protégé par un mot de passe. a plain text can be specified.exe folder: [Messages] 2784453965=Texte 2751226180=Données 744738530=Texte sécurisé 895337940=Données sécurisées 2817614158=Nom 1741937413=&Nom utilisateur: 4235002365=&Mot de passe: 16479868= Synopse mORMot Framework demo . the following FR. It will need an application restart.. begin SAD .) Since no form-level custom captions have been defined in this SynFile.Caption will be displayed using the text specified by 2817614158.EditLabel.) The main section of this text file is named [Messages]. By default. including formating characters (like %d). Note this will reflect the exact content of resourcestring or RTTI captions.3. 'Nom'. as expected by the code.g.Rev. using a low-level hook of the TForm. 3011148197=Please click on the "Extract" button to get its content. Some other text lines are separated by a comma.|Choisissez "Editer" pour le visualiser.Par %s le %s (. 388288630=Signé.18 Page 1029 of 1055 . for the framework main demo: procedure TMainForm.msg file could be made available in the SynFile. In our case. Adding a new language In order to translate the whole application into French. 1. using a menu or a combo box.Synopse mORMot Framework Software Architecture Design 1. Localization Take a look at the TLanguageFile class. Ribbon.msg file will be used to translate all screen layout.ActivePageIndex := 1.) i18nLanguageToRegistry(lngFrench). At next startup. See i18nAddLanguageItems.18 Page 1030 of 1055 . After the main language has been set.ToolBar. 2013 (... you can use the global Language instance in order to localize your application layout. i18nAddLanguageMenu and i18nAddLanguageCombo functions and procedures to create your own language selection dialog.Main SynFile Demo . for instance. SAD . for a final application. Above code will set the main application language as French. in order to translate the RTTI-level text into the current selected language. end.4.3. the content of a supplied FR. See for instance i18nDateText.pas.5. including all RTTI-generated captions. Of course. you'll need to change the language by a common setting. The mORMoti18n unit will register itself to some methods of mORMot. 24.18 Date: June 16.Rev. Main SynFile Demo source 25.1.5 engine version) 707 SynCommons SynCrypto Unit dependencies in the "Lib" directory Units located in the "Lib\SQLite3\" directory: Source File Name Description Page mORMot Common ORM and SOA classes for mORMot 715 mORMotHttpClient HTTP/1.18 Page 1031 of 1055 .2.Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16.1 RESTFUL JSON Client classes for mORMot 917 mORMoti18n Internationalization (i18n) routines and classes for mORMot 924 mORMotReport Reporting unit 934 mORMotToolBar ORM-driven Office 2007 Toolbar for mORMot 966 SAD . 1. emulated on XP) 700 SynZip Low-level access to ZLib compression (1. Main SynFile Demo used Units The Main SynFile Demo makes use of the following units.Main SynFile Demo .Rev. Units located in the "Lib\" directory: Source File Name Description Page SynCommons Common functions used by most Synopse projects 325 SynCrypto Fast cryptographic routines (hashing and cypher) 497 SynGdiPlus GDI+ library API access 576 SynTaskDialog Implement TaskDialog window (native on Vista/Seven. 2013 25. 2013 Source File Name Description Page mORMotUI Grid to display database content for mORMot 980 mORMotUILogin Some common User Interface functions and dialogs for mORMot 993 SynGdiPlus SynCommons mORMotReport mORMotUI mORMotUILogin mORMotToolBar mORMoti18n SynTaskDialog mORMot SynZip mORMotHttpClient Unit dependencies in the "Lib\SQLite3" directory Units located in the "Lib\SQLite3\Samples\MainDemo\" directory: Source File Name Description Page FileClient SynFile client handling 1034 FileEdit SynFile Edit window 1036 FileMain SynFile main Window 1038 FileServer SynFile server handling 1040 FileTables SynFile ORM definitions shared by both client and server 1042 SAD .18 Date: June 16.Rev.Synopse mORMot Framework Software Architecture Design 1. 1.18 Page 1032 of 1055 .Main SynFile Demo . Main SynFile Demo .Synopse mORMot Framework Software Architecture Design 1.Rev.18 Date: June 16. 2013 mORMoti18n mORMot SynZip FileTables FileServer SynCrypto mORMotReport SynCommons FileClient mORMotHttpClient FileMain mORMotToolBar SynGdiPlus FileEdit SynTaskDialog mORMotUI mORMotUILogin Unit dependencies in the "Lib\SQLite3\Samples\MainDemo" directory SAD . 1.18 Page 1033 of 1055 . 18 715 mORMotHttpClient HTTP/1. version 1.Rev.1 RESTFUL JSON Client classes for mORMot . version 1.this unit is a part of the freeware Synopse framework.this unit is a part of the freeware Synopse framework.18 934 mORMotToolBar ORM-driven Office 2007 Toolbar for mORMot . 2013 25. 1. TIF.this unit is a part of the freeware Synopse mORMot framework. version 1. licensed under a MPL/GPL/LGPL tri-license. licensed under a MPL/GPL/LGPL tri-license. licensed under a MPL/GPL/LGPL tri-license.2.pas unit . version 1.this unit is a part of the freeware Synopse mORMot framework.18 576 TSQLHttpClient TFileClient TSQLRibbon TFileRibbon FileClient class hierarchy Objects implemented in the FileClient unit: Objects Description Page TFileClient A HTTP/1. licensed under a MPL/GPL/LGPL tri-license.this unit is a part of the freeware Synopse mORMot framework.18 Page 1034 of 1055 .18 917 mORMoti18n Internationalization (i18n) routines and classes for mORMot .this unit is a part of the freeware Synopse mORMot framework. version 1. version 1.adds GIF.18 Date: June 16.pas unit Purpose: SynFile client handling Units used in the FileClient unit: Unit Name Description Page FileTables SynFile ORM definitions shared by both client and server 1042 mORMot Common ORM and SOA classes for mORMot . version 1. licensed under a MPL/GPL/LGPL tri-license. licensed under a MPL/GPL/LGPL tri-license.make available most useful GDI+ drawing methods .allows Antialiased rending of any EMF file using GDI+ .1 client to access SynFile 1035 FileClient. PNG and JPG pictures read/write support as standard TGraphic .18 966 SynCommons Common functions used by most Synopse projects . licensed under a MPL/GPL/LGPL tri-license.Synopse mORMot Framework Software Architecture Design 1.18 325 SynGdiPlus GDI+ library API access .18 924 mORMotReport Reporting unit . FileClient.this unit is a part of the freeware Synopse mORMot framework. 18 Date: June 16. reintroduce. 1.Rev.18 Page 1035 of 1055 . var Action): string. aAssociatedRecord: TSQLRecord). Overriden method used customize the report content FileClient. Client-side access to the remote RESTful service TFileRibbon = class(TSQLRibbon) Class used to create the User interface procedure CreateReport(aTable: TSQLRecordClass. aReport: TGDIPages. TestEnabled: boolean. override. 2013 Objects Description Page TFileRibbon Class used to create the User interface 1035 TFileClient = class(TSQLHttpClient) A HTTP/1.Synopse mORMot Framework Software Architecture Design 1. aID: integer. Used internaly to retrieve a given action procedure AddAuditTrail(aEvent: TFileEvent. AlreadyBegan: boolean=false).pas unit . Initialize the Client for a specified network Server name function OnSetAction(TableIndex. ToolbarIndex: integer.1 client to access SynFile constructor Create(const aServer: AnsiString). this unit is a part of the freeware Synopse mORMot framework. version 1. version 1.18 924 mORMotUI Grid to display database content for mORMot . licensed under a MPL/GPL/LGPL tri-license.18 576 SynTaskDialog Implement TaskDialog window (native on Vista/Seven. 1. licensed under a MPL/GPL/LGPL tri-license.Synopse mORMot Framework Software Architecture Design 1.18 325 SynCrypto Fast cryptographic routines (hashing and cypher) . version 1. licensed under a MPL/GPL/LGPL tri-license. version 1. version 1. SHA1.this unit is a part of the freeware Synopse mORMot framework.18 Date: June 16.this unit is a part of the freeware Synopse mORMot framework. licensed under a MPL/GPL/LGPL tri-license. FileEdit.this unit is a part of the freeware Synopse framework.18 Page 1036 of 1055 .this unit is a part of the freeware Synopse mORMot framework.3.optimized for speed (tuned assembler and VIA PADLOCK optional support) .Rev. emulated on XP) . version 1.implements AES.18 993 SynCommons Common functions used by most Synopse projects .18 700 TVistaForm TEditForm FileEdit class hierarchy Objects implemented in the FileEdit unit: FileEdit.18 715 mORMoti18n Internationalization (i18n) routines and classes for mORMot .this unit is a part of the freeware Synopse mORMot framework. licensed under a MPL/GPL/LGPL tri-license.make available most useful GDI+ drawing methods . licensed under a MPL/GPL/LGPL tri-license.pas unit .18 497 SynGdiPlus GDI+ library API access . version 1.this unit is a part of the freeware Synopse mORMot framework. XOR.adds GIF. version 1. licensed under a MPL/GPL/LGPL tri-license.18 980 mORMotUILogin Some common User Interface functions and dialogs for mORMot .this unit is a part of the freeware mORMot framework. ADLER32. licensed under a MPL/GPL/LGPL tri-license. PNG and JPG pictures read/write support as standard TGraphic .allows Antialiased rending of any EMF file using GDI+ . MD5.pas unit Purpose: SynFile Edit window Units used in the FileEdit unit: Unit Name Description Page FileTables SynFile ORM definitions shared by both client and server 1042 mORMot Common ORM and SOA classes for mORMot . SHA256 algorithms . TIF. 2013 25. 1. SynFile Edit window instance FileEdit.pas unit . Should be set to TRUE to disable any content editing property Rec: TSQLFile read fRec. Read-only access to the edited record Functions or procedures implemented in the FileEdit unit: Functions or procedures Description Page Cypher Will display a modal form asking for a password. then encrypt or uncrypt some BLOB content .18 Date: June 16. Will display a modal form asking for a password. then encrypt or uncrypt some BLOB content 1037 function Cypher(const Title: string. 2013 Objects Description Page TEditForm SynFile Edit window 1037 TEditForm = class(TVistaForm) SynFile Edit window .Synopse mORMot Framework Software Architecture Design 1.18 Page 1037 of 1055 .we don't use the standard Window generation (from mORMotUIEdit). Used to load a picture file into a BLOB content after 80% JPEG compression function SetRec(const Value: TSQLFile): boolean. var Picture: RawByteString): boolean. created as RAD function LoadPicture(const FileName: TFileName.returns TRUE if the password was correct and the data processed .returns FALSE on error (canceled or wrong password) Variables implemented in the FileEdit unit: EditForm: TEditForm. Encrypt: boolean): boolean.Rev. var Content: TSQLRawBlob. but a custom window. Set the associated record to be edited property ReadOnly: boolean read fReadOnly write fReadOnly. pas unit Purpose: SynFile main Window Units used in the FileMain unit: Unit Name Description Page FileClient SynFile client handling 1034 FileEdit SynFile Edit window 1036 FileServer SynFile server handling 1040 FileTables SynFile ORM definitions shared by both client and server 1042 mORMot Common ORM and SOA classes for mORMot . version 1. licensed under a MPL/GPL/LGPL tri-license.this unit is a part of the freeware Synopse mORMot framework. 1.this unit is a part of the freeware Synopse framework.18 980 mORMotUILogin Some common User Interface functions and dialogs for mORMot .18 Page 1038 of 1055 . FileMain.18 966 mORMotUI Grid to display database content for mORMot . licensed under a MPL/GPL/LGPL tri-license.1 RESTFUL JSON Client classes for mORMot .this unit is a part of the freeware Synopse mORMot framework.allows Antialiased rending of any EMF file using GDI+ . version 1. version 1.pas unit .Rev.this unit is a part of the freeware Synopse mORMot framework.this unit is a part of the freeware Synopse mORMot framework.this unit is a part of the freeware mORMot framework. TIF.4. licensed under a MPL/GPL/LGPL tri-license. licensed under a MPL/GPL/LGPL tri-license. version 1. licensed under a MPL/GPL/LGPL tri-license. licensed under a MPL/GPL/LGPL tri-license.18 924 mORMotToolBar ORM-driven Office 2007 Toolbar for mORMot .18 917 mORMoti18n Internationalization (i18n) routines and classes for mORMot .18 325 SynGdiPlus GDI+ library API access .adds GIF. PNG and JPG pictures read/write support as standard TGraphic . version 1.this unit is a part of the freeware Synopse mORMot framework. version 1.18 715 mORMotHttpClient HTTP/1.this unit is a part of the freeware Synopse mORMot framework. licensed under a MPL/GPL/LGPL tri-license. licensed under a MPL/GPL/LGPL tri-license.18 576 TSynForm TMainForm FileMain class hierarchy FileMain.Synopse mORMot Framework Software Architecture Design 1.18 Date: June 16. version 1. 2013 25. version 1.make available most useful GDI+ drawing methods .18 993 SynCommons Common functions used by most Synopse projects . Rev. The associated database client Ribbon: TFileRibbon. 1.Synopse mORMot Framework Software Architecture Design 1. override.18 Page 1039 of 1055 . 2013 Objects implemented in the FileMain unit: Objects Description Page TMainForm SynFile main Window 1039 TMainForm = class(TSynForm) SynFile main Window Client: TFileClient. Release all used memory FileMain.pas unit . The associated Ribbon which will handle all User Interface destructor Destroy.18 Date: June 16. 18 325 TSQLRestserverDB TFileServer FileServer class hierarchy Objects implemented in the FileServer unit: Objects Description Page TFileServer A server to access SynFile data content 1040 TFileServer = class(TSQLRestserverDB) A server to access SynFile data content Server: TSQLHttpServer. override.an optional database record can be specified in order to be associated with the event FileServer. Database server-side trigger which will add an event to the TSQLAuditTrail table procedure Event(var Ctxt: TSQLRestServerCallBackParams). version 1.this unit is a part of the freeware Synopse mORMot framework.18 Page 1040 of 1055 .this unit is a part of the freeware Synopse mORMot framework.Synopse mORMot Framework Software Architecture Design 1. 2013 25.1 server destructor Destroy. version 1.18 715 mORMoti18n Internationalization (i18n) routines and classes for mORMot . licensed under a MPL/GPL/LGPL tri-license.pas unit .Rev. FileServer. A RESTful service used from the client side to add an event to the TSQLAuditTrail table .pas unit Purpose: SynFile server handling Units used in the FileServer unit: Unit Name Description Page FileTables SynFile ORM definitions shared by both client and server 1042 mORMot Common ORM and SOA classes for mORMot . version 1. 1. Event: TSQLEvent. licensed under a MPL/GPL/LGPL tri-license. licensed under a MPL/GPL/LGPL tri-license.5.this unit is a part of the freeware Synopse mORMot framework. The runing HTTP/1.1 server constructor Create. Release used memory and data function OnDatabaseUpdateEvent(Sender: TSQLRestServer.18 924 SynCommons Common functions used by most Synopse projects .18 Date: June 16. aID: integer): boolean. Create the database and HTTP/1. aTable: TSQLRecordClass. 18 Date: June 16. 2013 procedure AddAuditTrail(aEvent: TFileEvent. 1.Rev.Synopse mORMot Framework Software Architecture Design 1. Add a row to the TSQLAuditTrail table FileServer. aAssociatedRecord: TRecordReference=0).18 Page 1041 of 1055 . const aMessage: RawUTF8=''.pas unit . 2013 25.Synopse mORMot Framework Software Architecture Design 1. licensed under a MPL/GPL/LGPL tri-license. licensed under a MPL/GPL/LGPL tri-license.18 Date: June 16. used to track events and status 1043 TSQLData An uncrypted Data table 1043 TSQLFile An abstract class.this unit is a part of the freeware Synopse mORMot framework.optimized for speed (tuned assembler and VIA PADLOCK optional support) .18 715 mORMoti18n Internationalization (i18n) routines and classes for mORMot . licensed under a MPL/GPL/LGPL tri-license. version 1. 1. MD5.5 engine version) .pas unit Purpose: SynFile ORM definitions shared by both client and server Units used in the FileTables unit: Unit Name Description Page mORMot Common ORM and SOA classes for mORMot . XOR. SHA1.this unit is a part of the freeware Synopse mORMot framework.this unit is a part of the freeware Synopse framework. version 1.18 497 SynZip Low-level access to ZLib compression (1.this unit is a part of the freeware Synopse mORMot framework. FileTables.implements AES.18 325 SynCrypto Fast cryptographic routines (hashing and cypher) . version 1.Rev. with common fields 1043 TSQLMemo An uncrypted Memo table 1043 FileTables. version 1.18 924 SynCommons Common functions used by most Synopse projects .pas unit .2. SHA256 algorithms . version 1.18 707 TSQLRecord TSQLAuditTrail TSQLMemo TSQLRecordSigned TSQLFile TSQLSafeMemo TSQLData TSQLRibbonTabParameters TFileRibbonTabParameters TSQLSafeData FileTables class hierarchy Objects implemented in the FileTables unit: Objects Description Page TFileRibbonTabParamet ers The type of custom main User Interface description of SynFile 1043 TSQLAuditTrail An AuditTrail table.18 Page 1042 of 1055 . licensed under a MPL/GPL/LGPL tri-license. licensed under a MPL/GPL/LGPL tri-license.this unit is a part of the freeware Synopse mORMot framework.6. ADLER32. Rev. with common fields TSQLMemo = class(TSQLFile) An uncrypted Memo table . used to track events and status TFileRibbonTabParameters = object(TSQLRibbonTabParameters) The type of custom main User Interface description of SynFile Actions: TFileActions. faCopy.will contain some binary file content after AES-256 cypher . faImport.18 Date: June 16. Set of available actions TFileEvent = FileTables. a BLOB field) TSQLSafeMemo = class(TSQLData) A crypted SafeMemo table . faQuery. faPrintPreview.e.is also used a parent for all cyphered tables (since the content is crypted.Synopse mORMot Framework Software Architecture Design 1.will contain some text TSQLData = class(TSQLFile) An uncrypted Data table .can contain any binary file content . faEdit. i. faUnmarkAll. 1. faSettings ). faSign. faExtract. faRefresh.18 Page 1043 of 1055 . faMark. The internal available actions.just a direct sub class ot TSQLData to create the "SafeMemo" table with the exact same fields as the "Data" table TSQLSafeData = class(TSQLData) A crypted SafeData table .just a direct sub class ot TSQLData to create the "SafeData" table with the exact same fields as the "Data" table TSQLAuditTrail = class(TSQLRecord) An AuditTrail table. faExport. The SynFile actions Types implemented in the FileTables unit: TFileAction = ( faNoAction. as used by the User Interface TFileActions = set of TFileAction. 2013 Objects Description Page TSQLSafeData A crypted SafeData table 1043 TSQLSafeMemo A crypted SafeMemo table 1043 TSQLFile = class(TSQLRecordSigned) An abstract class. faCreate. faDelete.will contain some text after AES-256 cypher .pas unit . it should be binary. i.faPrintPreview]. feRecordImported..faPrintPreview. FieldWidth: 'IddId'. (Table: TSQLData.faQuery]. Will define the 3d User Interface ribbon group. FieldWidth: 'IddId'. ShowID: true.. FieldWidth: 'IddId'. paWithPicture. FieldWidth: 'IddId'. Actions: DEF_ACTIONS).18 Date: June 16. Actions: [faDelete.faUnmarkAll.faCreate. (Table: TSQLSafeMemo. feRecordExported ).Rev.Status. feServerStarted. This constant will define most of the User Interface property .faMark. Select: DEF_SELECT. 1.18 Page 1044 of 1055 .faPrintPreview. [faMark. ReverseOrder: true.faSettings]). Select: DEF_SELECT. Actions: DEF_ACTIONS_DATA).SignatureTime'. i. feRecordCreated.Created.4] of TFileRibbonTabParameters = ( (Table: TSQLAuditTrail. 2013 ( feUnknownState.faExtract].faQuery. FileActionsToolbar[FileActionsToolbar_MARKINDEX] [faMark. Actions available for data tables (not for TSQLAuditTrail) DEF_SELECT = 'Name. Group: GROUP_SAFE. Select: 'Time. Some default actions. The TCP/IP port used for the HTTP server . Group: GROUP_SAFE. Group: GROUP_CLEAR.StatusMessage'. uncrypted tables GROUP_MAIN = 0.e. Actions: DEF_ACTIONS). Select: DEF_SELECT. Default fields available for User Interface Grid FileActionsToolbar: array[0.. Used to map which actions/buttons must be grouped in the toolbar FileActionsToolbar_MARKINDEX = 2.faSettings]. FileTabs: array[0. as used by the TSQLAuditTrail table TPreviewAction = ( paPrint. Some actions to be used by the User Interface of a Preview window Constants implemented in the FileTables unit: DEF_ACTIONS = [faMark. feRecordModified. (Table: TSQLMemo. Will define the 2nd User Interface ribbon group.in a production application.faExport]. paAsPdf.. main tables GROUP_SAFE = 2.the framework will create most User Interface content from the values stored within GROUP_CLEAR = 1.faEdit. available for all tables DEF_ACTIONS_DATA = DEF_ACTIONS+[faExtract]-[faImport. [faSettings] ).e.3] of TFileActions = ( [faRefresh.Synopse mORMot Framework Software Architecture Design 1.. paDetails ). FieldWidth: 'gIZ'. paAsText. crypted tables SERVER_HTTP_PORT = '888'.pas unit . i.faRefresh.. Select: DEF_SELECT. should be made customizable Functions or procedures implemented in the FileTables unit: FileTables. feServerShutdown. [faExport.Modified. Group: GROUP_MAIN. feRecordDeleted.faCopy.e.e.this is shared as constant by both client and server side . (Table: TSQLSafeData.faQuery] will be the marked actions i. Actions: DEF_ACTIONS_DATA) ). feRecordDigitallySigned. Will define the first User Interface ribbon group.KeyWords. Group: GROUP_CLEAR. The internal events/states. Layout: llClient. Create the database model to be used .Rev.pas unit .Synopse mORMot Framework Software Architecture Design 1. 2013 Functions or procedures Description Page CreateFileModel Create the database model to be used 1045 function CreateFileModel(Owner: TSQLRest): TSQLModel. 1.18 Date: June 16.18 Page 1045 of 1055 .shared by both client and server sides FileTables. SWRS implications Software Architecture Design Reference Table The following table is a quick-reference guide to all the Software Requirements Specifications (SWRS) document items.SWRS implications .1.Rev.18 Page 1046 of 1055 . and ready to be accessed from outside any Delphi Client (e.2.1 The framework shall be Client-Server oriented 1047 A RESTful mechanism shall be implemented 1047 DI-2.1.1.1.1 over TCP/IP protocol communication shall be made available by some dedicated classes.3 The framework shall use an innovative ORM (Object-relational mapping) approach.1.3 Client-Server Windows GDI Messages communication shall be made available by some dedicated classes 1049 DI-2.1.1.1 SAD .1.4 Client-Server HTTP/1. the implement should be AJAX ready) 1049 DI-2.2 Client-Server Named Pipe communication shall be made available by some dedicated classes 1048 DI-2.1.2. based on classes RTTI (Runtime Type Information) 1050 DI-2.5 The framework shall offer a complete SOA process 1051 DI-2.g.2. 1.Synopse mORMot Framework Software Architecture Design 1.1.1.1.4 The framework shall provide some Cross-Cutting components 1051 DI-2.1 Client-Server Direct communication shall be available inside the same process 1048 DI-2.2 The framework libraries. SWRS # Description Page DI-2.18 Date: June 16.1 The SQLite3 engine shall be embedded to the framework 1052 DI-2. including all its SQLite3 related features.1.2.1.2.2. shall be tested using Unitary testing 1053 DI-2. 2013 26.1.2 UTF-8 JSON format shall be used to communicate 1049 DI-2. By design.3. SWRS # DI-2. but both client and server may reside in the same system. A server machine is a host that is running one or more server programs which share its resources with clients. 2013 SWRS # Description Page DI-2.2 Toolbars shall be able to be created from code.1. called clients.1.1 The framework shall be Client-Server oriented Design Input 2.Rev. 715 26.1. Application shall easily change the protocol used. This specification is implemented by the following units: Unit Name Description Page Common ORM and SOA classes for mORMot mORMot See in particular TSQLRecord. and User Interface generated from RTTI should be included in this i18n mechanism 1054 DI-2. SWRS # DI-2.1 A Database Grid shall be made available to provide data browsing in the Client Application . the only requirement is that protocols and associated parameters are expected to match between the Client and the Server. TSQLRest.1.SWRS implications .2. over various communication protocols. but in an unified way.3. Client–Server model of computing is a distributed application structure that partitions tasks or workloads between service providers. just by adjusting the class type used in the client code. Clients therefore initiate communication sessions with servers which await (listen for) incoming requests. Often clients and servers communicate over a computer network on separate hardware.1 A RESTful mechanism shall be implemented SAD .1.1 (Initial release): The framework shall be Client-Server oriented. with full preview and export as PDF or TXT files.Synopse mORMot Framework Software Architecture Design 1.18 Page 1047 of 1055 .1. The Synopse mORMot Framework shall implement such a Client-Server model by a set of dedicated classes.1. A client does not share any of its resources.it shall handle easy browsing.18 Date: June 16.3.3 Internationalization (i18n) of the whole User Interface shall be made available by defined some external text files: Delphi resourcestring shall be translatable on the fly. on the fly customization of the cell content 1053 DI-2. Client Server ORM/SOA framework 26. shall be integrated 1054 26. TSQLRestClientURI and TSQLTableJSON. TSQLRestServer. 1.1. called servers. but requests a server's content or service function.1.1.2 A reporting feature. by column resizing and sorting. custom window dialogs automaticaly translated before their display.3. using RTTI and enumerations types for defining the action 1054 DI-2.1. and service requesters. 1. 26. This specification is implemented by the following units: Unit Name Description Page Common ORM and SOA classes for mORMot mORMot 715 See in particular TSQLRestServer. URIRequest. TSQLRestClientURINamedPipe.ExportServerNamedPipe.2 (Initial release): Commmunication should be available directly in the same process memory.SWRS implications .3.1 protocols.1. Windows messages or HTTP/1. Clients initiate requests to servers.2.Create and TSQLRestClientURI.1.18 715 Page 1048 of 1055 .1.1. Requests and responses are built around the transfer of "representations" of "resources".2.Synopse mORMot Framework Software Architecture Design 1.1. 26. SAD .Rev. This specification is implemented by the following units: Unit Name Description Page Common ORM and SOA classes for mORMot mORMot 715 See in particular TSQLRest. so called "resources" are individual records of the underlying database. USEFASTMM4ALLOC and TSQLRestClientURIDll.1.18 Date: June 16. 2013 Design Input 2. as was stated in SWRS # DI-2. In the Synopse mORMot Framework. by a SQL-like query statement.Create. servers process requests and return appropriate responses. SWRS # DI-2.1 Client-Server Direct communication shall be available inside the same process Design Input 2. A resource can be essentially any coherent and meaningful concept that may be addressed. or remotly using Named Pipes. This specification is implemented by the following units: Unit Name Description Page Common ORM and SOA classes for mORMot mORMot See in particular TSQLRestServer.1 (Initial release): A RESTful mechanism shall be implemented. SWRS # DI-2. REST-style architectures consist of clients and servers. TSQLRestServer and TSQLRestClientURI. 1. A representation of a resource is typically a document that captures the current or intended state of a resource.4. or list of individual fields values extracted from these databases.1.2 Client-Server Named Pipe communication shall be made available by some dedicated classes Client-Server Named Pipe communication shall be made available by some dedicated classes. Client-Server Direct communication shall be available inside the same process.1.1.1.1. the implement should be AJAX ready) Client-Server HTTP/1.1 client and server protocol SynCrtSock See in particular THttpServer. and ready to be accessed from outside any Delphi Client (e.1.1 over TCP/IP protocol communication shall be made available by some dedicated classes. SWRS # DI-2.Create.1.URI. TSQLRestServer.Rev.6.1 RESTFUL JSON Client classes for mORMot mORMotHttpClient 917 See in particular TSQLHttpClient. 2013 26.ExportServerMessage and TSQLRestClientURIMessage.1.1.2. 26.18 Date: June 16.1.7.1. SWRS # DI-2.Create.1.18 Page 1049 of 1055 . This specification is implemented by the following units: Unit Name Description Page Common ORM and SOA classes for mORMot mORMot See in particular TSQLRestClientURI.Create.2 (Initial release): UTF-8 JSON format shall be used to communicate.2 UTF-8 JSON format shall be used to communicate Design Input 2.Synopse mORMot Framework Software Architecture Design 1. SWRS # DI-2.1.Create. 1.1 over TCP/IP protocol communication shall be made available by some dedicated classes. HTTP/1.AddServer.3 Client-Server Windows GDI Messages communication shall be made available by some dedicated classes Client-Server Windows GDI Messages communication shall be made available by some dedicated classes. THttpApiServer.SWRS implications .OnRequest.DBServer and TSQLHttpServer.g. This specification is implemented by the following units: Unit Name mORMot Description Page Common ORM and SOA classes for mORMot See in particular 715 TSQLRestClientURI and TSQLRestServer.2. TSQLHttpServer. 479 HTTP/1. SAD .Request and THttpServerGeneric. and ready to be accessed from outside any Delphi Client (e.1 RESTFUL JSON Server classes for mORMot mORMotHttpServer See in particular TSQLHttpServer.5.Create.1. the implement should be AJAX ready).g. 920 Classes implementing HTTP/1.4 Client-Server HTTP/1. 715 26. THttpServerGeneric. UpdateFrom. The first 128 characters of the Unicode character set (which correspond directly to the ASCII) use a single octet with the same binary value as in ASCII. ready to be inserted to the underlying database. and allowing output in multiple languages at the same time. It therefore provide an easy way of data formating between the Client and the Server. JSONEncode. so even knowing the language was insufficient information to display it correctly.1.CreateJSONWriter. For many languages there has been more than one single-byte encoding in usage. in order to be easily interpreted by the Server. TJSONWriter.1. easily creating JavaScript object from JSON content. 715 26. with parsers available for virtually every programming language. Therefore. JSONDecode. as defined in the Software Architecture Design (SAD) document. UTF-8 can encode any Unicode character. JSON (an acronym for JavaScript Object Notation) is a lightweight text-based open standard designed for human-readable data interchange. JSON should be used also within the transmission of request rows of data.1. This specification is implemented by the following units: Unit Name Description Page Common functions used by most Synopse projects SynCommons See in particular TTextWriter. 1.3 The framework shall use an innovative ORM (Object-relational mapping) approach. in a disposition which could make it compatible with direct JavaScript interpretation (i.e. SWRS # DI-2.Create. is used in the Synopse mORMot SAD . TTextWriter.SWRS implications . ORM.8.Create. TSQLTableJSON. TSQLTableJSON. in order to facilitate AJAX application development).3 (Initial release): The framework shall use an innovative ORM (Object-relational mapping) approach.AddJSONEscape. as defined in the Software Architecture Design (SAD) document. TSQLRecord. is used in the Synopse mORMot Framework for all Client-Server communication. From the Client to the Server. based on classes RTTI (Runtime Type Information) Design Input 2.GetJSONValues. 325 Common ORM and SOA classes for mORMot mORMot See in particular TSQLTable. avoiding the need to figure out and set a "code page" or otherwise indicate what character set is in use. it is language-independent. TSQLRecord.Synopse mORMot Framework Software Architecture Design 1. which will convert the supplied field values into proper SQL content. GetJSONObjectAsSQL and UnJSONFirstField. UTF-8 encodes each character (code point) in 1 to 4 octets (8-bit bytes). record content is also JSON-encoded. JSON shall be used in the framework for returning individual database record content.Create.18 Page 1050 of 1055 . JSONEncodeArray. based on classes RTTI (Runtime Type Information). The Synopse mORMot Framework shall use UTF-8 encoding for the character transmission inside its JSON content.Rev.GetJSONValues.18 Date: June 16. Despite its relationship to JavaScript. UTF-8 (8-bit Unicode Transformation Format) is a variable-length character encoding for Unicode. IsJSONString. GetJSONField and JSON_CONTENT_TYPE. 2013 JSON. 3. This specification is implemented by the following units: Unit Name Description Page Common functions used by most Synopse projects SynCommons 325 See in particular TSynLog and PatchCodePtrUInt. inserted into the database model. so you benefit of consisting APIs and documentation. Object-relational mapping (ORM. O/RM. All crosscutting scenarios are coupled.GetValue. JSON/RESTful orientation from the ground up.Via some TSQLRecord inherited classes. and O/R mapping) is a programming technique for converting data between incompatible type systems in relational databases and object-oriented programming languages.10. and consumed in the Client via native Delphi methods.1. TPropInfo.18 Date: June 16. 1. and accessible via some RESTful URI . This creates. TClassType.SetValue and TSQLRecordProperties.By some RESTful services. . SWRS # DI-2. a "virtual object database" that can be used from within the Delphi programming language.Rev.9.1.SWRS implications . 26. 715 26. and some dedicated Client-side methods.5 (Initial release): The framework shall offer a complete SOA process. logging and testing (framework uses test-driven approach and features stubbing and mocking).1. cache. TPropInfo. TTypeInfo. a lot of code-reuse.ClassProp.4 The framework shall provide some Cross-Cutting components Design Input 2.1. SWRS # DI-2. your application's business logic can be implemented in several ways using mORMot: .1. TSQLRecord.18 Page 1051 of 1055 . 2013 Framework for accessing data record fields directly from Delphi Code. implemented in the Server as published methods. In order to follow a Service Oriented Architecture design. security.1.Synopse mORMot Framework Software Architecture Design 1.5 The framework shall offer a complete SOA process Design Input 2. in effect. SAD .see SWRS # DI-2. Accessing database records (for reading or update) shall be made by using these classes properties. This specification is implemented by the following units: Unit Name Description Page Common ORM and SOA classes for mORMot mORMot See in particular TClassProp. The published properties of classes inheriting from a new generic type named TSQLRecord are used to define the field properties of the data. TEnumType.1. Cross-Cutting infrastructure layers shall be made available for handling data filtering and validation.this is implemented by our ORM architecture . TSQLRecord.GetJSONValues.4 (Initial release): The framework shall provide some Cross-Cutting components. session. TServiceFactoryClient.dll distribution. This specification is implemented by the following units: Unit Name mORMot Description Page Common ORM and SOA classes for mORMot See in particular 715 TSQLRestServer. SQlite3 engine 26.1.18 Date: June 16. TSQLBlobStream and ESQLException.statically linked . SQLite3 Database engine direct access SynSQLite3 See in particular TSQLite3LibraryDynamic.1 The SQLite3 engine shall be embedded to the framework Design Input 2. 715 26.Defining some RESTful service contracts as standard Delphi interface. TSQLTableDB. 1. TServiceContainerServer and TServiceContainer. TSQLite3Statement. related to the Client-Server purpose or the framework . The Synopse mORMot Framework shall enhance the standard SQLite3 database engine by introducing some new features stated in the Software Architecture Design (SAD) document. TSQLRequest.18 Page 1052 of 1055 .1 (Initial release): The SQLite3 engine shall be embedded to the framework.Synopse mORMot Framework Software Architecture Design 1. and interact directly from the Delphi application process.2. TSQLite3Blob. TServiceFactoryServer. TSQLite3Value. SAD .see SWRS # DI-2.1.SWRS implications . The SQLite3 database engine is used in the Synopse mORMot Framework as its kernel database engine. TSQLite3ValueArray. TSQLDataBase.2. TSQLRequest.1. 647 SQLite3 Database engine .Execute. TSQLite3DB.2. or using official external sqlite3. TSQLTableDB. SQLite3 embedded Database engine used as the mORMot SQL kernel mORMotSQLite3 959 See in particular TSQLRestServerDB and TSQLRestClientDB.obj for Windows 32 bit SynSQLite3Static 696 See in particular TSQLite3LibraryStatic. TServiceContainerCLient. SQLite3 is an ACID-compliant embedded relational database management system contained in a C programming library. TSQLite3FunctionContext.2. 2013 . This specification is implemented by the following units: Unit Name Description Page Common ORM and SOA classes for mORMot mORMot See in particular TServiceFactory.Create. SWRS # DI-2. TSQLite3Library. and then run it seamlesly on both client and client sides. This library shall be linked statically to the Synopse mORMot Framework.Rev. Rev.3.3. TTestFileBased. All testing shall be run at once.2 (Initial release): The framework libraries.18 Date: June 16.SWRS implications . SWRS # DI-2.2. on the fly customization of the cell content Design Input 2. with buttons and toolbars shall be easily being created from the code. This testing shall be defined by classes.1. using RTTI and data auto-description.it shall handle easy browsing. User interface 26. TTestMemoryBased. 642 26.2. or after any modification to the framework code.3. A Database Grid shall be made available to provide data browsing in the Client Application . This specification is implemented by the following units: Unit Name Description SAD . in order to avoid most regression bug.1. for example before any software release.18 Page Page 1053 of 1055 .2.Synopse mORMot Framework Software Architecture Design 1. This specification is implemented by the following units: Unit Name Description Page Automated tests for common units of the Synopse mORMot Framework SynSelfTests See in particular TTestLowLevelCommon. with no RAD needed.it shall handle easy browsing.1 (Initial release): An User Interface. TTestBasicClasses. TSQLDBSQLite3Statement and TSQLDBSQLite3ConnectionProperties.2 The framework libraries. The Synopse mORMot Framework shall use all integrated Unitary testing features provided by a common testing framework integrated to all Synopse products. SWRS # DI-2.1 A Database Grid shall be made available to provide data browsing in the Client Application . 2013 Unit Name Description Page SQLite3 direct access classes to be used with our SynDB architecture SynDBSQLite3 See in particular TSQLDBSQLite3Connection. 1. TTestSQLite3Engine.3.2. shall be tested using Unitary testing Design Input 2. on the fly customization of the cell content. 564 26. by column resizing and sorting. in which individual published methods define the actual testing of most framework features. including all its SQLite3 related features. by column resizing and sorting. shall be tested using Unitary testing. including all its SQLite3 related features. TTestLowLevelTypes. TTestFileBasedWAL and TTestClientServerAccess. DateTimeToText. TSQLLister and TSQLCustomToolBar.3.4.1.Translate and _. 2013 Unit Name Description Page Grid to display database content for mORMot mORMotUI 980 See in particular mORMotToolBar TSQLTableToGrid.3.Create.3. 26. This specification is implemented by the following units: Unit Name Description Page Internationalization (i18n) routines and classes for mORMot mORMoti18n See in particular TLanguage. and User Interface generated from RTTI should be included in this i18n mechanism Internationalization (i18n) of the whole User Interface shall be made available by defined some external text files: Delphi resourcestring shall be translatable on the fly.3.2.Rev.SWRS implications .StringToUTF8.3. 1.3.1. TLanguageFile. S2U. SWRS # DI-2. custom window dialogs automaticaly translated before their display.UTF8ToString. TLanguageFile.18 Page 1054 of 1055 .3. using RTTI and enumerations types for defining the action.2 Toolbars shall be able to be created from code. U2S.3 Internationalization (i18n) of the whole User Interface shall be made available by defined some external text files: Delphi resourcestring shall be translatable on the fly. SWRS # DI-2.Create. and User Interface generated from RTTI should be included in this i18n mechanism.DateToText. 26.TimeToText. 924 26. SWRS # DI-2. TLanguageFile. TLanguageFile.Create.18 Date: June 16. ORM-driven Office 2007 Toolbar for mORMot See in particular 966 TSQLLister.Synopse mORMot Framework Software Architecture Design 1. using RTTI and enumerations types for defining the action Toolbars shall be able to be created from code.Create. TLanguageFile.Init. This specification is implemented by the following units: Unit Name Description Page ORM-driven Office 2007 Toolbar for mORMot mORMotToolBar 966 See in particular TSQLRibbon. TLanguageFile. TLanguageFile.2 SAD . TSQLRibbonTab. custom window dialogs automaticaly translated before their display. shall be integrated Design Input 2.18 600 Page 1055 of 1055 . which could be used stand-alone.g. Reports shall not be created using a RAD approach (e.3. with full preview and export as PDF or TXT files. 1.RenderMetaFile.Rev. by using some dedicated methods. shall be integrated. defining bands and fields with the mouse on the IDE).2 (Initial release): A reporting feature. or linked to its database mechanism. adding text. any kind of report shall be generated. but shall be defined from code. GDI+ library API access SynGdiPlus 576 See in particular TGDIPlus. The Synopse mORMot Framework shall provide a reporting feature. SAD .18 Date: June 16. PDF file generation SynPdf See in particular TPdfDocument and TPdfCanvas. and exported as PDF or TXT on request.DrawAntiAliased. This specification is implemented by the following units: Unit Name Description Page Reporting unit mORMotReport See in particular 934 TGDIPages. 2013 A reporting feature. with full preview and export as PDF or TXT files. Therefore. tables or pictures to the report. This reports shall be previewed on screen.SWRS implications .Synopse mORMot Framework Software Architecture Design 1.
Copyright © 2024 DOKUMEN.SITE Inc.