#1 Re: mORMot 2 » The Big Divide » 2024-11-03 02:47:01

I think current repo is good for me.
Subfolder name indicates it's function, very clear.

But the document or TFM(The fuck manual) is too big to read.
To find a correct class to implement my program is hard work too.

So, maybe we could introduce some divided sample project(some "best practices" I think?), more than samples we have got now.
Then freshmen could step up more easily.

Maybe we could maintain some pratices wiki?

#2 mORMot 1 » A port of MormotReport » 2022-10-23 15:32:00

uian2000
Replies: 1

Hi,

I've ported MormotReport.pas to mormot.ui.report.pas.

Just some adoption of uses and procedures.

please check it. thanks.

link is here https://github.com/synopse/mORMot2/pull/124

#3 Re: mORMot 1 » Delphi compilation error with latest mORMot (just checked out today) » 2022-03-08 02:52:14

Current static  objects version is 3.37.2(?), while mormot.db.raw.sqlite3.static is at version 3.38.0.

You may tempery avoid this issue by comment out this line and relevant calls.

#5 Re: mORMot 1 » [Fixed] CallbackReleased in mormot2 causes av. » 2022-02-28 14:36:30

Thanks, ab. you are amazing.
I've walked pass these lines for many times, but found nothing.
This pr do fix this issue.

Thank you again!

regards.
uian

#6 Re: mORMot 1 » [Fixed] CallbackReleased in mormot2 causes av. » 2022-02-28 03:54:39

Hi, ab
I've made a pull request to demonstrate this issue.
Ex31-chat server/client works well in mormot1, but can go wrong in mormot2.

regards.
uian

#7 Re: mORMot 1 » [Fixed] CallbackReleased in mormot2 causes av. » 2022-02-24 09:02:27

Client subscribes a service by calling service.Subscribe(aClientName, aClientInterface).
Then service will do this work by calling methid InterfaceArrayAdd(fClients, aClientInterface) .


I'll try mormot1 later, with the result posted here.

thanks smile

#8 Re: mORMot 1 » [Fixed] CallbackReleased in mormot2 causes av. » 2022-02-24 00:36:33

Hi ab,I think I may have found the key to the problem. The point is that the same interface is repeatedly released.
When I commented out InterfaceArrayDelete in CallbackReleased, server keeps running without av but callbacks were not released either.

I guess there's something wrong with this point in the framework.
You've mentioned a concept about re-release of interface (weak pointer), is it related here?

regards.
uian

#9 Re: mORMot 1 » Dependency injection in interface based service » 2022-01-25 01:24:57

talexone wrote:

One can override only the same ancestor method. If the method was declared with a different parameters it can be only overload or reintroduce.

You are right.

Chaa wrote:

See TInjectableObjectRest.

This is quite the answser.
More over, you can inherite your service from TInjectableObjectRest, then override the constructor  CreateWithResolverAndRest.
This way DI automaticly processed when you define interface implementation.

Regards.

#10 Re: mORMot 1 » Dependency injection in interface based service » 2022-01-24 02:09:14

This constructor should be override, not reintroduced.
Otherwise, you should create instance by hand, then register it using overloaded version of ServiceDefine(aSharedImplementation, [aInterfaces])

Edit 2022 01 24 1556
Wired DI features are implemented in REST part of the code, not SOA part.

regards

#11 mORMot 1 » [Fixed] CallbackReleased in mormot2 causes av. » 2022-01-23 04:42:08

uian2000
Replies: 7

Hi, ab.

I am trying something similer to restws.longwork, with additional implementation of CallbackReleased procedure.

  IDataService = interface(IInvokable)
    ['{9DDC69FF-5212-4F64-9B98-ABFBF14A27D4}']
    ....
    procedure CallbackReleased(const callback: IInvokable; const interfaceName: RawUTF8);

  TDataService = class(TInjectableObjectRest, IDataService)
  protected
    fClients: TInterfaceDynArray;
    ....

procedure TDataService.CallbackReleased(const callback: IInvokable;  const interfaceName: RawUTF8);
begin
  InterfaceArrayDelete(fClients, callback);
end;

When a client released, this procedure is processed then av occurred in mormot.core.interfaces

procedure TInterfaceMethodExecuteRaw.AfterExecute;
var
  i, a: PtrInt;
  arg: PInterfaceMethodArgument;
begin
  // finalize managed arrays for each call
  Finalize(fRawUtf8s);
  Finalize(fStrings);
  Finalize(fWideStrings);
  if fMethod^.ArgsManagedFirst >= 0 then
  begin
    for i := 0 to fMethod^.ArgsUsedCount[imvvObject] - 1 do
      fObjects[i].Free;
    for i := 0 to fMethod^.ArgsUsedCount[imvvInterface] - 1 do
      IUnknown(fInterfaces[i]) := nil;       <-------------- av here   Line7372

Am I implementing it in a wrong way?
My env: Win10/X64/Delphi XE/git@20220123

Best regards.

#12 Re: mORMot 1 » Two issues about TZipRead » 2022-01-02 10:13:16

I have tried this commit, and it truely worked.
Thanks for your great work! smile

#13 Re: mORMot 1 » Two issues about TZipRead » 2021-12-29 11:30:36

