#1 Re: mORMot 1 » D7 Personal, problem when compiling runtime package » 2011-11-07 11:11:22

it seems that the concern is about 1.15 version.
I have some older version (from may 2011, don't know which revision it was) on my HDD which compiles properly.

#2 mORMot 1 » D7 Personal, problem when compiling runtime package » 2011-11-07 10:31:37

migajek
Replies: 3

Hi,
I need to compile the runtime package (plugin for my application) which uses SynCommons, however - while linking, I get this error: Need imported data reference ($G) to access 'VarCopyProc' from unit 'SynCommons'.

What however is *really* strange is that the plugin works properly (it's supposed to generate PDF report, maybe the pdf-related code does not use the 'problematic' part of code?)

I've tried of course including {$G+}  and {$IMPORTEDDATA ON} in Synopse.inc but it didn't solved the problem.

#3 Re: mORMot 1 » THttpServerGeneric - threading, related to TSQLRestServer » 2011-07-13 13:05:12

well I'm not sure how about FastCGI specs, but on my linux-running http server, FastCGI is configured with MAX number of threads to spawn. However when server starts it spawns several threads, and - as request number raises - it spawns new threads, until number reaches max.

#4 Re: mORMot 1 » Sending Objects (serialized as JSON?) with RESTServer callbacks » 2011-07-13 13:03:15

ab wrote:

Just transfer the content as RawUTF8.

And use the corresponding functions of SQLite3Commons.

thank you.
I didn't expected it to be SO trivial wink

#5 mORMot 1 » Sending Objects (serialized as JSON?) with RESTServer callbacks » 2011-07-13 11:59:22

migajek
Replies: 2

Hi,
since object serialization to/from JSON is used internally I wonder what'd be the easiest way to send serialized objects between Client / Server using REST callbacks?

Thanks,
mg

#6 Re: mORMot 1 » THttpServerGeneric - threading, related to TSQLRestServer » 2011-07-13 09:38:14

ab wrote:

All server threads are created at once, at HTTP server initialization.

I thought threads creation depends on number of requests (like FastCGI) wink

#7 Re: mORMot 1 » THttpServerGeneric - threading, related to TSQLRestServer » 2011-07-12 15:34:16

ab wrote:

I've updated the documentation to explicitly states this requirement:

An important point is to remember that the implementation of the callback method must be thread-safe. In fact, the TSQLRestServer. URI method expects such callbacks to handle the thread-safety on their side. It's perhaps some more work to handle a critical section in the implementation, but, in practice, it's the best way to achieve performance and scalability: the resource locking can be made at the tiniest code level.

thank you smile

Is there some possibility to have my Service notified when new thread is shipped?

#8 mORMot 1 » THttpServerGeneric - threading, related to TSQLRestServer » 2011-07-12 10:39:37

migajek
Replies: 6

Hi,
if I understood the code & docs properly, the instance of TSQLRestServer I'm exposing through TSQLite3HttpServer might be used in context of several threads (is thread pooling implemented for this?). If I'm correct, do I have to make sure TSQLRestServer callbacks are thread-safe, or are they synchronized by http thread?

#9 Re: mORMot 1 » Remote JSON REST Service - calling COM in Service fails » 2011-07-11 17:12:36

I've modified TSQLite3HttpServer.Create to use one more parameter : const AServerInstance: THttpServerGeneric = nil.
see this (modified) part of code

  {$ifndef USETCPPREFIX}
  try
    // first try to use fastest http.sys
    if AServerInstance = nil then
      fHttpServer := THttpApiServer.Create(false)
    else
      fHttpServer:= AServerInstance;
    if fHttpServer.InheritsFrom(THttpApiServer) then
    for i := 0 to high(aServers) do begin


and here is "my" server:


  TmyServer = class(THttpApiServer)
  protected
    destructor Destroy; override;
    procedure Execute; override;
  end;

procedure TMyServer.Execute;
begin
  CoInitialize(nil);
    inherited;
end;

destructor TmyServer.Destroy;
begin
  CoUninitialize();
  inherited;
end;

the above example works on the first request.

Now if I change the parent class to THttpServer (so it won't use kernel.sys) the example does not work at all.
Even though the CoInitialize is called (I've debugged it), when calling CoCreateObject in request it fails saying CoInitialize wasn't called ;]

any ideas here?

I've built a trivial sample to prove that it's not about threads:
and, yes, it works. each call to GetValue works as expected.

type
  ttestthread = class(TThread)
  private
    fClient: IeClient;
  protected
    destructor Destroy; override;
    procedure Execute; override;
  end;

procedure ttestthread.Execute;
var s: string;
begin
  CoInitialize(nil);
    fClient.Init;
    while true do
    begin
      Sleep(1000);
      fClient.GetValue('Random', s);
      s:= s + 'abc';
    end;
end;

destructor ttestthread.Destroy;
begin
  CoUninitialize();
  inherited;
end;


procedure TForm1.Button1Click(Sender: TObject);
var
  client: IeClient;
  t: ttestthread;
begin
  client:= Te.Create;
  if not client.Init() then
    raise Exception.Create('Could not init Client!');
  t:=ttestthread.Create(true);
  t.fClient:= client;
  t.Resume;


end;

any ideas what are differences between this and THttpServer?
some context management? Thread pooling?

#10 Re: mORMot 1 » Remote JSON REST Service - calling COM in Service fails » 2011-07-11 15:14:01

Hi,

first of all it seems the call to CoInitialize need to be done in Execute; method.
second of all, for some reason it need to be called for each request - otherwise I get the same error as previous on the second request (even though CoUninitialized is called in thread Destructor.)

are there any low-level tricks behind handling Request, which may cause this behavior?

once again,
1. CoInitialize is called at the very beginning of Execute; method
2. CoUninitialize is called in Destructor
3. calling CoCreateObject in the registered REST Server method works only for the first time - second call throws exception saying "CoInitialize was not called"
4. it works if I move CoInitialize to REST Server method...

any ideas?

#11 Re: mORMot 1 » SynDBOracle: Open Source native Oracle access » 2011-07-11 11:57:34

Wow, that is pretty impressive!
I'm glad that, once you gave up using ZEOS and chosen OleDB instead, there's still possibility to introduce direct, native drivers like that one smile

Hope to see others, including MySQL for example smile

#12 Re: mORMot 1 » Remote JSON REST Service - calling COM in Service fails » 2011-07-07 15:47:39

ab wrote:

The HTTP server has its own thread(s) so you'll need to call CoInitialize for each thread.
You may do this by overriding the THttpApiServer.Create constructor (if you use THttpApiServer for the HTTP server class). Without forgetting to call CoUninitialize in an overriden constructor.

I'm using TSQLite3HttpServer which, as I can see, tries to use THttpApiServer if possible, if not - it falls back to the higher-level ones.
That would require me not only to override methods in one class (HttpApiServer) but also the others (just in case the first one won't be used).
Not to mention the need to modify TSQLite3HttpServer in order to use "my" classes.

I wonder if there's any better "place" (method) to hook in thread creation?

#13 mORMot 1 » Remote JSON REST Service - calling COM in Service fails » 2011-07-07 12:04:03

migajek
Replies: 28

Hi,
I've extended your "06 - Remote JSON REST Service" example, so that server-side calls some external libraries using COM in order to return value when requested.
Simply, I need to expose results of some local COM calls over HTTP.

Thus I modified your example to use TSQLite3HttpServer and TSQLite3HttpClient instead of Named Pipes.

Now the function which uses COM is called in TServerForm.Button1Click (yeah, I've added a Form to the server).
Now when I run the server and click it's Button1, it works as expected - obtains the values from COM call.

Unfortunately, if I call ServerForm.Button1Click from my Service (descendant of TSQLRestServer) it fails, saying CoInitialize was not called.

Is that kind of thread/context problem?
It is really weird, once again - if I click the button itself, it works. If I run the client which - over HTTP - requests the server to call the OnClick code, it fails on CreateComObject saying "CoInitialize" was not called. If I click the button itself again, it works fine again.

#14 Re: mORMot 1 » Record generator tool » 2011-06-23 23:22:52

ab wrote:

Are ActiveX and ComObj units part of PE version?

yes, both are available.

#15 Re: mORMot 1 » Record generator tool » 2011-06-23 12:09:24

You should certainly generate RawUTF8 instead of UTF8String, for proper UTF-8 handling.

indeed, my bad.

ab wrote:

I'm thinking also of a similar generator, but for reverse engenering of a Database instead: from an existing DB, in whatever format (thanks to OleDB drivers of our mORMot), some mapping classes will be generated.

well, I guess you're quite busy developing mORMot, maybe I could take care of creating such a basic tool?
Yet, I don't think current version of SynOleDB is able to handle such a thing wink
// BTW, SynOleDB uses OleDB which breaks the compatibility with D7PE, since OleDB is not a part of PE version sad

#16 mORMot 1 » Record generator tool » 2011-06-22 11:58:24

migajek
Replies: 7

Hi,
since I'm using Delphi 7 Personal which has no tools for class autocompletion, I had to write my own pseudo-meta-language tool.

It simply works by specifying fields one by one like following:

name:str
age:int
weight:float

the result is complete class declaration code, including class name, private variables and published properties.

additionally each field might be marked with ";r" and/or ";w" flags which will cause the generator to use getter and/or setter respectively for specific field.


for example

Name:str
Surname:str
Phone:str;r;w
Age:int;r
Weight:float

results in

    TSQLPerson = class(TSQLRecord)
    private
        fName: UTF8String;
        fSurname: UTF8String;
        fPhone: UTF8String;
        fAge: integer;
        fWeight: float;


        function GetPhone():UTF8String;

        procedure SetPhone(const AValue: UTF8String);

        function GetAge():integer;
    published
        property Name: UTF8String read fName write fName;
        property Surname: UTF8String read fSurname write fSurname;
        property Phone: UTF8String read GetPhone write SetPhone;
        property Age: integer read GetAge write fAge;
        property Weight: float read fWeight write fWeight;

    end;



function TSQLPerson.GetPhone():UTF8String;
begin
    result:= fPhone;
end;

procedure TSQLPerson.SetPhone(const AValue: UTF8String);
begin
    fPhone:= AValue;
end;

function TSQLPerson.GetAge():integer;
begin
    result:= fAge;
end;

the tool has also ability to parse back from Delphi class declaration to meta-language, but it'll work correctly only if the code follows the pattern used for code generation (private variable: fFieldName, setters / getters: Get/SetFieldName etc etc)


Here's the link (binary + source):

http://code.google.com/p/synopse-sqlite … p&can=2&q=

#18 Re: mORMot 1 » SQLite3 Framework updated to 1.12 - including engine 3.7.5 » 2011-05-19 12:10:14

Hi,
I'm very glad to see the latest Fossil version to use TMS optionally.
The code is mentioned to be 1.13 release, however I'm not able to found 'official' release - just the Fossil leaves - which don't contain sqlite3.obj ... could you please tell me where to download official release?

Thanks,
m

#20 Re: mORMot 1 » Synopse SQLite3 Framework Demo » 2011-05-04 11:36:27

Hi,
I've modified the demo so it is compatible with current (as for 4 May 2011) sources from Fossil.
BTW where's the official release 1.13 available?

#21 Re: mORMot 1 » Update - memory corruption problem? » 2011-02-22 21:34:48

thanks, I missed it somehow ... sorry.

#22 Re: mORMot 1 » Main Field Name problem » 2011-02-22 21:29:26

ab wrote:

You're trying to reinvent the wheel...

indeed. that's because I needed to implement very simple TSQLRibbon equivalent, but TMS-independent.
Removing TMS dependencies from UIEdit form was fast and easy, so I decided to create very simple general editor with grid preview on my own ... anyway, thanks for the tips!

#23 Re: mORMot 1 » Demo application + some question / remarks. » 2011-02-22 21:24:55

FillMany works on pivot tables, while I'm talking about "direct" relations, so I don't see how is it supposed to work?

#24 Re: mORMot 1 » Record Validation? » 2011-02-22 21:19:51

Thank you smile I'll update the source and dig into it tomorrow smile

#25 Re: PDF Engine » Question and possible bug (or installation problem?)?? » 2011-02-22 21:17:03

Arnaud, possibly it's the same problem I had when dealing with empty TGDIPages.

I wanted to create instance of TGDIPages on application startup, then - later - fill it with data.

creating empty TGDIPages and assigning a parent caused List index out of bounds(0) error.

I had no time for tracking the issue so I simply added those two lines

  fReport.BeginDoc;
  fReport.EndDoc;

but I guess it might be the same problem as Martin had.

#26 Re: mORMot 1 » Demo application + some question / remarks. » 2011-02-19 16:04:47

some thoughts ...


* FillOne -> at first, free all "related" objects (if they were created with FillOne)
* there should be a list of objects to free, so we won't confuse them with manually assigned objects.
* FillOne loads initializes all the 'related' fields with their instances
* each initialized instance is added to 'to-remove' list.
* there should be some 'guard' in order to protect from loading circual references.

#27 Re: mORMot 1 » Main Field Name problem » 2011-02-19 13:25:37

ab wrote:

If you put a _ before the property name, like _FullName, it won't appear in the UIEditor.

Thanks, but

1. appears in the Grid (TSQLTableToGrid)
2. uses additional memory in the database (which is not that important, but still...)
3. I guess it's slower than ID-based record identification

but for a quick fix it's pretty good wink

#28 Re: mORMot 1 » Main Field Name problem » 2011-02-19 11:11:50

ab wrote:

We'll need to have some other custom display of record if there is no unique field: like Name+' '+FirstName or such...

Yes, that's what I did as for now - I did following:

    function GetFullName: RawUTF8;
published
    property FullName: RawUTF8 read GetFullName stored false;

/// ....

function TSQLPerson.GetFullName: RawUTF8;
begin
  result:= fSurname + ', ' + fName;
end;

which actually works, but is tricky - creates completely unnecessary field in SQL, also displays the field in UIEditor.

If I don't define my own unique field, ID is default one, right?
So, how about using ID as unique field for internal operations (storing it in ComboBox.Items.Objects casted to TObject) while for displaying create virtual method in TSQLRecord, called GetUniqueDisplayName - which could be implemented by user, or - if it's not implemented - just use first sftUTF8Text field?

#29 Re: mORMot 1 » Update - memory corruption problem? » 2011-02-19 10:54:46

it seems that the new code fixed that bug smile Thank you !! smile
Now the only thing left here is the record-not-being-unlocked bug wink

#30 Re: mORMot 1 » Demo application + some question / remarks. » 2011-02-19 00:01:41

ab wrote:
role:= TSQLUserRole.Create(globalClient, fRoles.Dest.ID);

but in the last case, the ID value must be up to 1,048,576 (i.e. $100000).

from what I investigated the trick, it just changes the way it's written from PtrInt(fRoles.Dest) to fRoles.Dest.ID.

But still I have no direct access to the "real" Dest object, I need to create & later free it manually.

Let's say I have a TSQLLesson which has property Teacher: TSQLPerson.

to speed up development Id like to write code like this:

var
l: TSQLLesson;
begin
l:= TSQLLesson.Create(db, fLessonID);

ShowMessage(l.Teacher.Name);

correct me if I'm wrong but currently framework doesn't support it, I need to declare TSQLLesson.GetTeacher
which returns

function TSQLLesson.GetTeacher: TSQLPerson;
begin
result:= TSQLPerson.Create(db, Teacher.ID); // or PtrInt(Teacher);

and of course handling memory free manually.

Do you think it'd be possible to automate the object retrieval & freeing that way?

#31 Re: mORMot 1 » Update - memory corruption problem? » 2011-02-18 21:02:18

investigating the problem, I found out that it is something about "GetJSONObjectAsSQL", part called "if Update" in "Return" subroutine.

Changing that part to much slower but definitely "safe" code (see below) I've elminated the error described above ... but now there's a problem with freeing TSQLRestClientURI object. FastMM detects operation on freed object on shutdown.
See the stack trace to the error...
greenshot2011218215633.png

BTW commenting out the FreeAndNil(dbConnection) part results in memory leak but no errors ... seems like there's some "after-update" operation pending, finally called on finalization...


  if Update then begin
    // returns 'COL1="VAL1", COL2=VAL2' (UPDATE SET format)
    result:= '';
    for F := 1 to FieldsCount do begin
      result:= result + Fields^;
      if InlinedParams then begin
        result:= result + '=:(';
      end else begin
        result:= result + '=';
      end;
        result:= result + Values^;
      if InlinedParams then begin
        result:= result + '):,';
      end else begin
        result:= result + ',';
      end;
      inc(Fields);
      inc(Values);
    end;
    result[length(result)]:= ' ';

well that's all I found, I hope it helps you somehow


//////
further investigating
I found out that each edited record doesn't get unlocked right after edition. It's ID stays on the Model's list of Locked IDs. That is why the "calling operation on freed object" error occurs.
But also, because of this bug, I'm not able to edit same record twice during the application runtime.

#32 Re: mORMot 1 » Main Field Name problem » 2011-02-18 17:21:49

ab wrote:

stored false;

there's so much I have to learn about RTTI yikes

yeah, indeed making that field unique is not the best idea ... but current way of handling automated relation edition makes it practically useless sad

#33 Re: PDF Engine » TGDIPages - draw text - character encoding problem » 2011-02-18 17:16:27

MultiByteToWideChar method solved the problem big_smile smile Thank you!

#35 Re: PDF Engine » TGDIPages - draw text - character encoding problem » 2011-02-18 13:17:14

Delphi7 ... Regional characters - ą ę ś ć ź ł ń ó ż
GetACP returns 1250.
TextAlign := taLeft; just before printing the sting.

#36 Re: mORMot 1 » Update - memory corruption problem? » 2011-02-18 13:12:43

Ok, I have changed the declaration to RawUTF8 on all the fields.
I'm using Delphi 7. And the problem still occurs...

actually the problem is reproducible on my sqlite-framework-demo which as you know doesn't require TMS.

#37 Re: mORMot 1 » Main Field Name problem » 2011-02-18 13:11:38

ok, so I've reverted all the changes back to your version. Than declaret two records:

    TSQLCourse = class(TSQLRecord)
    private
    //fields declaration here
    published
        property Instructor: TSQLPerson read fInstructor write fInstructor;
        property Person: TSQLPerson read wPerson write fPerson;

and

    TSQLPerson = class(TSQLRecord)
    private
        fName: RawUTF8;
        fSurname: RawUTF8;
        fPhone: RawUTF8;
    published
        property Name: RawUTF8 read fName write fName;
        property Surname: RawUTF8 read fSurname write fSurname;
        property Phone: RawUTF8 read fPhone write fPhone;
    end;


I have some "person" records.
Now when I call TRecordEditForm on TSQLCourse, both comboboxes are empty ...

//debugging the model creation, I found out that in my case the P^.StoredProc never equals to integer(false), so the "Unique" flag is never being set to true ... thus fMainFieldName[false,x] is never filled with data.

// it seems that P^.StoredProc always equals to decimal number 1. At least for all the records I debugged it, including MainDemo records.

#38 mORMot 1 » Main Field Name problem » 2011-02-17 23:21:29

migajek
Replies: 10

Hi,
I'm playing with the UIEdit, and I tried editing the record which has related fields ...
first of all I was quite amazed that the related fields were of combobox type wink

But all the combos were empty. Debugging and investigating I found out that fMainFieldName contains empty string for each model.
Following that path I changed SQLIte3Commons:9068 from "sftUTF8Text: begin" to "sftUTF8Text, sftAnsiText: begin"
(I haveall the fields declared as UTF8String, BTW ... but the type was always sftAnsiText).

so it now fills "non-unique" array of names ... but still the "unique" part is empty .. what am I doing wrong?

#39 mORMot 1 » Update - memory corruption problem? » 2011-02-17 22:25:52

migajek
Replies: 7

Hi,
it seems that most recent leaf (downloaded from Fossil today) has some memory corruption problem while calling "update" method.

here's the most simple example of application (sources) which throws AV on application closing, if "update" was called.
http://migajek.us.to/tmp/synopsesqlite-update-bug.zip

in my more complex case I get following error report (FastMM):

FastMM has detected an error during a FreeMem operation. The block footer has been corrupted. 

The block size is: 84

This block was allocated by thread 0xFCC, and the stack trace (return addresses) at the time was:
402A03 [System][@GetMem]
404959 [System][@NewAnsiString]
404F1D [System][@LStrSetLength]
4AB2EE [SQLite3Commons.pas][SQLite3Commons][Return][6387]
4AB5AD [SQLite3Commons.pas][SQLite3Commons][GetJSONObjectAsSQL][6462]
4AB6BD [SQLite3Commons.pas][SQLite3Commons][GetJSONObjectAsSQL][6480]
5611A5 [SQLite3.pas][SQLite3][TSQLRestServerDB.EngineUpdate][3634]
4B1BF8 [SQLite3Commons.pas][SQLite3Commons][TSQLRestServer.URI][11031]
5618A7 [SQLite3.pas][SQLite3][TSQLRestClientDB.URI][3870]
4B0221 [SQLite3Commons.pas][SQLite3Commons][TSQLRestClientURI.Update][10161]
5B2CEC [frmRecordListing.pas][frmRecordListing][TFrame2.EditRecord][92]

The block is currently used for an object of class: Unknown

The allocation number is: 4261

The current thread ID is 0xFCC, and the stack trace (return addresses) leading to this error is:
402A23 [System][@FreeMem]
4048CE [System][@LStrArrayClr]
5611F7 [SQLite3.pas][SQLite3][TSQLRestServerDB.EngineUpdate][3637]
4B1BF8 [SQLite3Commons.pas][SQLite3Commons][TSQLRestServer.URI][11031]
5618A7 [SQLite3.pas][SQLite3][TSQLRestClientDB.URI][3870]
4B0221 [SQLite3Commons.pas][SQLite3Commons][TSQLRestClientURI.Update][10161]
5B2CEC [frmRecordListing.pas][frmRecordListing][TFrame2.EditRecord][92]
5B2E4B [frmRecordListing.pas][frmRecordListing][TFrame2.btnEditClick][160]
4630DE [Controls][TControl.Click]
45A76D [StdCtrls][TButton.Click]
45A861 [StdCtrls][TButton.CNCommand]

followed by 'invalid pointer operation'.
Finally, the debugger shows following line

            OK := EngineUpdate(Table,ID,SentData);

SQLite3Commons.pas:11031

#40 mORMot 1 » TSQLRecord + TSQLTableToGrid - table freeing memory issue. » 2011-02-17 21:30:54

migajek
Replies: 2

Hi,
I have a code as following:

private
 fRec: TSQLRecord;

// ...
begin
fRec:= TSQLPerson.CreateAndFillPrepare(dbClient, '');

fGridAdapter:= TSQLTableToGrid.Create(DrawGrid1, fRec.FillTable , dbClient);

now the problem is I can't free "fRec" on form destroy, because it also frees it's table - which is later freed by TSQLTableToGrid destructor.

So I end up with TSQLRecord leaking, or double freeing memory block ...

there should be way to tell one of those objects (probably TSQLTableToGrid ?) "hey, it's not your table, don't free it!!"

Or is there such flag somewhere?

#41 PDF Engine » TGDIPages - draw text - character encoding problem » 2011-02-17 19:23:56

migajek
Replies: 6

Hi,
so I have this problem, I need to print some 'regional' characters. They're handled incorrectly.
System character set is windows-1250.
Regular Canvas.Textout handles these characters correctly.

Here's the screenshot (left - Edit1 on the left, report on the right)
tmpfu.png

and the code

        DrawText('direct ' + Edit1.Text);
        DrawText('utf8ToString' + UTF8ToString(Edit1.Text));
        DrawText('StringToUTF8' + StringToUTF8(Edit1.Text));

yeah, I know those conversions doesn't make sense but I just wanted to try everything before asking for help wink

#42 Re: mORMot 1 » Demo application + some question / remarks. » 2011-02-16 21:04:30

I did so. I'm sorry, I was pretty sure you use svn wink So I didn't updated the source archives, just commited the lates version to svn

#43 Re: mORMot 1 » In my SQLite3 Framework TODO list » 2011-02-16 20:58:02

ab wrote:

GO for the standard buttons!
smile

smile can't wait to see that, especially the UIEdit form which seems to be perfect for quick object population / edition.

#44 Re: mORMot 1 » Record Validation? » 2011-02-16 20:56:01

so you can use the exact same code for a rich Client or a HTML page...

I don't get that, probably because I have absolutely no experience with web services in Delphi. Not even 'hello world' wink

ok, I'm looking forward to hear your proposals tongue

#45 Re: mORMot 1 » Record Validation? » 2011-02-16 20:07:19

I don't know "RTTI callbacks" so I'll have to investigate them a bit wink
But anyway it might be convenient to expose them somehow, in case I want to do validation on my own (in example - creating own editor for a model) so that I can handle validation messages.

#46 Re: mORMot 1 » In my SQLite3 Framework TODO list » 2011-02-16 20:05:26

To be honest, I prefer those most standard buttons and others components look, over the "glassy" look of recent Office interfaces.

#47 Re: mORMot 1 » In my SQLite3 Framework TODO list » 2011-02-16 19:39:16

ab wrote:

Which version of Delphi do you use?

Delphi 7PE for my "personal" projects wink By "personal" I mean each project done in my spare time.

Do you plan to use the Delphi Ribbon component available since Delphi 2009?

not for personal projects wink

I think I could use it, or (even better for compatibility with all Delphi versions) standard VCL components (Win32 Button, Tabs, ToolBar)....

What I love about the framework is it's compatibility with D7... Please, don't break it that way ! wink

Compiler defines would do the thing here, I believe.

#48 Re: mORMot 1 » Record Validation? » 2011-02-16 19:37:34

that event handler is pretty good idea for a quick fix, but doesn't solve the problem in my opinion.

first of all, I think it'd be good to keep the logics separated from presentation layer, so the validation part should be done on the Record, not the editor.
Let's say I need to store IP address in a record, and I have pretty much ways of adding/editing record (for example, creating the new record directly or modifying it's data inside of a grid). No matter what "editor" I use, the "IP" fields still needs to be valid IP address.

From what I learned using PHP frameworks, automated data validation is very important and convenient. My suggestion is to expand TSQLRecord with methods like this:

//pseudo code

// run the validation of data
// implemented in TSQLRecord, 
// calls the GetValidationRules and check data against rules one-by-one.
// Validate method is called each time the object is about to be saved
// or is edited
function Validate(): boolean; 

// returns list of rules
// actually implemented by final (inheriting) class.
// each validation rule consists of 
// * field name to which rule applies, 
// * rule name or even better - rule class
// * rule additional parameters (string - JSON-formated? array of const? I dunno ...)
function GetValidationRules: TValidationRules;

// registers a callback to be called on validation error
procedure RegisterValidationCallback(CB: TValidationCallback);

// Field: field name 
// Message: message returned by validation rule
// FieldValue: proposed field value / field value after filtering
// AllowContinue: if set to true, it means there was no error in fact, the validator acts as a "filter" here (see below)
TValidationCallback = procedure (const AField: string; AMessage: string; AFieldValue: string; AAllowContinue: boolean)



example filters:
TRegexpRule:
 * checks given value against regexp provided as parameter. if it doesn't pass, do callback, with message "sorry it doesn't validate against regexp"

TToLowercaseFilter:
 * calls Callback with AAllowContinue = true and  AField = lowercase(OriginalFieldValue)
 this doesn't throw an actual error but ensures the field will be lowercase.

actually it might be wise to separate Rules from Filters, or give them separate callbacks.


implementation of GetValidationRules for my case would return array looking like this:

[['Email', TEmailRule, 'allowedDomains:.com;.pl;.eu;.us'],
['Userip', TIPRule],
['Userlogin', TLowercaseFilter],
['Userlogin', TStringLengthRule, 'minLength:5|maxLength:25']]

that is just an idea, I know many things might be hard to implement in delphi, they might not be optimal etc but hopefully I know what I have in my mind.

That way one would be able to simply define filters, expand filtering (creating own filters), handle errors (for example, when creating custom "editor" for the record, just registerValidationCallback and add labels containing errors for each field).



What do you think about it?

#49 mORMot 1 » Record Validation? » 2011-02-16 18:13:44

migajek
Replies: 9

Hi,
let's say I have a simple record adding procedure, which creates record and fills it with a data provided by user (possibly using SQLite3UIEdit). What is the proper approach for validating data (like, checking if the string is not too short, or - as in my case - validate the provided string against regexp).
thanks,
migajek

#50 Re: mORMot 1 » In my SQLite3 Framework TODO list » 2011-02-16 17:43:53

Hi,
is there any progress in making the Framework independent from TMS? I'm about to start a bit more serious project with Synopse Framework, as for now I can use TMS Pack demo I guess, but one day I'll need to make my app independent ...

Board footer

Powered by FluxBB