#1 Re: mORMot 2 » Can u see if there some bug mine or of mormot here? » 2024-03-07 21:01:18

Arnold

First of all I want to congratulate you on the mormot. this is a great framework. Despite the vast documentation, many things are evident in it for those who are starting to use the framework.

I would like to understand the reason for this limitation, I am not talking about complex queries here, just talking about the fields to be returned by the ORM query.

This is not a complex query, I simply do the join to filter the records in the where clause.

From what I understand when using VirtualTableExternalRegisterAll with SQLITE_MEMORY_DATABASE_NAME my ID fields have to be treated as RowId when mentioning them in my source code. mormot will automatically convert RowID to ID to run against the database. Am I right?

What I don't understand is why something as basic as returning fields cannot be done in a simple way and consistent with what programmers are used to doing. Again this is not a criticism but an attempt to improve mormot so that we can make mormot closer to what programmers are used to.

So here samples that shouls be works IMHO:

vAmostras := FRestOrm.Orm.RetrieveDocVariantArray(TAmostra, '', 'left outer join Solicitacao s on (s.RowId = Amostra.solicitacao)', [],  'RowID');
Should be bring all Amostra records, just field ID, but mormot raise error "no such column: RowId" and not is because join

vAmostras := FRestOrm.Orm.RetrieveDocVariantArray(TAmostra, '', 'left outer join Solicitacao s on (s.RowId = Amostra.solicitacao)', [],  '');
vAmostras := FRestOrm.Orm.RetrieveDocVariantArray(TAmostra, '', 'left outer join Solicitacao s on (s.RowId = Amostra.solicitacao)', [],  '*');
vAmostras := FRestOrm.Orm.RetrieveDocVariantArray(TAmostra, '', 'left outer join Solicitacao s on (s.RowId = Amostra.solicitacao)', [],  'Amostra.*');
All this should be bring the samething, all  amostra records.
by your documentation, the last parameter as '' should be bring all fields except RowId/Id and blob fields

vAmostras := FRestOrm.Orm.RetrieveDocVariantArray(TAmostra, '', 'left outer join Solicitacao s on (s.RowId = Amostra.solicitacao)', [],  'Amostra.*, s.*');
Should be bring all Amostra records and all fields, and all fields of solicitacao (as extra properties on variant).

What I mean is that it doesn't matter that the joins I put on where, should return only TORM´s fields passed on first parameter.
Unless I put join fields in the fields, but in this case I will be bringing the information in json without any problems

#2 mORMot 2 » Can u see if there some bug mine or of mormot here? » 2024-03-06 20:53:41

mrbar2000
Replies: 2

I have this instruction:

var
  vAmostras: Variant;
begin
  vAmostras := FRestOrm.Orm.RetrieveDocVariantArray(TAmostra, '',
    'left outer join Solicitacao s on (s.RowId = Amostra.solicitacao)',
    [],  <MYFIELDS>);
...
end;

I make many tests replacing <MYFIELDS>

<MYFIELDS> = 'RowId'
Log: EXC       ESqlite3Exception {Message:"Error SQLITE_ERROR (1) [SELECT RowId FROM Amostra left outer join Solicitacao s on (s.RowId = Amostra.solicitacao)] using 3.44.2 - no such column: RowId",ErrorCode:1,SQLite3ErrorCode:"secERROR"} [Main] at 8f207c


<MYFIELDS> = 'Id'
Log: EXC            ESqlite3Exception {Message:"Error SQLITE_ERROR (1) [SELECT Id FROM Amostra left outer join Solicitacao s on (s.RowId = Amostra.solicitacao)] using 3.44.2 - no such column: Id",ErrorCode:1,SQLite3ErrorCode:"secERROR"} [Main] at 8f207c

<MYFIELDS> = 'amostra.RowId, s.numero, amostra.numero'
Log: works and bring Amostra ID rightly

<MYFIELDS> = 'amostra.Rowid, amostra.*'
Log: works and return amostra.Id, others fields...

<MYFIELDS> = 'amostra.*, s.numero, amostra.numero'
Log: works but dont return amostra.Id neither amostra.RowId

<MYFIELDS> = 'amostra.RowId'
Log: don't execute sql nothing at logger

<MYFIELDS> = 'amostra.Id'   
Log: don't execute sql nothing at logger

<MYFIELDS> = 'amostra.*'
Log: don't execute sql nothing at logger

<MYFIELDS> = 'amostra.Id, s.numero, amostra.numero'
Log: EXC       ESqlite3Exception {Message:"Error SQLITE_ERROR (1) [SELECT amostra.Id, s.numero, amostra.numero FROM Amostra left outer join Solicitacao s on (s.RowId = Amostra.solicitacao)] using 3.44.2 - no such column: amostra.Id",ErrorCode:1,SQLite3ErrorCode:"secERROR"} [Main] at 8f207c

<MYFIELDS> = '*'
Log:  EXC       ESqlite3Exception {Message:"Error SQLITE_ERROR (1) [SELECT RowID,DataCriacao,UltimaAlteracao,Numero,Solicitacao,Exames,DataEtiqueta,Rack,Linha,Coluna FROM Amostra left outer join Solicitacao s on (s.RowId = Amostra.solicitacao)] using 3.44.2 - no such column: RowID",ErrorCode:1,SQLite3ErrorCode:"secERROR"} [Main] at 8f207c

<MYFIELDS> = ''
Log: EXC       ESqlite3Exception {Message:"Error SQLITE_ERROR (1) [SELECT RowID,DataCriacao,UltimaAlteracao,Numero,Solicitacao,Exames,DataEtiqueta,Rack,Linha,Coluna FROM Amostra left outer join Solicitacao s on (s.RowId = Amostra.solicitacao)] using 3.44.2 - no such column: RowID",ErrorCode:1,SQLite3ErrorCode:"secERROR"} [Main] at 8f207c

