#101 Re: mORMot 2 » CreateAndFillPrepareJoined fails when ORM table gets 2nd row » 2023-07-06 12:34:31

tbo
damiand wrote:

But, it is a many (TDoctor) to one (TLocArea) relation, not a m:n.

In this case, I would write it as follows:

type
  TLocationArea = class(TOrm)
  ...

  TLocationAreaID = type TID;

  TDoctor = class(TOrm)
  ...
  published
    property LocationAreaID: TLocationAreaID
      read fLocationAreaID write fLocationAreaID;

var
  dataArr: TArray<TDoctor>;
begin
  ...RetrieveListObjArray(dataArr, TDoctor, 'LocationAreaID=?', [1234]);

Or if no automatism is desired, then like this: "property LocationAreaID: TID".

With best regards
Thomas

#102 Re: mORMot 2 » SynDBremote on Mormot2 » 2023-06-22 13:31:52

tbo
Stemon63 wrote:

where I can find Mormot 1 SynDbremote in new Mormot2?

If you change from mORMot version 1 to 2, a simple grep over the new source code is often helpful. When I search for "dbremote" I get hits that don't look bad. Can't say more, never used these classes myself.

With best regards
Thomas

#103 Re: mORMot 2 » Using TCollection inTOrm » 2023-06-19 18:42:46

tbo
mdoyle wrote:

Create with parameters and CreateAndFiilPrepare don’t work anymore. Any recommendations how to use TCollection and TPersistance from now on?

You make the same mistake again. If you do your own initializations in the constructor of an ORM object, you can NEVER take the overloaded constructors as long as Arnaud solved the problem with InternalCreate function. The overridden constructor is not called and thus the own variable classes are not initialized and all calls go to nothing. I think that this change of Arnaud was very unfortunate, but currently it is as it is. Change it as follows:

procedure TTestData.TestCreateAndFillPrepare;
...
  Order := TOrmOrderBook.Create;  // AndFillPrepare(TestClient.Orm, '', []);
  try
    Order.FillPrepare(TestClient.Orm, '', []);


procedure TTestData.TestCreate;
...
  Order := TOrmOrderBook.Create;  // (TestClient.Orm, 'OrderNo = ?', ['Order1']);
  try
    TestClient.Orm.Retrieve(FormatUtf8('OrderNo = ?', [], ['Order1']), Order);

I think if you want changes, you need to push Arnaud a little bit. wink

With best regards
Thomas

#104 Re: mORMot 1 » How to use OpenSSL for https requests? » 2023-06-09 20:11:47

tbo

Oops, Arnaud was faster.

mrauter wrote:

How can I connect to a HTTPS endpoint using OpenSSL and Mormot?

Under mORMot1 with cUrl. Define USELIBCURL. With function SynCrtSock.HttpGet.

With best regards
Thoms

#105 Re: mORMot 2 » Error 'file not found "fastmm4.dcu" in delphi7 using mormot2 » 2023-06-07 15:16:14

tbo
lfyey121 wrote:

Does mormot2 not support delphi7?

As described in the documentation: "Note that before Delphi 2006, you will need to download and install FastMM4 heap memory manager".

With best regards
Thomas

#106 Re: mORMot 2 » TRecordVersion doesn't work as expected » 2023-06-05 18:31:59

tbo
mdoyle wrote:

I updated the gist. Please check again https://gist.github.com/martin-doyle/00 … ceac4698fc.

Delphi 11.3, mORMot 2.1.5499
I have only tested case TTestReplicationSimple "AddCase([TTestReplicationSimple])" for the first time. I get this error reported:

EInOutError {Message:"E/A-Fehler 6"} [Main] at 6c74b3

When I run all three test cases, I get this error reported:

...
fail  #4064 SameRecord ID Master: 107 Slave: 107 
fail  SynReplicationTests.TTestReplicationBatch(02fea050) Replication batch - Test batch update [SameRecord ID Master: 107 Slave: 107] 
EXC   EInOutError {Message:"E/A-Fehler 6"} [Main] at 6b84b3

I think every test case should pass without exception. Sorry, have no time to take a closer look in the next few days.

With best regards
Thomas

#107 Re: mORMot 2 » TRecordVersion doesn't work as expected » 2023-06-04 14:14:47

tbo
mdoyle wrote:

I think your upload is not complete. The file Test1.json is missing.

With best regards
Thomas

#108 Re: mORMot 2 » TRecordVersion doesn't work as expected » 2023-06-02 13:38:16

tbo
avavdoshin wrote:

Here is a working example with results in csv: https://gist.github.com/avavdoshin/fd1d … f8f0638691
Record versions in this example doesn't changes for updates, so this changes will not be replicated to slave database.

I think you are using Batch incorrectly in your example. In mORMot "ex" and "test" directory, or in this forum post, you can find examples of how to use TRestBatch. Just search for "TRestBatch.Create", "BatchStart" or "BatchSend". Use TRestBatch in your example exactly as they are used in mORMot. Then compare the results and report it here. Or someone else from the forum can help. Maybe I have some time on the weekend, then I can also look again. Otherwise you have to wait until Arnaud is back.

With best regards
Thomas

