Encode JSON to a FireDAC Memory Table without REST Request

14 Responses

  1. Okba Ch says:

    try
    e := o.GetEnumerator; //<- Error types'TJSONPairEnumerator' and 'TJSONObject.TEnumerator'

    if not e.MoveNext then begin
    exit;

    delphi 10.3.3 //2019
    how can fix that

  2. I ended up making a quick and dirty JsonParser that does the job:

    type tdatasets = tobjectlist;

    function DecodeJSon(txt : string) : tdatasets;
    var i : integer;
    literal : boolean;
    vartext, valtext : string;
    CurrentDataset : tfdMemtable;
    DataBuffer : tstringlist;

    var CurrentState : (sGetVar, sGetVal);

    Procedure CloseDataset;
    begin
    DataBuffer.Clear;
    //DataBuffer.ValueFromIndex
    end;

    Procedure NewRecord;
    begin
    //
    end;

    Procedure PostRecord;
    var i : integer;
    begin
    if DataBuffer.count > 0 then
    with CurrentDataset do
    begin
    if fieldcount = 0 then
    for i := 0 to DataBuffer.count-1 do
    FieldDefs.Add(DataBuffer.KeyNames[i], ftString, length(DataBuffer.valuefromindex[i]));
    open;
    append;
    try
    for i := 0 to DataBuffer.count-1 do
    CurrentDataset.fields[i].asstring := DataBuffer.ValueFromIndex[i];
    except
    DataBuffer := DataBuffer;
    end;
    post;

    form1.memo1.lines.add(DataBuffer.Text);

    DataBuffer.Clear;

    end;
    end;

    Procedure NewDataset;
    begin
    PostRecord;
    CurrentDataset := tfdmemtable.Create( nil);
    result.Add(CurrentDataset);
    CurrentState := sGetvar;
    end;

    procedure AddPair;
    begin
    if vartext=” then exit;
    DataBuffer.add(vartext+’=’+valtext);
    valtext := ”;
    vartext := ”;
    Currentstate := sGetVar;
    end;

    begin
    result := tobjectList.Create;
    DataBuffer := tStringList.Create;
    literal := false;
    for I := 1 to length(txt) do
    begin
    if txt[i]= ‘”‘ then
    Literal := not literal
    else
    if not literal then
    case txt[i] of
    ‘:’ : begin CurrentState := sGetVal; Continue; end;
    ‘[‘ : NewDataset;
    ‘]’ : CloseDataset;
    ‘{‘ : NewRecord;
    ‘,’ : AddPair;
    ‘}’ : begin Addpair; PostRecord; end;
    end;
    if (CurrentState=sGetval) or literal then
    begin
    if CurrentState=sGetVar then
    vartext := vartext + txt[i] else
    valtext := valtext + txt[i];
    //literal := true;
    end;
    end;
    end;

    var datasets : tdatasets;

    procedure TForm1.FormCreate(Sender: TObject);
    begin
    datasets := DecodeJson(memo1.Lines.Text);
    DataSource1.DataSet := datasets[0];
    datasets[0].open;

    DataSource2.DataSet := datasets[1];
    datasets[1].open;
    end;

  3. Works very well, thank you.
    My JSON is nested, so I will try change the code, so that it can consume nested JSONs as well, and returning a list of datasets. Would that work?

  4. Hi, I try to use that component and it works very well where size of data is less than 20 chars on string type. I try to define own fields with size about 250 and data are still truncated after 20 :(. The same is when You put presented JSON. Could You look on that?

    • I haven’t looked at this code in quite some time, and had no intention of maintenance on it, but will take another look.
      As I recall, I did some things in the code to marshal data-types, which I probably shouldn’t have done because everything in JSON is a string.
      I’ve since written this replacement : https://github.com/chapmanworld/deRest
      I’ve been planning a video on how to use deREST, but not gotten to it yet.
      1) Install the pkg_deREST package.
      2) Drop a TFDConnection on your module and wire it up to the database.
      3) Drop a TRESTAPI component on the module.
      4) Add items to the Collections property (each item needs a reference to the FD connection, a public name for it’s endpoint, the name of a key field, and the name of a table to expose).
      It’ll then do more or less the same thing.
      Please watch this blog for a video soon with more detail.

      • On second thought – I’m going to make some quick changes to deREST and put a video together today. Hold tight.

        • Thank you so much, I will do it. By the way, a component such as this could be in the standard distribution 🙂 and would be really useful for communication with IoT where the standard REST is “too heavy”.

          • Ack Sorry, I realize that I was replying regarding the wrong component.
            I’m looking into this problem now…

          • Okay, so it’s a bit of a work around, but it’s the FieldDef size that seems to be the problem. So after wiring the component up, right click the FDMemTable and select ‘FieldsEditor’. Right click inside the fields editor and “add all fields”. At this point it should show you the fields that are added by the adapter, you can select the field you need to alter, and set it’s size property.

            I tried throwing in a check for that, but it didn’t work out.
            I thought that your comments were referring to a different component that I wrote, and recently re-wrote, but I’ll keep to my promise, I’ll re-write this also as a more stable component and include it into my deREST component set.

            http://chapmanworld.com/2018/07/21/instantly-expose-a-table-as-a-rest-endpoint-again/

  5. jxluron@gmail.com says:

    Hello,
    yes, I am French, sorry for my English. I’m talking about data accented in the json: after the assignment to the fdmemtable, when the application is compiled under windows, the data is no longer accentuated. when the application is compiled under android, the accents are misinterpreted: for example “Fougère” becomes “Foug?re”.
    the solution that I was given: line 202
    // o: = TJSONObject.ParseJSONValue (TEncoding.ASCII.GetBytes (‘{“data”:’ + fJSON.Text + ‘}’), 0) as TJSONObject;
    // to manage the accents
    o: = TJSONObject.ParseJSONValue (TEncoding.UTF8.GetBytes (‘{“data”:’ + fJSON.Text + ‘}’), 0) as TJSONObject;
    and it works ! THANK YOU very much for this very useful component.

    :o)

    delaio.

  6. jxluron@gmail.com says:

    hello Craig,

    your component works well but I have two problems:
    – Some values exceed 255 characters: the data is truncated
    (Solution: Replace Line 121 FieldDef.DataType: = TFieldType.ftString; by FieldDef.DataType: = TFieldType.ftMemo; it’s ok !?!!)
    – the accents do not appear under windows and are displayed under Android.

    I do not know how to solve the problem. thanks for your help.

    delaio.

    • It looks like both issues lie outside the component.

      1) The solution you give looks good for strings longer than 255 characters, the field type ftString tells FireDAC that it’s dealing with a short string (max 255 characters), which I think is a vestige of it being a BDE replacement.

      2) I’m not sure what you mean by the accents appearing, but my guess is that your text has accents? In which case, it would depend on how FMX renders the font for the target platform. If you can give more information (perhaps a test app source) I’ll happily take a closer look.

      craig [dot] chapman [at] embarcadero [dot] com

      btw, have you tried placing a simple TLabel on your form and setting a caption with accents? (i.e. not just the data returned from the component)

  7. There is a case-sensitivity bug.

    Change line 105 of jsonadapt.pas from:

    n := Lowercase(Trim(p.JsonString.ToString));
    to
    n := p.JsonString.ToString;

    This should resolve the bug. Note, this component will only work in cases where the json field name is a valid SQL field name.

Leave a Reply