#1 2010-06-21 16:20:43

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,660
Website

Overall RTTI usage

The Delphi language (aka Object Pascal) provided Runtime Type Information (RTTI) more than a decade ago. In short, Runtime Type Information is information about an object's data type that is set into memory at run-time. The RTTI support in Delphi has been added first and foremost to allow the design-time environment to do its job, but developers can also take advantage of it to achieve certain code simplifications. The Synopse SQLite3 Database Framework makes huge use of RTTI, from the database level to the User Interface. Therefore, the resulting program has the advantages of very fast development (Rails-like), but with the robustness of strong typing, and the speed of one of the best compiler available.

In short, it allows the software logic to be extracted from the code itself. Here are the places where this technology was used:
- All database structures are set in the code by normal classes definition, and most of the needed SQL code is created on the fly by the framework, before calling the SQLite3 database engine, resulting in a true Object-relational mapping (ORM) framework;
- All User Interface is generated by the code, by using some simple data structures, relying on enumerations (see next paragraph);
- Most of the text displayed on the screen does rely on RTTI, thanks to the Camel approach (see below), ready to be translated into local languages;
- All internal Event process (such as Button press) relies on enumerations RTTI;
- Options and program parameters are using RTTI for data persistency and screen display (e.g. the Settings window of your program can be created by pure code): adding an option is a matter of a few code lines.

In Delphi, enumeration types or Enum provides a way of to define a list of values. The values have no inherent meaning, and their ordinality follows the sequence in which the identifiers are listed. These values are written once in the code, then used everywhere in the program, even for User Interface generation.

For example, some toolbar actions can be defined with:

type
  /// Worklist toolbar actions
  TPeopleAction = (
    paCreateNew, paDelete, paEdit, paQuit);

Then this TPeopleAction enumerate type is used to create the User Interface ribbon of the Worklist window, just by creating an array of set of this kind:

  BarEdit: array[0..1] of set of TPeopleAction = (
    [paCreateNew, paDelete, paEdit],
    [paQuit] );

The caption of the buttons to be displayed on the screen is then extracted by the framework using "Camel Case": the second button, defined by the paCreateNew identifier in the source code, is displayed as "Create new" on the screen, and this "Create new" is used for direct i18n of the software. For further information about "Camel Case" and its usage in Object Pascal, Java, Dot Net, Python see CamelCase.

Advantages of the RTTI can therefore by sum up:
- Software maintenability, since the whole program logic is code-based, and the User Interface is created from it. It therefore avoid RAD (Rapid Application Development) abuse, which mix the User Interface with data logic, and could lead into "write fast, try to maintain" scenarios;
- Enhanced code security, thanks to Object Pascal strong typing;
- Direct database access from the language object model, without the need of writing SQL or use of a MVC framework;
- User Interface coherency, since most screen are created on the fly;
- Easy i18n of the software, without additional components or systems.

Offline

#2 2011-01-04 14:42:05

ingoberg
Member
Registered: 2010-11-20
Posts: 17

Re: Overall RTTI usage

Is there anyway that RTTI can be built into the TSQLRecord class so that it is easy to extract Field Types and Field Values? (Perhaps it is and I failed to see it). For example, it would be nice to be able to pass a field index and get field value in return.

Offline

#3 2011-01-04 21:15:19

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,660
Website

Re: Overall RTTI usage

See FieldIndex and FieldProp methods of TSQLRecord.
To loop through all fields, see the FieldIndex method implementation: use a loop with P: PPropInfo then P := P^.Next.

Then use the PPropInfo pointer to get all types and values, as expected. For example, you have GetValue GetOrdValue GetInt64Value GetExtendedValue GetLongStrValue methods.

Since version 1.11, you can use the TSQLRecordProperties class to retrieve all RTTI easily, for a given TSQLRecordClass. I'll make visible the PropsCacheGet function for the version 1.12.

Thanks for your interest!

Offline

#4 2011-01-05 03:03:39

ingoberg
Member
Registered: 2010-11-20
Posts: 17

Re: Overall RTTI usage

Thanks - This is great. I extended my TSQLRecord class with two methods GetFieldValue and SetFieldValue, which simplifies my life a lot when I set and receive  values from a data grid that I create on the fly.

Offline

#5 2011-02-01 14:43:48

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,660
Website

Re: Overall RTTI usage

That's it.

As I wrote above, the PropsCacheGet function has been made public.

I've also added some methods, which could be useful in case of a Grid usage:
- new TPropInfo.SetVariant/GetVariant methods
- new GetFieldValue/SetFieldValue and GetFieldVariant/SetFieldVariant methods for TSQLRecord
Those methods accept a property name as parameter, and allow access to all properties of a TSQLRecord instance.

See http://synopse.info/fossil/info/a5189713f7

Offline

#6 2011-02-02 08:54:02

corchi72
Member
Registered: 2010-12-10
Posts: 232

Re: Overall RTTI usage

Hi, when compiling the version e9cafa3892879d29 this error occurs:
"endeclared identifier : TSQLCache"

in class :

TSQLDataBase = class
  private
    fDB: TSQLite3DB;
    fFileName: TFileName;
    fTransactionActive: boolean;
    fLock: TRTLCriticalSection;
    /// if not nil, cache is used - see UseCache property
    fCache: TSQLCache;
.....

Offline

#7 2011-02-02 09:04:11

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,660
Website

Re: Overall RTTI usage

You didn't refresh all the files.

You need to update SynCommons, SQLite3 and SQLite3Commons units, at least with the latest version available from the source code repository.
Your SQLite3 unit was not updated.

Offline

#8 2011-02-02 09:50:38

corchi72
Member
Registered: 2010-12-10
Posts: 232

Re: Overall RTTI usage

I went to this link http://synopse.info/fossil/info/0088bc5396 I downloaded zip Archive: Synops OpenSource-0088bc539614c694.zip

Offline

#9 2011-02-02 13:17:12

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,660
Website

Re: Overall RTTI usage

Offline

#10 2012-04-28 03:08:51

coblongpamor
Member
From: Bali-Indonesia
Registered: 2010-11-07
Posts: 130
Website

Re: Overall RTTI usage

is there any simple method to get classtype from PPropInfo? instead of using

TSQLRecordClass(P^.PropType^^.ClassType^.ClassType)

thank you.

Offline

#11 2012-04-28 06:59:52

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,660
Website

Re: Overall RTTI usage

No, there is not direct access, since it will depend on the property type.

Why are you using PPropInfo in your code?
Perhaps some other methos are missing at TSQLRecordProperties level.

Offline

#12 2012-04-28 11:53:18

coblongpamor
Member
From: Bali-Indonesia
Registered: 2010-11-07
Posts: 130
Website

Re: Overall RTTI usage

i need to know the Class of sftID SQLFieldType
this is what SetRecord() procedure does in the RecordEditForm

sftID:
  if aClient<>nil then begin
	// ID field (TSQLRecord descendant) is handled by a TComboBox component
	// with all possible values of the corresponding TSQLRecord descendant
	IDClass := TSQLRecordClass(P^.PropType^^.ClassType^.ClassType);
	CB := TComboBox.Create(Scroll);
....

Offline

Board footer

Powered by FluxBB