I forgot my configuration:

  FConfigDB := TSqlDBPostgresConnectionProperties.Create(
    '191.101.78.31:5001',
    'DB_SOROTRACK',
    'microprocess',
    'mpPost19dokcer!');
  FOrmModel := CreateModel;
  VirtualTableExternalRegisterAll(FOrmModel, FConfigDB);
  FOrmModel.Props[TAmostra].ExternalDB.MapField('Solicitacao', 'IdSolicitacao');
  FRestOrm := TRestClientDB.Create(FOrmModel, nil, SQLITE_MEMORY_DATABASE_NAME, TRestServerDB, false, '');
  FRestOrm.Server.Server.CreateMissingTables;

I want use ORM but can put my owner sqls too.
I read and reread documentation and dont understand when use RowID or ID (my field) too.

#3 Re: mORMot 2 » How to define alias to TOrm use on RetrieveDocVariant » 2024-03-04 19:49:28

Other thing I'm doing a POST passing filter on body

{{URL}}/amostra/listar
    .Post('/amostra/listar', 'amostraService/listaramostras')

  TFiltro = packed record
    Amostra: RawUTF8;
    EventoTipo: Integer;
    Solicitacao: RawUTF8;
    Paciente: RawUTF8;
    Posto: RawUTF8;
    PeriodoTipo: Integer;
    PeriodoInicial: TDateTime;
    PeriodoFinal: TDateTime;
  end;

function TAmostraService.ListarAmostras(const pFiltro: TFiltro): TServiceCustomAnswer;

Why I have to pass:

[{ "Amostra": "1234567891"}]

instead of

{ "Amostra": "1234567891" }

???

#4 Re: mORMot 2 » How to define alias to TOrm use on RetrieveDocVariant » 2024-03-04 19:44:29

Great, I'm testing.

Arnold I think I found a possible bug:

FRestOrm.Orm.RetrieveDocVariantArray(TAmostra, '', FWhere, TDocVariantData(FWhereParamValues).ToArrayOfConst,
     'Amostra.*') <<<<< this doesn't work. I lost a time debugging

FRestOrm.Orm.RetrieveDocVariantArray(TAmostra, '', FWhere, TDocVariantData(FWhereParamValues).ToArrayOfConst,
     '*') <<<<< this work

#5 mORMot 2 » How to define alias to TOrm use on RetrieveDocVariant » 2024-02-29 15:38:38

mrbar2000
Replies: 4

Question 1
var
  vAmostras: Variant;
...
  vAmostras := FRestOrm.Orm.RetrieveDocVariantArray(TAmostra, '',
    'left outer join Solicitacao s on (s.RowId = Amostra.solicitacao)', [], 's.numero, s.paciente, Amostra.*');

>>>  SELECT s.numero, s.paciente, amostra.* FROM Amostra left outer join solicitacao s on (s.Id = Amostra.solicitacao)

I whould like define a alias to orm amostra  ===> a

  vAmostras := FRestOrm.Orm.RetrieveDocVariantArray(TAmostra, '',
    'left outer join Solicitacao s on (s.RowId = a.solicitacao)', [], 's.numero, s.paciente, a.*');

>>>  mormot cannot execute this select because it don't know about alias A.

i try too:

  vAmostras := FRestOrm.Orm.RetrieveDocVariantArray(TAmostra, '',
    'a left outer join Solicitacao s on (s.RowId = a.solicitacao)', [], 's.numero, s.paciente, a.*');

but mormot generate this select

>>>  SELECT s.numero, s.paciente, a.* FROM Amostra WHERE a left outer join solicitacao s on (s.Id = Amostra.solicitacao)

Question 2

There is some way to pass the raw sql to orm? something like below. Be by ORM or other method do RestORM or other way?

  vAmostras := FRestOrm.Orm.RetrieveDocVariantArray(TAmostra,
      'SELECT s.numero, s.paciente, a.* FROM Amostra a '+
      'left outer join solicitacao s on (s.Id = Amostra.solicitacao) '+
      'WHERE s.numero = ?', [12345]);

#6 mORMot 2 » TormMany with diferent source and dest fieldnames » 2024-02-21 21:04:03

mrbar2000
Replies: 1

I have this class.

  TContatos = class(TOrmMany)
  private
    FSource: TPessoa;
    FDest: TContato;
  published
    property Source: TPessoa read FSource;
    property Dest: TContato read FDest;
  end;

mormot create table with: id, source, dest
How to do mormot create the table with:
id, pessoa, contato?
or
id , pessoaid, contatoid?

#7 mORMot 2 » Get Objects and your relations » 2024-02-21 20:47:25

mrbar2000
Replies: 0

Sry brind this questions but I need help.

this is my model:

  TContatos = class(TOrmMany)
  private
    FSource: TPessoa;
    FDest: TContato;
  published
    property Source: TPessoa read FSource;
    property Dest: TContato read FDest;
  end;
  
  TContato = class(TOrm)
  private
    FTelefone: RawUTF8;
    FEmail: RawUTF8;
  published
    property Telefone: RawUTF8 read FTelefone write FTelefone;
    property Email: RawUTF8 read FEmail write FEmail;
  end;
  
  TRacas = (rPoodle, rViraLata, rPitbull, rShawShaw);

  TPet = class(TOrm)
  private
    FRaca: TRacas;
    FNome: RawUTF8;
    FDono: TPessoa;
  published
    property Raca: TRacas read FRaca write FRaca;
    property Nome: RawUTF8 read FNome write FNome;
    property Dono: TPessoa read FDono write FDono;
  end;
  
  TCidade = class(TOrm)
  private
    FNome: RawUTF8;
  published
    property Nome: RawUTF8 read FNome write FNome;
  end;

  TPessoa = class(TOrm)
  private
    FNome: RawUTF8;
    FIdade: Integer;
    FCidade: TCidade;
    FContatos: TContatos;
    FPets: TObjectList;
  public
    function NewContato(const pEmail, pFone: RawUtf8): TContato;
    function NewPet(const pRaca: TRacas; const pNome: RawUTF8): TPet;
    property Pets: TObjectList read FPets write FPets;
    destructor Destroy; override;
  published
    property Nome: RawUTF8 read FNome write FNome;
    property Idade: Integer read FIdade write FIdade;
    property Cidade: TCidade read FCidade write FCidade;
    property Contatos: TContatos read FContatos write FContatos;
  end;

this is my data on database

