#1 2015-05-23 11:34:44

uian2000
Member
Registered: 2014-05-06
Posts: 68

Issue when convert variant to TVarRec

Methods of interface inherited from IInvokable do not accept params of array of const.
So I pass array of variant, and make revert convertion at server side.

Interface.Method

function Query(out ItemList: TObjectList; const Sample: TSQLRecord; 
   const Params: string; const Bounds: array of Variant): Integer;

invert convertion

procedure MakeBounds(Variants: array of Variant; var VarRecs: TVarRecArray);
var
  I: Integer;
begin
  SetLength(VarRecs, Length(Variants));
  for I := Low(Variants) to High(Variants) do
    VariantToVarRec(Variants[i], VarRecs[i]);
end;

function TCoreResources.Query(out ItemList: TObjectList; const Sample: TSQLRecord;
  const Params: string; const Bounds: array of Variant): Integer;
var
  vBounds: TVarRecArray;
begin
  MakeBounds(Bounds, vBounds);
  ItemList := GetCoreService.RetrieveList(PSQLRecordClass(Sample)^,
    Params, vBounds);
  if Assigned(ItemList) then Result := ItemList.Count else Result := 0;
end;

Exception

20150523 19303823  ! EXC   ESynException ("TJSONSerializer.AddVariantJSON(VType=
64808)") at 004361D9  stack trace API 004429A2 0040492C
! Core service - Test got interface core resources
! Exception ESynException raised with messsage:
!  TJSONSerializer.AddVariantJSON(VType=64808)

Exception occured in TTextWriter.AddVariantJSON, where variant.VType = 64808,but param passed is just AnsiString 'Hello'.

Somebody help?

Offline

#2 2015-05-23 12:34:40

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,183
Website

Re: Issue when convert variant to TVarRec

You need a true fixed type for each parameter, e.g. TVariantDynArray type in this case.

But I think that the best is just to use a single variant as parameter, passing a TDocVariant custom type, using e.g. _ArrFast([...]).
_ArrFast([...]) will allow to use an array of const, convert it into a TDocVariant custom variant type, passed as variant kind of parameter, and serialized properly as JSON on the wire.

BTW, do not forget to use "const" for array parameters:

MakeBounds(const Variants: array of Variant...

for best performance.

Offline

#3 2015-05-24 11:20:33

uian2000
Member
Registered: 2014-05-06
Posts: 68

Re: Issue when convert variant to TVarRec

ab wrote:

You need a true fixed type for each parameter, e.g. TVariantDynArray type in this case.

But I think that the best is just to use a single variant as parameter, passing a TDocVariant custom type, using e.g. _ArrFast([...]).
_ArrFast([...]) will allow to use an array of const, convert it into a TDocVariant custom variant type, passed as variant kind of parameter, and serialized properly as JSON on the wire.

BTW, do not forget to use "const" for array parameters:

MakeBounds(const Variants: array of Variant...

for best performance.

Thanks ab.
For the params accept by FormatUTF8 is only array of const.
I dident found any method that make the conversion from TDocVariant to array of const.
Some hints?

Or make a choice of using RetrieveListJSON method for the absence of SQLWhereBounds?

Offline

#4 2015-05-24 13:55:06

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,183
Website

Re: Issue when convert variant to TVarRec

I've added the new TDocVariantData.ToArrayOfConst overloaded functions, which are able to be passed as FormatUTF8() parameter.
See http://synopse.info/fossil/info/d3f44776ea

var vr: TTVarRecDynArray;
....
  Doc.ToArrayOfConst(vr);
  s := FormatUTF8('[?,?,?]',[],vr,true);
  check(s='["one",2,3]');
  s := FormatUTF8('[%,%,%]',vr,[],true);
  check(s='[one,2,3]');
  s := FormatUTF8('[?,?,?]',[],Doc.ToArrayOfConst,true);
  check(s='["one",2,3]');
  s := FormatUTF8('[%,%,%]',Doc.ToArrayOfConst,[],true);
  check(s='[one,2,3]');

Offline

#5 2015-05-26 13:34:57

uian2000
Member
Registered: 2014-05-06
Posts: 68

Re: Issue when convert variant to TVarRec

ab wrote:

I've added the new TDocVariantData.ToArrayOfConst overloaded functions, which are able to be passed as FormatUTF8() parameter.
See http://synopse.info/fossil/info/d3f44776ea

Thank you ab!
This patch really fix my situation.

My codes

function MakeBounds(Bounds: array of const): Variant; overload;
begin
  Result := _ArrFast(Bounds);
end;

function MakeBounds(Bounds: Variant): TTVarRecDynArray; overload;
begin
  Result := TDocVariantData(Bounds).ToArrayOfConst;
end;

Offline

#6 2015-05-26 13:38:13

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,183
Website

Re: Issue when convert variant to TVarRec

Happy to help.

You may have coded:

function MakeBounds(const Bounds: array of const): Variant; overload; inline;
begin
  Result := _ArrFast(Bounds);
end;

function MakeBounds(const Bounds: Variant): TTVarRecDynArray; overload; inline;
begin
  DocVariantDataSafe^(Bounds).ToArrayOfConst(result);
end;

Offline

#7 2015-06-02 14:31:59

uian2000
Member
Registered: 2014-05-06
Posts: 68

Re: Issue when convert variant to TVarRec

ab wrote:

Happy to help.

You may have coded:

function MakeBounds(const Bounds: array of const): Variant; overload; inline;
begin
  Result := _ArrFast(Bounds);
end;

TYVM ab!
This inline is a key word I never ever uses. big_smile

Offline

#8 2015-06-29 15:01:30

Cahaya
Member
Registered: 2015-06-21
Posts: 36

Re: Issue when convert variant to TVarRec

Hi AB,

procedure TForm1.Button1Click(Sender: TObject);
var
    vBounds : variant;
    vArrOfConst : TTVarRecDynArray;
begin
  vBounds := _ArrFast([1000,'HELLO WORLD',NOW]);
  vArrOfConst := TDocVariantData(vBounds).ToArrayOfConst;

  ShowMessage(String(vArrOfConst[1].vPChar));
end;

Why I don't see "HELLO WORLD" ?

Thank you.

Offline

#9 2015-06-29 19:20:46

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,183
Website

Re: Issue when convert variant to TVarRec

Because it is stored as a vtVariant reference to the original variant, not a plain String.

Offline

#10 2015-06-30 06:37:26

Cahaya
Member
Registered: 2015-06-21
Posts: 36

Re: Issue when convert variant to TVarRec

Thank you AB.

It becomes,

 ShowMessage(vArrOfConst[1].vVariant^);

It is a very useful feature for passing param Query.

Last edited by Cahaya (2015-06-30 06:37:48)

Offline

#11 2015-06-30 09:26:35

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,183
Website

Re: Issue when convert variant to TVarRec

Yes, everything is passed as a vtVariant reference from the original TDocVariant.Values[] storage, for best efficiency.

Offline

#12 2015-07-24 16:20:22

Cahaya
Member
Registered: 2015-06-21
Posts: 36

Re: Issue when convert variant to TVarRec

Hi AB,

  vJSONContent := '{"Customer_No":1,"Name":"Cahaya Harapan"}';
  v := _Json(vJsonContent);

how to convert DocVariantDataSafe(v)^.Values to array of const ? In this case [1,'Cahaya Harapan']

Thanks a lot

Offline

#13 2015-07-25 02:32:42

Cahaya
Member
Registered: 2015-06-21
Posts: 36

Re: Issue when convert variant to TVarRec

Sorry AB, I will answer my own question. smile

procedure TForm1.btVariantClick(Sender: TObject);
var
   vVar : variant;
   vVarRec : TTVarRecDynArray;
   //vJsonContent : rawUTF8;
begin
  //vJSONContent := '{"customers":[{"Customer_No":1,"Name":"Cahaya Harapan"},{"Customer_No":2,"Name":"Dustin Tsai"}]}';
  //vJSONContent := '{"Customer_No":1,"Name":"Cahaya Harapan"}';
  //v := _Json(vJsonContent);
  vVar := _ArrFast([]); {Custom type of variant by mormot}
  DocVariantData(vVar)^.AddItem(1);
  DocVariantData(vVar)^.AddItem('Cahaya Harapan');
  vVarRec := DocVariantData(vVar)^.ToArrayOfConst;
  SQLValues(vVarRec);
end;

AB, I can not pass array of variant to DocVariantData.ToArrayOfConst. Is it normal because you use custom vartype in mormot variant.

Thank you alot.

Last edited by Cahaya (2015-07-25 02:33:14)

Offline

Board footer

Powered by FluxBB