Hi, ab.

Thanks for your fix, that's efficent and do works for me.

I've digging a new issue.

According to TZipRead.Create(Buf...), directory is not count as Entry.

constructor TZipRead.Create(BufZip: PByteArray; Size: PtrInt; Offset: Int64);
...
    if P[-1] = fZipNamePathDelim then
    begin
      h := hnext;
      continue; // ignore void folder entry
    end;
...

But, when we need to search a data descriptor before a directory, the result will be descriptor of this directory not that file.

[local file header n] (file n) <-- Entry[n].localoff
[zipped file data n]
[data descriptor n]
[local file header n+1] (directory after target file)
[zipped file data n+1]
[data descriptor n+1]
[local file header n+2] (file under nearby directory)  <-- Entry[n+1].localoff
[zipped file data n+2]
[data descriptor n+2]

In this case RetrieveFileInfo will return false.

Regards wink

#14 Re: mORMot 1 » Two issues about TZipRead » 2021-12-28 14:14:30

I didn't find a good size to reduce mem, I'll try this one.

Thanks ab. wink

#16 Re: mORMot 1 » Two issues about TZipRead » 2021-12-09 09:49:19

1.I'll do some test and make a pr if I could fix it.

2.For TZipRead only, I think add a FaverEncode param in constructor might be a good option.
Most of  times, one zip file is built with one single Charset, so let the user fix unstanderd files dose make sense.

#17 mORMot 1 » Two issues about TZipRead » 2021-12-09 05:44:39

uian2000
Replies: 10

Hi, ab

I'm working on a project extracting zipped files online and found two issues about TZipRead.

1. TZipRead demonds more too big WorkMem to extract content files when fileinfo is stored in DataDiscriptor.
I must assign WorkingMem to filesize to make it run, even the half will fail.

TZipRead.Create(BufZip: PByteArray; Size: PtrInt; Offset: Int64);
//  ...
    if e^.localoffs >= Offset then
    begin
      // can unzip directly from existing memory buffer
      e^.local := @BufZip[Int64(e^.localoffs) - Offset];
      with e^.local^.fileInfo do
        if flags and FLAG_DATADESCRIPTOR <> 0 then
          // crc+sizes in "data descriptor" -> call RetrieveFileInfo()
          if (zcrc32 <> 0) or
             (zzipSize <> 0) or
             (zfullSize <> 0) then
            raise ESynZip.CreateUtf8('%.Create: data descriptor (MacOS) with ' +
              'sizes for % %', [self, e^.zipName, fFileName]);
//  ...

In constructor, BuffZip must contain even the first local info to setup Entry.local, else we must call RetrieveFileInfo to get local.

function TZipRead.RetrieveFileInfo(Index: integer;
  out Info: TFileInfoFull): boolean;
//  ...
  if e^.local = nil then
  begin
    local.DataSeek(fSource, e^.localoffs + fSourceOffset);
    if local.fileInfo.flags and FLAG_DATADESCRIPTOR <> 0 then
      raise ESynZip.CreateUtf8('%: increase WorkingMem for data descriptor ' +
        '(MacOS) support on % %', [self, e^.zipName, fFileName]);
    Info.localfileheadersize := local.Size;
  end
  else
  begin
    Info.localfileheadersize := e^.local^.Size;
    if e^.local^.fileInfo.flags and FLAG_DATADESCRIPTOR <> 0 then
//  ...

But in RetrieveFileInfo() Exception will be raised because Entry.local equals nil!

Maybe we should try to setup Entry.local first because we just skipped this step in the constructor?

2.Sometimes charset of filename is not setup correctly in zip files, in that case TZipRead.NameToIndex will not work well.
Can I specify a default encoding type when I open a file, and use this default encoding type (such as UTF8) instead of the OemToFileName when ansi7 detection fails?

Best regards.

#18 Re: mORMot 1 » Lazarus pkg fix » 2021-03-28 05:01:24

Hi there,

I've updated my Pull-Request.
Please have a look.

Regards.

#19 Re: mORMot 1 » Lazarus pkg fix » 2021-03-25 11:31:26

I'm sorry, some changes missed in my pull-request.
I can't push that to github.com duel to my terrible network.
Please, somebody fix this pr

filename: packages/lazarus/mormot2.lpk
changes line 12:
original

<OtherUnitFiles Value="../../src/app;../../src/core;../../src/db;../../src/lib;../../src/net;../../src/orm;../../src/rest;../../src/soa;../../src/tools/ecc"/>

changed

<OtherUnitFiles Value="../../src/app;../../src/core;../../src/db;../../src/lib;../../src/net;../../src/orm;../../src/rest;../../src/soa;
// add content begin here
../../src/crypt;
// add content end here
../../src/tools/ecc"/>

#20 mORMot 1 » Lazarus pkg fix » 2021-03-25 05:49:02

uian2000
Replies: 2

hi ab

I've make a pull/24 fix issues for crypto units rename/move effected to lazarus pkg.
Please check it. big_smile

#21 Re: mORMot 1 » Domain events with persistence » 2021-03-21 13:58:21

In my opinion, master/slave replication function is used for database maintainer, not for regular user.

