/Horse-XSuperObjects

Utility for reading and writing Json files in Pascal

Primary LanguagePascalMIT LicenseMIT

Horse-XSuperObjects

This package is not my own, I just created middleware to facilitate the import and installation of the package in projects using BOSS.

All rights and credits are for:

Vladimir Krapotkin

Original project repository:

https://github.com/onryldz/x-superobject

⚙️ Installation

Installation is done using the boss install command:

$ boss install https://github.com/claudneysessa/Horse-XSuperObjects

Delphi Cross Platform Rapid JSON

###Basic

{
  "name": "Onur YILDIZ", 
  "vip": true,
  "telephones": ["000000000", "111111111111"],
  "age": 24,
  "size": 1.72,
  "adresses": [
    {
      "adress": "blabla",
      "city": "Antalya",
      "pc": 7160
    },
    {
      "adress": "blabla",
      "city": "Adana",
      "pc": 1170
    }
  ]
}

###Delphi Side

// foo
var
  X: ISuperObject;
begin
  X := SO;
  X.S['name'] := 'Onur YILDIZ';
  X.B['vip'] := true;
  with X.A['telephones'] do
  begin
   Add('000000000');
   Add('111111111111');
  end;
  X.I['age'] := 24;
  X.F['size'] := 1.72;
  with X.A['adresses'].O[0] {Auto Create} do
  begin
    S['adress'] := 'blabla';
    S['city'] := 'Antalya';
    I['pc'] := 7160;
  end;
  // or
  X.A['adresses'].O[1].S['adress'] := 'blabla';
  X.A['adresses'].O[1].S['city'] := 'Adana';
  X.A['adresses'].O[1].I['pc'] := 1170;

###Super Expressions

const
  JSON = '{ "o": { '+
         '    "1234567890": {'+
         '    "last use date": "2010-10-17T01:23:20",'+
         '    "create date": "2010-10-17T01:23:20",'+
         '    "name": "iPhone 8s"'+
         '        }'+
         '  },'+
         '  "Index": 0, '+
         '  "Data": {"Index2": 1}, '+
         '  "a": [{'+
         '    "last use date": "2010-10-17T01:23:20",'+
         '    "create date": "2010-11-17T01:23:20",'+
         '    "name": "iPhone 8s",'+
         '    "arr": [1,2,3] '+
         '  }, '+
         '  {'+
         '    message: "hello"'+
         '  }]'+
         '}';

var
  X: ISuperObject;
  NewJSon: ISuperObject;
  NewArray: ISuperArray;
begin
  X := SO(JSON);
  ShowMessage( X['o."1234567890"."last use date"'].AsString );
  ShowMessage( X['a[Index]."create date"'].AsString );
  ShowMessage( X['a[Data.Index2].message'].AsString );
  X['a[0].arr'].AsArray.Add('test1');
  // -----
  NewJSON := X['{a: a[Index], b: a[Data.Index2].message, c: o."1234567890".name, d: 4, e: a[0].arr[2], f: " :) "}'].AsObject;
  NewArray := X['[a[Index], a[Data.Index2].message, Data.Index2, Index, 1, "1", "test"]'].AsArray;
end;

###Where

var
  FilterJSON: ISuperObject;
begin
  FilterJSON := SO('{ Table: [ '+
                   '   { '+
                   '      Name: "Sakar SHAKIR", ' +
                   '      Sex: "M",  ' +
                   '      Size: 1.75 '+
                   '   }, '+
                   '   {  '+
                   '      Name: "Bulent ERSOY", ' +
                   '      Sex: "F",  ' +
                   '      Size: 1.60 '+
                   '   }, '+
                   '   { '+
                   '      Name: "Cicek ABBAS", ' +
                   '      Sex: "M",  ' +
                   '      Size: 1.65 '+
                   '   } '+
                   '  ] '+
                   '}');
  Memo1.Lines.Add(
      FilterJSON.A['Table'].Where(function(Arg: IMember): Boolean 
      begin
        with Arg.AsObject do
             Result := (S['Sex'] = 'M') and (F['Size'] > 1.60)
      end).AsJSON
  );
end;

Output

 [
    {
      "Name":"Sakar SHAKIR",
      "Sex":"M",
      "Size":1.75
    },
    {
      "Name":"Cicek ABBAS",
      "Sex":"M",
      "Size":1.65
    }
 ]