Pessoa
id,"nome","idade","cidade"
1,"Pedro","25","1"
2,"Maria","39","2"

pet
id,"raca","nome","dono"
1,0,"miau","1"
2,1,"auau","1"
3,3,"goal","1"
4,1,"sansao","2"

cidade
id,"nome"
1,"Conquista"
2,"Jequié"

contato
id,"telefone","email"
1,"77 988526666","pedro@gmail.com"
2,"77 988526666","joao@gmail.com"
3,"73 999566489","jose@gmail.com"

contatos
id,"source","dest"
1,"1","1"
2,"1","2"
3,"2","3"
4,"2","1"

There is some way to retrieve all Pessoa with all properties? Cidade, Contatos, Pets, How can I do this?

my tries:

var
  vPessoas: TPessoa;
  vCidade: TCidade;
  vContato: TContato;
  vOrm: IRestOrm;
  vIdPessoa: TID;
  vI: Integer;
begin
  vPessoas := TPessoa.CreateAndFillPrepareJoined(FRestOrm.Orm, '', [], []);
  try
	  Memo2.Lines.Add(Format('Quantidade de pessoas: %d', [vPessoas.FillTable.RowCount]));  // ok return 2 pessoa
	  while vPessoas.FillOne do
	  begin
      Memo2.Lines.Add(Format('Id: %d', [vPessoas.ID]));
      Memo2.Lines.Add(Format('Nome: %s', [vPessoas.Nome]));
      Memo2.Lines.Add(Format('Idade: %d', [vPessoas.Idade]));
      Memo2.Lines.Add(Format('Cidade: %s', [vPessoas.Cidade.Nome]));

      vPessoas.Contatos.FillPrepareMany(FRestOrm.Orm, 'RowId>=?', [], [vPessoas.ID]);
      Memo2.Lines.Add(Format('Quantidade de Contatos: %d', [vPessoas.Contatos.FillTable.RowCount])); // ERROR HERE. return 0 should be 2 (pedro and joao) <<<<<<
      while vPessoas.Contatos.Dest.FillOne do  // fillone return false
      begin
        Memo2.Lines.Add(Format('  Contato: %s - %s', [vI, vPessoas.Contatos.Dest.Email, vPessoas.Contatos.Dest.Telefone])); //is not retrieving email and telefone value
      end;
      vPessoas.FillClose;

      // pets is nil on this moment then i do this, but i don´t know if is the better aproach.  <<<<<<

      vPessoas.Pets := FRestOrm.RetrieveList(TPet, 'dono=?', [vPessoas.Id]);
      Memo2.Lines.Add(Format('Quantidade de Pets: %d', [vPessoas.Pets.Count]));  ok 3 from first pessoa and 1 to second
      for vI := 0 to vPessoas.Pets.Count-1 do
        Memo2.Lines.Add(Format('  Pets %d: %s', [vI, TPet(vPessoas.Pets[vI]).Nome]));

      Memo2.Lines.Add('-----------------------');

      vPessoas.Pets.Clear;
      vPessoas.Pets.Free;
      vPessoas.Pets := nil;
	  end;
  finally
	  vPessoas.Free;
  end;

 

I try too
vPessoas := TPessoa.CreateAndFillPrepareMany(FRestOrm.Orm, '', [], []); 
but this way it retrieve 4 pessoa on while

I try too
vPessoas.Contatos.FillPrepareMany(FRestOrm.Orm, 'RowId>=?', [], [vPessoas.ID]);
but vPessoas.Contatos.FillTable.RowCount return 0 and vPessoas.Contatos.FillOne return false

I try too
vPessoas.Contatos.FillMany(FRestOrm.Orm, vPessoas.ID);
vPessoas.Contatos.FillTable.RowCount return 2 ok but vPessoas.Contatos.FillOne return false

Oh my god!!!! I read documentation already and cannot make this work.

#8 mORMot 2 » How to make where in column text json » 2024-02-01 12:26:33

mrbar2000
Replies: 1

Hello Community,

I'm facing a challenge with my API and would appreciate your help.

1 - In my project, I have the "TAmostra" table, where one of the columns is "Dados", of type "TDados", containing various fields.

  TDados = packed record
    NumeroSolicitacao: RawUTF8;
	DataSolcitacao: TDateTime;
    Exames: RawUTF8;
    Paciente: RawUTF8;
    Posto: RawUTF8;
    Atendente: RawUTF8;
    DataEtiqueta: TDateTime;
    Temperatura: Double;
    Motivo: RawUTF8;
    Rack: RawUTF8;
    Linha: RawUTF8;
    Coluna: Int64;
  end;

  TAmostra = class(TOrm)
  private
    FNumero: RawUTF8;
    FDados: TDados;
  published
    property Numero: RawUTF8 index 40 read FNumero write FNumero;
    property Dados: TDados read FDados write FDados;
  end;
  
  TEvento = class(TOrm)
  private
    FTipo: TTipoEvento;
    FAmostra: TAmostra;
  published
    property Id: 
    property Tipo: TTipoEvento read FTipo write FTipo;
    property Amostra: TAmostra read FAmostra write FAmostra;
  end;  

How can I create a SELECT query to Evento join with Amostra by Dados.DataSolcitacao? SomethingLike:

SELECT A.*
FROM EVENTO A
LEFT OUTER JOIN AMOSTRA B ON (B.ID = A.ID)
WHERE B.AMOSTRA.DADOS.DATASOLICITACAO BETWEEN '01.12.2023' AND '01.01.2024'

if this not is possible, i can transform TDados in TOrm too, add TDados into TAmostra. then how make this retrieve on ORM?

SELECT A.*
FROM EVENTO A
INNER JOIN AMOSTRA B ON (B.ID = A.ID)
INNER JOIN DADOS C ON (C.ID = B.IDSOLCITACAO)
WHERE C.DATASOLICITACAO BETWEEN '01.12.2023' AND '01.01.2024'

I appreciate any guidance or suggestions you can offer.

Best regards,

#10 Re: mORMot 2 » Differences in quering database from mormot2 » 2023-12-11 11:51:47

This is really very confusing!!!! RowID e ID

#11 mORMot 2 » Great performance framework » 2023-11-27 20:08:29