So, maybe you can implement master/slave replication with the old fasion.
And implement regular function with interface-orinted fasion.

#22 Re: mORMot 1 » HttpGet of mormot2 didn't encode address properly. » 2021-02-25 13:30:34

Thank you @mpv, your explanation is very convincing.

Thank you @ab, you've build this awesome framework.

#23 Re: mORMot 1 » HttpGet of mormot2 didn't encode address properly. » 2021-02-25 04:21:18

Because TWebBrowser.Navigate() automatically executes UrlEncode, I thought HttpGet should behave the same way.

If httpGet itself is positioned to simply make http requests, that's right.

#24 Re: mORMot 1 » HttpGet of mormot2 didn't encode address properly. » 2021-02-23 22:02:05

thx @tbo, will try your approach.

thx @ab, I've post a sample here
Pastebin-uMain.pas.
Pastebin-uMain.dfm.
pls check it.

Delphi XE,Windows 7 X64

thank you.
big_smile

#25 Re: mORMot 1 » HttpGet of mormot2 didn't encode address properly. » 2021-02-23 16:19:18

Address part of uri was not encoded.

when I make a request like this.

HttpGet('http://127.0.0.1/hello world');

Server side Ctxt.Url will be

'/hello'

But if it was made by a TWebBrowser.Navigate(), that Ctxt.Url will be

'/hello%20world'

#26 mORMot 1 » HttpGet of mormot2 didn't encode address properly. » 2021-02-23 08:48:52

uian2000
Replies: 10

Hi ab,

I've used mormot2 as working toolbox.
I've making use of THttpServer as a server, while using TWebBrowser as client.
They can work around very well.

When I fetch some data from THttpServer with HttpGet, Uri.Address was truncated before blank.

I've make an additional step, which might be a default behavior of HttpGet.

var
  uri: TUri;
begin
  if not uri.From(aUrl) then Exit;
  HttpGet(Format('%s://%s:%s/%s',[uri.Schema, uri.Server, uri.Port, UrlEncode(uri.Address)]));
end;

#28 Re: mORMot 1 » mORMot 2 in Good Shape » 2021-01-23 12:27:34

Good news of 2021.

I've test this trunk under Win10 X64, code page 936(zh-cn,中文简体).

When I compile and run this test project with D7, 6 asserts failed, but with DXE, about 2,353 asserts failed.

Errors occurred when processing characters. I know it's complicated, Just commit this issue, and hope some HERO could resolve it.

Compiled with D7.

 1.2. Core process:
  - RTTI: 1,338 assertions passed  390us
  - Url encoding: 200 assertions passed  411us
!  - Encode decode JSON: 1 / 427,570 FAILED  28.77s
  - Wiki markdown to html: 56 assertions passed  731us
  - Variants: 99 assertions passed  515us
!  - Mustache renderer: 5 / 58 FAILED  36.61ms
  - TDocVariant: 91,785 assertions passed  102.82ms
  - TDecimal128: 17,446 assertions passed  2.02ms
  - BSON: 245,072 assertions passed  20.04ms
     100000 TBsonObjectID.ComputeNew in 18.91ms i.e. 5,287,368/s, aver. 0us
  - TSelectStatement: 221 assertions passed  627us
  - TSynMonitorUsage: 1,202 assertions passed  603us
  Total failed: 6 / 785,047  - Core process FAILED  28.95s

Compile with DXE.

 1.1. Core base:
  - Ini files: 7,028 assertions passed  33.74ms
!  - UTF8: 14,000 / 1,205,874 FAILED  1.18s
  - Url decoding: 1,101 assertions passed  687us
!  - Baudot code: 6,285 / 10,007 FAILED  28.90ms
  - Iso 8601 date and time: 200,831 assertions passed  17.22ms
  Total failed: 20,285 / 19,604,610  - Core base FAILED  5.54s

 1.2. Core process:
!  - Mustache renderer: 5 / 58 FAILED  38.66ms
  - TDocVariant: 91,785 assertions passed  107.47ms
  - TDecimal128: 17,446 assertions passed  1.51ms
!  - BSON: 8 / 245,072 FAILED  4.40ms
     100000 TBsonObjectID.ComputeNew in 3.11ms i.e. 32,144,005/s, aver. 0us
  Total failed: 13 / 834,650  - Core process FAILED  8.41s

 1.4. Core ecc:
!  - Certificates and signatures: 6 / 91 FAILED  80.73ms
  Total failed: 6 / 521,825  - Core ecc FAILED  1.04s

Run log is too large to be post here....

I can't access pastbin.com by now, so I've just trimed error report.

#29 Re: mORMot 1 » Need help for post a json in a Body » 2020-02-28 15:46:38

hi, @Xantharim
I've make a sample, which show the same result between IndyHttp and WinHttp(from mORMot->SynCrtSock)

You can check it here.
And the result here

btnWinHttp
{"result":"UNKNOWN_USER","description":"unknown username","customerId":null,"configs":[]}
btnIndy
{"result":"UNKNOWN_USER","description":"unknown username","customerId":null,"configs":[]}

#30 Re: mORMot 1 » SynBzPas.pas and UnCompressBzMem - what is the unpacked size? » 2020-02-22 06:35:08

