#1 Re: SyNode » 03 - HelloSpiderMonkey52 does not work for FPC & win32 » Yesterday 20:29:01

It turns out that if I put the SetExceptionMask line

// https://forum.lazarus.freepascal.org/index.php?topic=70135.15
SetExceptionMask([exInvalidOp, exDenormalized, exZeroDivide, exOverflow, exUnderflow,exPrecision]);
try
  JS_Init();
  cx := JSContext.CreateNew(8 * 1024 * 1024);
  ...

at the very beginning of "HelloSpiderMonkey52.dpr", the sample works fine for FPC & win32.

Nevertheless, it is still confusing for me because the line

TSynFPUException.ForLibraryCode

is already called at the very beginning of `JSContext.CreateNew`.

SyNode/SpiderMonkey.pas:4190:class function JSContext.CreateNew(maxbytes: uint32; maxNurseryBytes: uint32; parentContext: PJSContext): PJSContext;
SyNode/SpiderMonkey.pas-4191-begin
SyNode/SpiderMonkey.pas-4192-  with TSynFPUException.ForLibraryCode do begin
SyNode/SpiderMonkey.pas-4193-    Result := JS_NewContext(maxbytes, maxNurseryBytes, parentContext);
SyNode/SpiderMonkey.pas-4194-    InitSelfHostedCode(Result);
SyNode/SpiderMonkey.pas-4195-  end;

Could you help to suggest why would there be "Invalid floating point operation" at "JSContext.CreateNew" when "TSynFPUException.ForLibraryCode" is already called at "JSContext.CreateNew" ? Many thanks !

#2 Re: SyNode » Missing DebuggerInit.js from Spidermonkey45Binding » Yesterday 19:04:10

mpv wrote:

I remove DebuggerInit from a demo - it's not required for demonstration purpose. The real life example can be found here but it's too complex for a demo app.


The link to download DebuggerInit.js seems to be broken - it leads to login page.
Could you help to update how to obtain and use DebuggerInit.js to debug js code in production ?
Many thanks !

#3 Re: mORMot 1 » TDynArray.GuessKnownType behaves wrong for FPC Linux. » Yesterday 17:30:14

For the time being, I have to put the following code to workaround this problem.
I also have to put in a property to write to Hasher.HashElement...

  FMethodsDA.Init(TypeInfo(TSMMethodDynArray), FMethods);
  // https://synopse.info/forum/viewtopic.php?id=7313
  {$IFNDEF MSWINDOWS}
  if @FMethodsDA.Hasher.DHashElement = nil then begin
    FMethodsDA.Hasher.DHashElement := DYNARRAY_HASHFIRSTFIELD[False, djSynUnicode];
  end;
  {$ENDIF}
  InitObject(aParent);

#4 mORMot 1 » TDynArray.GuessKnownType behaves wrong for FPC Linux. » Yesterday 16:30:41

ComingNine
Replies: 2

It seems that TDynArray.GuessKnownType behaves differently between Delphi Win32 and FPC Linux x86_64.
FPC is installed using the fpcupdeluxe tool and the latest 3.2 fixes branches.

As shown by the figure below, TDynArrayHashed.Init is called in SyNodeProto.TSMCustomProtoObject.Create.
KeSnnao.jpeg

As shown by the two figures below, TDynArrayHashed.Init goes through different routes between Delphi (win32) and FPC Linux x86_64 by design.

O9dqhMl.jpeg

o6kiKpr.jpeg

In the initialization of the associated hasher, i.e., TDynArrayHasher.Init, HashElement should be initialized to one of default functions. The HashElement under this circumstance is initialized to the function that handle djSynUnicode in Delphi, but nil in FPC Linux x86_64.

HL4wSy4.jpeg

It seems that, under FPC Linux x86_64, the reason why the HashElement under this circumstance has been initialized to nil is related to GuessKnownType or related to RTTI. An nil HashElement will cause subsequent ReHash to fail...

fhPT3ml.jpeg

Could you help to check and suggest how to fix ? Many thanks !

#5 SyNode » 03 - HelloSpiderMonkey52 does not work for FPC & win32 » 2025-07-07 13:29:13

ComingNine
Replies: 1

The SyNode sample "03-HelloSpiderMonkey52-cross" works for both `Delphi & win32` and `FPC & Linux64`.
However, the same sample does not work for `FPC & win32` (compiled on windows, or cross-compiled from linux).
The same synsm.dll used for `Delphi & win32` is used.
The error is access violation at `InitSelfHostedCode`.
For some compiling occasions, the error is `Invalid floating point operation` instead.
As shown by the figures, the operations for `Delphi & win32` and  `FPC & win32` seem to be identical.
I could not figure out the cause or the workaround.
Could you help to suggest what could be the cause and how to fix ? Many thanks !