mrbar2000
Replies: 8

Hi A. Bouchez

A friend mine was comparing some REST frameworks delphi:

horse (use indy or nethttp) https://github.com/HashLoad/horse
restdataware (use indy or nethttp) 
brooks framework (luse ibsagui Cross-platform library) https://github.com/risoflora/brookframework

We was impressive with benchmarks results with this comparassion.
this lib https://risoflora.github.io/libsagui/ is very very very faster and secure. more fast than HTTP.SYS and it is cross-plataform yet.

I know that u like adjust your framework to get more and more peformance.
My intention is this too.

U make a benchmark tool a sometime ago about this, where we can found this tests? can u include this lib on this benchmarks?

#12 Re: mORMot 2 » MVC and delete requests » 2023-11-27 19:48:42

ab wrote:

Note that the MVC requests are expected to be regular HTTP/Web request from HTML, so are usually GET and sometimes POST (from a form).
....
Please try https://github.com/synopse/mORMot2/commit/82ecb05f

Arnold I see your commit and I think that u put erro on your code no?

fAllowedMethods by default is [mGET, mPOST] but in some parts of code was [mGET, mHEAD]

sample

    if publishMvcInfo in fPublishOptions then
      fRestServer.ServiceMethodRegister(
before:
        MVCINFO_URI, RunOnRestServerRoot, bypass, [mGET, mHEAD]);
now:
        MVCINFO_URI, RunOnRestServerRoot, bypass, fAllowedMethods);

#13 Re: mORMot 2 » Can I call SOAP Server using mormot? » 2023-09-29 12:30:45

I understand u AB!

But we cannot force old companies chage your server to REST. Many companies using SOAP/XML.
I just would like some http socket client that could send a xml soap to this kind of server.

There some way? What base class could i use?

#14 mORMot 2 » Can I call SOAP Server using mormot? » 2023-09-28 15:55:36

mrbar2000
Replies: 3

What class I can use to call a third server that use SOAP?
I don´t would like use delphi THttpRIO!

#15 Re: mORMot 2 » TDocVariantData.AddOrUpdateValue seens dont work to variants values » 2023-08-21 20:31:46

I think that I found a problem guys.

var
  vParams1, vParams2: TDocVariantData;
  vJson: String;
begin
  vParams1.InitJson('{}');
  vQueryTmp := NewQuery(' SELECT * FROM EST_ENTRADA_ITEM WHERE CD_ENTRADA_ITEM = 8', []);
  vParams.AddOrUpdateValue('RetVariant1', vQueryTmp.FieldByName('CD_ENTRADA_ITEM').Value);  // integer field
  vParams.AddOrUpdateValue('RetVariant2', vQueryTmp.FieldByName('VL_TOTAL').Value);  // float field VarTypeAsText(VarType(pValue)) => double
  vParams.AddOrUpdateValue('RetVariant3', vQueryTmp.FieldByName('ST_NOTA_ITEM').Value); // smallint field
  vParams.AddOrUpdateValue('RetVariant4', vQueryTmp.FieldByName('DT_CONFIRMACAO').Value);  // datetime field
  vParams.AddOrUpdateValue('RetVariant5', vQueryTmp.FieldByName('VL_RECEBIDO').Value); // numeric(15,2) field (currency)

  vJson := vParams1.ToJson;
  // vJson = '{"RetVariant1":8,"RetVariant2":39.9000015258789,"RetVariant3":1,"RetVariant4":"2019-03-15T16:12:21","RetVariant5":29.24}'

  vParams2.InitJson(vJson);
  vJson := vParams1.ToJson;
  // '{"RetVariant1":8,"RetVariant2":"39.9000015258789","RetVariant3":1,"RetVariant4":"2019-03-15T16:12:21","RetVariant5":29.24}'

Why RetVariant2 change to a string? Why not hold 39.9000015258789?

I see that if I does
vParams2.InitJson(vJson, [dvoAllowDoubleValue]);
the value is converted correctly.

by default the options is []?

#16 Re: mORMot 2 » TDocVariantData.AddOrUpdateValue seens dont work to variants values » 2023-08-18 19:43:34

I solve this way. I hope that do not apear others type of variant. smile

function TCallServerParams.SetParam(const pName: String; pValue: Variant): ICallServerParams;
var
  vSqlTimeStamp: TSQLTimeStamp;
  vDateTime: TDateTime;
begin
  if VarIsSQLTimeStamp(pValue) then
  begin
    vSqlTimeStamp := VarToSQLTimeStamp(pValue);
    vDateTime := SQLTimeStampToDateTime(vSqlTimeStamp);
    FParams.AddOrUpdateValue(pName, vDateTime)
  end else
    FParams.AddOrUpdateValue(pName, pValue);
  Result := Self;
end;

#17 Re: mORMot 2 » TDocVariantData.AddOrUpdateValue seens dont work to variants values » 2023-08-18 18:18:23

tbo wrote:

You can play a bit with SQLTimeStampVariantType. Delphi just needs to know what you want:

var value: Variant := VarSQLTimeStampCreate(Now);  // <- Variant of type SQLTimeStampVariantType

Or have a look in Unit Data.SqlTimSt at class TSQLTimeStampData and TSQLTimeStampVariantType.

With best regards
Thomas

I know that if i convert the variant all works TBO. But I need avoid that my programmers fails during use of this. then I was thinking generate a exception on cases were the mormot cannot identify the vartype! Do you understand?

#18 Re: mORMot 2 » TDocVariantData.AddOrUpdateValue seens dont work to variants values » 2023-08-18 18:16:20

ab wrote:

I don't think such a method exists.

But its possible make it?

Where I can find on source code mormot.variants what vartypes it can treat?

#19 Re: mORMot 2 » TDocVariantData.AddOrUpdateValue seens dont work to variants values » 2023-08-18 14:27:59

Thanks guys.

A last question. There are something function to validate a variant type to know when mormot does not know what to do with the value of this variant?

#20 Re: mORMot 2 » TDocVariantData.AddOrUpdateValue seens dont work to variants values » 2023-08-17 20:55:15