###Delete

var
  FilterJSON: ISuperObject;
begin
  FilterJSON := SO('{ Table: [ '+
                   '   { '+
                   '      Name: "Sakar SHAKIR", ' +
                   '      Sex: "M",  ' +
                   '      Size: 1.75 '+
                   '   }, '+
                   '   {  '+
                   '      Name: "Bulent ERSOY", ' +
                   '      Sex: "F",  ' +
                   '      Size: 1.60 '+
                   '   }, '+
                   '   { '+
                   '      Name: "Cicek ABBAS", ' +
                   '      Sex: "M",  ' +
                   '      Size: 1.65 '+
                   '   } '+
                   '  ] '+
                   '}');
  Memo1.Lines.Add(
      FilterJSON.A['Table'].Delete(function(Arg: IMember): Boolean 
      begin
        with Arg.AsObject do
             Result := (S['Sex'] = 'M') and (F['Size'] > 1.60)
      end).AsJSON
  );
end;

Output

 [
    {
      "Name":"Bulent ERSOY",
      "Sex":"F",
      "Size":1.6
    }
 ]

###Sorting

var
  X: ISuperObject;
  A: ISuperArray;
begin
  X := SO('{b:1, a:2, d:4, c:2}');
  ShowMessage(X.AsJSON);
  X.Sort(function(Left, Right: IMember): Integer begin
    Result := CompareText(Left.Name, Right.Name);
  end);
  ShowMessage(X.AsJSON);

  A := SA('[{index:3}, {index:4}, {index:2}, {index:1}]');
  ShowMessage(A.AsJSON);
  A.Sort(function(Left, Right: IMember): Integer begin
    Result := CompareValue(Left.AsObject.I['index'], Right.AsObject.I['index']);
  end);
  ShowMessage(A.AsJSON);
end;

Output

 {"b":1,"a":2,"d":4,"c":2}
 {"a":2,"b":1,"c":2,"d":4}
 [{"index":3},{"index":4},{"index":2},{"index":1}]
 [{"index":1},{"index":2},{"index":3},{"index":4}]

###Variant

var 
  X: ISuperObject;
begin 
  X := TSuperObject.Create;
  X.V['A'] := 1;
  X.V['B'] := '2';
  X.V['C'] := 1.3;
  X.V['D'] := False;
  X.V['E'] := Null;
  X.V['F'] := Now;
  Memo1.Lines.Add(X.AsJSON);
end;

Output

 {
    "A": 1,
    "B": "2",
    "C": 1.3,
    "D": false,
    "E": null,
    "F": "2014-05-03T03:25:05.059"
 }

###Loops

const
  JSN = '{ '+
        ' "adresses": [ '+
        '   { '+
        '     "adress": "blabla", '+
        '     "city": "Antalya", '+
        '     "pc": 7160 '+
        '   },'+
        '   { '+
        '     "adress": "blabla", '+
        '     "city": "Adana", '+
        '     "pc": 1170 '+
        '   } '+
        ' ] '+
        '}';
var
  X, Obj: ISuperObject;
  J: Integer;
begin
  X := TSuperObject.Create(JSN);
  with X.A['adresses'] do
    for J := 0 to Lenght -1 do
    begin
      Obj := O[J];
      Obj.First;
      while not Obj.EoF do
      begin
         Memo1.Lines.Add( Obj.CurrentKey + ' = ' + VarToStr(Obj.CurrentValue.AsVariant));
         Obj.Next;
      end;
      Memo1.Lines.Add('------');
    end;
end;

Output adress = blabla city = Antalya pc = 7160

Or Enumerator

var
  X: ISuperObject;
  AMember,
  OMember: IMember;
begin
  X := TSuperObject.Create(JSN);

  for AMember in X.A['adresses'] do
  begin
      for OMember in AMember.AsObject do
          Memo1.Lines.Add(OMember.Name + ' = ' + OMember.ToString);

      Memo1.Lines.Add('------');
  end;

Output adress = blabla city = Adana pc = 1170


###Marshalling