According to the file format defination, we can not get that size before uncompress.

#31 Re: mORMot 1 » open source project- really? » 2020-02-13 17:50:34

I think @johnnysynop is just worried that we're going to take unnecessary litigation risks.

Perhaps you can submit relevant test methods, steps, and results to support your idea. If possible, submit the relevant patch to resolve the compatibility issues that @ab talked about.
It's always easy to talk, and doing some substantive work is better for the community as a whole.

Good luck.

#32 Re: mORMot 1 » Query by TSQLRecord returns nothing. » 2020-02-03 11:39:06

when I changes the property from TSQLRecord decedent class to TID, ALL TEST GOES FINE!
I think the reason is that TSQLRecord field stores the pointer of that instance.
It is mentioned here: TID Fields.

TSQLRecord published properties do match a class instance pointer, so are 32-bit (at least for Win32/Linux32 executables).

Question is: If these TSQLRecord fields just save dynamic values, then how could we use them?

This is the modified TestProject, all testcases passed.
And more, TSQLRestServerFullMemory server failed the last check, for it supports query with only one field, or it will return nothing.

mORMot.pas wrote:

function TSQLRestStorageInMemory.EngineList(const SQL: RawUTF8;
  ForceAJAX: Boolean; ReturnedRowCount: PPtrInt): RawUTF8;
// - GetJSONValues/FindWhereEqual will handle basic REST commands (not all SQL)
// only valid SQL command is "SELECT Field1,Field2 FROM Table WHERE ID=120;",
// i.e one Table SELECT with one optional "WHERE fieldname = value" statement
// - handle also basic "SELECT Count(*) FROM TableName;" SQL statement
// Note: this is sufficient for OneFieldValue() and MultiFieldValue() to work
var MS: TRawByteStringStream;
  ...
begin
  ...
      Stmt := TSynTableStatement.Create(SQL,
        fStoredClassRecordProps.Fields.IndexByName,
        fStoredClassRecordProps.SimpleFieldsBits[soSelect]);
      try
        if (Stmt.SQLStatement='') or  // parsing failed
           (length(Stmt.Where)>1) or // only a SINGLE expression is allowed yet  <--here
           not IdemPropNameU(Stmt.TableName,fStoredClassRecordProps.SQLTableName) then
          // invalid request -> return ''
          exit;
        if Stmt.SelectFunctionCount=0 then begin

So I replace TSQLRestServerFullMemory with TSQLRestServerDB. It dose make sense.

#33 Re: mORMot 1 » Query by TSQLRecord returns nothing. » 2020-02-02 14:57:01

I insert detail record like this. Is this a wrong way using TSQLRecord as reference?

var
  qMaster: TSQLRecordMaster;
  qDetail: TSQLRecordDetail;
begin
  ...
  // create qMaster and qDetail
  qDetail.Master:=qMaster;
  ...
  fRest.Add(qDetail);
  ...
end;

And the query of TSQLRecordDetail looks like this. Is it right?

var
  qMaster: TSQLRecordMaster;
  qDetail: TSQLRecordDetail;
begin
  ...
  // check value of qMaster
  with TSQLRecordDetail.AutoFree(qDetail, fRest, 'Master=?', [qMaster]) do
  while qDetail.FillOne do
  begin
     // do something with qDetail
  end;
end;

#34 mORMot 1 » Query by TSQLRecord returns nothing. » 2020-02-02 06:56:19

uian2000
Replies: 3

Hi, I have two TSQLRecord descendant classes, one refs another.

  // first class - to be referenced.
  TSQLRecordMaster=class(TSQLRecord)
  private
    fDummyName: RawUTF8;
  published
    property DummyName: RawUTF8 read fDummyName write fDummyName;
  end;

  // second class - references first one.
  TSQLRecordDetail=class(TSQLRecord)
  private
    fMaster: TSQLRecordMaster;
    fDummyName: RawUTF8;
  published
    property Master: TSQLRecordMaster read fMaster write fMaster;
    property DummyName: RawUTF8 read fDummyName write fDummyName;
  end;

both classes' insertion works fine, but the second class query always return nothing.

function TDummyService.DetailGet(aMaster: TMaster; out aDetails: TDetails):
    Integer;
var
  qMaster: TSQLRecordMaster;
  qDetail: TSQLRecordDetail;
begin
  Result := 0;
  with TSQLRecordMaster.AutoFree(qMaster,fRest,'DummyName=?',
    [aMaster.MasterName]) do
    if qMaster.FillOne then
      with TSQLRecordDetail.AutoFree(qDetail,fRest,'Master=?',
        [qMaster]) do
        while qDetail.FillOne do           // always jump to the end
        begin
          SetLength(aDetails, Result+1);
          aDetails[Result].Master := aMaster;
          aDetails[Result].DetailName := qDetail.DummyName;
          Inc(Result);
        end;
end;

I can find records of second class in the json file, so I'm sure that data exists.

[{"Master":[
{"RowID":1,"DummyName":"This is Master"}]
},{"Detail":[
{"RowID":1,"Master":35972812,"DummyName":"This is detail No.1"}]
}]

But why?
I've test this case On D7 & DXE, same result.