I know that using. FieldByName('DT_NASC').AsDateTime or VarToDateTime(...) works
but some other programmer can do not use this way and cause erros on runtime!

There are something that can be done on mormot internal to dont need make this conversion by hand????

#21 Re: mORMot 2 » TDocVariantData.AddOrUpdateValue seens dont work to variants values » 2023-08-17 14:20:08

I have edited my post.

ShowMessage(VarTypeAsText(VarType(vValue))) => SQLTimeStampVariantType

looking for this type i found in SqlTimst.pas

TSQLTimeStampVariantType = class(TPublishableVariantType)
SQLTimeStampVariantType: TSQLTimeStampVariantType = nil;

I think that this type of variant not is treated by TDocVariantData

How we can resolve this?

#22 mORMot 2 » TDocVariantData.AddOrUpdateValue seens dont work to variants values » 2023-08-16 20:50:47

mrbar2000
Replies: 14
var
  vValue: Variant;
  vQueryTmp: TSQLQuery;
  vParams: TDocVariantData;
const
  cSQL = ' SELECT DT_NASC FROM PACIENTE WHERE CD_PACIENTE = 1';
begin
  vQueryTmp := NewQuery(cSQL, []);
  try
    vQueryTmp.First;
    vValue := vQueryTmp.FieldByName('DT_NASC').Value;  // vValue here has '01/07/2020'
  finally
    FreeQuery(vQueryTmp);
  end;
  vParams.InitJson('{}');
  vParams.AddOrUpdateValue('MyInt', 10);
  vParams.AddOrUpdateValue('MyBoolean', True);
  vParams.AddOrUpdateValue('MyVariantDate', vValue);
 

   
  ShowMessage(vParams.ToJson)  => {"Myint":10,"MyBoolean":true,"MyVariantDate":null}' ?????

  I was expecting {"Myint":10,"MyBoolean":true,"MyVariantDate": '2020-07-01T00:00:00'}'

What I should?

#23 Re: mORMot 2 » Doubts about rsoSessionInConnectionOpaque » 2023-08-16 03:54:50

Tnks. I will study Better the auth mechanism I want jwt with authuser and authsession control.

#24 mORMot 2 » Doubts about rsoSessionInConnectionOpaque » 2023-08-14 16:07:41

mrbar2000
Replies: 2

When i ahould be use this in rest options?

#25 mORMot 2 » I found a bug during register service » 2023-08-02 21:01:18

mrbar2000
Replies: 1

i have created this record

  TUsuarioRecuperaSenha = packed record
    UserPass: RawByteString;
  end;
...
TUsuarioService = class(TServiceBase, IUsuarioService)
    function TrocaSenha(const pUsuario: TUsuarioTrocaSenha) : TServiceCustomAnswer;
...
GetApp.RegisterService(TUsuarioService, [TypeInfo(IUsuarioService)]);
GetApp.Put('/usuariotrocasenha', 'usuarioService/trocasenha');

I got erro on this part of mormot

constructor TInterfaceFactory.Create(aInterface: PRttiInfo);
...
        imvRecord:
          if ArgRtti.Size <= POINTERBYTES then     <<<<<<<<<<<<<<<<<<< shouldnt be "if ArgRtti.Size < POINTERBYTES then"  ??????????
            raise EInterfaceFactory.CreateUtf8(
              '%.Create: % record too small in %.% method % parameter: it ' +
              'should be at least % bytes (i.e. a pointer) to be on stack',
              [self, ArgTypeName^, fInterfaceName, URI, ParamName^, POINTERBYTES]);

If i put more fields on record it works

#26 mORMot 2 » Anyone has a JWT Authentication scheme » 2023-08-02 20:46:17

mrbar2000
Replies: 1

I see some posts on group about jwt. for sample:
1. https://synopse.info/forum/viewtopic.php?id=4840

but i have some problems with retrieve session, release session, etc..?
the implementation create 1 session to each request, when should be by user (TAuthSession.AuthUser).
I need refreshtoken too.
Anyone has a more complete implementation?
Anyone can help us?

#27 Re: mORMot 2 » Doubts about Variant with latebinding. » 2023-07-27 12:56:45

ab wrote:

To be honest, I don't expect "with ... do begin ... end" to work with late binding.
It is very confusing for the compiler and human reader.
Whatever solution you would find (like a pointer) just adds confusion.

I won't use late binding for such code, but rather TDocVariantData.Update([]) by name/value pairs.
Perhaps with _Safe().

You sugestion is something like this?

  TMyClasse = class
  private
    FParams: TDocVariantData;
  public
    procedure Params(const pName: String; pValue: Variant);
...
constructor TMyClasse.Create;
begin
  inherited;
  FParams.Init;  <<<<<<< _Safe(Need Variant) and return PDocVariant, then I have used .Init. Some problem with this?
end;

procedure TMyClasse.Params(const pName: String; pValue: Variant);
begin
  FParams.AddOrUpdateValue(pName, pValue);  <<<<<<<<
end;

There are some way to use a property published to use latebiding? If yes, what type should be this property? else thanks AB! I will following this way.

#28 mORMot 2 » Doubts about Variant with latebinding. » 2023-07-26 03:02:26

mrbar2000
Replies: 3

I need make a class that expose a published property called Params.
I would like that this property as Variant with latebinding.
How I can do this?

  v := TMyClasse.Create;
  with Variant(v.Params^) do  // this works, but i dislike have to use pointer
  begin
    Codigo := 10;
    Nome := 'Teste de acéntúàção';
    Data := StrToDate('18/09/1976');
    Valor := 1254.96;
  end;
  // v.Params = {"Codigo":10,"Nome":"Teste de acéntúàção ","Data":"1976-09-18","Valor":1254.96}
  
  with v.Params do  // <<<< how make this way (using Params: Variant)???????????
  begin
    Codigo := 10;.Codigo := 10;
    Nome := 'Teste de acéntúàção';
    Data := StrToDate('18/09/1976');
    Valor := 1254.96;
  end;
  // v.Params = {}

how should be my class?????
In this moment it use pointer. how return variant latebinding? or other thing to can use latebinding????

  TMyClasse = class
  private
    FParams: Variant;
    function GetParams: Pointer;
  public
    constructor Create;
    property Params: Pointer read GetParams;
  end;