type

  TTestSet = (ttA, ttB, ttC);

  TTestSets = set of TTestSet;
 
  TSubRec = record
    A: Integer;
    B: String; 
  end;

  TSubObj = class
    A: Integer;
    B: Integer; 
  end;  
  
  TTest = class // Field, Property Support
  private
    FB: String;
    FSubObj: TSubObj;
    FSubRec: TSubRec;
    FTestSets: TTestSets;
    FH: TDateTime;
    FJ: TDate;
    FK: TTime;
    FList: TObjectList<TSubObj>; // or TList<>; But only object types are supported
  public
    A: Integer;
    B: TTestSet;
    C: Boolean;
    property D: String read FB write FB;
    property E: TSubRec read FSubRec write FSubRec;
    property F: TSubObj read FSubObj write FSubObj;
    property G: TTestSets read FTestSets write FTestSets;
    property H: TDateTime read FH write FH;
    property J: TDate read FJ write FJ;
    property K: TTime read FK write FK;
    property L: TObjectList<TSubObj> read FList write FList;
  end;
  
  TTestRec = record // Only Field Support
    A: Integer;
    B: TTestSet;
    C: Boolean;
    D: String;
    E: TSubRec;
    F: TSubObj;
    G: TTestSets;
    H: TDateTime;
    J: TDate;
    K: TTime;
    L: TObjectList<TSubObj>; // or TList<>; But only object types are supported
  end;
  
  implementation
  ...
  
  var 
    Parse: TTest; // For Class;
    S: String;
  begin
    Parse := TTest.FromJSON('{"A": 1, "B": 0, "C": true, "D": "Hello", "E":{"A": 3, "B": "Delphi"}, "F": {"A": 4, "B": 5}, "G": [0,2], "H": "2014-05-03T03:25:05.059", "J": "2014-05-03", "K": "03:25:05", "L":[{"A": 4, "B": 5},{"A": 6, "B": 7}] }');
    S := Parse.AsJSON;
  end;
  
  
  ...
  var
    Parse: TTestRec; // For Record;
    S: String;
  begin
    Parse := TJSON.Parse<TTestRec>('{"A": 1, "B": 0, "C": true, "D": "Hello", "E":{"A": 3, "B": "Delphi"}, "F": {"A": 4, "B": 5}, "G": [0,2], "H": "2014-05-03T03:25:05.059", "J": "2014-05-03", "K": "03:25:05", "L":[{"A": 4, "B": 5},{"A": 6, "B": 7}]}');  
    S := TJSON.Stringify<TTestRec>(Parse);
  end;
  
type
  TRec = record // or class
    A: Integer;
    B: String;
  end;
  
  implementation
  ...
  
  var
    Test: TArray<TRec>;
    S: String;
  begin
    Test := TJSON.Parse<TArray<TRec>>('[{"A": 1, "B": "1"}, {"A": 2, "B": "2"}]');
    S := TJSON.Stringify<TArray<TRec>>(Test);
  end;

Collection (Limited)

type
  TXCollectionItem = class(TCollectionItem)
  private
    FA: String;
    FB: Integer;
  public
    property A: String read FA write FA;
    property B: Integer read FB write FB;
  end;
  
  TXCollection = class(TCollection)
  public
    constructor Create; reintroduce;
  end;
  
  TTest = class
  private
    FCollection: TXColleciton;
  public
    destructor Destroy; override;
    property Collection: TCollection read FCollection write FCollection;
  end;
  
  implementation
  ...
  
  constructor TXCollection.Create;
  begin
    inherited Create(TXCollectionItem);
  end;
  
  destructor TTest.Destroy;
  begin
    FCollection.Free;
    inherited;
  end;
  
  var
    Test: TTest;
  begin
    Test := TTest.FromJSON('{"Collection": [{"A": "Item 1", "B": 1}, {"A": "Item 2", "B": 1}]}');
    S := Test.AsJSON;
  end;

###Marshalling Attributes

TTest = class 
  public
    [ALIAS('Type')]
     Typ: String;
    [ALIAS('Unit')]
     Unt: Integer;
    [REVAL('', '*')]
     Filter: String;
    [DISABLE]
     BlaBlaBla: String;
    [REVAL(roEmptyArrayToNull)]
     Arr: TArray<String>;
  end;

  var X: Test;
  begin
    X := TTest.Create;
    X.Typ := 'XType';
    X.Unt := 2;
    X.Filter := '';
    X.BlaBlaBla := ':)';
    SetLength(X.Arr, 0);
    ShowMessage(X.AsJSON);
  end;

Output

 {
    "Type": "XType", 
    "Unit": 2, 
    "Filter": "*",
    "Arr": null
 }