Here(pastbin) comes the full source, so everyone could reproduce this issue.

I'm sorry for my ignorance of forum rules.

#35 Re: mORMot 1 » [solved.final]AV on accessing property Server of TInjectableObjectRest » 2020-01-31 16:08:23

You are awesome @ab.

I've failed several times on cloning my fork to local workspace due to my legacy network.
when i've been defeated, awo, it has been done!

I have checked that fix, it works for me!
Thank you for you great work, again. wink

#37 Re: mORMot 1 » [solved.final]AV on accessing property Server of TInjectableObjectRest » 2020-01-30 21:48:22

Hi ab, I've tried make initialization in another procedure, they are ugly.
so I introduced a new constructor of TInjectedObjectRest to make sure something could be done logically when instance was created.

codes here.

original TInjectableObjectRest

  TInjectableObjectRest = class(TInjectableObject)
  protected
    fFactory: TServiceFactoryServer;
    fServer: TSQLRestServer;
  public

then goes my new constructor

    /// initialize an instance, defining one dependency resolver factory and
    // restserver
    // - the resolver may be e.g. a TServiceContainer
    // - once the DI/IoC is defined, will call the AutoResolve() protected method
    constructor CreateWithResolverAndRest(aResolver: TInterfaceResolver;
      aFactory: TServiceFactoryServer; aServer: TSQLRestServer;
      aRaiseEServiceExceptionIfNotFound: boolean=true); virtual;

and new reference class

  /// class-reference type (metaclass) of a TInjectableObjectRest type
  TInjectableObjectRestClass = class of TInjectableObjectRest;

implimentation of constructor

{ TInjectableObjectRest }

constructor TInjectableObjectRest.CreateWithResolverAndRest(
  aResolver: TInterfaceResolver; aFactory: TServiceFactoryServer;
  aServer: TSQLRestServer; aRaiseEServiceExceptionIfNotFound: boolean=true);
begin
  inherited CreateWithResolver(aResolver, aRaiseEServiceExceptionIfNotFound);
  fFactory := aFactory;
  fServer := aServer;
end;

finally modified TServiceFactoryServer.CreateInstance

function TServiceFactoryServer.CreateInstance(AndIncreaseRefCount: boolean): TInterfacedObject;
var dummyObj: pointer;
begin
  case fImplementationClassKind of
  ickWithCustomCreate:
    result := TInterfacedObjectWithCustomCreateClass(fImplementationClass).Create;
  ickInjectable:
    result := TInjectableObjectClass(fImplementationClass).
       CreateWithResolver(Rest.Services,true);

/// modify begin here -- separate ickInjectableRest from previous condition 
  ickInjectableRest:
    result := TInjectableObjectRestClass(fImplementationClass).
       CreateWithResolverAndRest(Rest.Services,self,RestServer,true);
/// modify end here

  ickFromInjectedResolver: begin
    dummyObj := nil;
    if not TSQLRestServer(Rest).Services.
       TryResolveInternal(fInterface.fInterfaceTypeInfo,dummyObj) then
      raise EInterfaceFactoryException.CreateUTF8(
        'ickFromInjectedResolver: TryResolveInternal(%)=false',[fInterface.fInterfaceName]);
    result := TInterfacedObject(ObjectFromInterface(IInterface(dummyObj)));
    if AndIncreaseRefCount then // RefCount=1 after TryResolveInternal()
      AndIncreaseRefCount := false else
      dec(TInterfacedObjectHooked(result).FRefCount);
  end;
....

Could you please merge this patch , only if it is compatible to mormot framework?

#39 mORMot 1 » [solved.final]AV on accessing property Server of TInjectableObjectRest » 2020-01-30 19:01:10

uian2000
Replies: 7

hi there, I've implemented a class which inherited from TInjectableObjectRest.
I need to do some check on ORM, and boom, AV occurs.

My code is something like this:

constructor TSvcCacheXXX.CreateWithResolver(aResolver: TInterfaceResolver;
  aRaiseEServiceExceptionIfNotFound: boolean);
begin
  inherited;

  fModel := Server.Model;                      // AV!  Server is nil here.
  if -1 = fModel.GetTableIndex(TSQLXXX) then
    fModel.AddTable(TSQLXXX);

  Server.CreateMissingTables;
end;

I've done some work, and found relative code in mormot.pas:

function TServiceFactoryServer.CreateInstance(AndIncreaseRefCount: boolean): TInterfacedObject;
var dummyObj: pointer;
begin
  case fImplementationClassKind of
  ickWithCustomCreate:
    result := TInterfacedObjectWithCustomCreateClass(fImplementationClass).Create;
  ickInjectable, ickInjectableRest: begin
    result := TInjectableObjectClass(fImplementationClass).
       CreateWithResolver(Rest.Services,true);                        // Call of CreateWithResolver
    if fImplementationClassKind=ickInjectableRest then begin  // Factory and Server was assigned AFTER Create call of TInjectableObjectRest.CreateWithResolver
      TInjectableObjectRest(result).fFactory := self;                 // Assign of Factory
      TInjectableObjectRest(result).fServer := RestServer;       // Assign of Server
    end;
  end;
....