...
constructor TMyClasse.Create;
begin
  inherited;
  TDocVariant.New(FParams, [dvoValueCopiedByReference]);
end;

function TMyClasse.GetParams: Pointer;
begin
  Result := @FParams;
end;

#29 mORMot 2 » ByPassAuthentication on trouteruri » 2023-07-01 22:40:30

mrbar2000
Replies: 1

Hi guys

What you think about define ByPassAuthentication during router.get/post/....?

This way I would not have to make 2 services just to separate routes that need or nor of authentication.

Or there are other way?

#30 Re: mORMot 2 » How treat error in SQL Statement » 2023-03-31 14:52:59

Chaa wrote:

Also, in TRestStorageExternal methods like EngineList or EngineRetrieve and so on, exceptions are supressed in try..except block, without being stored anywhere.

do not store in StatementLastException ????????
This is a problem no?

#31 Re: mORMot 2 » Problem with RowID/ID to Virtual Fields on ORM select » 2023-03-31 10:26:02

Where i found help about The vantages to use sqlite ou external DB. Im using postgree database.

#32 mORMot 2 » How treat error in SQL Statement » 2023-03-30 16:16:28

mrbar2000
Replies: 3

I see that all code framework, if the statement is wrong the exception do not explode to user.

In the framework I see this piece of code in several parts:

      try
        ...
        GetAndPrepareStatementRelease(...);
        ...
      except
        on E: Exception do
          GetAndPrepareStatementRelease(E);
      end;

So if I assemble an invalid sql statement by mistake when doing the orm.RetrieveDocVariant does not generate an exception bringing up the null record. example:

function TProjetoService.Busca(pId: Int64): TServiceCustomAnswer;
var
  vProjeto, vPaineis: Variant;
begin
  TDocVariant.New(vProjeto);
  vProjeto := GlobalRepository.Orm.RetrieveDocVariant(TProjeto, '(ID=?)', [pId], '');
  if VarIsEmptyOrNull(vProjeto) then
    Result := ReturnRecordNotFound
  else
  begin
    vPaineis := GlobalRepository.Orm.RetrieveDocVariantArray(TPainel, '',
      '(IdProjeto=?)',
      [pId],
      'ID , Nome2');   <<<<<<<< Nome2 not exists, just Nome field  (in runtime this do not generate exception)
    vProjeto.Paineis := vPaineis;   <<<<< this part run normally bring um Json "Paineis" : null
    Result := ReturnOk(vProjeto);
  end;
end;

#33 mORMot 2 » Problem with RowID/ID to Virtual Fields on ORM select » 2023-03-30 15:53:11

mrbar2000
Replies: 2

Ab, in the code below I am using the RetrieveDocVariantArray function to perform a database search to bring tables's partial fields.
I need too bring a custom virtual string field with contatenated content.  See the following situations:

    // property ID, nome without virtual field concatenation, executes normally.
    vPaineis := GlobalRepository.Orm.RetrieveDocVariantArray(TPainel, '',
      '(IdProjeto=?)',
      [pId],
      'ID ,Nome');

    // property RowID concatenated with a string, executes normally.
    vPaineis := GlobalRepository.Orm.RetrieveDocVariantArray(TPainel, '',
      '(IdProjeto=?)',
      [pId],
      'RowID ,Nome, "/Projeto/" || RowId AS LINK');

    // property ID concatenated with a string, an error occurs.  i would like use this way
    vPaineis := GlobalRepository.Orm.RetrieveDocVariantArray(TPainel, '',
      '(IdProjeto=?)',
      [pId],
      'ID ,Nome, "/Projeto/" || ID AS LINK');

I need this field to make some type of HATEOAS https://en.wikipedia.org/wiki/HATEOAS

#34 Re: mORMot 2 » SOA by Interfaces with custom HTTP Status » 2023-03-28 12:04:54

Arnold, I would like to thank you for your comments here and apologize for the lack of knowledge in the framework, I'm still new to mormot, but I'll get there. Digging around the framework I discovered the properties:

TServiceFactoryServer's SetWholeOption([???])
optResultAsJsonObjectWithoutResult or optResultAsJsonObject

I just put the optResultAsJsonObjectWithoutResult option and the json I wanted was already returned the way I needed it.

function Busca(pId: Int64; var abc: TDTOProjeto; out pProjeto: TDTOProjeto; out pPaineis: TDTOPaineis): TServiceCustomStatus;

{
    "abc": {
        "RowID": 1,
        "Nome": "Projeto c",
        "DataCriacao": "2023-03-18T12:34:09",
        "UltimaAlteracao": "2023-03-18T12:34:09",
        "IdCriador": 5,
        "Paineis": []
    },
    "pProjeto": {
        "RowID": 1,
        "Nome": "Projeto c",
        "DataCriacao": "2023-03-18T12:34:09",
        "UltimaAlteracao": "2023-03-18T12:34:09",
        "IdCriador": 5,
        "Paineis": [
            {
                "RowID": 1,
                "Nome": "painel a",
                "DataCriacao": "2023-03-20T10:08:48",
                "UltimaAlteracao": "2023-03-20T10:08:48",
                "IdCriador": 5,
                "IdProjeto": 1
            }
        ]
    },
    "pPaineis": [
        {
            "RowID": 1,
            "Nome": "painel a",
            "DataCriacao": "2023-03-20T10:08:48",
            "UltimaAlteracao": "2023-03-20T10:08:48",
            "IdCriador": 5,
            "IdProjeto": 1
        }
    ],
    "Result": 0
}

long live the mormot!

#35 Re: mORMot 1 » Implementing OAuth2 » 2023-03-23 09:54:45

I world like a copy too please. Cannyou put on github?

#36 Re: GDI+ » RTL Error on closing delphi when using SYNGDI » 2023-03-21 16:28:33

I can do this into component, or i will need call manually into application when using the component?

#37 Re: GDI+ » RTL Error on closing delphi when using SYNGDI » 2023-03-21 11:27:46

i have commented the picture (GIF) that was registred. the error happen yet

I removed TGifImage of matrixes too

