sqldbrestjson.pp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2019 by the Free Pascal development team
  4. SQLDB REST bridge JSON input/output.
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. unit sqldbrestjson;
  12. {$mode objfpc}{$H+}
  13. interface
  14. uses
  15. Classes, SysUtils, fpjson, db, sqldbrestio, sqldbrestschema;
  16. Type
  17. { TJSONInputStreamer }
  18. TJSONInputStreamer = Class(TRestInputStreamer)
  19. private
  20. FJSON: TJSONData;
  21. Protected
  22. Property JSON : TJSONData Read FJSON;
  23. Public
  24. Destructor Destroy; override;
  25. Function SelectObject(aIndex : Integer) : Boolean; override;
  26. function GetContentField(aName: UTF8string): TJSONData; override;
  27. procedure InitStreaming; override;
  28. end;
  29. { TJSONOutputStreamer }
  30. TJSONOutputStreamer = Class(TRestOutputStreamer)
  31. Private
  32. FJSON : TJSONObject;
  33. FData : TJSONArray;
  34. FRow: TJSONData;
  35. Public
  36. procedure EndData; override;
  37. procedure EndRow; override;
  38. procedure FinalizeOutput; override;
  39. procedure StartData; override;
  40. procedure StartRow; override;
  41. // Return Nil for null field.
  42. function FieldToJSON(aPair: TRestFieldPair): TJSONData; virtual;
  43. procedure WriteField(aPair: TRestFieldPair); override;
  44. procedure WriteMetadata(aFieldList: TRestFieldPairArray); override;
  45. Procedure CreateErrorContent(aCode : Integer; Const aMessage: String); override;
  46. Property JSON : TJSONObject Read FJSON;
  47. Property Data : TJSONArray Read FData;
  48. Property Row : TJSONData Read FRow;
  49. Public
  50. Destructor Destroy; override;
  51. Class Function GetContentType: String; override;
  52. procedure InitStreaming; override;
  53. end;
  54. implementation
  55. uses DateUtils, sqldbrestconst;
  56. { TJSONInputStreamer }
  57. procedure TJSONInputStreamer.InitStreaming;
  58. Var
  59. Msg : String;
  60. begin
  61. FreeAndNil(FJSON);
  62. if (Stream.Size>0) then
  63. begin
  64. try
  65. FJSON:=GetJSON(Stream);
  66. except
  67. On E : Exception do
  68. begin
  69. Msg:=E.Message;
  70. FJSON:=Nil;
  71. end;
  72. end;
  73. if (FJSON=Nil) then
  74. Raise ESQLDBRest.CreateFmt(Statuses.GetStatusCode(rsInvalidContent),'Invalid JSON input: %s',[Msg]);
  75. end;
  76. end;
  77. destructor TJSONInputStreamer.Destroy;
  78. begin
  79. FreeAndNil(FJSON);
  80. inherited Destroy;
  81. end;
  82. function TJSONInputStreamer.SelectObject(aIndex: Integer): Boolean;
  83. begin
  84. Result:=(aIndex=0) and (FJSON<>Nil) and (FJSON is TJSONObject)
  85. end;
  86. function TJSONInputStreamer.GetContentField(aName: UTF8string): TJSONData;
  87. Var
  88. D : TJSONData;
  89. begin
  90. D:=(FJSON as TJSONObject).Find(aName);
  91. if D<>nil then
  92. Result:=D.Clone
  93. else
  94. Result:=nil;
  95. end;
  96. { TJSONOutputStreamer }
  97. procedure TJSONOutputStreamer.EndData;
  98. begin
  99. FData:=Nil;
  100. end;
  101. procedure TJSONOutputStreamer.EndRow;
  102. begin
  103. FRow:=Nil;
  104. end;
  105. procedure TJSONOutputStreamer.FinalizeOutput;
  106. Var
  107. S : TJSONStringType;
  108. begin
  109. if ooHumanReadable in OutputOptions then
  110. S:=FJSON.FormatJSON()
  111. else
  112. S:=FJSON.AsJSON;
  113. Stream.WriteBuffer(S[1],Length(S)*SizeOf(TJSONCharType));
  114. FreeAndNil(FJSON);
  115. end;
  116. procedure TJSONOutputStreamer.StartData;
  117. begin
  118. FData:=TJSONArray.Create;
  119. FJSON.Add(GetString(rpDataRoot),FData);
  120. end;
  121. procedure TJSONOutputStreamer.StartRow;
  122. begin
  123. if (FRow<>Nil) then
  124. Raise ESQLDBRest.Create(Statuses.GetStatusCode(rsError),SErrDoubleRowStart);
  125. FRow:=TJSONObject.Create;
  126. FData.Add(FRow);
  127. end;
  128. Function TJSONOutputStreamer.FieldToJSON(aPair: TRestFieldPair) : TJSONData;
  129. Var
  130. F : TField;
  131. begin
  132. Result:=Nil;
  133. F:=aPair.DBField;;
  134. If (aPair.RestField.FieldType=rftUnknown) then
  135. raise ESQLDBRest.CreateFmt(Statuses.GetStatusCode(rsError),SErrUnsupportedRestFieldType, [aPair.RestField.PublicName]);
  136. If (F.IsNull) then
  137. Exit;
  138. Case aPair.RestField.FieldType of
  139. rftInteger : Result:=TJSONIntegerNumber.Create(F.AsInteger);
  140. rftLargeInt : Result:=TJSONInt64Number.Create(F.AsLargeInt);
  141. rftFloat : Result:=TJSONFloatNumber.Create(F.AsFloat);
  142. rftDate : Result:=TJSONString.Create(FormatDateTime(GetString(rpDateFormat),DateOf(F.AsDateTime)));
  143. rftTime : Result:=TJSONString.Create(FormatDateTime(GetString(rpTimeFormat),TimeOf(F.AsDateTime)));
  144. rftDateTime : Result:=TJSONString.Create(FormatDateTime(GetString(rpDateTimeFormat),F.AsDateTime));
  145. rftString : Result:=TJSONString.Create(F.AsString);
  146. rftBoolean : Result:=TJSONBoolean.Create(F.AsBoolean);
  147. rftBlob : Result:=TJSONString.Create(FieldToBase64(F));
  148. end;
  149. end;
  150. procedure TJSONOutputStreamer.WriteField(aPair: TRestFieldPair);
  151. Var
  152. D : TJSONData;
  153. N : UTF8String;
  154. begin
  155. N:=aPair.RestField.PublicName;
  156. if FRow=Nil then
  157. Raise ESQLDBRest.CreateFmt(Statuses.GetStatusCode(rsError),SErrFieldWithoutRow,[N]);
  158. D:=FieldToJSON(aPair);
  159. if (D=Nil) and ((not HasOption(ooSparse)) or (FRow is TJSONArray)) then
  160. D:=TJSONNull.Create;
  161. if D<>Nil then
  162. If FRow is TJSONArray then
  163. TJSONArray(FRow).Add(D)
  164. else if FRow is TJSONObject then
  165. TJSONObject(FRow).Add(N,D);
  166. end;
  167. procedure TJSONOutputStreamer.WriteMetadata(aFieldList: TRestFieldPairArray);
  168. Var
  169. A : TJSONArray;
  170. F : TJSONObject;
  171. P : TREstFieldPair;
  172. begin
  173. A:=TJSONArray.Create;
  174. FJSON.Add(GetString(rpMetaDataRoot),TJSOnObject.Create([GetString(rpMetaDataFields),A]));
  175. For P in aFieldList do
  176. begin
  177. F:=TJSONObject.Create([GetString(rpFieldNameProp),P.RestField.PublicName,GetString(rpFieldTypeProp),typenames[P.RestField.FieldType]]);
  178. A.Add(F);
  179. Case P.RestField.FieldType of
  180. rftDate : F.Add(GetString(rpFieldDateFormatProp),GetString(rpDateFormat));
  181. rftTime : F.Add(GetString(rpFieldDateFormatProp),GetString(rpTimeFormat));
  182. rftDateTime : F.Add(GetString(rpFieldDateFormatProp),GetString(rpDateTimeFormat));
  183. rftString : F.Add(GetString(rpFieldMaxLenProp),P.DBField.Size);
  184. end;
  185. end;
  186. end;
  187. Class function TJSONOutputStreamer.GetContentType: String;
  188. begin
  189. Result:='application/json';
  190. end;
  191. procedure TJSONOutputStreamer.CreateErrorContent(aCode: Integer; const aMessage: String);
  192. Var
  193. ErrorObj : TJSONObject;
  194. begin
  195. ErrorObj:=TJSONObject.Create([GetString(rpErrorCode),aCode,GetString(rpErrorMessage),aMessage]);
  196. FJSON.Add(GetString(rpErrorRoot),ErrorObj);
  197. end;
  198. destructor TJSONOutputStreamer.Destroy;
  199. begin
  200. FreeAndNil(FJSON);
  201. inherited Destroy;
  202. end;
  203. procedure TJSONOutputStreamer.InitStreaming;
  204. begin
  205. FJSON:=TJSONObject.Create;
  206. end;
  207. initialization
  208. TJSONInputStreamer.RegisterStreamer('json');
  209. TJSONOutputStreamer.RegisterStreamer('json');
  210. end.