I'm I making a wrong use-case of TInjectableObjectRest.CreateWithResolver?
Or, should we do some tweak on the logical sequence of  creation call and property assignment?

#40 Re: mORMot 1 » How many requests are pending? » 2019-04-11 08:47:09

If you are talking about requests of mORMot, this open tickets may help you.

#41 mORMot 1 » How can I consume these services of Samples 35? » 2019-02-13 03:36:59

uian2000
Replies: 0

Hi ab,

Example 35 is a great example of DDD, which showing us the architecture and iterative process of a DDD projects.
In the very current state, this project registers a Windows service, which exposes two Delphi interfaces, providing conference booking and BookProcessSettings storage functions.
My question is, how do I consume/use the services provided by these two interfaces?

Would you mind continue iterating this project and show some practice on how you guys do the client part?

Thanks. smile

#43 Re: mORMot 1 » Unable to Compile ...2017-10-31_120956_9eb16ccca7, Delphi 2010 Win32 » 2017-11-05 16:25:15

Same error, same solution.

I've searched my dev environment, Delphi XE, found no method named TThread.TerminateSet.

I've searched that method on EMB api wiki, and it was first seen on version XE2.
http://docwiki.embarcadero.com/Librarie … dset&go=Go

I think we should make a more accurate condition of CompilerVersion.
By the way XE2 CompilerVersion is 23.

#44 Re: mORMot 1 » Bulk insert to tables » 2016-11-22 22:21:15

How about trying extract country names of SQLfile into csv format or lines.
Then you could load then using TStringList, and write loops to apply names in "Assign country;Add country" statement.

#45 Re: mORMot 1 » DDD Sample » 2016-11-17 18:49:32

DDD has too many idea to follow, Rest/Aggregate/EventSourcing/etc
I do learn good stuff in mORMot lib/framework, and I've make a little testcase like DDDPersistence, but far more things are disordered in my mind.
I don't know when to make a Service, or share whitch model between server and client and ....

I mean, mORMot is powerful but complicated, a clean uncoupled architecture example of DDD is appreciated.

#46 Re: mORMot 1 » Conflict between "stored AS_UNIQUE" and DDDPersistence. » 2016-04-02 13:51:07

And, when "stored AS_UNIQUE" was being commented, this update test would go through successfully.

#47 Re: mORMot 1 » Conflict between "stored AS_UNIQUE" and DDDPersistence. » 2016-04-02 11:46:17

ab wrote:

Which "error"?

cmd.SelectOneByCaption() returns cqrsNotFound, not cqrsSuccess.

ab wrote:

Perhaps after the Commit, the cmd instance is not re-usable for a select.

Please try to reassign a new cmd instance before SelectOneByCaption().

I've tried replace cmd with qry "Rest.Services.Resolve(iDomEntityQuery, qry)", qry.SelectOneByCaption() returns cqrsNotFound too.

Code here.

      entity := TSomeEntity.Create;
      Check(Rest.Services.Resolve(IDomEntityCommand, cmd));
      Check(Rest.Services.Resolve(iDomEntityQuery, qry));
      try
        // check effect of update
        for i := 1 to MAX do
        begin
          UInt32ToUtf8(i, iText);
          iText := PreFix + iText;
          Check(cqrsSuccess = qry.SelectOneByCaption(iText));   // error occurs here. qry.SelectOneByCaption() returns cqrsNotFound.
          Check(1 = qry.GetCount);       // error. result is 0
          Check(cqrsSuccess = qry.Get(entity));  // error
          Check(iText = entity.Caption);  // error
        end;

#48 mORMot 1 » Conflict between "stored AS_UNIQUE" and DDDPersistence. » 2016-04-02 02:53:42

uian2000
Replies: 3

Hi ab.
Thanks for your last fix of TSQLRestBatch.Update overthere http://synopse.info/forum/viewtopic.php?id=3183

Now here is another conflict.
When I put a "stored AS_UNIQUE" at definition of TSQLRecord* 's property, Checking of update will fail.
Definition of record.

  TSQLRecordSomeEntity = class(TSQLRecord)
  protected
    fCaption: RawUTF8;
  published
    property Caption: RawUTF8 read fCaption write fCaption [b]stored AS_UNIQUE[/b];  // changed here
  end;

and test of update.

        // test update
        for i := 1 to MAX do
        begin
          UInt32ToUtf8(i, iText);
          Check(cqrsSuccess = cmd.SelectOneByCaption(iText));
          Check(1 = cmd.GetCount);
          Check(cqrsSuccess = cmd.Get(entity));
          Check(iText = entity.Caption);
          iText := PreFix + iText;
          entity.Caption := iText;
          Check(cqrsSuccess = cmd.Update(entity));
        end;
        Check(cqrsSuccess = cmd.Commit);

        // check effect of update
        for i := 1 to MAX do
        begin
          UInt32ToUtf8(i, iText);
          iText := PreFix + iText;
          Check(cqrsSuccess = cmd.SelectOneByCaption(iText));   // error occurs here
          Check(1 = cmd.GetCount);
          Check(cqrsSuccess = cmd.Get(entity));
          Check(iText = entity.Caption);
        end;

