#51 Re: Free Pascal Compiler » mORMot and FPC 3.0/3.1.1 » 2017-03-08 12:03:06

hnb
d.ioannidis wrote:

... there is no need for special mormot version ...

that is true. newpascal-ccr/mORMot was created as temporary solution:

1. to host binary files in repository for supported platforms
2. was created for initial support for Mac.
3. as important part of CI for NewPascal

All is merged now into "upstream" mORMot repository, so even NewPascal CI system uses https://github.com/synopse/mORMot .

#52 Re: mORMot 1 » Lazarus 3.0.0 on win64 install » 2017-03-08 11:56:25

hnb
d.ioannidis wrote:

no need for NewPascal, mormot trunk works fine with current ...

Rather bad idea. We have many low level details and latest stable FPC is not fully functionally with mORMot. After all NewPascal is practically just special selected FPC trunk version (FPC trunk has Management Operators too). Generally:

NewPascal means = selected Lazarus Trunk + selected FPC trunk (with features preview) + selected mORMot version.

#53 Re: mORMot 1 » FPC dealing RawUTF8 problem » 2017-03-06 10:51:49

hnb

@ab did we have any bugreport on FPC mantis for this?

#54 Re: mORMot 1 » mORMot and current FPC trunk doesn't work » 2017-01-31 12:24:37

hnb

AOG is right. Usage of pure FPC trunk for mORMot has no sense and is extremely risky. I have special version of mORMot which is *almost* ready and compatible both with current FPC trunk and with next NewPascal release:

https://github.com/maciej-izak/mORMot/tree/fpc_newrtti

The branch of mORMot is incomplete yet (we have some serious bug around - and ready to use by FPC core team related patch):

http://bugs.freepascal.org/view.php?id=31249
http://bugs.freepascal.org/view.php?id=31305

#31249 will be fixed directly in NewPascal (or even in FPC trunk).

#55 Re: mORMot 1 » mORMot and current FPC trunk doesn't work » 2016-12-21 22:10:59

hnb