jCJmDaN.png

SCtHFUg.png

#6 Re: mORMot 1 » Cannot compile last timeline version » 2025-07-03 16:32:28

mpv wrote:

I can resolve an error "Class methods in record types must be static" - it's not a problem.

Problem is about E1030 Invalid compiler directive: 'external'

SpiderMonkey itself is a C++, so we need to export a C++ function as a cdecl.
To avoid unnecessary function call we export a variable what contains pointer to a C++ function from our wrapper - see synsm.h line 10 for example as such:

extern "C" {
  JS_PUBLIC_API(bool) (*SM_Initialize)(void) = &JS_Init;

SM_Initialize is a pointer to a function.

And when import it in the SpiderMonkey.pas using

type TJS_Initialize = function : Boolean; cdecl;
var JS_Init: TJS_Initialize external SpiderMonkeyLib name 'SM_Initialize';

I don't know how to do such in Delphi.


It seems that using an explicit SafeLoadLibrary followed by GetProcAddress, one can compile SpiderMonkey.pas in Delphi.

......
    SM52Lib := SafeLoadLibrary(SpiderMonkeyLib);
  Result := SM52Lib <> INVALID_MODULEHANDLE_VALUE;
  if Result then
  begin
    JS_Init := TJS_Initialize(GetProcAddress(SM52Lib, 'SM_Initialize')^);
    JS_ShutDown := TJS_ShutDown(GetProcAddress(SM52Lib, 'SM_ShutDown')^);
.....

The original SpiderMonkey.pas is  https://snips.sh/f/C8cKlLp-nw, the modified SpiderMonkey.pas using an explicit SafeLoadLibrary followed by GetProcAddress is https://snips.sh/f/5MQRzLzUmg.
I made a simple test and it seems to work fine.
Could you help to review and test and consider to incorporate ? : D Many thanks !

#7 Re: mORMot 1 » Cannot compile last timeline version » 2025-07-03 16:16:14

ComingNine wrote:
mpv wrote:

...
To avoid unnecessary function call we export a variable what contains pointer to a C++ function from our wrapper - see synsm.h line 10 for example as such:

extern "C" {
  JS_PUBLIC_API(bool) (*SM_Initialize)(void) = &JS_Init;

SM_Initialize is a pointer to a function.
...

Could you help to suggest how to build your wrapper SynSM.sln ?
When I open the solution in Visual Studio 2015, there are many errors that are related to includes. For example, "jspubtd.h" cannot resolve "#include "mozilla/Assertions.h"". In the file system, "Assertions.h" is under "mozilla-esr52\mfbt\Assertions.h" not "mozilla"... This seems to be a rather basic problem, since the instructions to build SpiderMonkey itself works, but I am not familiar with C++ or SpiderMonkey. Could you suggest what one needs to do to proceed ? Many thanks !

It seems that one can build SynSM.sln under windows following your how-to : D
One just needs to pay attention to some minor issues.
For example, when one follows the build SM52 how-to, put --disable-shared-js to the configure command line.
The js_static.lib is required for SynSM.sln.
Furthermore, during the mozbuild process, the include files required by SynSM.sln will be put under the i686-mingw/dist.

#8 Re: mORMot 1 » Cannot compile last timeline version » 2025-07-02 14:14:22

mpv wrote:

The last time I compiled this was in 2020. I'll be at my workstation at the end of July, so I can take a look. Unfortunately, I couldn't do it before

It is so great to hear from you ! smile

That will be more than good enough ! big_smile Many thanks !

#9 Re: mORMot 1 » Cannot compile last timeline version » 2025-07-02 09:45:12

mpv wrote:

...
To avoid unnecessary function call we export a variable what contains pointer to a C++ function from our wrapper - see synsm.h line 10 for example as such:

extern "C" {
  JS_PUBLIC_API(bool) (*SM_Initialize)(void) = &JS_Init;

SM_Initialize is a pointer to a function.
...

Could you help to suggest how to build your wrapper SynSM.sln ?
When I open the solution in Visual Studio 2015, there are many errors that are related to includes. For example, "jspubtd.h" cannot resolve "#include "mozilla/Assertions.h"". In the file system, "Assertions.h" is under "mozilla-esr52\mfbt\Assertions.h" not "mozilla"... This seems to be a rather basic problem, since the instructions to build SpiderMonkey itself works, but I am not familiar with C++ or SpiderMonkey. Could you suggest what one needs to do to proceed ? Many thanks !

#10 SyNode » SyNode with mORMot2, documentation or example to start with ? » 2023-12-11 12:53:28

ComingNine
Replies: 1

It seems `https://github.com/synopse/mORMot/tree/feature/synodeCleanup` is not quite in sync with master... Could you help to provide documentation or example to help to start using SyNode with mORMot2, preferably with Delphi and with FPC ?

#11 mORMot 1 » Inconsistency between receive timeout param and actual HTTP timeout ? » 2020-09-14 12:31:32

ComingNine
Replies: 1

It seems that TSQLHttpClient descendant will try to retry a service call after certain amount of time has lapsed. Furthermore, the client exists with an error code of 505 after another amount of time. However, there seems to be inconsistency between the receive timeout parameter when HttpClient is created and the timing of the second service call and client exit. Therefore, it seems to be confusing concerning setting up the receive timeout parameter.

The compilable programs can be viewed at viewed at gist. The server program is a simple shell wrapper. The client program tries to run a long-running shell command " date ; sleep 600 ".

parameter     second service call  client exit505
------------- ---------------------   ----------------------                   
default(30s)    180s (3m)                    480s (8m)
receiv + 13    258s (4m18s)                 558s (9m18s)
receiv + 15    270s (4m30s)                 510s (8m30s)
receiv + 17    282s (4m42s)                 522s (8m42s)
receiv + 70    300s (5m)                    600s (10m)
receiv + 100   450s (7m30s)                 690s (11m30s)

: data collected for http time out & retry

As seen in the table above, using the default parameters for creating HttpClient, the second service call occurs after 180s has elapsed. The 1st to 4th rows indicate that there is a multiple of 6 between the constructor receive timeout parameter and the timing of the second service call. However, the 5th and 6th rows indicate that there are no consistency.

Could you help to comment how to set up the receive timeout properly ? yikes
Many thanks !

#12 Re: mORMot 1 » Cannot compile last timeline version » 2020-08-17 13:13:41

Thank you for your efforts ! IIRC, to realize a pointer to external function in Delphi (and FPC as well), one does not use external keyword but SafeLoadLibrary followed by GetProcAddress. I have to try and return.

#13 Re: mORMot 1 » Cannot compile last timeline version » 2020-08-17 11:19:56

If the following two code blocks are equivalent to each other, the regex posted above could be used to automatically transform the hundreds of declarations in SpiderMonkey.pas big_smile

current

type TJS_Initialize = function : Boolean; cdecl;
var JS_Init: TJS_Initialize external SpiderMonkeyLib name 'SM_Initialize';

Delphi compatible

function SM_Initialize: Boolean; cdecl; external SpiderMonkeyLib name 'SM_Initialize';
type TJS_Initialize = function : Boolean; cdecl;
var JS_Init: TJS_Initialize = SM_Initialize; // external SpiderMonkeyLib name 'SM_Initialize';

#14 Re: mORMot 1 » Cannot compile last timeline version » 2020-08-16 17:22:42

The following regex could be helpful to alleviate the burden to support Delphi compatibility of SpiderMonkey.pas

(?gs)type\s([_A-Za-z]+)\s*=\s*(function|procedure)(.*?cdecl;)\s*var(\s[_A-Za-z]+):\s*([_A-Za-z]+)\s(external.*?;)

See also the online tester

#15 Re: mORMot 1 » Cannot compile last timeline version » 2020-08-16 14:10:37

Is there any news on this ? As @array81 reported, latest mORMot and SyNode are incompatible with each other when Delphi is used.

#16 Re: mORMot 1 » AV raised in TestSQL3 cross compiled by FPC. » 2019-07-25 12:50:56

Many thanks !

PS: I have just tried "FPC trunk SVN 40491; Lazarus trunk SVN 59757", as suggested from the documentation, and the same AV exists. big_smile

#17 mORMot 1 » AV raised in TestSQL3 cross compiled by FPC. » 2019-07-25 04:30:47

ComingNine
Replies: 2

The latest mORMot is cross compiled to linux64 by FPC on Windows. The console log is shown below.

 1.2. Low level types:
  - RTTI: 443 assertions passed  363us
  - Url encoding: 200 assertions passed  659us
  - Encode decode JSON: 396,397 assertions passed  132.40ms
  - Variants: 64 assertions passed  212us
  - Mustache renderer: 147 assertions passed  1.75ms
! Low level types - TDocVariant
! Exception EAccessViolation raised with messsage:
!  Access violation
  - TDecimal128: 17,446 assertions passed  1.89ms
  - BSON: 245,068 assertions passed  50.87ms
     100000 TBSONObjectID.ComputeNew in 49.84ms i.e. 2,006,179/s, aver. 0us
  - TSynTableStatement: 221 assertions passed  213us
  - TSynMonitorUsage: 1,202 assertions passed  212us
  Total failed: 0 / 732,939  - Low level types PASSED  714.93ms

The line indicated from the file log is shown below.

          TSynTestEvent(C.TestMethod[t])(); // run tests + Check() and TestFailed()

The version of fpc is

C:\fpcupdeluxe\fpc\bin\i386-win32 > fpc
Free Pascal Compiler version 3.3.1-r39711 [2018/09/08] for i386

Could you check this ? Many thanks !

PS: The same mORMot compiled by FPC on Windows as a Windows executable runs flawlessly.

#18 mORMot 1 » Cannot compile SynLog under Delphi 7 » 2019-07-25 04:18:33

ComingNine
Replies: 1

SynLog in the latest version cannot compile under Delphi 7. It seems that anonymous cannot create ticket any more. The two lines are thus shown below. Could you fix this ? smile

                    code                                      line no
before  R.Seek(PtrUInt(P)-PtrUInt(R.MappedBuffer));           
now     R.Seek(P-PByte(R.MappedBuffer));                      1736

before  W.WriteDirectEnd(PtrUInt(P)-Beg);
now     W.DirectWriteFlush(P-Beg,tmp);                        2044

#19 Re: Language » Working with windows logs (tutorial) » 2019-05-04 04:14:25

mpv wrote:

Since many of us use mORMot as a service I decided to provide small tutorial how to say Windows to format log messages correctly during Windows log output
...
Hope it help for somebody...

Can you help to inform how to work with linux logs, i.e., append to /var/log/messages or /var/log/the_subject_app ? Many thanks !

#20 Re: Delphi » Delphi new generation VCL » 2018-11-03 11:57:50

MSEide+MSEgui has been updated to 4.6.2. Could you help to comment whether it is possible to use mORMot with the current MSEide+MSEgui  ?

https://sourceforge.net/projects/mseide … gui/4.6.2/

#22 mORMot 1 » Latest mORMot.pas does not compile under latest FPC. » 2018-09-12 05:31:51

ComingNine
Replies: 24

Latest mORMot.pas does not compile using latest FPC for both i386-win32 and x86_64-linux. The line and msg shown are below.

Line 56264:             ParamName := @VMP^.Name;  
mORMot.pas(56264,30) Error: Variable identifier expected

The reason is in FPC 3.3.1-r39711 (installed using fpcupdeluxe), Name becomes a property. NamePtr should be used.

ParamName := VMP^.NamePtr;  

PS: It seems that anonymous cannot create ticket now ? There is no create ticket on the tickets link.

#23 Re: mORMot 1 » ExtendedToStr behaves inconsistently between FPC and Delphi » 2018-09-08 15:07:07

mpv wrote:

Dealing with floating with big precision is always a problem. In our applications we try to avoid it by limiting precision part to maximum 4 digits and adding division(factor). For example if we need to store 8 digits precision (0.66599631)  we store 2 field {value: 6659.9631, factor: 10000}. Hope it's help

Many thanks for your clever experience ! Is it because a number with maximum 4 digits can be exactly represented as Currency type ?

#24 Re: mORMot 1 » ExtendedToStr behaves inconsistently between FPC and Delphi » 2018-09-08 10:13:32

ab wrote:

Yes, this is a known inconsistency, since they have two diverse implementations.

Sad to hear. It should be noted that ExtendedToStr behaves also inconsistently between Delphi25Tokyo's Win32 and Win64.

#25 mORMot 1 » ExtendedToStr behaves inconsistently between FPC and Delphi » 2018-09-08 04:05:57

ComingNine
Replies: 5

As shown in the sample code on gist , the ExtendedToStr behaves inconsistently between FPC and Delphi. Could you help to suggest the workaround ?

PS: FloatToStrF and Format seem to behave inconsistent within FPC, and between FPC and Delphi.

#26 mORMot 1 » Float in a variant field of TSQLRecord becomes string when got back fr » 2018-09-03 14:40:13

ComingNine
Replies: 0

As shown in the gist, I am trying to store a float field into a variant field of a TSQLRecord. When the Variant field is assigned by calling ObjectToJSON, it has the correct internals.

   {"Val":1234.56789} 

Furthermore, the DB file has the correct float internals.

However, when the TSQLRecord is retrieved back from DB, its variant field contains string-based internals. As a result, the float field cannot be parsed back by calling ObjectLoadJSON.

   {"Val":"1234.56789"} 

Could you help to comment whether it is possible to prevent the transformation of the float internal into string internal ?

#27 mORMot 1 » Could you share the build env for static\i386 and x86_64 win64 .a file » 2018-08-13 14:40:04

ComingNine
Replies: 1

Could you share the build environment for static\i386-win and static\x86_64-win64 .a files ? For example, the OS and the toolchain versions and the gcc switches ? Many thanks ! smile

#28 Re: mORMot 1 » How to serialize record with enum property ? » 2018-07-30 17:21:05

Dear ab, many thanks !


Could you be kind enough to comment where these text settings you mentioned, i.e., woEnumSetsAsText or twoEnumSetsAsTextInRecord, can be applied to force enum serialization as text, for example, in the gist sample ? I mean, switching from

 (RecordSaveJSON(Rec, TypeInfo(TRec))); 

to

 (RecordSaveJSON(Rec, TypeInfo(TRec), True)); 

does not work.

#29 Re: mORMot 1 » How to serialize record with enum property ? » 2018-07-30 15:53:54

From your documentation , it seems that the solution is to switch from text-based serialization and deserialization to callback-based ones. big_smile Sorry for the trouble.

#30 Re: mORMot 1 » How to serialize record with enum property ? » 2018-07-30 14:54:04

From your documentation , it is suggested that "For other types (like enumerations or sets), you can simply use the unsigned integer types corresponding to the binary value, e.g. byte word cardinal Int64 (depending on the sizeof() of the initial value)." With such treatment, the updated gist code serializes the enum property within the record as unsigned integer.

Nevertheless, the enum property within the TObject can be serialized to human readable text, could you help to comment whether it is possible to serialize enum property within the record also as human readable text ?

{
        "E": 0,
        "K": "",
        "V": 0
}
{
        "ClassName":"TObj",
        "E": "meFirst",
        "K": "",
        "V": 0
}

#31 mORMot 1 » How to serialize record with enum property ? » 2018-07-30 14:28:54

ComingNine
Replies: 4

As shown in the gist code , the call to TTextWriter.RegisterCustomJSONSerializerFromText fails if the record definition contains enum type: ESynException 'Unregistered ptCustom for TJSONRecordTextDefinition.AddItem(E: TMYENUM)'.

Could you help to comment the correct way to deal with record type with enum property in JSON serialization ?
Many thanks !

#32 Re: mORMot 1 » Problem when deserializing class with array prop backed by methods. » 2018-07-17 02:39:58

Dear ab, it seems to me that the deserialization of the class fails because GetDynArray of an array prop backed by methods will set DynArray.fValue to nil, and consequently "From := DynArray.LoadFromJSON()" concludes all of the remaining JSON is invalid and jumps to the end of the JSON. Could you help to comment ?

Furthermore, the gist sample has been clarified. As shown in DeserializeClassWithPropertyBackedByMethods2.dpr, there is no two properties pointing the actual storage.

#33 mORMot 1 » Problem when deserializing class with array prop backed by methods. » 2018-07-16 09:06:39

ComingNine
Replies: 2

As shown in the sample, a class with an array prop backed by methods is serialized and then deserialized. The deserialization of the class fails because, since GetDynArray of that prop sets DynArray.fValue to nil, DynArray.LoadFromJSON concludes all of the remaining JSON is invalid and jumps to the end of the JSON. It would seem more proper if DynArray.LoadFromJSON only skips the very array property backed by methods instead of all the remaining JSON. Could you help to comment ?

#34 Re: mORMot 1 » Regression of ManyAdd/Many.../SourceGet/DestGet with "current" omitted » 2018-03-05 09:04:17

As discussed in https://synopse.info/forum/viewtopic.php?id=164, ManyAdd/ManyDelete/ManySelect/SourceGet/DestGet can be used with one less parameter - the "current" fSourceID/fDestID.

That is to say, in about 184th line of the "mORMot and Open Source friends-d573e7358a/SQLite3/Samples/ThirdPartyDemos/Migajek/synopse-sqlite-demo/Unit1.pas", both lines below should work. Nevertheless, only the second one works in the latest source.

      cust.Tasks.ManyAdd(globalClient, task.ID, true)
      cust.Tasks.ManyAdd(globalClient, cust.ID, task.ID, true)

Could you help to comment whether the situation is made clearer ? big_smile

#35 Re: mORMot 1 » Regression of ManyAdd/Many.../SourceGet/DestGet with "current" omitted » 2018-03-05 08:47:40

Sorry for the confusion.

I did not manage to find the fix... 

The diff was intended to show how to reproduce the regression . Could you help to check and fix ?

#36 mORMot 1 » Regression of ManyAdd/Many.../SourceGet/DestGet with "current" omitted » 2018-03-05 06:08:50

ComingNine
Replies: 4

As discussed in https://synopse.info/forum/viewtopic.php?id=164, ManyAdd/ManyDelete/ManySelect/SourceGet/DestGet can be used with one less parameter - the "current" fSourceID/fDestID.

However, in the latest sample code "mORMot and Open Source friends-d573e7358a\SQLite3\Samples\ThirdPartyDemos\Migajek\synopse-sqlite-demo", the overloaded methods with one less parameter does not work, as tested with the following modifications

HiWin10@MICROSO-8C7VFP4 /cygdrive/d/mORMot and Open Source friends-d573e7358a/SQLite3/Samples/ThirdPartyDemos/Migajek/synopse-sqlite-demo
$ diff Unit1.pas ../synopse-sqlite-demo.original/
184,185c184
<   ACustomer.Tasks.DestGet(globalClient, fIds);
<   // ACustomer.Tasks.DestGet(globalClient, ACustomer.ID, fIds);
---
>   ACustomer.Tasks.DestGet(globalClient, ACustomer.ID, fIds);
371,372c370
<                     cust.Tasks.ManyAdd(globalClient, task.ID, true)
<                     // cust.Tasks.ManyAdd(globalClient, cust.ID, task.ID, true)
---
>                     cust.Tasks.ManyAdd(globalClient, cust.ID, task.ID, true)
374,375c372
<                     cust.Tasks.ManyDelete(globalClient, task.ID);
<                     // cust.Tasks.ManyDelete(globalClient, cust.ID, task.ID);
---
>                     cust.Tasks.ManyDelete(globalClient, cust.ID, task.ID);

Could you help to fix the behavior ? Many thanks for your efforts ! smile

#37 Re: SyNode » Complaining invalid arrow-function arguments in latest source. » 2018-02-13 17:40:17

Thank you very much for your helpful suggestions and comments !

PS: SM52 + Linux sounds quite interesting ! Great contributions from you !

#38 Re: SyNode » Complaining invalid arrow-function arguments in latest source. » 2018-02-13 12:16:04

The exception is seen with Win XE8/XE Tokyo, x32, SM45.

When SM52 is defined, the exception is not seen. Many thanks for your instructive test. Nevertheless, could you help to comment whether SM45 is deprecated in your company ?

#39 SyNode » Complaining invalid arrow-function arguments in latest source. » 2018-02-13 03:36:48

ComingNine
Replies: 5

With the latest mORMot & SyNode, the sample "02 - Binding" raises exception of "invalid arrow-function arguments (parentheses around the arrow-function may help)" during startup. Could you help to fix it ?

#40 Re: mORMot 1 » Could you add UnRegisterClassForJSON methods into mORMot.pas ? » 2017-12-22 16:58:57

In addition to the post above, fLastClass needs to be reset to nil after removal... smile

procedure TJSONSerializerRegisteredClass.RemoveOnce(aItemClass: TClass);
begin
  fSafe.Lock;
  try
    if PtrUIntScanExists(pointer(List),Count,PtrUInt(aItemClass)) then begin
      Remove(aItemClass);
      if fLastClass = aItemClass then
        fLastClass := nil;
    end;  
  finally
    fSafe.UnLock;
  end;
end;

#41 mORMot 1 » Could you add UnRegisterClassForJSON methods into mORMot.pas ? » 2017-12-22 09:25:20

ComingNine
Replies: 1

When utilizing JSON serialization, one would try and test different versions of a specific class (isolated in different units). Under such circumstances, UnRegisterClassForJSON methods could be useful big_smile

....

    procedure RemoveOnce(aItemClass: TClass);

....

    class procedure UnRegisterClassForJSON(aItemClass: TClass); overload;
    class procedure UnRegisterClassForJSON(const aItemClass: array of TClass); overload;

....

procedure TJSONSerializerRegisteredClass.RemoveOnce(aItemClass: TClass);
begin
  fSafe.Lock;
  try
    if PtrUIntScanExists(pointer(List),Count,PtrUInt(aItemClass)) then
      Remove(aItemClass);
  finally
    fSafe.UnLock;
  end;
end;

....

class procedure TJSONSerializer.UnRegisterClassForJSON(aItemClass: TClass);
begin
  if JSONSerializerRegisteredClass=nil then
    GarbageCollectorFreeAndNil(JSONSerializerRegisteredClass,
      TJSONSerializerRegisteredClass.Create);
  JSONSerializerRegisteredClass.RemoveOnce(aItemClass);
end;

class procedure TJSONSerializer.UnRegisterClassForJSON(const aItemClass: array of TClass);
var i: integer;
begin
  for i := 0 to high(aItemClass) do
    UnRegisterClassForJSON(aItemClass[i]);
end;

#42 Re: mORMot 1 » Could you add to SynTests.pas the generation of dunit-report.xml ? » 2017-12-22 05:42:53

In the source code shown, SynTests is slightly modified to generate dunit-report.xml. The generated file can be useful for automating the testing of multiple executable files.


Can you help to review and include the changes  ? big_smile

#43 mORMot 1 » Could you add to SynTests.pas the generation of dunit-report.xml ? » 2017-12-05 07:08:05

ComingNine
Replies: 2

When using DUnit, a dunit-report.xml containing test statistics will be generated. This can be useful for automating the testing of multiple executable files, because one can use tools (e.g., FinalBuilder) to check whether there are failures during automated tests. 

Therefore, could you help to add the functionality of generating dunit-report.xml to SynTests.pas ? smile

#44 Re: mORMot 1 » Record property serialization in Delphi < 2010, no type info? » 2017-12-03 16:32:09

ab wrote:

...
And the root cause of the problem is that a record published property has no RTTI in the property field of the class, anyway. So adding a ref-counted field won't be enough...

Many thanks for your knowledgeable comments !

However, for the "won't be enough" part, as shown in a trivial example which is compilable under D7 and a SO post, it seems that adding a ref-counted field will be enough to generate RTTI for the record, for other records that contain it, and for the class that somehow publishes the record. Could you comment about or a possible counter-example ? big_smile

#45 Re: mORMot 1 » Record property serialization in Delphi < 2010, no type info? » 2017-12-03 13:36:17

In D7, you could try to define an additional ref-counted field within the record to force rtti generation for your simple record types.
See http://codeverge.com/embarcadero.delphi … pe/1040908

#46 Re: mORMot 1 » Record property serialization in Delphi < 2010, no type info? » 2017-12-03 02:22:14

See example of serializing record in "10.1.3.2.4. Text-based definition" smile

#47 Re: Source Code repository » SQLite3: "Many to Many" relationship updates » 2017-11-26 08:21:56

It seems that TSQLRecordMany.FillMany and TSQLRecordMany.DestGetJoined provide rather similar functionality: retrieving dest items related to certain source item. Could you help to comment the difference between them ? For example, what are the different situations where either FillMany or DestGetJoined fits better ?  yikes

After playing around a bit, now the difference becomes more clear to me... Sorry for the trouble! big_smile

...ThirdPartyDemos\Migajek\synopse-sqlite-demo...

procedure TForm1.LoadTasksForCustomer(const ACustomer: TSQLCustomer; const AList: TStrings);
var
 tasks: TSQLTasks;
 MsgUTF8: RawUTF8;
 Msg: string;
 task: TSQLTask;
 fIds: TIDDynArray;
begin
  // Can be created directly
  tasks := TSQLTasks.Create;
  try
    // How to get Dest IDs
    // tasks.DestGet(globalClient, fIds); // Does not work
    tasks.DestGet(globalClient, ACustomer.ID, fIds); // Works
    // ACustomer.Tasks.DestGet(globalClient, ACustomer.ID, fIds); // Original
    task:= TSQLTask.CreateAndFillPrepare(globalClient, TInt64DynArray(fIds));
    AList.BeginUpdate();
    AList.Clear();
    try
      while task.FillOne do
        AList.AddObject(Format('%s', [UTF8ToString(task.Text)]), Pointer(task.id));
    finally
      AList.EndUpdate();
      FreeAndNil(task);
    end;

    // How to get Pivot instances, and Dest instances later
    tasks.FillMany(globalClient, ACustomer.ID);
    while tasks.FillOne do begin
      // MsgUTF8 := tasks.Dest.Text;
      task := TSQLTask.Create(globalClient, tasks.Dest.ID);
      try
        MsgUTF8 := task.Text;
        Msg := UTF8ToString(MsgUTF8);
        Msg := 'Get Dest through Pivot: ' + UTF8ToString(MsgUTF8);
        OutputDebugString(PChar(Msg));
      finally
        task.Free;
      end;
    end;

    // How to get Dest instances directly
    task := tasks.DestGetJoined(globalClient, '', ACustomer.ID) as TSQLTask;
    try
      while task.FillOne do begin
        MsgUTF8 := task.Text;
        Msg := 'Directly get Dest: ' + UTF8ToString(MsgUTF8);
        OutputDebugString(PChar(Msg));
      end;
    finally
      task.Free;
    end;

  finally
    tasks.Free;
  end;
end;

procedure TForm1.lbTasksClick(Sender: TObject);
var
  tasks: TSQLTasks;
  task: TSQLTask;
  cust: TSQLCustomer;
  clientsIds: TIDDynArray;
  i, j: integer;
  MsgUTF8: RawUTF8;
  Msg: string;
begin
  gbEditTask.Visible:= lbTasks.ItemIndex <> -1;
  if not gbEditTask.Visible then
    exit;

  gbEditTask.Visible:= lbTasks.Items.Objects[lbTasks.ItemIndex] <> nil;
  if not gbEditTask.Visible then
    exit;

  task:= LoadTask(integer(lbTasks.Items.Objects[lbTasks.ItemIndex]));
  cbTaskPriority.ItemIndex:= Ord(task.Priority);
  cbTaskPriority.Tag:= task.ID;

  FillCustomersList(CheckListBox1.Items, true);
  CheckListBox1.Tag:= task.ID;
  // load list of customers assigned to the given task
  cust:= TSQLCustomer.Create();
  try
    cust.Tasks.SourceGet(globalClient, task.ID, clientsIds);
    for i:= low(clientsIds) to high(clientsIds) do
      begin

        // find the client on the list (by ID)
        for j:= 0 to CheckListBox1.Count -1 do
          if Integer(CheckListBox1.Items.Objects[j]) = clientsIds[i] then
              CheckListBox1.Checked[j]:= true;
      end;
  finally
    cust.Free();
    FreeAndNil(task);
  end;

  // Learn about FillManyFromDest
  tasks := TSQLTasks.Create;
  try
    tasks.FillManyFromDest(globalClient, integer(lbTasks.Items.Objects[lbTasks.ItemIndex]));
    while tasks.FillOne do begin
      cust := TSQLCustomer.Create(globalClient, tasks.Source.ID);
      try
        MsgUTF8 := cust.FirstName;
        Msg := UTF8ToString(MsgUTF8);
        Msg := 'Get Source through Pivot: ' + UTF8ToString(MsgUTF8);
        OutputDebugString(PChar(Msg));
      finally
        cust.Free;
      end;
    end;
  finally
    tasks.Free;
  end;
end;

#48 Re: mORMot 1 » Typo in example code of many-to-many relationship in the documentation » 2017-11-26 07:59:03

Another typo

    /// retrieve all records associated to a particular Dest record, which
    // has a TSQLRecordMany property
    // - returns the Count of records corresponding to this aSource record    <<<<<<<<<<<<<<<<<<<<<<< "this aSource record" should be "this aDest record" ?
    // - use a "for .." loop or a "while FillOne do ..." loop to iterate
    // through all Dest items, getting also any additional 'through' columns    <<<<<<<<<<<<<<<<<<<<<<< "through all Dest items" should be "through all Source items" ?
    // - the optional aAndWhereSQL parameter can be used to add any additional
    // condition to the WHERE statement (e.g. 'Salary>:(1000): AND Salary<:(2000):')
    // according to TSQLRecordMany properties - note that you should better use
    // inlined parameters for faster processing on server, so you may call e.g.
    // ! aRec.FillManyFromDest(Client,DestID,FormatUTF8('Salary>? AND Salary<?',[],[1000,2000]));
    function FillManyFromDest(aClient: TSQLRest; aDestID: TID;
      const aAndWhereSQL: RawUTF8=''): integer;

Moreover, would you also include test for FillManyFromDest in SynSelfTests.pas ? big_smile

#49 mORMot 1 » Typo in example code of many-to-many relationship in the documentation » 2017-11-26 04:16:06

ComingNine
Replies: 1

https://synopse.info/files/html/Synopse … 01.18.html

...
5.5.2.2.1. Introducing TSQLRecordMany
...

    for i := 1 to high(dID) do
    begin
      Check(MS.DestList.SourceGet(aClient,dID[i],res));
      if not Check(length(res)=1) then   <<<<<<<<<<<<<<<<<<<<<<<<<<< should be CheckFailed as shown in SynSelfTests.pas
        Check(res[0]=sID[i]);
      Check(MS.DestList.ManySelect(aClient,sID[i],dID[i]));
      Check(MS.DestList.AssociationTime=i);
    end;
for i := 1 to high(sID) do
begin
  Check(MS.DestList.DestGet(aClient,sID[i],res));
  if Check(length(res)=1) then   <<<<<<<<<<<<<<<<<<<<<<<<<<< should be CheckFailed as shown in SynSelfTests.pas
    continue; // avoid GPF
  Check(res[0]=dID[i]);

big_smile

#50 Re: mORMot 1 » Display wrong characters even though data are intact after AES enc/dec » 2017-11-20 09:51:52

Many thanks for your help ! tongue
It works after the following change:

...
  {$IFDEF FPC}
  plain := mmoPlain.Text;
  {$ELSE ~FPC}
  plain := StringToUTF8(mmoPlain.Text);
  {$ENDIF ~FPC}
...
  {$IFDEF FPC}
  mmoPlain.Text := plain;
  {$ELSE ~FPC}
  mmoPlain.Text := UTF8ToString(plain);
  {$ENDIF ~FPC}
...

Board footer

Powered by FluxBB