I've inspect result of cmd.GetAll() after update using a DynArray, values retrived is equal to iText "PreFix = iText". But cmd.SelectOneByCaption(iText) fails.
Is there any thing I'v doing wrong?

Here the full/Single unit file. for your convenience.

unit DDDPersistenceMain;

interface

uses
  Classes, SysUtils,
  SynCommons, mORMot, mORMotDDD,
  SynTests;

type
  TSomeEntity = class(TSynPersistent)
  protected
    fCaption: RawUTF8;
  published
    property Caption: RawUTF8 read fCaption write fCaption;
  end;

  TSomeEntityObjArray = array of TSomeEntity;

  TSQLRecordSomeEntity = class(TSQLRecord)
  protected
    fCaption: RawUTF8;
  published
    property Caption: RawUTF8 read fCaption write fCaption stored AS_UNIQUE;
  end;

  IDomEntityQuery = interface(ICQRSService)
    ['{74EA5045-2062-47D0-AE0F-E9163BBC731B}']
    function SelectOneByCaption(const aCaption: RawUTF8): TCQRSResult;
    function SelectAllByCaption(const aCaption: RawUTF8): TCQRSResult;
    function SelectAll: TCQRSResult;
    function Get(out aAggregate: TSomeEntity): TCQRSResult;
    function GetAll(out aAggretates: TSomeEntityObjArray): TCQRSResult;
    function GetNext(out aAggregate: TSomeEntity): TCQRSResult;
    function GetCount: Integer;
  end;

  IDomEntityCommand = interface(IDomEntityQuery)
    ['{FEC02E2A-A76F-4CDD-B378-E4E1EA6043F9}']
    function Add(const aAggregate: TSomeEntity): TCQRSResult;
    function Update(const aUpdatedAggregate: TSomeEntity): TCQRSResult;
    function Delete: TCQRSResult;
    function DeleteAll: TCQRSResult;
    function Commit: TCQRSResult;
    function Rollback: TCQRSResult;
  end;

  TInfraRepoEntity = class(TDDDRepositoryRestCommand, IDomEntityCommand, IDomEntityQuery)
  public
    function SelectOneByCaption(const aCaption: RawUTF8): TCQRSResult;
    function SelectAllByCaption(const aCaption: RawUTF8): TCQRSResult;
    function SelectAll: TCQRSResult;
    function Get(out aAggregate: TSomeEntity): TCQRSResult;
    function GetAll(out aAggregates: TSomeEntityObjArray): TCQRSResult;
    function GetNext(out aAggregate: TSomeEntity): TCQRSResult;
    function Add(const aAggregate: TSomeEntity): TCQRSResult;
    function Update(const aUpdatedAggregate: TSomeEntity): TCQRSResult;
  end;

  TInfraRepoEntityFactory = class(TDDDRepositoryRestFactory)
  public
    constructor Create(aRest: TSQLRest; aOwner: TDDDRepositoryRestManager=nil); reintroduce;
    class procedure RegressionTests(test: TSynTestCase);
  end;

  TTestRepoEntity = class(TSynTestCase)
  published
    procedure TestSelf;
  end;

  TTestSuit = class(TSynTests)
  published
    procedure TestAll;
  end;

  procedure RunTestProject;

implementation

procedure RunTestProject;
begin
  with TTestSuit.Create() do
  try
    Run;
    ReadLn;
  finally
    Free;
  end;
end;

{ TInfraRepoEntity }

function TInfraRepoEntity.Add(const aAggregate: TSomeEntity): TCQRSResult;
begin
  Result := ORMAdd(aAggregate);
end;

function TInfraRepoEntity.Get(out aAggregate: TSomeEntity): TCQRSResult;
begin
  Result := ORMGetAggregate(aAggregate);
end;

function TInfraRepoEntity.GetAll(out aAggregates: TSomeEntityObjArray): TCQRSResult;
begin
  Result := ORMGetAllAggregates(aAggregates);
end;

function TInfraRepoEntity.GetNext(out aAggregate: TSomeEntity): TCQRSResult;
begin
  Result := ORMGetNextAggregate(aAggregate);
end;

function TInfraRepoEntity.SelectAll: TCQRSResult;
begin
  Result := ORMSelectAll('', []);
end;

function TInfraRepoEntity.SelectAllByCaption(const aCaption: RawUTF8): TCQRSResult;
begin
  Result := ORMSelectAll('Caption=?', [aCaption], (''=aCaption));
end;

function TInfraRepoEntity.SelectOneByCaption(
  const aCaption: RawUTF8): TCQRSResult;
begin
  Result := ORMSelectOne('Caption=?', [aCaption], (''=aCaption));
end;

function TInfraRepoEntity.Update(
  const aUpdatedAggregate: TSomeEntity): TCQRSResult;
begin
  Result := ORMUpdate(aUpdatedAggregate);
end;

{ TInfraRepoEntityFactory }

constructor TInfraRepoEntityFactory.Create(aRest: TSQLRest;
  aOwner: TDDDRepositoryRestManager);
begin
  inherited Create(IDomEntityCommand,TInfraRepoEntity,TSomeEntity,aRest,TSQLRecordSomeEntity,aOwner);
  AddFilterOrValidate(['*'], TSynFilterTrim.Create);
  AddFilterOrValidate(['Caption'],TSynValidateNonVoidText.Create);
