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.