const
  PicturesExt: array[0..4] of TFileName =
    ('jpg','jpeg','png','tif','tiff');
  PictureClasses: array[0..4] of TGraphicClass =
    (TJpegImage,TJpegImage,TPngImage,TTiffImage,TTiffImage);

....

procedure TGDIPlus.RegisterPictures;
var
  i: integer;
begin
  SendDebug('register!');
  // launch Gdip.RegisterPictures to initialize the GDI+ library if necessary
  if (Self=nil) and (Gdip=nil) then
  begin
    SendDebug('gdipo criando!');
    Gdip := TGDIPlus.Create('gdiplus.dll');
  end;
  // register JPG and PNG pictures as TGraphic
  if GetClass('TTiffImage')=nil then
  begin
    RegisterClass(TJpegImage);
    RegisterClass(TPngImage);
    //RegisterClass(TGifImage);   <<<<<<<<<<<<
    RegisterClass(TTiffImage);
    for i := 0 to high(PicturesExt) do
      TPicture.RegisterFileFormat(PicturesExt[i],
        PictureName(PictureClasses[i]),PictureClasses[i]);
  end;
end;

#38 GDI+ » RTL Error on closing delphi when using SYNGDI » 2023-03-20 21:13:10

mrbar2000
Replies: 4

AB,

Do you still provide any support for SynGDI Plus?

I have created a ThumbView component that uses the GR32 lib. In this component I put:

uses
  Windows, Messages, Math, SysUtils, Classes, Controls, Types,
  StdCtrls, Dialogs, Contnrs, CommCtrl, ActiveX, Graphics, Forms,
  GR32_Image, GR32, GR32_Transforms, GR32_RangeBars, GR32_Blend,
  SynGdiPlus,
  BackgroundWorker;

....

//initialization
//  Gdip.RegisterPictures;
end.

When I install the component without this initialization I can close delphi without any problems.

but if i uncomment that initialization Gdip.RegisterPictures, when I close delphi I get the following message

erro.png

#39 Re: GDI+ » Register SynGdiPlus formats in Delphi 7 IDE? » 2023-03-19 13:07:47

I have The same problem. I remove line that registerclass tgif because my delphi são that is duplicated register class.

Then now when I closet The delphi I get a Access violation in rtl70.bpl

#40 Re: mORMot 2 » SOA by Interfaces with custom HTTP Status » 2023-03-18 13:15:55

What u think Arnold?

What i can see about the code, all workflow abou soa via interfaces is internal. Then i think this idea is viable.

#41 Re: mORMot 2 » SOA by Interfaces with custom HTTP Status » 2023-03-15 14:27:40

Good Morning Arnold,

I thought TServiceCustomStatus was only for non mormot clients.

Atualmente o mormot traz no result uma matriz com valores diversos. E não é possível ler isso de clientes não mormot. Veja isso.

TPaineis = array or TPainel

function BuscaPaineis(idProject: integer; out paineis: TPaineis): boolean;

// if I put an idProject that doesn't exist, for example, a Json arrives in this format:
{
  "result" = [ [], false ]
}

// if I put an idProject that exists for example a Json arrives in this format:
{
  "result" = [ [{"painel": 'painel1'}, {"painel": 'painel1'}],  true ] 
}

A non-mormot client is expecting just an array of TPainel. Which is not the case with the true and false into array.

An example response that mormot could return and handle without impacting applications that use interface-based SOA could look like this:

function BuscaPaineis(idProject: integer; out paineis: TPaineis): boolean;

{
  "result" = [{"painel": 'painel1'}, {"painel": 'painel1'}],
  "return" = true
}

I will further detail the problems I am trying to solve as I want to work with interface based SOA. But I need the mormot server to return the JSON in a way that can be read by any 3rd party application.

1) Return the custom HTTP code
2) The returned JSON should follow a pattern for when the result is 200..399.
3) When the return is 400..599 I need the returned JSON to follow an exception pattern with the proper error message. This type really should not be an exception, even though they are expected errors. They should not be logged or handled by the framework.

When I use TServiceCustomStatus I can return the statuscode that I want, great!
But when I return a code between 400...599 I have to return a Json with the reason for this error.
So I thought of TServiceCustomStatus as a record. And I adjusted the code so that anyone who wants to use Mormot and is not using a Mormot client.

Maybe a way to standardize this would be that every return from mormot would return

{ 
    "<result> or <classname>": <Jsonobject> or <JsonArray> 
    "errormessage": "<empty> or <custom error message>"  <<< not out parameter but a TServiceCustomStatus.ErroMessage field 
    "return" : <null is procedure> or <value of function result>   <<< if function is TServiceCustomStatus then TServiceCustomStatus.Status
}

Without losing the cardinal TServiceCustomStatus obviously. HTTPStatus code would return TServiceCustomStatus.Status too.

I'm asking this because my frontend tool (as well as many others) already evaluates the http statuscode to be able to direct the workflow to a success or error routine.

We don't always have control over the frontend that will be using our API, and some of these clients don't have the facility to change their programming.
I know someone here may say that it is the clients that should implement according to the API specification, but I have clients that use no-code tools that just receive the json and treat this json according to the returned http statuscode.

In summary. Your mormot clients would not have to change their programming at all, because if I have the following methods in the interface they would return the following json:

function TABC.FindOrder(Id: Integer; out Order: TOrder; out Items: TItems): TServiceCustomStatus;
{ 
    "output1" or "order": { "id": 1, ... } 
    "output2" or "items": [{ "id": 10, ... }, { "id": 11, ... }, { "id": 12, ... }]
    "errormessage": ""
    "return" : 200  <<<< the same of HTTPStatus code returned
}

function TABC.FindOrder(Id: Integer; out Order: TOrder; out Items: TItems): boolean;
{ 
    "output1" or "order": { "id": 1, ... } 
    "output2" or "items": [{ "id": 10, ... }, { "id": 11, ... }, { "id": 12, ... }]
    "errormessage": ""
    "return" : true <<<< HTTPStatus code always 200 if result <> TServiceCustomStatus
}

To internaol SOA process, "errormessage" field would be ignored unless the programmer put an out errormessage in the parameters.