At the moment we need to wait - I am working with Sven from FPC core team on some important changes for RTTI (few notes : http://synopse.info/forum/viewtopic.php?id=3689 ). mORMot will be updated too, but it has not much sense at the moment. Generally for mORMot NewPascal is recommended. If for some reasons you like to use "pure FPC trunk" the latest stable and recommended for mORMot is r35095 (pre RTTI.pas). Latest NewPascal (v1.0.39) is synced with r35095.

TLTR: For mORMot users I see 2 options:

* use NewPascal (for latest fresh stuff) instead of FPC trunk otherwise you will have many troubles tongue
* use latest stable FPC 3.0.x (older FPC stable like 2.6.x means also many troubles)

#56 Re: mORMot 1 » Breaking changes in FPC for RTTI » 2016-12-16 10:12:56

hnb
hnb wrote:

Sorry but no. The only proper solution is to use {$ifndef VER3_0} (FPC has official support only for latest stable version and for trunk (2.6.x is not officially supported anymore so {$ifndef VER3_0} make sense). Eventually if we like to support somehow 2.6.x we could use {$if FPC_FULLVERSION>30100} instead of {$ifndef VER3_0}.

I know that you are not happy about that but IMO is impossible to put for each change new FPC_HAS_* ... sad I do what I can best for improved RTTI. Finally we have small steps in right direction.

#57 Re: mORMot 1 » Breaking changes in FPC for RTTI » 2016-12-15 09:12:22

hnb

I will inform about all breaking changes in this topic. We have again small update in https://github.com/newpascal/freepascal … 437b3288e1

First post updated (InitTable field)!

#58 Re: mORMot 1 » Lazarus package » 2016-12-14 18:15:16

hnb

I mean moving units to directories. We should for example move

PasZip, SynBidirSock, SynBigTable, SynCommons, SynCrtSock, SynCrypto, SynFastWideString, SynFPCTypInfo, SynLog, SynLZ, SynLZO, SynMustache, SynSSPIAuth, SynWinSock, SynZip, SynZipFiles, SynTests

to "Common" directory or something similar.

Note: Zeos is excellent example of good designed packages for Lazarus.

#59 Re: mORMot 1 » Breaking changes in FPC for RTTI » 2016-12-14 18:08:42

hnb

Sorry but no. The only proper solution is to use {$ifndef VER3_0} (FPC has official support only for latest stable version and for trunk (2.6.x is not officially supported anymore so {$ifndef VER3_0} make sense). Eventually if we like to support somehow 2.6.x we could use {$if FPC_FULLVERSION>30100} instead of {$ifndef VER3_0}.

FPC is open source so IMO we (as mORMot community) don't need to provide support for versions older than 3.0.x...

#60 Re: mORMot 1 » Lazarus package » 2016-12-14 12:16:19

hnb

IIRC for packages we need to refresh mORMot source code tree and that is main problem...

#61 Re: mORMot 1 » new book about mORMot » 2016-12-14 10:06:35

hnb

Thanks for your work. First real book about mORMot!

Btw. nice to see NewPascal in description smile

erick wrote:

Use either Delphi Professional or the free and open source New Pascal to develop on Windows, Linux and other platforms.  Active Directory authentication and local passwords are both demonstrated.

#62 mORMot 1 » Breaking changes in FPC for RTTI » 2016-12-14 09:32:50

hnb
Replies: 4

Hi,

we have very important changes for FPC (comes from NewPascal with a few adjustments):

https://github.com/newpascal/freepascal … 9ffaa8a6ad

RTTI layout for records is different and in few cases more Delphi compatible. Maybe not directly compatible... Now is possible to obtain access to *real* managed fields (by RTTI INIT table for records by InitTable field). New layout:

  PRecordInfoFull=^TRecordInfoFull;
  TRecordInfoFull={$ifdef USE_PACKED} packed{$endif USE_PACKED}
  record
    InitTable: Pointer; // PRecordInfoInit
    Size: Longint;
    Count: Longint;
    { Elements: array[count] of TRecordElement }
  end;

  PRecordInfoInit=^TRecordInfoInit;
  TRecordInfoInit= {$ifdef USE_PACKED}packed{$endif USE_PACKED}
  record
    Terminator: Pointer;
    Size: Longint;
    Count: Longint;
    { Elements: array[count] of TRecordElement }
  end;

This RTTI is incompatible (yet) with NewPascal. I need to merge this in proper way. In NewPascal InitTable/Terminator is placed after Size field.

Anyway more breaking changes is coming... So be aware.

#63 Re: mORMot 1 » Lazarus package » 2016-12-12 17:28:02

hnb

We have initial idea of packages (see packages directory): https://github.com/maciej-izak/mORMot/tree/packages

I think we can add some script *.bat/*.sh file for auto-reorganizing source directory for packages.

Proposed packages:

unnamed.png

* Package mORMot_Commons
  modules:
    PasZip, SynBidirSock, SynBigTable, SynCommons, SynCrtSock, SynCrypto,
    SynFastWideString, SynFPCTypInfo, SynLog, SynLZ, SynLZO, SynMustache,
    SynSSPIAuth, SynWinSock, SynZip, SynZipFiles, SynTests
  required packages:
    FCL (standard basic package for packages)

* Package mORMot_SQLite3
  modules:
    mORMot, mORMotSQLite3, SynSQLite3
  required packages:
    mORMot_Commons

* Package mORMot_REST
  modules:
    mORMotHttpClient, mORMotHttpServer, mORMotWrappers,
  required packages:
    mORMot_SQLite3

* Package mORMot_SQLite3Static
  modules:
    SynSQLite3Static
  required packages:
    mORMot_SQLite3

* Package mORMot_DB
  modules:
    mORMotDB, mORMotMongoDB, SynDB, SynDBODBC, SynDBOracle, SynDBRemote,
    SynDBSQLite3, SynMongoDB
  required packages:
    mORMot_SQLite3

* Package mORMot_ZEOS (needs some work/idea for paths to ZEOS)
  modules:
    SynDBZeos
  required packages:
    * zdbc
    * mORMot_DB

#64 Re: mORMot 1 » Load/save TSQLRestBatch from/to file? » 2016-11-23 08:54:54

hnb

@ab this code is not used in presented "batch save/load system" (just too much copy/paste from my helper module). Btw. It works perfectly on all of my FPC targets and is very standard for Pascal: ARM, Linux/Windows... without problems.

@edwinsn you have string per operation: Add has own string, Delete  has own string, Update  has own string. The best idea is to store this "batch" strings in separate files (or in single SQLite file as records):

FileFromString(TBatchCacheFactory.Add(...), 'C:\add001.txt');
FileFromString(TBatchCacheFactory.Update(...), 'C:\update001.txt');
FileFromString(TBatchCacheFactory.Delete(...), 'C:\delete001.txt');

...

myDb.BatchSend(nil, StringFromFile('C:\add001.txt'));
myDb.BatchSend(nil, StringFromFile('C:\update001.txt'));
myDb.BatchSend(nil, StringFromFile('C:\delete001.txt'));

you can also try to use somehow single text file smile mORMot is super elastic.

#65 Re: mORMot 1 » Load/save TSQLRestBatch from/to file? » 2016-11-22 23:35:55

hnb

sad I didn't know that it is impossible yet and I have created solution for this.

First you need additional factory to produce batch string:

type
  TBatchAction = (baInsert, baUpdate, baDelete);

  TBatchCacheFactory = class
  public
    class function Insert(AServer: TSQLRestServerDB; ARecord: TSQLRecord; AForceID: Boolean = false;
      const CustomFields: TSQLFieldBits = []): RawUTF8; overload;
    class function Insert(AServer: TSQLRestServerDB; ARecord: TSQLRecord; AForceID: Boolean = false;
      const CustomCSVFields: RawUTF8 = '*'): RawUTF8; overload;

    class function Update(AServer: TSQLRestServerDB; ARecord: TSQLRecord; const CustomFields: TSQLFieldBits = []): RawUTF8; overload;
    class function Update(AServer: TSQLRestServerDB; ARecord: TSQLRecord; const CustomCSVFields: RawUTF8): RawUTF8; overload;
    class function Delete(AServer: TSQLRestServerDB; ARecord: TSQLRecordClass; AID: TID): RawUTF8;
  end;

implementation

{ TBatchCacheFactory }

class function TBatchCacheFactory.Insert(AServer: TSQLRestServerDB; ARecord: TSQLRecord;
  AForceID: Boolean; const CustomFields: TSQLFieldBits): RawUTF8;
var
  LBatch: TSQLRestBatch;
begin
  with TAutoFree.One(LBatch, TSQLRestBatch.Create(AServer, nil)) do
  begin
    LBatch.Add(ARecord, true, AForceID, CustomFields);
    LBatch.PrepareForSending(Result);
  end;
end;

class function TBatchCacheFactory.Update(AServer: TSQLRestServerDB; ARecord: TSQLRecord;
 const CustomFields: TSQLFieldBits): RawUTF8;
var
  LBatch: TSQLRestBatch;
begin
  with TAutoFree.One(LBatch, TSQLRestBatch.Create(AServer, nil)) do
  begin
    LBatch.Update(ARecord, CustomFields);
    LBatch.PrepareForSending(Result);
  end;
end;

class function TBatchCacheFactory.Delete(AServer: TSQLRestServerDB; ARecord: TSQLRecordClass;
  AID: TID): RawUTF8;
var
  LBatch: TSQLRestBatch;
begin
  with TAutoFree.One(LBatch, TSQLRestBatch.Create(AServer, nil)) do
  begin
    LBatch.Delete(ARecord, AID);
    LBatch.PrepareForSending(Result);
  end;
end;

class function TBatchCacheFactory.Insert(AServer: TSQLRestServerDB;
  ARecord: TSQLRecord; AForceID: Boolean;
  const CustomCSVFields: RawUTF8): RawUTF8;
begin
  Result := Insert(AServer, ARecord, AForceID, ARecord.RecordProps.FieldBitsFromCSV(CustomCSVFields));
end;

class function TBatchCacheFactory.Update(AServer: TSQLRestServerDB; ARecord: TSQLRecord;
  const CustomCSVFields: RawUTF8): RawUTF8;
begin
  Result := Update(AServer, ARecord, ARecord.RecordProps.FieldBitsFromCSV(CustomCSVFields));
end;

next you need some helpers for existing mORMot classes:

type
  TSQLRestBatchHelper = class helper for TSQLRestBatch
  public
    function Add(Value: TSQLRecord; SendData: boolean; ForceRecordClass: TSQLRecordClass; ForceID: boolean=false;
      const CustomFields: TSQLFieldBits=[]; DoNotAutoComputeFields: boolean=false): integer; overload;
  end;

  { TSQLRestHelper }

  TSQLRestHelper = class helper for TSQLRest
  public
    function BatchSend(Batch: TSQLRestBatch; const Data: RawUTF8; var Results: TIDDynArray): integer; overload;
    function BatchSend(Batch: TSQLRestBatch; const Data: RawUTF8): integer; overload;
    function Update(Value: TSQLRecord; ForceRecordClass: TSQLRecordClass;
      const CustomFields: TSQLFieldBits=[]; DoNotAutoComputeFields: boolean=false): boolean; overload;
  end;

implementation

{ TSQLRestHelper }

function TSQLRestHelper.BatchSend(Batch: TSQLRestBatch; const Data: RawUTF8;
  var Results: TIDDynArray): integer;
var
  LData: RawUTF8;
begin
  LData := Copy(Data, 1);
  try
    if Batch <> nil then
      result := EngineBatchSend(Batch.Table,LData,Results,Batch.Count)
    else
      result := EngineBatchSend(nil,LData,Results,0)
  except
    on Exception do // e.g. from TSQLRestServer.EngineBatchSend()
      result := HTTP_SERVERERROR;
  end;
end;

function TSQLRestHelper.BatchSend(Batch: TSQLRestBatch; const Data: RawUTF8
  ): integer;
var
  Results: TIDDynArray;
begin
  Result := BatchSend(Batch,Data,Results);
end;

function TSQLRestHelper.Update(Value: TSQLRecord;
  ForceRecordClass: TSQLRecordClass; const CustomFields: TSQLFieldBits;
  DoNotAutoComputeFields: boolean): boolean;
var
  DefaultClass: TSQLRecordClass;
begin
  Result := False;

  if (self=nil) or (Value=nil) or (ForceRecordClass=nil) then
    exit;

  if not PSQLRecordClass(Value)^.InheritsFrom(ForceRecordClass) then
    exit;

  DefaultClass := PSQLRecordClass(Value)^;
  PSQLRecordClass(Value)^ := ForceRecordClass;
  result := Self.Update(Value, CustomFields, DoNotAutoComputeFields);
  PSQLRecordClass(Value)^ := DefaultClass;
end;

{ TSQLRestBatchHelper }

function TSQLRestBatchHelper.Add(Value: TSQLRecord; SendData: boolean;
  ForceRecordClass: TSQLRecordClass; ForceID: boolean;
  const CustomFields: TSQLFieldBits; DoNotAutoComputeFields: boolean): integer;
var
  DefaultClass: TSQLRecordClass;
begin
  result := -1;
  if (self=nil) or (Value=nil) or (fBatch=nil) or (ForceRecordClass=nil) then
    exit;

  if not PSQLRecordClass(Value)^.InheritsFrom(ForceRecordClass) then
    exit;

  DefaultClass := PSQLRecordClass(Value)^;
  PSQLRecordClass(Value)^ := ForceRecordClass;
  result := Self.Add(Value, SendData, ForceID, CustomFields, DoNotAutoComputeFields);
  PSQLRecordClass(Value)^ := DefaultClass;
end;

now put all together:

  LBatch := TBatchCacheFactory.Update(AServer, LMyRecord, LCSV); // save batch to string
  { ... }
  { save batch to file or anywhere }
  { ... }
  FServer.BatchSend(nil, LBatch); // execute our string

done! ^^

#66 Re: mORMot 1 » Implementing OAuth2 » 2016-10-19 09:50:07

hnb
ab wrote:

I will work on OAuth2 this weekend.

Thanks for sharing.

@ab any progress ? Seems like OAuth2 work takes more than one weekend ;)

#67 Re: SyNode » Beta release of SyNode - ES6 JavaScript + NPM modules » 2016-10-12 12:05:25

hnb
ComingNine wrote:

It seems that the memory footer corruption can be avoided with some modification of TSynTempBuffer to avoid the re-allocation in TSynTempBuffer.Init. The reason is unclear. Could ab or you help to correct the root problem ?

Maybe related to http://synopse.info/forum/viewtopic.php?id=3468 ?

#68 Re: mORMot 1 » Master/Slave replications - tips :) » 2016-10-06 11:39:18

hnb

@ab: TSynUniqueIdentifierGenerator might be good for new projects but this solution is not perfect (for example is impossible to use TSynUniqueIdentifierGenerator for large existing systems).

@oz: I have 1 Master, N Slaves for described scenario (but in background I have much more complicated architecture with N Masters but that is managed outside mORMot by other tools). The idea for "1 Master - N Slaves" is simple and can be improved by ORM system. What we have:

* android clients (with local SQLite3 DB)
* 1 server mORMot server
* 1 PostgreSQL DB
* Existing big project developed for more than 10 years with 500+ tables (so I can't start from scratch - structures like TSynUniqueIdentifierGenerator are useless for me).

The first step is model:

  TSQLmaster = class(TSQLRecord)
    // ...
  end;
  TCACHE_master = class(TSQLmaster) // could be generated by ORM
  protected 
    fiid: RawUTF8;
    fcreation_time: TDateTime;
  published  
    property iid: RawUTF8 index 38 read fiid write fiid;
    property creation_time: TDateTime read fcreation_time write fcreation_time;
  end; 

  TSQLdetail = class(TSQLRecord)
    // ...
  end;
  TCACHE_detail = class(TSQLdetail) // could be generated by ORM
  protected 
    fiid: RawUTF8;
    fcreation_time: TDateTime;
  published  
    property iid: RawUTF8 index 38 read fiid write fiid;
    property creation_time: TDateTime read fcreation_time write fcreation_time;
  end;
  TCACHE_CACHE_detail = class(TCACHE_detail); // could be generated by ORM

In presented model we have 5 tables: master, CACHE_master, detail, CACHE_detail, CACHE_CACHE_detail
How it is handled by client? For the client, insertion for new records into master/detail table is forbidden. We have simple schema:

* insert for new detail record for correlated master record means hidden insertion into CACHE_detail table
* insert for new master record means hidden insertion into CACHE_master table
* insert for new detail record for correlated CACHE_master record means hidden insertion into CACHE_CACHE_detail table

Each insert above means also assigning for iid and creation_time:

  newrecord.iid := GUIDToRawUTF8(RandomGUID);
  newrecord.creation_time := DBServerDateTime;  

thanks this solution I can receive new data from server without problem and I don't need to send records from CACHE_* tables in the same time (but that scenario is also possible smile.

When client like to send data (or few parts) I have special record for that purpose:

  TSYNC_CACHE = class(TSQLRecord)  
  protected 
    fiid: RawUTF8;
    fcreation_time: TDateTime;
    { ... 
      structures (for example dynamic arrays) to handle CACHE_* tables and batching 
    }
  published  
    property iid: RawUTF8 index 38 read fiid write fiid;
    property creation_time: TDateTime read fcreation_time write fcreation_time;
    { ...
      structures (for example dynamic arrays) to handle CACHE_* tables and batching }
    }
  end;

on server side I have local SQLite3 file DB to track all iid which is the key for proper working, in some cases mORMot can send twice (or even more) the same data, or even corrupted data but this is different topic. Anyway TSYNC_CACHE and each item inside needs iid. When server has done all insertions described in TSYNC_CACHE (with insertions into iid table) then server sends back TSYNC_CACHE to client but with new correct ID and optionally with new values for some columns for each record inside TSYNC_CACHE.

Also very important for proper ID is right configuration for regular tables on Server side:

  procedure AddEngineComputeId(AClass: TSQLRecordClass);
  begin
    LRestStorage := TSQLRestStorageExternal.Instance(AClass, AServer);
    LRestStorage.EngineAddForcedID := 0;
    LRestStorage.OnEngineAddComputeID := aRestServer.OnEngineAddComputeID; // here inside OnEngineAddComputeID is called nextval for postgreSQL sequence
  end;

  procedure AddEngineIgnoreId(AClass: TSQLRecordClass); // for simple insert
  begin
    LRestStorage := TSQLRestStorageExternal.Instance(AClass, AServer);
    LRestStorage.EngineAddForcedID := 1;
  end;

thanks to mORMot and metaclasses, manipulations between CACHE_* and original tables on client/server side is easy. All described above can be handled on ORM level in very elastic way with many policies. The topic is complex and is very hard to decribe many aspects in one post. Thanks to CACHE_* tables, batching and iid table (and mORMot of course) I have done full CRUD + master/slave replication + online/offline modes smile

#69 Re: mORMot 1 » Master/Slave replications - tips :) » 2016-10-05 06:50:31

hnb

Comment from ab: http://synopse.info/forum/viewtopic.php … 877#p17877

so my "two way" master/slave replication with offline functionality is developed outside mORMot sources tongue. Anyway code attached above is the key to start any serious work wink

#70 Re: mORMot 1 » Android TSQLHttpClientWinSock connect problem » 2016-09-30 08:13:05

hnb

@AOG:

GClientPing is a global variable and is created together with regular clients (at application startup). I need that because  TSQLHttpClientWinSock is not thread safe. I have few threads in application:

1. GUI
2. Data sync
3. Ping

About security: I have private WiFi network in each place where my application is used. Additionally is used standard hcSynShaAes for data compression.

About functionality, look at new topic:

http://synopse.info/forum/viewtopic.php?id=3569

#71 mORMot 1 » Master/Slave replications - tips :) » 2016-09-30 08:11:57

hnb
Replies: 9

I'd like to start new topic, maybe it will help someone. The discussion starts here:

http://synopse.info/forum/viewtopic.php … 890#p21890

My application has almost full functionality when is offline (except printing wink - for that server is needed). I made my own replication master/slave which is fully functional in offline mode (each slave can add or modify records even in offline). Each table (lets call normal table "main table") on client side has one or more special "cache" tables (each of "cache" table has exactly the same columns - technically each "cache" table is descendant of main table). I have my own extensions for mORMot for that. On the server side each cache table is simple converted into original table (and each of record from "cache" table is converted and sent back as record for "main table" to client, the process is monitored/protected so even when I lose connection at critical moment of sync all is tracked in proper way thanks to unique GUID for each action). The core code for improved master/slave replication (rejected by ab tongue):

uses
  mORMot, SynCommons, SysUtils;

type
  TSQLRestBatchHelper = class helper for TSQLRestBatch
  public
    function Add(Value: TSQLRecord; SendData: boolean; ForceRecordClass: TSQLRecordClass; ForceID: boolean=false;
      const CustomFields: TSQLFieldBits=[]; DoNotAutoComputeFields: boolean=false): integer; overload;
  end;

  { TSQLRestHelper }

  TSQLRestHelper = class helper for TSQLRest
  public
    function BatchSend(Batch: TSQLRestBatch; const Data: RawUTF8; var Results: TIDDynArray): integer; overload;
    function BatchSend(Batch: TSQLRestBatch; const Data: RawUTF8): integer; overload;
    function Update(Value: TSQLRecord; ForceRecordClass: TSQLRecordClass;
      const CustomFields: TSQLFieldBits=[]; DoNotAutoComputeFields: boolean=false): boolean; overload;
  end;

implementation

{ TSQLRestHelper }

function TSQLRestHelper.BatchSend(Batch: TSQLRestBatch; const Data: RawUTF8;
  var Results: TIDDynArray): integer;
var
  LData: RawUTF8;
begin
  LData := Copy(Data, 1);
  try
    if Batch <> nil then
      result := EngineBatchSend(Batch.Table,LData,Results,Batch.Count)
    else
      result := EngineBatchSend(nil,LData,Results,0)
  except
    on Exception do // e.g. from TSQLRestServer.EngineBatchSend()
      result := HTTP_SERVERERROR;
  end;
end;

function TSQLRestHelper.BatchSend(Batch: TSQLRestBatch; const Data: RawUTF8
  ): integer;
var
  Results: TIDDynArray;
begin
  Result := BatchSend(Batch,Data,Results);
end;

function TSQLRestHelper.Update(Value: TSQLRecord;
  ForceRecordClass: TSQLRecordClass; const CustomFields: TSQLFieldBits;
  DoNotAutoComputeFields: boolean): boolean;
var
  DefaultClass: TSQLRecordClass;
begin
  Result := False;

  if (self=nil) or (Value=nil) or (ForceRecordClass=nil) then
    exit;

  if not PSQLRecordClass(Value)^.InheritsFrom(ForceRecordClass) then
    exit;

  DefaultClass := PSQLRecordClass(Value)^;
  PSQLRecordClass(Value)^ := ForceRecordClass;
  result := Self.Update(Value, CustomFields, DoNotAutoComputeFields);
  PSQLRecordClass(Value)^ := DefaultClass;
end;

{ TSQLRestBatchHelper }

function TSQLRestBatchHelper.Add(Value: TSQLRecord; SendData: boolean;
  ForceRecordClass: TSQLRecordClass; ForceID: boolean;
  const CustomFields: TSQLFieldBits; DoNotAutoComputeFields: boolean): integer;
var
  DefaultClass: TSQLRecordClass;
begin
  result := -1;
  if (self=nil) or (Value=nil) or (fBatch=nil) or (ForceRecordClass=nil) then
    exit;

  if not PSQLRecordClass(Value)^.InheritsFrom(ForceRecordClass) then
    exit;

  DefaultClass := PSQLRecordClass(Value)^;
  PSQLRecordClass(Value)^ := ForceRecordClass;
  result := Self.Add(Value, SendData, ForceID, CustomFields, DoNotAutoComputeFields);
  PSQLRecordClass(Value)^ := DefaultClass;
end;

The most important parameter is "ForceRecordClass" (to convert cache table into main table). With a little of work my mechanism can be automated for any ORM master/slave replication. Behind scenes is extensively used batching. I have also additional batch parser to extract records from batch like "PUT@table_name,{...}". The topic is complicated but the end effect is amazing. The client/slave can be offline even for very long time (few days?) and all is synchronized very well, thanks to "cache" tables idea. In addition should be possible to manage politics for conflicts (for now I have one rule: "first client wins").

The key code to start any work is presented above. smile

#72 Re: mORMot 1 » Android TSQLHttpClientWinSock connect problem » 2016-09-28 07:44:55

hnb

@AOG

From my experience the best values for release for production (in WiFi network) are:

const
  DEFAULT_CONNECT_TIMEOUT = 3000;

...

    AClient := TSQLHttpClientWinSock.Create(AIP, APort, GModel,
      SynCrtSock.HTTP_DEFAULT_SENDTIMEOUT, SynCrtSock.HTTP_DEFAULT_RECEIVETIMEOUT, DEFAULT_CONNECT_TIMEOUT);

In addition if connection is successful I have dedicated thread (and client GClientPing - created with the same parameters as presented above) for ping purposes (online/offline status):

const
  PING_MS_DELTA = DEFAULT_CONNECT_TIMEOUT;  

...

class function TSyncProcess.TSync.Ping: Boolean;
var
  LNow, LThen: TDateTime;
  LTryPing: Boolean;
begin
  LNow := TimeLogToDateTime(GClientPing.ServerTimeStamp);
  LThen := TimeLogToDateTime(FLastPingTimeStamp);

  LTryPing := (FLastPingTimeStamp = 0) or (MilliSecondsBetween(LNow, LThen) > PING_MS_DELTA);

  if LTryPing or FLastPingResult then
  begin
    try
      Result := GClientPing.ServerTimeStampSynchronize;
    except
      Result := False;
    end;

    Result := Sync.StatusCodeIsSuccess(GClientPing) and Result;
    FLastPingResult := Result;
    FLastPingTimeStamp := GClientPing.ServerTimeStamp;
  end
  else
    Result := FLastPingResult;
end;  

#73 Re: mORMot 1 » Some findings after spent an afternoon fiddling Linux/Lazarus/mORMot » 2016-09-12 08:30:25

hnb

NewPascal is developed to put all together. AOG has done new pre-release under NewPascal project, to omit confusion. But we need to finish few details:

https://github.com/dathox/newpascalpack … ss-v1.0.22

NewPascal is Windows only (for now but it might change in future) with cross compilation for many platforms (on the way - see newpascalcross-v1.0.22).

I need to finish series of patches for FPC compiler to keep NewPascal as close as possible with "official" FPC trunk and for documentation purposes. Cooperation with FPC core team is hard, and they are only happy with simple minor patches like:

http://bugs.freepascal.org/view.php?id=30494

FPC core team is not happy with major patches:

http://bugs.freepascal.org/view.php?id=30534

Whatever FPC core team decide (maybe they wish to not including few of patches), we need to put all reports from bugtracker together for documentation purposes. Project like NewPascal needs to have clear and transparent way to document every of change.

Approach of FPC core team is depressing for me...

I am working on new tool for auto-downloading latest mORMot for NewPascal (and for downloading latest NewPascal). When tool will be ready, then I will separate mORMot from NewPascal release.

#74 Re: mORMot 1 » Delphi for Linux preview - what do you think? » 2016-09-05 08:07:57

hnb
ab wrote:

... it is about to be merged in the official FPC trunk AFAIR.

It may takes months or years.

#75 Re: mORMot 1 » Delphi for Linux preview - what do you think? » 2016-08-29 12:25:58

hnb
edwinsn wrote:

Do you think of mORMot will follow? Maybe it's too earlier to talk about any decisions this at the moment, but this news is still worth discussing smile

Waste of time. Delphi has "mORMot incompatible" EULA which makes mORMot usage (development?) illegal in Delphi. Delphi Linux compiler will be ARC only which is big problem.

#76 Re: SyNode » Beta release of SyNode - ES6 JavaScript + NPM modules » 2016-08-25 16:46:52

hnb

Amazing! My inner version of NewPascal uses NodeJS for few purposes, but thanks to your work I think is worth to review my code and support this effort smile

mpv wrote:

- fpc support? linux support? x64 support?

FPC is the most important part. The Delphi licence (after XE2) is evil:

Licensee agrees not to use the Product to develop an application that is directly competitive to the Product or to any other Embarcadero products

Seems like mORMot breaks that point in many fields, IMO very bad licence for mORMot... The comment from Embarcadero employee is for me very strange and nasty:

Jim McKeeth wrote:

There isn't really any official clarification on what that means. The license agreement is the official clarification - anything "official" beyond that would limit the scope of the agreement.

My understanding is similar to what +Roland Kossow said. Anything that someone would do to specifically target or clone our products. I expect that unless what you are doing is pretty blatant there won't be a reaction.

Basically, don't try to bite the hand that feeds you.

Another point for support for FPC: Delphi Linux compiler will be ARC only.

For extended RTTI for FPC we need to push forward NewPascal project.

#77 mORMot 1 » TSynDictionary for TSynMustache.HelperFind » 2016-08-25 12:20:28

hnb
Replies: 0

Hi,

what do you think? TSynDictionary might be good to improve performance of TSynMustache.HelperFind.

#78 Re: mORMot 1 » NaN, Infinity, -Infinity for PostgreSQL » 2016-08-25 09:40:20

hnb

@mpv presented solution will not work with TNullableFloat. For TNullableFloat better is:

NULL -> null
NaN -> -0.0
Infinity -> 1.7976931348623157e+308 (int64 with first byte 0 and all other 1)
-Infinity -> 5e-324

But maybe someone have better solution for NaN ?

#79 Re: Delphi » Free starter edition » 2016-08-23 12:39:55

hnb
AOG wrote:

Yes !
Could you imagine ... the power of mORMot with Delphi starter ... all for free !!
Unfortunately ... just limited in time ... at least the Delphi part.

I think that is the main reason why it is limited in time wink

#81 Re: mORMot 1 » NaN, Infinity, -Infinity for PostgreSQL » 2016-08-12 15:44:05

hnb

for NaN string 'NaN' (or other string) might be better (to omit conflict with TNullableFloat usage).

According to JSON spec, there is no Infinity or NaN values: http://json.org/

Few solutions from  Javascript engines: https://lavag.org/topic/16217-cr-json-l … ment-99058

#82 mORMot 1 » NaN, Infinity, -Infinity for PostgreSQL » 2016-08-12 12:26:37

hnb
Replies: 7

Hi,

we have broken implementation of handling ftDouble field, line 1266 in SynDBZeos:

      ftDouble:
        if fDBMS in [dMySQL,dPostgreSQL] then begin
          P := fResultSet.GetPAnsiChar(col+FirstDbcIndex,Len); 

In addition to ordinary numeric values, the floating-point types have several special values, P can point to following values/strings:

Infinity
-Infinity
NaN

(source: https://www.postgresql.org/docs/current … meric.html )

for example presented SQL for PostgreSQL won't work with mORMot (that code can corrupt whole ORM data set!):

select CAST('NaN' AS float) as x

How can we handle NaN, Infinity, -Infinity in mORMot? NaN, Infinity, -Infinity are very important for my integration with mORMot for large existing code base. NaN, Infinity, -Infinity is non standard for JSON format but I think we can handle this is similar way like for BASE64 by introducing something similar to JSON_BASE64_MAGIC_QUOTE:

JSON_NAN_MAGIC
JSON_INFINITY_MAGIC
JSON_NEGINFINITY_MAGIC

#83 mORMot 1 » j2oIgnoreUnknownProperty - possible bug for dyn. array property » 2016-08-10 08:36:20

hnb
Replies: 0

Hi,

for published field (of dynamic array type) for each array item (each item is TSQLRecord descendant) ignoring of unknown properties won't work. Very dangerous and IMO unexpected behavior.

Is that by design?

#84 mORMot 1 » Possible bug in TSynTempBuffer.Init » 2016-08-09 21:25:47

hnb
Replies: 1

Hi,

I think we have bug for TSynTempBuffer.Init(SourceLen: integer);  in newer versions of Delphi for TSynTempBuffer (declared as record).

The field tmp is not initialized so on the stack we lose trailing #0 (same for buf, the newly allocated memory is not initialized in any way, and may contain garbage data).

Is that by design?

#85 Re: mORMot 1 » Generics.Collections for mORMot » 2016-07-29 11:06:53

hnb
AOG wrote:

may I add a feature request ?
a threadsafe list ?
;-)

That one feature is not on my TODO list (yet). Contribution is welcome! Finally it is Open Source wink

#86 mORMot 1 » Generics.Collections for mORMot » 2016-07-29 08:00:02

hnb
Replies: 3

I am a little surprised that Generics.Collections is part of mORMot "REST-tester" demo. Maybe is worth to move generics-collections in better place in mORMot tree? Keeping that library inside demo is IMO bad idea. Since I have commit rights to fossil I can update Generics.Collections if needed.

#87 mORMot 1 » NewPascal with mORMot - first release » 2016-07-13 20:08:38

hnb
Replies: 3

Hi,

finally! New release with mORMot and Generics.Collections included is available (at http://newpascal.org ). All works out of box. Just unpack and become mORMot programmer. NP = NewPascal = NoProblems (almost... see below)

Note 0: no cross compilation (yet), only avalible target is Win32
Note 1: IMO we need to refresh mORMot source code tree. Maybe only locally for NewPascal purposes... I know you don't like this ab tongue
Note 2: Code insight (Code Completion etc) won't work (for example when mORMot module is used). It is +/- Lazarus bug, but well organized source tree can easily eliminate this bug (good example is Zeos).

#89 Re: mORMot 1 » [Patch] Custom RTTI PropInfo for custom types » 2016-07-11 07:07:44

hnb

Any feedback ? tongue Can I commit my changes to fossil?

#90 Re: mORMot 1 » NewPascal preview - fork for mORMot » 2016-07-07 10:34:46

hnb
AOG wrote:

Ok.

I have created a NewPascal release that can also be used for cross-compiling.

Can we include that into NewPascalPack Continous Integration system? Btw. you have full admin rights for newpascal repo inside dathox.

#91 Re: mORMot 1 » [Patch] Custom RTTI PropInfo for custom types » 2016-07-06 06:19:39

hnb

Ping. Attached patch has no performance issue for existing code base... That feature has critical meaning for my projects.

Corrected patch: https://drive.google.com/file/d/0B4PZhd … sp=sharing

#92 Re: mORMot 1 » NewPascal preview - fork for mORMot » 2016-06-30 10:16:55

hnb
Edwin Yip wrote:

b) Supports enhanced rtti needed by the mORMot framework, if I understand it correctly.

Ready thanks to patch from AOG smile

newpascalpack 1.0.3:
http://newpasca.org
https://github.com/dathox/newpascalpack/releases

#93 mORMot 1 » [Patch] Custom RTTI PropInfo for custom types » 2016-06-30 09:43:47

hnb
Replies: 6

Hi!

I have idea for custom RTTI PropInfo for custom types. Patch attached:

(moved below)

Example usage:

type
  TDouble_Precision2 = type Double;

  TSQLPropInfoRTTIDouble_Precision2 = class(TSQLPropInfoRTTIDouble)
  public
    procedure GetValueVar(Instance: TObject; ToSQL: boolean;
      var result: RawUTF8; wasSQLString: PBoolean); override;
  end;

implementation

procedure TSQLPropInfoRTTIDouble_Precision2.GetValueVar(Instance: TObject; ToSQL: boolean;
  var result: RawUTF8; wasSQLString: PBoolean);
var
  D: Double;
begin
  if wasSQLString<>nil then
    wasSQLString^ := false;
  Result := FormatFloat('0.00', PropInfo.GetExtendedValue(Instance));
end;

begin
  RegisterSQLPropInfo(TypeInfo(TDouble_Precision2), TSQLPropInfoRTTIDouble_Precision2);
end.

#94 mORMot 1 » NewPascal preview - fork for mORMot » 2016-06-26 23:22:02

hnb
Replies: 47

http://newpascal.org

I'd like to present the preview of new initiative (and maybe foundation) to support mORMot and other mostly used open source Pascal projects/libraries with recent FPC trunk version (tested in production) tuned for mORMot purposes smile. It works even on pendrive - just unpack in any location and have fun. mORMot integration is in progress. All is based on github infrastructure. Any suggestions/propositions are welcome!

#95 Re: SyNode » Adding JavaScript support for mORMot framework » 2016-06-18 18:12:30

hnb

I'd like to see mORMot not as core of SupraEngine for critical "gamedev data" but as optional usage to handle: game saving, network, replays, more DB oriented games like tycoon/management games... I think we can somehow adjust mORMot for more game oriented usage. I think there are a lot of possibilities. I can't imagine gamedev without mORMot - well tested on many fields.

#96 Re: SyNode » Adding JavaScript support for mORMot framework » 2016-06-18 17:09:31

hnb

My current "lobby goal" is to convince BaRo for using mORMot for presented Unity-style engine smile just amazing - game structures and fluent usage of DB backends...

#97 Re: mORMot 1 » Some findings after spent an afternoon fiddling Linux/Lazarus/mORMot » 2016-06-18 16:58:48

hnb
ab wrote:

We may use this policy: let mORMot work directly with FPC trunk and latest FPC stable branch (e.g. upcoming 3.0.2).

We can get example from FPC RTL:

FPC RTL must be compileable with the latest release and with trunk. Make cycle compiles 3 times compiler. First pass will compile the RTL
with latest stable release.

To get ride of breaking changes between stable release and trunk version is used:

{$if FPC_FULLVERSION>30100} or {$IFNDEF VER3_0} 

FPC_FULLVERSION is IMO more PRO wink. I see 3 scenarios to handle:

1. FPC_FULLVERSION>30100 to detect FPC trunk
2. FPC_FULLVERSION<30100 to detect latest release
3. FPC_NEWPASCAL or NPC to detect our tuned fork.

maybe I will be able to run complete auto-build system for our fork in this weekend.

#98 Re: Free Pascal Compiler » FPC parameter passing for dynamic arrays » 2016-06-18 08:30:55

hnb

The change for dynamic arrays is right move. The topic is quiet old. See my post (in 2013 my post was +/- ignored...):

http://lists.freepascal.org/fpc-devel/2 … 32586.html

You can try to track how it is done in PascalScript (with my patch for this breaking change):

http://forum.lazarus.freepascal.org/ind … #msg196402
http://bugs.freepascal.org/view.php?id=29230

#99 mORMot 1 » Improper SynCrossPlatformJSON detail for \u escape sequences » 2016-06-10 19:41:23

hnb
Replies: 1

Hi,

during my discussion with Benjamin Rosseaux  (aka BeRo) he raised important thing about "\u" escape in JSON:

The most JSON parsers (incl. SynCrossPlatformJSON, as it seems) does it wrong, these have often a incorrect handling of \uXXXX escape sequences: They are pushing even at a surrogate pair of two UTF16 codeunits these parsed UTF16 codeunits simply directly as raw UTF8 sequences (i.e. without first converting this surrogate two UTF16 codeunits to a full unicode codepoint and then from that to the destination encoding, for example UTF8), so that the result is often only CESU8 (or Java's Modified UTF-8) but not valid UTF8 in these cases, see https://en.wikipedia.org/wiki/CESU-8 .

anyway our core GetJSONField in SynCommons.pas for mORMot looks proper. Is some special reason why the SynCrossPlatformJSON implements only CESU8/"Java's Modified UTF-8" escape \u sequence?

#100 Re: mORMot 1 » [Zeos] varchar length for PostgreSQL is always multiplied by 4 » 2016-06-09 13:59:09

hnb

@ab, @miab3

thanks for the answers. It was problem on my machine + probably old trunk ZEOS 7.2, anyway now all works as expected.

Board footer

Powered by FluxBB