sqldbrestdataset.pp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2019 by Michael Van Canneyt, member of the
  4. Free Pascal development team
  5. Simple SQLDBRESTBridge JSON dataset component and connection.
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. unit sqldbrestdataset;
  13. {$mode objfpc}
  14. interface
  15. uses
  16. Classes, SysUtils, JS, web, db, JSONDataset, restconnection;
  17. Type
  18. { TSQLDBRestConnection }
  19. TSQLDBRestConnection = Class(TRestConnection)
  20. private
  21. FConnectionsResourceName: String;
  22. FCustomViewResourceName: String;
  23. FDataProperty: String;
  24. FmetaDataProperty: String;
  25. FMetaDataResourceName: String;
  26. FonGetResources: TNotifyEvent;
  27. FPassword: String;
  28. FResourceList: TStrings;
  29. FUserName: String;
  30. procedure DoResources(Sender: TObject);
  31. function DoStoreDataProp: Boolean;
  32. function DoStoreMetadata: Boolean;
  33. function DoStoreMetadataProp: Boolean;
  34. Protected
  35. Procedure SetupRequest(aXHR : TJSXMLHttpRequest); override;
  36. Function GetUpdateBaseURL(aRequest: TRecordUpdateDescriptor): String; override;
  37. Function GetReadBaseURL(aRequest: TDataRequest): String; Override;
  38. Public
  39. Constructor create(aOwner : TComponent); override;
  40. Destructor Destroy; override;
  41. Procedure GetResources(OnResult : TNotifyEvent = Nil);
  42. Property ResourceList : TStrings Read FResourceList;
  43. Published
  44. Property OnGetResources : TNotifyEvent Read FonGetResources Write FOnGetResources;
  45. Property metaDataProperty : String read FmetaDataProperty Write FmetaDataProperty Stored DoStoreMetadataProp;
  46. Property DataProperty : String read FDataProperty Write FDataProperty Stored DoStoreDataProp;
  47. Property MetaDataResourceName : String Read FMetaDataResourceName Write FMetaDataResourceName Stored DoStoreMetadata;
  48. Property UserName : String Read FUserName Write FUserName;
  49. Property Password : String Read FPassword Write FPassword;
  50. Property ConnectionsResourceName : String Read FConnectionsResourceName Write FConnectionsResourceName;
  51. Property CustomViewResourceName : String Read FCustomViewResourceName Write FCustomViewResourceName;
  52. // Published from TRESTCOnnection
  53. Property BaseURL;
  54. Property PageParam;
  55. Property OnGetURL;
  56. Property OnUpdateURL;
  57. end;
  58. { TSQLDBRestDataset }
  59. { TQueryParam }
  60. TQueryParam = class(TParam)
  61. private
  62. FEnabled: Boolean;
  63. Public
  64. Procedure Assign(Source : TPersistent); override;
  65. function AsQuery : String;
  66. Published
  67. Property Enabled : Boolean Read FEnabled Write FEnabled;
  68. end;
  69. { TQueryParams }
  70. TQueryParams = Class(TParams)
  71. private
  72. function GetP(aIndex : Integer): TQueryParam;
  73. procedure SetP(aIndex : Integer; AValue: TQueryParam);
  74. Public
  75. function AddParam(aName : string; aEnabled : Boolean = False) : TQueryParam; overload;
  76. Property Params[aIndex : Integer] : TQueryParam Read GetP Write SetP; default;
  77. end;
  78. TGetQueryParamsEvent = Procedure (Sender : TDataset; IsReadURL : Boolean; var QueryString : String) of object;
  79. TSQLDBRestDataset = Class(TJSONDataset)
  80. private
  81. FAutoApplyUpdates: Boolean;
  82. FConnection: TSQLDBRestConnection;
  83. FDatabaseConnection: String;
  84. FOnGetQueryParams: TGetQueryParamsEvent;
  85. FParams: TQueryParams;
  86. FResourceID: String;
  87. FResourceName: String;
  88. FSQL: TStrings;
  89. function CleanSQL: String;
  90. function CustomViewResourceName: String;
  91. procedure DoSQLChange(Sender: TObject);
  92. procedure SetConnection(AValue: TSQLDBRestConnection);
  93. procedure SetParams(AValue: TQueryParams);
  94. procedure SetResourceID(AValue: String);
  95. procedure SetResourceName(AValue: String);
  96. procedure SetSQL(AValue: TStrings);
  97. Protected
  98. Procedure DoAfterPost; override;
  99. Procedure DoAfterDelete; override;
  100. function MyURL(isRead : Boolean): String; virtual;
  101. Function CreateQueryParams : TQueryParams; virtual;
  102. function GetURLQueryParams(IsRead : Boolean): string; virtual;
  103. function DataPacketReceived(ARequest: TDataRequest): Boolean; override;
  104. function GetStringFieldLength(F: TJSObject; AName: String; AIndex: Integer): integer;virtual;
  105. function StringToFieldType(S: String): TFieldType; virtual;
  106. Function DoGetDataProxy: TDataProxy; override;
  107. Procedure MetaDataToFieldDefs; override;
  108. Public
  109. Constructor Create(aOwner : TComponent); override;
  110. Destructor Destroy; override;
  111. Class Function DefaultBlobDataToBytes(aValue : JSValue) : TBytes; override;
  112. Class Function DefaultBytesToBlobData(aValue : TBytes) : JSValue; override;
  113. Function ParamByName(const aName : String) : TQueryParam;
  114. Published
  115. // Connection to use to get data
  116. Property Connection: TSQLDBRestConnection Read FConnection Write SetConnection;
  117. // The resource to get/post/put/delete
  118. Property ResourceName : String Read FResourceName Write SetResourceName;
  119. // When set, the CustomView resource (as set in CustomViewResourceName) is used. Use with care!
  120. Property SQL : TStrings Read FSQL Write SetSQL;
  121. // Database connection to use for the resource. Will be appended to URL.
  122. property DatabaseConnection : String Read FDatabaseConnection Write FDatabaseConnection;
  123. // Parameters to send (use for filtering)
  124. Property Params : TQueryParams Read FParams Write SetParams;
  125. {
  126. If you want to get a single resource, set the ID of the resource here.
  127. This is equivalent to setting a parameter ID to the specified value.
  128. }
  129. Property ResourceID : String Read FResourceID Write SetResourceID;
  130. // Get additional parameters with this event.
  131. Property OnGetQueryParams : TGetQueryParamsEvent Read FOnGetQueryParams Write FOnGetQueryParams;
  132. // Always immediatly call ApplyUpdates after post and delete.
  133. Property AutoApplyUpdates : Boolean Read FAutoApplyUpdates Write FAutoApplyUpdates;
  134. end;
  135. implementation
  136. uses DateUtils;
  137. Type
  138. { TServiceRequest }
  139. TServiceRequest = Class(TObject)
  140. Private
  141. FOnMyDone,
  142. FOnDone : TNotifyEvent;
  143. FXHR: TJSXMLHttpRequest;
  144. function GetResult: String;
  145. function GetResultJSON: TJSObject;
  146. function GetStatusCode: Integer;
  147. function onLoad(Event{%H-}: TEventListenerEvent): boolean;
  148. Public
  149. Constructor Create(Const aMethod,aURL,aUserName,aPassword : String; aOnDone1 : TNotifyEvent; aOnDone2 : TNotifyEvent = Nil);
  150. Procedure Execute;
  151. Property RequestResult : String read GetResult;
  152. Property ResultJSON : TJSObject read GetResultJSON;
  153. Property OnDone : TNotifyEvent Read FOnDone;
  154. Property StatusCode : Integer Read GetStatusCode;
  155. end;
  156. { TQueryParam }
  157. procedure TQueryParam.Assign(Source: TPersistent);
  158. Var
  159. P : TQueryParam absolute Source;
  160. begin
  161. if Source is TQueryParam then
  162. begin
  163. FEnabled:=P.Enabled;
  164. end;
  165. inherited Assign(Source);
  166. end;
  167. function TQueryParam.AsQuery: String;
  168. var
  169. B : TBytes;
  170. I : Integer;
  171. begin
  172. Result:='';
  173. if Not Enabled then
  174. exit;
  175. Case DataType of
  176. ftInteger : Result:=IntToStr(AsInteger);
  177. ftAutoInc,
  178. ftLargeInt : Result:=IntToStr(AsLargeInt);
  179. ftBoolean : Result:=IntToStr(Ord(AsBoolean));
  180. ftFloat : Str(asFloat,Result);
  181. ftDate : Result:=DateToISO8601(asDateTime);
  182. ftTime : Result:=DateToISO8601(asDateTime);
  183. ftDateTime : Result:=DateToISO8601(asDateTime);
  184. ftBlob :
  185. begin
  186. B:=AsBlob;
  187. Result:='';
  188. For I:=0 to Length(B)-1 do
  189. Result:=TJSString(Result).Concat(TJSString.fromCharCode(B[I]));
  190. end;
  191. ftMemo : Result:=AsMemo;
  192. else
  193. Result:=AsString
  194. end;
  195. Result:=Name+'='+Result;
  196. end;
  197. { TQueryParams }
  198. function TQueryParams.GetP(aIndex : Integer): TQueryParam;
  199. begin
  200. Result:=Items[aIndex] as TQueryParam
  201. end;
  202. procedure TQueryParams.SetP(aIndex : Integer; AValue: TQueryParam);
  203. begin
  204. Items[aIndex]:=aValue;
  205. end;
  206. function TQueryParams.AddParam(aName: string; aEnabled: Boolean): TQueryParam;
  207. begin
  208. Result:=add As TQueryParam;
  209. Result.Name:=aName;
  210. Result.Enabled:=aEnabled;
  211. end;
  212. { TServiceRequest }
  213. constructor TServiceRequest.Create(const aMethod,aURL, aUserName, aPassword: String; aOnDone1 : TNotifyEvent; aOnDone2 : TNotifyEvent = Nil);
  214. begin
  215. FOnMyDone:=aOnDone1;
  216. FOnDone:=aOnDone2;
  217. FXHR:=TJSXMLHttpRequest.New;
  218. FXHR.AddEventListener('load',@onLoad);
  219. FXHR.open(aMethod,aURL,true);
  220. (* else
  221. begin
  222. // FXHR.withCredentials := true;
  223. FXHR.open(aMethod,aURL,true,aUserName,aPassword);
  224. end;*)
  225. FXHR.setRequestHeader('Content-Type', 'application/json');
  226. FXHR.setRequestHeader('Authorization', 'Basic '+window.btoa(aUserName+':'+aPassword));
  227. end;
  228. procedure TServiceRequest.Execute;
  229. begin
  230. FXHR.send;
  231. end;
  232. function TServiceRequest.GetResult: String;
  233. begin
  234. Result:=FXHR.responseText;
  235. end;
  236. function TServiceRequest.GetResultJSON: TJSObject;
  237. begin
  238. if SameText(FXHR.getResponseHeader('Content-Type'),'application/json') then
  239. Result:=TJSJSON.parseObject(RequestResult)
  240. else
  241. Result:=nil;
  242. end;
  243. function TServiceRequest.GetStatusCode: Integer;
  244. begin
  245. Result:=FXHR.Status;
  246. end;
  247. function TServiceRequest.onLoad(Event: TEventListenerEvent): boolean;
  248. begin
  249. if Assigned(FOnMyDone) then
  250. FOnMyDone(Self);
  251. Result:=False;
  252. end;
  253. { TSQLDBRestConnection }
  254. function TSQLDBRestConnection.DoStoreMetadata: Boolean;
  255. begin
  256. Result:=(FMetadataResourceName<>'metadata');
  257. end;
  258. function TSQLDBRestConnection.DoStoreMetadataProp: Boolean;
  259. begin
  260. Result:=(FMetaDataProperty<>'metaData');
  261. end;
  262. procedure TSQLDBRestConnection.SetupRequest(aXHR: TJSXMLHttpRequest);
  263. begin
  264. aXHR.setRequestHeader('Content-Type', 'application/json');
  265. aXHR.setRequestHeader('Accept', 'application/json');
  266. if (UserName<>'') then
  267. aXHR.setRequestHeader('Authorization', 'Basic '+window.btoa(UserName+':'+Password));
  268. // Will call the OnSetupHTTPRequest handler
  269. inherited SetupRequest(aXHR);
  270. end;
  271. function TSQLDBRestConnection.GetUpdateBaseURL(aRequest: TRecordUpdateDescriptor): String;
  272. Var
  273. DS : TSQLDBRestDataset;
  274. begin
  275. Result:=inherited GetUpdateBaseURL(aRequest);
  276. DS:=TSQLDBRestDataset(aRequest.Dataset);
  277. Result:=IncludeTrailingPathDelimiter(Result)+DS.MyURL(False);
  278. end;
  279. function TSQLDBRestConnection.GetReadBaseURL(aRequest: TDataRequest): String;
  280. Var
  281. DS : TSQLDBRestDataset;
  282. begin
  283. Result:=inherited GetReadBaseURL(aRequest);
  284. DS:=TSQLDBRestDataset(aRequest.Dataset);
  285. Result:=IncludeTrailingPathDelimiter(Result)+DS.MyURL(True);
  286. end;
  287. procedure TSQLDBRestConnection.DoResources(Sender: TObject);
  288. Var
  289. R : TServiceRequest absolute Sender;
  290. J,Res : TJSObject;
  291. A : TJSArray;
  292. i : Integer;
  293. begin
  294. FResourceList.Clear;
  295. if (R.StatusCode=200) then
  296. begin
  297. J:=R.ResultJSON;
  298. if J=Nil then
  299. exit;
  300. A:=TJSArray(J.Properties['data']);
  301. For I:=0 to A.Length-1 do
  302. begin
  303. Res:=TJSObject(A[i]);
  304. FResourceList.Add(String(Res.Properties['name']));
  305. end;
  306. end;
  307. If Assigned(R.OnDone) then
  308. R.OnDone(Self);
  309. If Assigned(OnGetResources) then
  310. OnGetResources(Self);
  311. end;
  312. function TSQLDBRestConnection.DoStoreDataProp: Boolean;
  313. begin
  314. Result:=(FDataProperty<>'data');
  315. end;
  316. constructor TSQLDBRestConnection.create(aOwner: TComponent);
  317. begin
  318. inherited create(aOwner);
  319. FResourceList:=TStringList.Create;
  320. FMetaDataResourceName:='metadata';
  321. FmetaDataProperty:='metaData';
  322. FDataProperty:='data';
  323. TStringList(FResourceList).Sorted:=true;
  324. end;
  325. destructor TSQLDBRestConnection.Destroy;
  326. begin
  327. FreeAndNil(FResourceList);
  328. inherited Destroy;
  329. end;
  330. procedure TSQLDBRestConnection.GetResources(OnResult: TNotifyEvent);
  331. Var
  332. aURL : String;
  333. R : TServiceRequest;
  334. begin
  335. aURL:=IncludeTrailingPathDelimiter(BaseURL)+MetaDataResourceName+'?fmt=json';
  336. R:=TServiceRequest.Create('GET',aURL,Self.UserName,Self.Password,@DoResources,OnResult);
  337. R.Execute;
  338. end;
  339. { TSQLDBRestDataset }
  340. procedure TSQLDBRestDataset.SetConnection(AValue: TSQLDBRestConnection);
  341. begin
  342. if FConnection=AValue then Exit;
  343. if Assigned(FConnection) then
  344. FConnection.RemoveFreeNotification(Self);
  345. FConnection:=AValue;
  346. if Assigned(FConnection) then
  347. FConnection.FreeNotification(Self);
  348. end;
  349. procedure TSQLDBRestDataset.SetParams(AValue: TQueryParams);
  350. begin
  351. if FParams=AValue then Exit;
  352. FParams.Assign(AValue);
  353. end;
  354. procedure TSQLDBRestDataset.SetResourceID(AValue: String);
  355. begin
  356. if FResourceID=AValue then Exit;
  357. CheckInactive;
  358. FResourceID:=AValue;
  359. end;
  360. function TSQLDBRestDataset.GetURLQueryParams(IsRead :Boolean) : string;
  361. Procedure AddToResult(aQuery : string);
  362. begin
  363. if aQuery='' then
  364. exit;
  365. If Result<>'' then
  366. Result:=Result+'&';
  367. Result:=Result+aQuery;
  368. end;
  369. Var
  370. I : Integer;
  371. begin
  372. Result:='';
  373. if IsRead then
  374. begin
  375. if SameText(ResourceName,CustomViewResourceName) then
  376. AddToResult('SQL='+EncodeURIComponent(CleanSQL));
  377. For I:=0 to Params.Count-1 do
  378. AddToResult(Params[I].AsQuery);
  379. end;
  380. if Assigned(FOnGetQueryParams) then
  381. FOnGetQueryParams(Self,IsRead,Result);
  382. end;
  383. function TSQLDBRestDataset.MyURL(isRead: Boolean): String;
  384. Var
  385. Qry : String;
  386. begin
  387. Result:=DatabaseConnection;
  388. if (Result<>'') and (Result[Length(Result)]<>'/') then
  389. Result:=Result+'/';
  390. Result:=Result+ResourceName;
  391. if IsRead and (ResourceID<>'') then
  392. Result:=Result+'/'+EncodeURIComponent(ResourceID);
  393. Qry:=GetURLQueryParams(IsRead);
  394. if Qry<>'' then
  395. Result:=Result+'?'+Qry;
  396. end;
  397. procedure TSQLDBRestDataset.DoSQLChange(Sender: TObject);
  398. begin
  399. if Trim(FSQL.Text)<>'' then
  400. FResourceName:=CustomViewResourceName;
  401. end;
  402. procedure TSQLDBRestDataset.SetResourceName(AValue: String);
  403. begin
  404. if FResourceName=AValue then Exit;
  405. CheckInactive;
  406. if Not SameText(aValue,CustomViewResourceName) then
  407. FSQL.Clear;
  408. FResourceName:=AValue;
  409. end;
  410. function TSQLDBRestDataset.CustomViewResourceName : String;
  411. begin
  412. if Assigned(Connection) then
  413. Result:=Connection.CustomViewResourceName
  414. else
  415. Result:='customView';
  416. end;
  417. function TSQLDBRestDataset.CleanSQL: String;
  418. begin
  419. Result:=StringReplace(SQL.Text,#13#10,' ',[rfReplaceAll]);
  420. Result:=StringReplace(Result,#10,' ',[rfReplaceAll]);
  421. Result:=StringReplace(Result,#10,' ',[rfReplaceAll]);
  422. end;
  423. procedure TSQLDBRestDataset.SetSQL(AValue: TStrings);
  424. begin
  425. if FSQL=AValue then Exit;
  426. FSQL.Assign(AValue);
  427. end;
  428. procedure TSQLDBRestDataset.DoAfterPost;
  429. begin
  430. inherited DoAfterPost;
  431. if AutoApplyUpdates then
  432. ApplyUpdates;
  433. end;
  434. procedure TSQLDBRestDataset.DoAfterDelete;
  435. begin
  436. inherited DoAfterDelete;
  437. if AutoApplyUpdates then
  438. ApplyUpdates;
  439. end;
  440. function TSQLDBRestDataset.CreateQueryParams: TQueryParams;
  441. begin
  442. Result:=TQueryParams.Create(Self,TQueryParam);
  443. end;
  444. class function TSQLDBRestDataset.DefaultBlobDataToBytes(aValue: JSValue): TBytes;
  445. begin
  446. Result:=BytesOf(Window.atob(String(aValue)));
  447. end;
  448. class function TSQLDBRestDataset.DefaultBytesToBlobData(aValue: TBytes
  449. ): JSValue;
  450. begin
  451. Result:=Window.Btoa(StringOf(aValue));
  452. end;
  453. function TSQLDBRestDataset.ParamByName(const aName: String): TQueryParam;
  454. begin
  455. Result:=TQueryParam(Params.ParamByName(aName));
  456. end;
  457. function TSQLDBRestDataset.DoGetDataProxy: TDataProxy;
  458. begin
  459. Result:=Connection.DataProxy;
  460. end;
  461. function TSQLDBRestDataset.StringToFieldType(S: String): TFieldType;
  462. begin
  463. if (s='int') then
  464. Result:=ftInteger
  465. else if (s='bigint') then
  466. Result:=ftLargeInt
  467. else if (s='float') then
  468. Result:=ftFloat
  469. else if (s='bool') then
  470. Result:=ftBoolean
  471. else if (s='date') then
  472. Result:=ftDate
  473. else if (s='datetime') then
  474. Result:=ftDateTime
  475. else if (s='time') then
  476. Result:=ftTime
  477. else if (s='blob') then
  478. Result:=ftBlob
  479. else if (s='string') then
  480. Result:=ftString
  481. else
  482. if MapUnknownToStringType then
  483. Result:=ftString
  484. else
  485. Raise EJSONDataset.CreateFmt('Unknown JSON data type : %s',[s]);
  486. end;
  487. function TSQLDBRestDataset.GetStringFieldLength(F: TJSObject; AName: String;
  488. AIndex: Integer): integer;
  489. Var
  490. I,L : Integer;
  491. D : JSValue;
  492. begin
  493. Result:=0;
  494. D:=F.Properties['maxLen'];
  495. if Not jsIsNan(toNumber(D)) then
  496. begin
  497. Result:=Trunc(toNumber(D));
  498. if (Result<0) then
  499. Raise EJSONDataset.CreateFmt('Invalid maximum length specifier for field %s',[AName])
  500. else if Result=0 then // memofield
  501. Result:=1000000
  502. end
  503. else
  504. begin
  505. For I:=0 to Rows.Length-1 do
  506. begin
  507. D:=FieldMapper.GetJSONDataForField(Aname,AIndex,Rows[i]);
  508. if isString(D) then
  509. begin
  510. l:=Length(String(D));
  511. if L>Result then
  512. Result:=L;
  513. end;
  514. end;
  515. end;
  516. if (Result=0) then
  517. Result:=20;
  518. end;
  519. procedure TSQLDBRestDataset.MetaDataToFieldDefs;
  520. Var
  521. A : TJSArray;
  522. F : TJSObject;
  523. I,FS : Integer;
  524. N: String;
  525. ft: TFieldType;
  526. D : JSValue;
  527. begin
  528. FieldDefs.Clear;
  529. D:=Metadata.Properties['fields'];
  530. if Not IsArray(D) then
  531. Raise EJSONDataset.Create('Invalid metadata object');
  532. A:=TJSArray(D);
  533. For I:=0 to A.Length-1 do
  534. begin
  535. If Not isObject(A[i]) then
  536. Raise EJSONDataset.CreateFmt('Field definition %d in metadata is not an object',[i]);
  537. F:=TJSObject(A[i]);
  538. D:=F.Properties['name'];
  539. If Not isString(D) then
  540. Raise EJSONDataset.CreateFmt('Field definition %d in has no or invalid name property',[i]);
  541. N:=String(D);
  542. D:=F.Properties['type'];
  543. If IsNull(D) or isUndefined(D) then
  544. ft:=ftstring
  545. else If Not isString(D) then
  546. begin
  547. Raise EJSONDataset.CreateFmt('Field definition %d in has invalid type property',[i])
  548. end
  549. else
  550. begin
  551. ft:=StringToFieldType(String(D));
  552. end;
  553. if (ft=ftString) then
  554. fs:=GetStringFieldLength(F,N,I)
  555. else
  556. fs:=0;
  557. FieldDefs.Add(N,ft,fs);
  558. end;
  559. end;
  560. constructor TSQLDBRestDataset.Create(aOwner: TComponent);
  561. begin
  562. inherited Create(aOwner);
  563. FSQL:=TStringList.Create;
  564. TStringList(FSQL).OnChange:=@DoSQLChange;
  565. FParams:=CreateQueryParams;
  566. BlobFormat:=bfBase64;
  567. end;
  568. destructor TSQLDBRestDataset.Destroy;
  569. begin
  570. FreeAndNil(FSQL);
  571. FreeAndnil(FParams);
  572. inherited Destroy;
  573. end;
  574. function TSQLDBRestDataset.DataPacketReceived(ARequest: TDataRequest): Boolean;
  575. Var
  576. O : TJSObject;
  577. A : TJSArray;
  578. smetadata,sroot : String;
  579. begin
  580. Result:=False;
  581. If isNull(aRequest.Data) then
  582. exit;
  583. If isString(aRequest.Data) then
  584. O:=TJSOBject(TJSJSON.Parse(String(aRequest.Data)))
  585. else if isObject(aRequest.Data) then
  586. O:=TJSOBject(aRequest.Data)
  587. else
  588. DatabaseError('Cannot handle data packet');
  589. sRoot:=Connection.DataProperty;
  590. sMetaData:=Connection.metaDataProperty;
  591. if (sroot='') then
  592. sroot:='data';
  593. if (smetadata='') then
  594. smetadata:='metaData';
  595. { if (IDField='') then
  596. idField:='id';}
  597. if O.hasOwnProperty(sMetaData) and isObject(o[sMetaData]) then
  598. begin
  599. if not Active then // Load fields from metadata
  600. metaData:=TJSObject(o[SMetaData]);
  601. { if metaData.hasOwnProperty('idField') and isString(metaData['idField']) then
  602. IDField:=string(metaData['idField']);}
  603. end;
  604. if O.hasOwnProperty(sRoot) and isArray(o[sRoot]) then
  605. begin
  606. A:=TJSArray(o[sRoot]);
  607. Result:=A.Length>0;
  608. AddToRows(A);
  609. end;
  610. end;
  611. end.