xtool/contrib/mORMot/SQLite3/Samples/ThirdPartyDemos/EMartin/TSynRestDataset
Razor12911 39fb5ae479 support for delphi 11.1 2022-05-13 19:02:12 +02:00
..
FishFactSyn source upload 2022-01-17 22:16:47 +02:00
Demo.bpg source upload 2022-01-17 22:16:47 +02:00
ReadMe.md source upload 2022-01-17 22:16:47 +02:00
SampleData.pas source upload 2022-01-17 22:16:47 +02:00
Server.dpr source upload 2022-01-17 22:16:47 +02:00
SynRestMidasVCL.pas support for delphi 11.1 2022-05-13 19:02:12 +02:00
SynRestVCL.pas support for delphi 11.1 2022-05-13 19:02:12 +02:00
fMain.dfm source upload 2022-01-17 22:16:47 +02:00
fMain.pas source upload 2022-01-17 22:16:47 +02:00

ReadMe.md

TSynRestDataset

By EMartin (Esteban Martin).

Presentation

Migrating from RemObjects to mORMot I had to implement a GUI functionality that RemObjects has, an editable dataset connected through URL (RO version 3 use SOAP and other components adapters, etc.).

My implementation is basic and the most probably is not the best, but works for me, the same use RESTful URL for get and update data, also get data from a mORMot interface based services returning a mORMot JSON array but cannot update because the table not exists.

In this folder there are two units: SynRestVCL.pas and SynRestMidasVCL.pas, both have some duplicated code from its counterpart (SynDBVCL.pas and SynDBMidasVCL.pas) and the others, but the rest are modifications with use of RESTful instead of the TSQLDBConnection (this require the database client installed in the client machine).

A TSQLModel is required because the TSynRestDataset get the fields definition column type and size from this. Also is used from the TSQLRecord the defined validations (I used InternalDefineModel) and the ComputeFieldsBeforeWrite (I used this for default values).

This was developed with Delphi 7 on Windows 7 and probably (almost sure) is not cross platform.

If this serves for others may be the best option will be that ab integrate this in the framework and make this code more mORMot. Meanwhile I will update on the google drive. I hope this is helpful to someone.

Example 1: from a table

// defining the table
TSQLRecordTest = class(TSQLRecord)
private
  fDecimal: Double;
  fNumber: Double;
  fTestID: Integer;
  fText: RawUTF8;
  fDateTime: TDateTime;
protected
  class procedure InternalDefineModel(Props: TSQLRecordProperties); override;
public
  procedure ComputeFieldsBeforeWrite(aRest: TSQLRest; aOccasion: TSQLEvent); override;
published
  property Test_ID: Integer read fTestID write fTestID;
  property Text: RawUTF8 index 255 read fText write fText;
  property Date_Time: TDateTime read fDateTime write fDateTime;
  property Number: Double read fNumber write fNumber;
  property Decimal_: Double read fDecimal write fDecimal;
end;

...

{ TSQLRecordTest }

procedure TSQLRecordTest.ComputeFieldsBeforeWrite(aRest: TSQLRest; aOccasion: TSQLEvent);
begin
  inherited;
  fDateTime := Now;
end;

class procedure TSQLRecordTest.InternalDefineModel(Props: TSQLRecordProperties);
begin
  AddFilterNotVoidText(['Text']);
  AddFilterOrValidate('Text', TSynValidateNonNull.Create);
end;

// client
type
  TForm3 = class(TForm)
    DBGrid1: TDBGrid;
    DBNavigator1: TDBNavigator;
    btnOpen: TButton;
    edtURL: TEdit;
    dsRest: TDataSource;
    procedure FormCreate(Sender: TObject);
    procedure btnOpenClick(Sender: TObject);
    procedure DBNavigator1Click(Sender: TObject; Button: TNavigateBtn);
  private
    { Private declarations }
    fRestDS: TSynRestDataset;
  public
    { Public declarations }
  end;

...

procedure TForm3.FormCreate(Sender: TObject);
begin
  fRestDS := TSynRestDataset.Create(Self);
  fRestDS.Dataset.SQLModel := TSQLModel.Create([TSQLRecordTest], 'root');
  dsRest.Dataset := fRestDS;
end;

procedure TForm3.btnOpenClick(Sender: TObject);
begin
  fRestDS.Close;
  fRestDS.CommandText := edtURL.Text; // edtURL.Text = 'http://localhost:8888/root/Test/select=*
  fRestDS.Open;
  // you can filter by
  // where: fRestDS.CommandText := edtURL.Text; // edtURL.Text = 'http://localhost:8888/root/Test/select=*&where=CONDITION
  // fRestDS.Open;
  // named parameter: fRestDS.CommandText := edtURL.Text; // edtURL.Text = 'http://localhost:8888/root/Test/select=*&where=:PARAMNAME
  // fRestDS.Params.ParamByName('PARAMNAME').Value := XXX
  // fRestDS.Open;
end;

procedure TForm3.DBNavigator1Click(Sender: TObject; Button: TNavigateBtn);
begin
  if (Button = nbPost) then
    fRestDS.ApplyUpdates(0);
end;

Example 2: from a service

 // defining the table, the service name and operation name are required
TSQLRecordServiceName_OperationName = class(TSQLRecord)
private
  fText: RawUTF8;
published
  property Text: RawUTF8 index 255 read fText write fText;
end;

...

// server (the implementation)

TServiceName =class(TInterfacedObjectWithCustomCreate, IServiceName)
public
  ...
  // this function can also be function OperationName(const aParamName: RawUTF8): RawUTF8;
  function OperationName(const aParamName: RawUTF8; out aData: RawUTF8): Integer;
  ...
end;

...

function TServiceName.OperationName(const aParamName: RawUTF8; out aData: RawUTF8): Integer;
begin
   Result := OK;
   aData := '[{"text":"test"},{"text":"test1"}]';    
end;

...

// client
type
  TForm3 = class(TForm)
    DBGrid1: TDBGrid;
    DBNavigator1: TDBNavigator;
    btnOpen: TButton;
    edtURL: TEdit;
    dsRest: TDataSource;
    procedure FormCreate(Sender: TObject);
    procedure btnOpenClick(Sender: TObject);
    procedure DBNavigator1Click(Sender: TObject; Button: TNavigateBtn);
  private
    { Private declarations }
    fRestDS: TSynRestDataset;
  public
    { Public declarations }
  end;

...

procedure TForm3.FormCreate(Sender: TObject);
begin
  fRestDS := TSynRestDataset.Create(Self);
  fRestDS.Dataset.SQLModel := TSQLModel.Create([TSQLRecordServiceName_OperationName], 'root');
  dsRest.Dataset := fRestDS;
end;

procedure TForm3.btnOpenClick(Sender: TObject);
begin
  fRestDS.Close;
  fRestDS.CommandText := edtURL.Text; // edtURL.Text = 'http://localhost:8888/root/ServiceName.OperationName?aParamName=XXX
  fRestDS.Open;
  // you can filter by named parameter:
  // fRestDS.CommandText := edtURL.Text; // 'http://localhost:8888/root/ServiceName.OperationName?aParamName=:aParamName
  // fRestDS.Params.ParamByName('aParamName').Value := XXX
  // fRestDS.Open;
end;

procedure TForm3.DBNavigator1Click(Sender: TObject; Button: TNavigateBtn);
begin
  if (Button = nbPost) then
    fRestDS.ApplyUpdates(0); // raise an error "Cannot update data from a service"
end;

Forum Thread

See http://synopse.info/forum/viewtopic.php?id=2712

License

Feel free to use and/or append to Lib and extend if needed.