end;

class procedure TInfraRepoEntityFactory.RegressionTests(test: TSynTestCase);
  procedure TestOne(Rest: TSQLRest);
  const
    PreFix = 'Modified';
    MAX = 1000;
  var
    cmd: IDomEntityCommand;
    qry: IDomEntityQuery;
    entity: TSomeEntity;
    entitys: TSomeEntityObjArray;
    i,entityCount: Integer;
    iText: RawUTF8;
  begin
    with test do
    begin
      entity := TSomeEntity.Create;
      Check(Rest.Services.Resolve(IDomEntityCommand, cmd));
      try
        // test Add
        for i := 1 to MAX do
        begin
          UInt32ToUtf8(i,iText);
          entity.Caption := '  ' + iText;
          Check(cqrsSuccess = cmd.Add(entity));
        end;
        Check(cqrsSuccess = cmd.Commit);

        // test select
        for i := 1 to MAX do
        begin
          UInt32ToUtf8(i, iText);
          // testing SelectAllByCaption
          Check(cqrsSuccess = cmd.SelectAllByCaption(iText));
          Check(1 = cmd.GetCount);
          Check(cqrsSuccess = cmd.GetNext(entity));
          Check(iText = entity.Caption);
          // testing SelectOneByCaption
          Check(cqrsSuccess = cmd.SelectOneByCaption(iText));
          Check(1 = cmd.GetCount);
          Check(cqrsSuccess = cmd.Get(entity));
          Check(iText = entity.Caption);
        end;

        // test update
        for i := 1 to MAX do
        begin
          UInt32ToUtf8(i, iText);
          Check(cqrsSuccess = cmd.SelectOneByCaption(iText));
          Check(1 = cmd.GetCount);
          Check(cqrsSuccess = cmd.Get(entity));
          Check(iText = entity.Caption);
          iText := PreFix + iText;
          entity.Caption := iText;
          Check(cqrsSuccess = cmd.Update(entity));
        end;
        Check(cqrsSuccess = cmd.Commit);

        // check effect of update
        for i := 1 to MAX do
        begin
          UInt32ToUtf8(i, iText);
          iText := PreFix + iText;
          Check(cqrsSuccess = cmd.SelectOneByCaption(iText));   // error occurs here
          Check(1 = cmd.GetCount);
          Check(cqrsSuccess = cmd.Get(entity));
          Check(iText = entity.Caption);
        end;

        // test delete
        Check(cqrsSuccess = cmd.SelectAll);
        Check(cqrsSuccess = cmd.DeleteAll);
        Check(cqrsSuccess = cmd.Commit);
        Check(cqrsSuccess = cmd.SelectAll);
        Check(0 = cmd.GetCount);
      finally
        entity.Free;
      end;
    end;
  end;
var
  RestServer: TSQLRestServerFullMemory;
  RestClient: TSQLRestClientURI;
begin
  RestServer := TSQLRestServerFullMemory.CreateWithOwnModel([TSQLRecordSomeEntity]);
  try // first try directly on server side
    RestServer.ServiceContainer.InjectResolver([TInfraRepoEntityFactory.Create(RestServer)],true);
    TestOne(RestServer); // sub function will ensure that all I*Command are released
  finally
    RestServer.Free;
  end;
  RestServer := TSQLRestServerFullMemory.CreateWithOwnModel([TSQLRecordSomeEntity]);
  try // then try from a client-server process
    RestServer.ServiceContainer.InjectResolver([TInfraRepoEntityFactory.Create(RestServer)],true);
    RestServer.ServiceDefine(TInfraRepoEntity,[IDomEntityCommand,IDomEntityQuery],sicClientDriven);
    test.Check(RestServer.ExportServer);
    RestClient := TSQLRestClientURIDll.Create(TSQLModel.Create(RestServer.Model),@URIRequest);
    try
      RestClient.Model.Owner := RestClient;
      RestClient.ServiceDefine([IDomEntityCommand],sicClientDriven);
      TestOne(RestServer);
      RestServer.DropDatabase;
      USEFASTMM4ALLOC := true; // for slightly faster process
      TestOne(RestClient);
    finally
      RestClient.Free;
    end;
  finally
    RestServer.Free;
  end;
end;

{ TTestRepoEntity }

procedure TTestRepoEntity.TestSelf;
begin
  TInfraRepoEntityFactory.RegressionTests(Self);
end;

{ TTestSuit }

procedure TTestSuit.TestAll;
begin
  AddCase([TTestRepoEntity]);
end;

initialization
  TJSONSerializer.RegisterObjArrayForJSON([
    TypeInfo(TSomeEntityObjArray), TSomeEntity]);

  TInterfaceFactory.RegisterInterfaces([
    TypeInfo(IDomEntityQuery), TypeInfo(IDomEntityCommand)]);
end.

#50 mORMot 1 » Bookmark of mORMot pdf document disappeared. » 2016-03-29 09:24:54

uian2000
Replies: 2

Bookmark disappeared in current download of document (pdf version), which is present when it is in 2015.09.14 .

Is this a feature or a bug?

Board footer

Powered by FluxBB