#109 Re: mORMot 2 » TRecordVersion doesn't work as expected » 2023-05-30 11:38:30

tbo
avavdoshin wrote:

Does anybody else using TRecordVersion in mormot2?

I use TRecordVersion. Since I haven't noticed anything negative yet, I haven't looked for a bug either. Can you give us any more information, such as:

Delphi 11.3, mORMot2 GitHub commit 5186

Or a whole example, as Martin Doyle has done here. Then it is easier to search for the error.

With best regards
Thomas

#110 Re: mORMot 2 » D7 compile mormot.db.rad.unidac.pas error » 2023-05-28 19:18:53

tbo
zuoluoq wrote:

and why is the dINformix setted as ''?

I think you have to wait until Arnaud is back.

With best regards
Thomas

#111 Re: mORMot 2 » Using TCollection inTOrm » 2023-05-28 13:00:41

tbo
mdoyle wrote:

By the way, I like the idea of embedding detail data within the record (sharding). Would be interesting to know what other people use, just schemaless TDocVariant?

I use it in conjunction with SOA and WebApps (TMcvApplication) when records are mostly just read, and can recommend it. This saves many JOINs when combining the data from different tables of the DB. As an example, you have events with presentations. In the overview are displayed: Date, topic, location, room, speaker, etc. Only the date comes from the schedule table. Everything else are foreign keys into other tables. Having an extra field here that contains all the data from other tables needed for display reduces the effort considerably and makes viewing fast. And because the data composition changes very rarely and everything is handled via SOA functions, it is practically no effort to maintain this field.

With best regards
Thomas

#112 Re: mORMot 2 » IRestOrm.add don't report duplicate error » 2023-05-26 13:46:07

tbo
larand54 wrote:

How could I solve this?

As described in the documentation:

// - on success, returns the new RowID value; on error, returns 0
// - on success, Value.ID is updated with the new RowID

In service you can write the following:

type
  TOrmArticle = class(TOrm);

function TArticleService.Add(const pmcItem: TOrmArticle): TID;
var
  restServer: TRestServerDB;
begin
  Result := -1;
  if pmcItem <> Nil then
  begin
    restServer := GetDBRestServer;
    if restServer <> Nil then
      Result := restServer.Server.Add(pmcItem, True, False);
  end;
end;

In client then the following:

var
  data: TOrmArticle;
begin
  ...
  data.IDValue := service.Add(data);
  if data.IDValue > 0 then

Or have a look into function AddOrUpdate.

With best regards
Thomas

#113 Re: mORMot 2 » Unit mormot.lib.win7zip, support for -ssw switch and compression issue » 2023-05-24 16:15:30

tbo
WG42 wrote:

Could you add the skippedFile(s) functionality also to the AddFile() function?

This is not necessary because AddFile() does not include a locked file. See following example:

var fileStream: THandleStream := Nil;
try
  var testFile: TFileName := 'c:\mORMot2\src\lib\mormot.lib.win7zip.pas';
  fileStream := TFileStreamEx.Create(testFile, fmOpenRead);

  var skippedFiles: TFileNameDynArray;
  var libWriter: I7zWriter := New7zWriter(fh7z);
  libWriter.SetCompressionLevel(3);
  if libWriter.AddFile(testFile, StringToUtf8(ExtractFileName(testFile))) then
    libWriter.SaveToFile(MakePath([Executable.ProgramFilePath, 'TestData.7z']))
  else
    AddString(TStringDynArray(skippedFiles), testFile);

  for var fileName: TFileName in libWriter.AddFiles('c:\mORMot2\src\', '', '*.pas;*.inc', True) do
    AddString(TStringDynArray(skippedFiles), fileName);

  ShowMessage(Format('File(s) could not be added! Count: %d', [Length(skippedFiles)]));
finally
  fileStream.Free;
end;

With best regards
Thomas

#114 Re: mORMot 2 » Using TCollection inTOrm » 2023-05-24 13:52:36

tbo
mdoyle wrote:

Is TCollection still supported and what is the recommended way of using it?

You are right, now you have to write the following:

procedure TTestData.TestRetreiveOrmWithCollection;
...
  TestClient := TRestClientDB.Create(FModel, nil, DataFile, TRestServerDB, false, '');
  try
    Order := TOrmOrderBook.Create;
    try
      if Order.FillPrepare(TestClient.Orm, '', []) then
      begin

The documentation is also not entirely clear at this point. Let's see what Arnaud says when he gets back.

With best regards
Thomas

#115 Re: mORMot 2 » Calculated fields are actually created as table fields in the DB? » 2023-05-22 12:10:54

tbo
damiand wrote:

In case I don't want a calculated field to be actually created as a db table field, do I have to use a public calculation function instead (e.g. GetFullName), and not a published property?

Yes, you can write it like this:

TPerson = class(TOrm)
private
  ...
  function GetFullName: RawUTF8;
public
  property FullName: RawUTF8 read GetFullName;
published
  property FirstName: RawUTF8 index 50 read fFirstName write fFirstName;
  property SurName: RawUTF8 index 50 read fSurName write fSurName;
end;

But for clarity, I would write it this way:

TCustomPerson = class(TOrmBaseRecord)
private
  fFirstName, fSurName: RawUTF8;
published
  property FirstName: RawUTF8 index 50 read fFirstName write fFirstName;
  property SurName: RawUTF8 index 50 read fSurName write fSurName;
end;

TPerson = class(TCustomPerson)
private
  function GetFullName: RawUTF8;
public
  property FullName: RawUTF8 read GetFullName;
end;

Then, if necessary, you can derive the ORM object TOrmBaseRecord on the server or client from different base objects using a compiler switch. On the server derived from the class TOrm and on the client from the class TObjectWithID. All TCustom... classes could be shared between server and client. The specializations are done only in the final classes. I have already described the technique here in the forum.

With best regards
Thomas

#116 Re: mORMot 1 » Temporary in-memory storage with TSQLRestTempStorage » 2023-05-19 20:22:43

tbo

An example for a batch can be found here (mORMot 2). For a background process search for TSynBackgroundTimer/TSQLRestBackgroundTimer in mORMot source code. All information on how to use it can be found in the help description of the class.

With best regards
Thomas

#117 Re: mORMot 2 » Problem adding object to an ObjArray in a service. » 2023-05-11 21:35:11

tbo
larand54 wrote:

I' understand that I do something really wrong but how should I do?

For me, the following looks clearer:

procedure TSubProject.AddArticle(pmArticle: TArticle);
begin
  if pmArticle <> Nil then
    ObjArrayAdd(FArticles, pmArticle);
end;

function TDHSSyncRepository.AddArticleToSubProject(pmSubProject: TSubProject; out pmoArticle: TArticle): TSyncRepoError;
begin
  Result := srNotFound;
  if pmSubProject = Nil then Exit; //=>
  if RetrieveArticle(pmoArticle) <> srSuccess then Exit; //=>

  pmSubProject.AddArticle(pmoArticle);
  Result := srFound;
end;

With best regards
Thomas

#118 Re: mORMot 2 » Unit mormot.lib.win7zip, support for -ssw switch and compression issue » 2023-05-11 14:13:44

tbo
ab wrote:

Please try https://github.com/synopse/mORMot2/commit/9674e7ee
- the exception should be intercepted for locked files during  the process
- AddFiles() will return the list of locked files which were not marked to be added

Commit 5441 (9674e7e) works as expected. Thanks for this. The following test was passed:

var fileStream: THandleStream := Nil;
try
  fileStream := TFileStreamEx.Create('c:\mORMot2\src\lib\mormot.lib.win7zip.pas', fmOpenRead);
  var libWriter: I7zWriter := New7zWriter(fh7z);
  var skippedFiles: TFileNameDynArray := libWriter.AddFiles('c:\mORMot2\src\', '', '*.pas;*.inc', True);
  if Length(skippedFiles) > 0 then
    ShowMessage(Format('Skipped Files: %d', [Length(skippedFiles)]));

  libWriter.SaveToFile(MakePath([Executable.ProgramFilePath, 'TestData.7z']));
finally
  fileStream.Free;
end;

IsFileReadable function added in AddFiles makes no measurable difference in timing.

With best regards
Thomas

#119 Re: mORMot 2 » Unit mormot.lib.win7zip, support for -ssw switch and compression issue » 2023-05-10 18:36:20

tbo
WG42 wrote:

Maybe the ProgressCallback could result/send something once a file is done compressing or once a file has not been compressed due to an error. Like this in ProgressCallback we could catch these errors for logging.

Or an additional wish, the function AddFiles would have as return a list of files that could not be packed.

With best regards
Thomas

#120 Re: mORMot 2 » Unit mormot.lib.win7zip, support for -ssw switch and compression issue » 2023-05-10 18:12:05

tbo
ab wrote:

1) The files are opened as fmOpenReadDenyNone = fmOpenRead or fmShareDenyNone
in T7zWriter.GetStream() so they should be opened once currently opened by another program.

If you want to save a folder with function I7zWriter.AddFiles and open a file of this folder before, an exception is thrown:

var fileStream: THandleStream := TFileStreamEx.Create('c:\mORMot2\src\lib\mormot.lib.win7zip.pas', fmOpenRead);
try
  var libWriter: I7zWriter := New7zWriter(fh7z);
  libWriter.AddFiles('c:\mORMot2\src\', 'mORMot2_2023-05-01', '*.pas;*.inc', True);
  libWriter.SaveToFile(MakePath([Executable.ProgramFilePath, 'TestMultiData.7z']));
finally
  fileStream.Free;
end;

The two exceptions are as follows:

ExceptionMessage="TFileStreamEx.Create(c:\mORMot2\src\lib\mormot.lib.win7zip.pas) failed as ERROR_SHARING_VIOLATION"
ExceptionName="EOSException"
ExceptionAddress=763A8FC2
---------------------------
ExceptionMessage="T7zWriter.SaveToStream error 8007000E (Für diesen Vorgang sind nicht genügend Speicherressourcen verfügbar)"
ExceptionName="E7Zip"
ExceptionAddress=763A8FC2

The behavior is normal, unless the file would have been opened with fmOpenRead or fmShareDenyWrite/ or fmShareDenyNone. The question would be rather, couldn't you skip this file without canceling the whole process?

With best regards
Thomas

#121 Re: mORMot 2 » T7zWriter.SaveToFile, Mode error » 2023-05-09 20:16:55

tbo

Commit 5434 (e4a5ff6) works as expected. All my tests passed. Thanks for this.

With best regards
Thomas

#122 Re: mORMot 2 » IList<T> in services » 2023-05-07 13:33:37

tbo
larand54 wrote:

It seems to require too much effort to be worth solving ?

In the client program I work with Spring4D. Here there is also an IList. For this I have connections for various components. The bridge between the two looks like this:

type
  TOrmArticleList = class(Spring.Collections.Lists.TObjectList<TOrmArticle>);
  TOrmArticleObjArray = array of TOrmArticle;

function ...CreateArticleList(const pmcSectionID: TID): TOrmArticleList;
var
  service: IArticle;
  dataArr: TOrmArticleObjArray;
begin
  if not dmDB.RestServer.Resolve(IArticle, service) then Exit(Nil); //=>

  service.GetAllItems(pmcSectionID, [asActive], dataArr);
  Result := TOrmArticleList.Create(dataArr, True);
end;

mORMot provides an ObjArray that fills the list. With the Spring4D classes I have many functions that I don't have to implement myself. If you only need the IList interface, you can write like this:

Result := TCollections.CreateObjectList<TOrmArticle>(dataArr, True);

With best regards
Thomas

#123 Re: mORMot 2 » T7zWriter.SaveToFile, Mode error » 2023-05-06 20:57:14

tbo
ab wrote:

I am not sure it is possible to modify an archive in place, to be honest.

With my modification for function SaveToFile, it works for this test:

procedure SaveFolderTo7Zip(const pmcFolder, pmc7ZipFileName: TFileName;
  const pmc7ZipInternalDir: TFileName = ''; const pmcFileMask: TFileName = '*';
  pmNew7Zip: Boolean = False; const pmOnProgress: T7zProgressCallback = Nil);
var
  libWriter: I7zWriter;
begin
  if not pmNew7Zip
    and FileExists(pmc7ZipFileName) then
  begin
    libWriter := New7zWriter(pmc7ZipFileName, fh7z)
  end
  else
    libWriter := New7zWriter(fh7z);

  libWriter.SetCompressionLevel(3);
  if Assigned(pmOnProgress) then
    libWriter.SetProgressCallback(pmOnProgress);

  libWriter.AddFiles(pmcFolder, pmc7ZipInternalDir, pmcFileMask, True);
  libWriter.SaveToFile(pmc7ZipFileName);
end;

Call then as follows:

var
  zipFileName: TFileName;
begin
  zipFileName := MakePath([Executable.ProgramFilePath, 'TestMultiData.7z']);
  SaveFolderTo7Zip('c:\mORMot2\src\', zipFileName, 'mORMot_2023-05-01', '*.pas;*.inc', {pmNew7Zip=}False, ProgressCallback);
  SaveFolderTo7Zip('c:\mORMot2\src\', zipFileName, 'mORMot_2023-05-02', '*.pas;*.inc', {pmNew7Zip=}False, ProgressCallback);
  SaveFolderTo7Zip('c:\mORMot2\src\', zipFileName, 'mORMot_2023-05-03', '*.pas;*.inc', {pmNew7Zip=}False, ProgressCallback);
  SaveFolderTo7Zip('c:\mORMot2\src\', zipFileName, 'mORMot_2023-05-04', '*.pas;*.inc', {pmNew7Zip=}False, ProgressCallback);
  SaveFolderTo7Zip('c:\mORMot2\src\', zipFileName, 'mORMot_2023-05-05', '*.pas;*.inc', {pmNew7Zip=}False, ProgressCallback);
end;

The result in TestMultiData.7z file looks as expected:

mORMot_2023-05-01\app
mORMot_2023-05-01\core
...
mORMot_2023-05-02\...
mORMot_2023-05-03\...
mORMot_2023-05-04\...
mORMot_2023-05-05\...

I have checked with a tool that compares directories, everything is OK for me.

With best regards
Thomas

#124 mORMot 2 » T7zWriter.SaveToFile, Mode error » 2023-05-05 21:01:02

tbo
Replies: 4

The following source code for testing. If 7z file exists, open it, otherwise create it:

var zipFileName: TFileName := MakePath([Executable.ProgramFilePath, 'TestDaten.7z']);
if FileExists(zipFileName) then
  libWriter := New7zWriter(zipFileName, fh7z)
else
  libWriter := New7zWriter(fh7z);

For it to work, function SaveToFile must be changed as follows:

begin
  fFileName := DestName;
  // f := TFileStreamEx.Create(DestName, fmCreate);
  if fUpdateReader <> Nil then
    f := TFileStreamEx.Create(DestName, fmOpenWrite or fmShareDenyNone)
  else
    f := TFileStreamEx.Create(DestName, fmCreate);
  try
    SaveToStream(f);

Without this change it makes no sense to open a file for editing because it cannot be saved with SaveToFile.

With best regards
Thomas

#125 Re: mORMot 2 » Function I7zWriter.AddFiles » 2023-05-05 18:20:38

tbo

Now these tests have been passed:

libWriter.AddFiles('c:\mORMot2\src\', '', '*', True);
libWriter.AddFiles('c:\mORMot2\src\', 'mORMot_2023-05-05', '*', True);
libWriter.AddFiles('c:\mORMot2\src\', 'mORMot_2023-05-05', '*.pas', True);
libWriter.AddFiles('c:\mORMot2\src\', 'mORMot_2023-05-05', '*.pas;*.inc', True);

With this it works as expected. Thanks for this.

With best regards
Thomas

#126 mORMot 2 » Function I7zWriter.AddFiles » 2023-05-04 20:01:54

tbo
Replies: 2

Delphi 11.3, mORMot2 GitHub commit 5420 (e4ccc8e)

Function I7zWriter.AddFiles:

/// add (or replace) some files from a folder within the archive
procedure AddFiles(const Dir, Path, Wildcard: TFileName; recurse: boolean);

I can't find a reasonable use for the "Path" and "Wildcard" parameters. If I write the following:

libWriter.AddFiles('c:\mORMot2\src\', 'mormot_2023-05-04', '*', True);

The result is a 7z file without files with a directory structure that looks like this:

mormot_2023-05-04\c_\mORMot2\src\app
mormot_2023-05-04\c_\mORMot2\src\core
...

It would be interesting if "Path" was the starting path in the 7z file. Then you could create something like this, for example:

mormot_2023-04-28\app
mormot_2023-04-28\core
...
mormot_2023-05-04\app
mormot_2023-05-04\core

This would be a very useful functionality.

I can't find a useful use for the "Wildcard" either. Only for "*" I get a result. Which values are intended here? The only solution that works for me is:

libWriter.AddFiles('c:\mORMot2\src\', '', '*', True);

I would have liked it better to use FindFiles from unit mormot.core.search here.

With best regards
Thomas

#127 Re: mORMot 2 » Unit mormot.lib.win7zip, memory leak » 2023-05-04 15:21:21

tbo

With Commit 5420 (e4ccc8e), it behaves as expected in my tests. Thanks a lot for that.

With best regards
Thomas

#128 Re: mORMot 2 » Unit mormot.lib.win7zip, memory leak » 2023-05-04 13:16:01

tbo
ab wrote:

There was no leak I am afraid. The TRawByteStream was properly released.
With your soReference modification, I have an access violation now during normal process.

You're right. Sorry, didn't test properly there. That works:

libWriter.AddStream(TRawByteStringStream.Create(content), soReference, faArchive, 0, 0, 'TestFolder', false, false);

A stream with no content for any combination results in an memory leak:

libWriter.AddStream(TRawByteStringStream.Create(''), soReference {soOwned}, faDirectory, 0, 0, 'TestFolder', True, False);

This error message is displayed:

An unexpected memory leak has occurred. The unexpected small block leaks are:
21 - 28 bytes: TRawByteStringStream x 1

Without content it only works properly with soOwned. That was the thread that triggered this post.

With best regards
Thomas

#129 mORMot 2 » function MakeFileName request » 2023-05-01 23:02:05

tbo
Replies: 1

Could a function like this be introduced:

function MakeFileName(const pmcPart: array of const; pmLastIsExt: Boolean): TFileName;
var
  ext: RawUtf8;
begin
  if pmLastIsExt
    and (Length(pmcPart) > 1)
    and VarRecToUtf8IsString(pmcPart[High(pmcPart)], ext) then
  begin
    Result := MakePath(Slice(pmcPart, Length(pmcPart) - 1));
    if (Result <> '')
      and (ext <> '') then
    begin
      if ext[1] = '.' then
        Result := Result + Utf8ToString(ext)
      else
        Result := Result + '.' + Utf8ToString(ext);
    end;
  end
  else
    Result := MakePath(pmcPart);
end;

Then you could write the following without looking at anything:

const
  PNG_EXT = 'png';
begin
  ShowMessage(MakeFileName([Executable.ProgramFilePath, 'One', 'TestFile', PNG_EXT], True));
  ShowMessage(MakeFileName(['C:', 'One', 'TestFile', ExtractFileExt(Executable.ProgramFileName)], True));

With best regards
Thomas

#130 mORMot 2 » Unit mormot.lib.win7zip, memory leak » 2023-05-01 21:08:35

tbo
Replies: 6

Delphi 11.3, mORMot2 GitHub commit 5395 (bda0951)

1) Memory leak in function T7zWriter.AddBuffer. Must soOwned be used and not soReference.

procedure T7zWriter.AddBuffer(const ZipName: RawUtf8;
  const Data: RawByteString);
begin
  AddStream(TRawByteStringStream.Create(Data), soReference,  // <-- soOwned
    faArchive, 0, 0, ZipName, false, false);
end;

2) In function T7zWriter.AddStream should be written:

...
item.Stream := Stream;
// item.Size := Stream.Size;
if Stream <> Nil then
  item.Size := Stream.Size;

3) Can an T7zWriter.AddDirectory function be added?

With best regards
Thomas

#131 Re: mORMot 2 » Record helper for RawUtf8 » 2023-04-28 13:50:39

tbo
ab wrote:

It may help some people, ...

That was the reason I asked. I prefer to answer questions in a forum about programming problems with concrete source code. Most with reference to mORMot. The new functions, which are unknown, often discourage, although the solution, thanks to mORMot, is better. If it was more similar to actual Delphi source code, it could be easier to teach. Rarely you get such a concrete feedback how good the result has become by using mORMot.

With best regards
Thomas

#132 mORMot 2 » Record helper for RawUtf8 » 2023-04-27 21:17:42

tbo
Replies: 7

Could a record helper for RawUtf8 be useful for current Delphi versions?

type
  TRawUtf8Helper = record helper for RawUtf8
  public
    procedure From(const pmcValue: String); inline;
    function ToString: String; inline;
    function ToInteger: Integer; overload; inline;
    function ToInteger(pmDefault: Integer): Integer; overload; inline;
    function ToInteger(pmMin, pmMax: Integer; pmDefault: Integer = 0): Integer; overload; inline;

procedure TRawUtf8Helper.From(const pmcValue: String);
begin
  Self := StringToUtf8(pmcValue);
end;

function TRawUtf8Helper.ToInteger: Integer;
begin
  Result := Utf8ToInteger(Self);
end;

function TRawUtf8Helper.ToInteger(pmDefault: Integer): Integer;
begin
  Result := Utf8ToInteger(Self, pmDefault);
end;

function TRawUtf8Helper.ToInteger(pmMin, pmMax, pmDefault: Integer): Integer;
begin
  Result := Utf8ToInteger(Self, pmMin, pmMax, pmDefault);
end;

function TRawUtf8Helper.ToString: String;
begin
  Result := Utf8ToString(Self);
end;

Then you could write like this:

var
  s: String;
  u: RawUtf8;
begin
  s := '12';
  u.From(s);
  ShowMessage(u.ToString);
  var i: Integer := u.ToInteger(8, 12);

With best regards
Thomas

#133 Re: mORMot 2 » Small mORMot articles with outside view » 2023-04-25 18:31:30

tbo

I have published my seventh article with the topic mORMot here (forum Delphi-PRAXIS). The title is: Realize a JSON-Viewer with DocVariant and Virtual TreeView. The text is written in German, the sourcecode uses english names. Sourcecode and program can be found in the appendix.

The program is a simple JSON-Viewer. With the example code you get:

  • A document can be loaded from a file or imported via the clipboard. It can be saved again in packed format as a file.

  • Individual branches of a document can be saved as a file or exported to the clipboard as an object with extension root node as an attribute.

  • Each branch can be displayed in a separate view window and closed by double-clicking on the tab. In multiple view the delete function is locked.

  • A simple editor to edit values of attributes or to delete entries or whole branches.

Here is the translation into English with Google Translator. The result is not perfect (rather not so good), also some formatting is destroyed, but it is readable.

With best regards
Thomas

#134 mORMot 2 » Small mORMot articles with outside view » 2023-04-25 18:27:05

tbo
Replies: 1

This thread continues the series "A small example in response to a question". The articles were published in German in the Delphi Praxis Forum. Included in the article announcement is a link for translation into English using Google Translator. The result is not perfect, also some formatting is destroyed, but it is readable.

If you liked an article, you can leave a comment in the Delphi-Praxis Forum. It is a friendly forum and comments in English language are possible. If you write a comment, please do not follow each other too quickly, so that the article is well placed in the activities view for a long time.

With best regards
Thomas

#135 Re: mORMot 2 » Unit mormot.core.os, {$ifdef} {$else} » 2023-04-19 15:31:08

tbo
ab wrote:

I don't think so.

You are right. When I look at it in Delphi 11.3, it is highlighted correctly. I had looked at it with another editor and there the display was misleading. I think the spelling {$else OSWINDOWS} confused me because I just write {$else}. Sorry for the wrong warning.

With best regards
Thomas

#136 mORMot 2 » Unit mormot.core.os, {$ifdef} {$else} » 2023-04-19 13:33:52

tbo
Replies: 2

Delphi 11.3, mORMot2 GitHub commit 5323 (752e7f6), unit mormot.core.os

I think the second last {$else OSWINDOWS} is too much here.

{$ifdef OSWINDOWS}  // line 1030

{$ifdef UNICODE}    // line 1032
...
{$else}             // line 1039
...
{$endif UNICODE}    // line 1062
...
{$else OSWINDOWS}   // line 1082
...
{$endif OSWINDOWS}  // line 1101

With best regards
Thomas

#137 Re: Other components » SynMustache and logical conditions. » 2023-04-16 21:48:23

tbo
Bsaidus wrote:

Thanks igor for help, but it do not work for me.

You do not register the default helper, so "IF" is not available to you. You have to write it like this:

mustache.RenderJSON(Context, Nil, TSynMustache.HelpersGetStandardList)

All in all, I would not solve this during generation, but calculate it outside and then pass it. How to use Mustache is described in this article with source code.

With best regards
Thomas

#138 mORMot 2 » Error with output "false" » 2023-04-08 21:27:35

tbo
Replies: 1

Delphi 11.3, mORMot2 GitHub commit 5225 (da76642)

The word "false" is displayed incorrectly in the output. It concerns only the case "false" and not "true". All other data types are also displayed correctly. The string for "false" has the hex value "05 66 61 6C 73", but should have "66 61 6C 73 65". You can reproduce it with following test source code:

var
  p: PDocVariantData;
begin
  p := _Safe(_Json('{"EnableCORS":false}'));
  ShowMessage(Utf8ToString(FormatUtf8('%: %', [p.Names[0], p.Value[0]])));

With best regards
Thomas

#139 Re: mORMot 1 » WEB authentication using MORMOT » 2023-03-31 14:50:47

tbo
radexpol wrote:

I know what you're feeling, I had the same problem on this forum and couldn't find the solution that stopped my progress. Everyone suggest me the holy documentation that I don't understand and it does not show the real solutions. I hate documentation, a lot of simple samples is enough in many other projects such as DevExpress, DMVC and many many more. Does someone read DevExpress documentation to start making cool apps ?? No visual components, no real support, very slow responses, hard developing for every stupid projects, no simple swagger integration.

When I look at your profile, you've only asked questions here, never really helped others, and yet you've always been answered. When I read your comment, I think: Find the mistake!

#140 Re: mORMot 2 » assign a part of a TdocVariant to a record » 2023-03-31 14:46:12

tbo
dcoun wrote:

I have a Tdocvariant in a variant variable and I want to assign a part of it ("var1") to an other pascal variable (var1) which is a record with the same structure.

Do you mean this?

type
  TArrItem = packed record
    a, b: RawUtf8;
  end;

  TDataItem = packed record
    v1: array of TArrItem;
    v2: RawUtf8;
  end;

  TDataItemList = array of TDataItem;

const
  JSON_DATA: RawJson = '{"var1":[{"v1":[{"a":"1","b":"2"},{"a":"3","b":"4"}],"v2":"something"}]}';
var
  doc: TDocVariantData;
  list: TDataItemList;
begin
  doc.InitJson(JSON_DATA, mFastFloat);
  if DynArrayLoadJson(list, Pointer(doc.A['var1'].ToJson), TypeInfo(TDataItemList)) <> Nil then
    ShowMessage(Utf8ToString(FormatUtf8('% - %', [list[0].v1[0].a, list[0].v2])));

Arnaud does it in a similar way in a few places.

With best regards
Thomas

#141 Re: mORMot 1 » WEB authentication using MORMOT » 2023-03-30 16:13:55

tbo
claudneysessa wrote:

A little empathy is lacking in wanting to help others.

If you want help, you should allow it. A good start would be to answer my first question. The following start, for example, would be helpful:

Server: Delphi 11.3, mORMot2 GitHub commit 5186
My web application is a PWA. I would like to implement the authentication with JavaScript.

If someone has something suitable, they will help you. It has worked for thousands of others.

If no one has an answer, then follow my second recommendation. Look at the respective implementation in the units mormot.rest.server and mormot.rest.client. In the unit mormot.rest.client you will find the class TRestClientAuthenticationDefault. Set a breakpoint in the relevant functions (ClientComputeSessionKey etc.) and follow the further steps.

With best regards
Thomas

#142 mORMot 2 » GitHub Commit 1460ba7 (5186) » 2023-03-30 15:39:45

tbo
Replies: 1

Delphi 11.3, mORMot2 GitHub commit 5186
Unit mormot.net.sock.pas, line 1891

[dcc32 Fehler] mormot.net.sock.pas(1891): E2004 Bezeichner redeklariert: "ip4"
[dcc32 Fehler] mormot.net.sock.pas(1891): E2004 Bezeichner redeklariert: "port"

The following prevents it:

function TNetAddr.SetIP4Port(pmIP4: cardinal; pmPort: TNetPort): TNetResult;

With best regards
Thomas

#143 mORMot 2 » Extend AuthenticationRegister function » 2023-03-29 20:26:06

tbo
Replies: 1

Until some time ago, the following could be written:

CreateWithOwnModel([TAuthGroup, TFileAuthUser], {HandleUserAuthentication=} False, pmcRootName);
// Register authentication methods selectively
AuthenticationRegister(TRestServerAuthenticationDefault);

Now the following must not be forgotten to be added:

fPublishedMethodAuthIndex := ServiceMethodRegister('auth', Auth, {bypassauth=}true, [mGET]);

Couldn't the AuthenticationRegister function be extended and do it at the same time?

AuthenticationRegister(aMethod: TRestServerAuthenticationClass; pmRegisterAuthMethod: Boolean = True): TRestServerAuthentication;

With best regards
Thomas

#144 Re: mORMot 1 » WEB authentication using MORMOT » 2023-03-29 19:24:06

tbo
claudneysessa wrote:

I'm asking for help because I've tried everything exactly as stated in the manual, in the doc on the forums... And I can't find the problem

First of all, you didn't write which programming language you are working with.

It could be that the source code for JS authentication you find in the forum is no longer up to date. In any case, you have to read the documentation. If you don't understand the process from the description, write a simple Delphi example for server and client, or take an existing example and follow the process in the debugger. It is helpful at the beginning if you first switch off the timestamp check on the server. You do this like this:

(AuthenticationRegister(TRestServerAuthenticationDefault) as TRestServerAuthenticationSignedUri).NoTimestampCoherencyCheck := True;

With best regards
Thomas

#145 Re: mORMot 2 » TOrm with ChildObjects » 2023-03-08 16:44:04

tbo
mrbar2000 wrote:

2) This model create 2 tables Painel and Projeto but fill just Projeto and create a string field into Projeto table to store all TPanel as json. How I can store projeto and painel in diferent tables, but yet so make the same RETRIEVE above?

Look closely at my source code from Post #4 and extend your service function with the one shown there for loading TPaineis here. You will get the desired result only with a DTO. A direct generation from the ORM is not possible with your specifications.

With best regards
Thomas

#146 Re: mORMot 2 » TOrm with ChildObjects » 2023-03-07 16:52:22

tbo
mrbar2000 wrote:

What type of TOrmPhoneObjArray? and How I can get a person id=? and the orm bring the person with all phones?

type TOrmPhoneObjArray = array of TOrmPhone; Class TObjectWithID has the property IDValue. Just try my source code.

With best regards
Thomas

#147 Re: mORMot 2 » TOrm with ChildObjects » 2023-03-07 16:45:07

tbo
mrbar2000 wrote:

1) Will be dificult mount reports. because by default FastReport and others reports generators work with Datasets, then we need get the records master detail in tables.

FastReport can work with many sources, DataSets are just one of them. Read this article. This type of connection is much more flexible.

mrbar2000 wrote:

3) How to find something into objects that are store in this field blob?

It does not have to be stored in a blob field. It can also be stored as JSON. SQLite, for example, can execute queries directly on these fields. Read this article for more information.

mrbar2000 wrote:

How u treat this? Store all objects as documents (nosql style)?

We don't know your requirements. mORMot can be operated in many ways and is not limited to one. The help is extensive, many questions have already been answered in the forum and there are articles to be found on the internet. The best is to create a small example for each possibility and see if it fits for your own application.

With best regards
Thomas

#148 Re: mORMot 2 » How delphi to deserialization json as std::map » 2023-03-06 22:24:55

tbo
chen ken wrote:

But I can't use a json string , such as :"{"name":"mark","data":[1,2,3,4,5],"some":{"11.1":"Hello","22.2":",","44.4":"World"}}".

const
  _JSON = '{"name":"mark","data":[1,2,3,4,5],"some":{"11.1":"Hello","22.2":",","44.4":"World"}}';
var
  doc: TDocVariantData;
begin
  if doc.InitJson(_JSON) then
  begin
    ShowMessage(doc.S['name']);
    ShowMessage(doc.O['some'].S['11.1']);
    ShowMessage(VarToStr(doc.A['data'].Value[1]));
  end;

With best regards
Thomas

#149 Re: mORMot 2 » TOrm with ChildObjects » 2023-03-06 22:10:33

tbo

I don't really understand your description. The problem is that there are several ways to solve it. If it is necessary for you to have the phone numbers in a separate table, you can use one of the following options (there are even more possibilities):

type
  TOrmPersonID = type TID;

  TOrmPhone = class(TOrm)
  private
    FPersonID: TOrmPersonID;
  published
    property PersonID: TOrmPersonID
      read FPersonID write FPersonID;

  TOrmPerson = class(TOrm)
  public
    property Phones: TOrmPhoneObjArray

procedure TOrmPerson.GetAllPhones(out pmoList: TOrmPhoneObjArray);
const
  _SQL_WHERE = '(PersonID=?)';
begin
  RestServer.Server.RetrieveListObjArray(pmoList, TOrmPhone, _SQL_WHERE, [IDValue]);
end;

Or another option:

type
  TOrmPerson = class(TOrm)
  private
    FPhones: TIDDynArray;
  public
    function AddPhone(const pmPhoneID: TID): Integer;
    procedure DeletePhone(const pmPhoneID: TID);
  published
    property Phones: TIDDynArray
      read FPhones;

function TOrmPerson.AddPhone(const pmPhoneID: TID): Integer;
begin
  Result := AddInt64Once(TInt64DynArray(FPhones), pmPhoneID);
end;

procedure TOrmPerson.DeletePhone(const pmPhoneID: TID);
var
  idx: Integer;
begin
  idx := Int64ScanIndex(Pointer(FPhones), Length(FPhones), pmPhoneID);
  if idx >= 0 then
    DeleteInt64(TInt64DynArray(FPhones), idx);
end;

It is easier if you save the phone numbers in the people table as a list (TObjectList<TPhone>), without creating a Phone table. If you have been working with databases for a while, you have to get used to this technique.

With best regards
Thomas

#150 Re: mORMot 2 » Serializing an array of records How To? » 2023-02-23 16:02:11

tbo

If you want to look at the JSON functionality mentioned by ttomas, you can find the example ORM-DocVariant here.

With best regards
Thomas

Board footer

Powered by FluxBB