#42 Re: mORMot 2 » SOA by Interfaces with custom HTTP Status » 2023-03-14 15:09:03

Hi, I make some changes in TServiceCustomStatus
and put a PR #160

What did u think?
Are u see some problem in my changes?

#43 Re: mORMot 2 » TOrm with ChildObjects » 2023-03-08 13:11:36

Hi guys I try. look this sample:

  TPainel = class;

  TPaineis = array of TPainel;

  TProjeto = class(TOrm)
  private
    FPaineis: TPaineis;
  published
    property Paineis: TPaineis read FPaineis;
  end;

  TPainel = class(TOrm)
  private
    FIdProjeto: TProjeto;
  published
    property IdProjeto: TProjeto read FIdProjeto write FIdProjeto;
  end;

when I use this code

function TProjetoService.Busca(pId: Int64): TServiceCustomAnswer;
var
  vProjeto: TProjeto;
  vAuto: IAutoFree;
begin
  vAuto := TOrm.AutoFree([@vProjeto, TProjeto]);
  if not GlobalRepository.Orm.Retrieve(pId, vProjeto) then
    Result := ReturnRecordNotFound
  else
    Result.Content := ObjectToJson(vProjeto);
end;

I receive this:

{
    "RowID": 1,
    "Nome": "Projeto a",
    "DataCriacao": 135770589581,
    "UltimaAlteracao": 135770590233,
    "IdCriador": 5,
    "Paineis": "[{\"RowID\":1,\"Nome\":\"painel a\",\"DataCriacao\":0,\"UltimaAlteracao\":0,\"IdCriador\":5,\"IdProjeto\":1},{\"RowID\":2,\"Nome\":\"painel b\",\"DataCriacao\":0,\"UltimaAlteracao\":0,\"IdCriador\":5,\"IdProjeto\":1},{\"RowID\":3,\"Nome\":\"painel c\",\"DataCriacao\":0,\"UltimaAlteracao\":0,\"IdCriador\":5,\"IdProjeto\":1}]"
}

I whould like this:

{
    "Id": 1,
    "Nome": "Projeto a",
    "IdCriador": 5
    "Paineis": [
        {
	    "Id": 1,
	    "Nome": "painel a",
	    "IdCriador": 5,
	    "IdProjeto":1
	 },
	{
	    "Id": 2,
	    "Nome": "painel b",
	    "IdCriador": 5,
	    "IdProjeto":1
	 },
	{
	    "Id": 3,
	    "Nome": "painel c",
	    "IdCriador": 5,
	    "IdProjeto":1
	}
    ]
}

1) How orm method i should be use to RETRIEVE the object TProjeto with the array Paineis filled? There are some?

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?

#45 Re: mORMot 2 » TOrm with ChildObjects » 2023-03-07 12:54:37

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

#46 Re: mORMot 2 » TOrm with ChildObjects » 2023-03-07 12:18:19

Thanks. Phone is just a sample.

I will use this strategy for more complex classes. Order and OrderItem for sample.
I dont think that OrderItem shoud be saved into a blob into order table.

Reasons:
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.
2) A bussiness inteligence tool that work with database need get OrderItems to make the graphics. Imagine this stored in blobs.
3) How to find something into objects that are store in this field blob?
    Sample1: I want bring all orders that have product "xyz" (where product is into a blob field)
    Sample2: I want sum(orderitem.total) where product "xyz" in a period (where product is into a blob field)
4) I think that exist other reason that do not appear in my mind at the moment.

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

#47 Re: mORMot 2 » TOrm with ChildObjects » 2023-03-06 19:08:00

I see all documentation. But TOrmMany is to pivottable, and i dont have source and dest in this case.
I what just a property returning list of objects TPhone into person!
Or I dont understand very well how to use!

Remerber that Tperson 1 - (0..n) Tphone (on database are different tables)

#48 Re: mORMot 2 » SOA by Interfaces with custom HTTP Status » 2023-03-06 15:45:10

Problem with this is that we have to treat all input/output parameters of service method, getting of Ctx. very hard work!

There are some other way?

#49 mORMot 2 » TOrm with ChildObjects » 2023-03-06 15:42:11

mrbar2000
Replies: 9

I Have 2 tables in my database

Person (id, name)
Phone (id, idPerson, number)

1) How can i map this in mormot?

  TPerson = class;

  TPhone = class(TOrm);
  private
    FIdPerson: TPerson;
    FNumber: RawUTF8;
  published
    property Number: RawUTF8 index 25 read FNumber write FNumber;
    property IdPerson: TPerson read FIdPersonwrite FIdPerson;
   

  TPerson = class(TOrm)
  private
    FNome: RawUTF8;
  published
    property Nome: RawUTF8 index 100 read FNome write FNome;
    property Phones: ???????? read FPhones   <<<<  that property type can i use here? (need persist in 2 separated tables)
  end;

2) How I can call retrieve on orm and bring some person (id=10 for sample) and all your Phones?

#50 mORMot 2 » SOA by Interfaces with custom HTTP Status » 2023-03-06 14:00:11

mrbar2000
Replies: 11

Hi All,

I see that when implementing services interface based the framework always return 200.
But we whould like return others httpstatus.

then we discover TServiceCustomAnswer. this resolve the httpstatus problem, but this return do not accept parameters out neither var

sample. What i would like do:

function TProjetoService.GetProjetoPaineis(out pProjeto: TOrmProjeto): TServiceCustomAnswer;
begin
  if not FRestOrm.Retrieve(pProjeto.Id, pProjeto) then
    Result := ReturnError(Format('(%s) '+cErrorRecordNotFound, [GetClassName]), HTTP_NOTFOUND)
  // else following the course, will return 200 ok!!!!
end;

function TServiceBase.ReturnError(const pErrorMessage: RawUTF8; pStatus: cardinal): TServiceCustomAnswer;
var
  vError: Variant;
begin
  TDocVariant.New(vError);
  vError.ErrorMessage := pErrorMessage;
  vError.StatusCode := pStatus;
  Result.Content := VariantSaveJson(vError);
  Result.Status := pStatus;
end;


How we can do this? What the recomendation?

Board footer

Powered by FluxBB