sqldbrestio.pp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862
  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 Dispatcher basic I/O environment.
  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 sqldbrestio;
  12. {$mode objfpc}{$H+}
  13. interface
  14. uses
  15. Classes, SysUtils, fpjson, sqldb, db, httpdefs, sqldbrestschema;
  16. Type
  17. TVariableSource = (vsNone,vsQuery,vsContent,vsRoute,vsHeader);
  18. TVariableSources = Set of TVariableSource;
  19. TRestOutputOption = (ooMetadata,ooSparse,ooHumanReadable);
  20. TRestOutputOptions = Set of TRestOutputOption;
  21. TNullBoolean = (nbNone,nbFalse,nbTrue);
  22. TNullBooleans = set of TNullBoolean;
  23. Const
  24. AllVariableSources = [Low(TVariableSource)..High(TVariableSource)];
  25. allOutputOptions = [Low(TRestOutputOption)..High(TRestOutputOption)];
  26. Type
  27. TRestStringProperty = (rpDateFormat,
  28. rpDateTimeFormat,
  29. rpTimeFormat,
  30. rpDataRoot,
  31. rpMetaDataRoot,
  32. rpErrorRoot,
  33. rpFieldNameProp,
  34. rpFieldTypeProp,
  35. rpFieldDateFormatProp,
  36. rpFieldMaxLenProp,
  37. rpHumanReadable,
  38. rpFieldList,
  39. rpExcludeFieldList,
  40. rpConnection,
  41. rpResource,
  42. rpIncludeMetadata,
  43. rpSparse,
  44. rpRowName,
  45. rpMetaDataFields,
  46. rpMetaDataField,
  47. rpErrorCode,
  48. rpErrorMessage,
  49. rpFilterEqual,
  50. rpFilterLessThan,
  51. rpFilterGreaterThan,
  52. rpFilterLessThanEqual,
  53. rpFilterGreaterThanEqual,
  54. rpFilterIsNull,
  55. rpLimit,
  56. rpOffset,
  57. rpOrderBy,
  58. rpMetadataResourceName,
  59. rpInputFormat,
  60. rpOutputFormat,
  61. rpCustomViewResourceName,
  62. rpCustomViewSQLParam,
  63. rpXMLDocumentRoot
  64. );
  65. TRestStringProperties = Set of TRestStringProperty;
  66. TRestGetVariableEvent = Procedure (Sender : TObject; Const aName : UTF8String; Out aVal : UTF8String) of object;
  67. { TRestStringsConfig }
  68. TRestStringsConfig = Class(TPersistent)
  69. private
  70. FValues : Array[TRestStringProperty] of UTF8String;
  71. function GetRestPropName(AIndex: Integer): UTF8String;
  72. function IsRestStringStored(AIndex: Integer): Boolean;
  73. procedure SetRestPropName(AIndex: Integer; AValue: UTF8String);
  74. Public
  75. Class Function GetDefaultString(aString : TRestStringProperty) :UTF8String;
  76. Function GetRestString(aString : TRestStringProperty) :UTF8String;
  77. Procedure SetRestString(aString : TRestStringProperty; AValue :UTF8String);
  78. Procedure Assign(aSource : TPersistent); override;
  79. Published
  80. // Indexes here MUST match TRestProperty
  81. Property RESTDateFormat : UTF8String Index ord(rpDateFormat) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  82. Property RESTDateTimeFormat : UTF8String Index ord(rpDateTimeFormat) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  83. Property RESTTimeFormat : UTF8String Index ord(rpTimeFormat) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  84. Property DataProperty : UTF8String Index ord(rpDataRoot) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  85. Property MetaDataRoot : UTF8String Index ord(rpMetaDataRoot) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  86. Property ErrorProperty : UTF8String Index ord(rpErrorRoot) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  87. Property FieldNameProperty : UTF8String Index ord(rpFieldNameProp) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  88. Property FieldTypeProperty : UTF8String Index ord(rpFieldTypeProp) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  89. Property DateFormatProperty : UTF8String Index ord(rpFieldDateFormatProp) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  90. Property MaxLenProperty : UTF8String Index ord(rpFieldMaxLenProp) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  91. Property HumanReadableParam : UTF8String Index ord(rpHumanReadable) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  92. Property FieldListParam : UTF8String Index ord(rpFieldList) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  93. Property ExcludeFieldListParam : UTF8String Index ord(rpExcludeFieldList) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  94. Property ConnectionParam : UTF8String Index Ord(rpConnection) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  95. Property ResourceParam : UTF8String Index ord(rpResource) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  96. Property IncludeMetadataParam : UTF8String Index ord(rpIncludeMetadata) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  97. Property SparseParam : UTF8String Index Ord(rpSparse) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  98. Property RowName : UTF8String Index Ord(rpRowName) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  99. Property MetadataFields : UTF8String Index Ord(rpMetadataFields) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  100. Property MetadataField : UTF8String Index Ord(rpMetadataField) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  101. Property ErrorCode : UTF8String Index ord(rpErrorCode) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  102. Property ErrorMessage : UTF8String Index ord(rpErrorMessage) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  103. Property FilterParamEqual : UTF8String Index ord(rpFilterEqual) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  104. Property FilterParamLessThan : UTF8String Index ord(rpFilterLessThan) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  105. Property FilterParamGreaterThan : UTF8String Index ord(rpFilterGreaterThan) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  106. Property FilterParamLessThanEqual : UTF8String Index ord(rpFilterLessThanEqual) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  107. Property FilterParamGreaterThanEqual : UTF8String Index ord(rpFilterGreaterThanEqual) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  108. Property FilterParamIsNull : UTF8String Index ord(rpFilterIsNull) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  109. Property LimitParam : UTF8string Index ord(rpLimit) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  110. Property OffsetParam : UTF8string Index ord(rpOffset) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  111. Property SortParam : UTF8string Index ord(rpOrderBy) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  112. Property MetadataResourceName : UTF8string Index ord(rpMetadataResourceName) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  113. Property InputFormatParam : UTF8string Index ord(rpInputFormat) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  114. Property OutputFormatParam : UTF8string Index ord(rpOutputFormat) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  115. Property CustomViewResourceName : UTF8string Index ord(rpCustomViewResourceName) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  116. Property CustomViewSQLParam : UTF8string Index ord(rpCustomViewSQLParam) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  117. Property XMLDocumentRoot : UTF8string Index ord(rpXMLDocumentRoot) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  118. end;
  119. { TRestStreamer }
  120. TRestStreamer = Class(TObject)
  121. private
  122. FStream: TStream;
  123. FOnGetVar : TRestGetVariableEvent;
  124. FStrings: TRestStringsConfig;
  125. Public
  126. // Registry
  127. Class Function GetContentType : String; virtual;
  128. Constructor Create(aStream : TStream;aStrings : TRestStringsConfig;aOnGetVar : TRestGetVariableEvent);
  129. Function GetString(aString : TRestStringProperty) : UTF8String;
  130. Property Strings : TRestStringsConfig Read FStrings;
  131. procedure InitStreaming; virtual; abstract;
  132. Function GetVariable(const aName : UTF8String) : UTF8String;
  133. Property Stream : TStream Read FStream;
  134. end;
  135. TRestStreamerClass = Class of TRestStreamer;
  136. TRestInputStreamer = Class(TRestStreamer)
  137. Public
  138. // Select input object aIndex. Must return False if no such object in input
  139. // Currently aIndex=0, but for batch operations this may later become nonzero.
  140. Function SelectObject(aIndex : Integer) : Boolean; virtual; abstract;
  141. // Return Nil if none found. If result is non-nil, caller will free.
  142. Function GetContentField(aName : UTF8string) : TJSONData; virtual; abstract;
  143. Class Procedure RegisterStreamer(Const aName : String);
  144. Class Procedure UnRegisterStreamer(Const aName : String);
  145. end;
  146. TRestInputStreamerClass = Class of TRestInputStreamer;
  147. { TRestOutputStreamer }
  148. TRestOutputStreamer = Class(TRestStreamer)
  149. private
  150. FOutputOptions: TRestOutputOptions;
  151. Protected
  152. procedure SetOutputOptions(AValue: TRestOutputOptions); virtual;
  153. Public
  154. Class Procedure RegisterStreamer(Const aName : String);
  155. Class Procedure UnRegisterStreamer(Const aName : String);
  156. function RequireMetadata : Boolean; virtual;
  157. Function FieldToString(aFieldType : TRestFieldType; F : TField) : UTF8string; virtual;
  158. function FieldToBase64(F: TField): UTF8String; virtual;
  159. Function HasOption(aOption : TRestOutputOption) : Boolean;
  160. Procedure CreateErrorContent(aCode : Integer; Const aMessage: String); virtual; abstract;
  161. Procedure CreateErrorContent(aCode : Integer; Const Fmt: String; Const Args : Array of const);
  162. Procedure WriteMetadata(aFieldList : TRestFieldPairArray); virtual; abstract;
  163. Procedure StartData; virtual; abstract;
  164. Procedure StartRow; virtual; abstract;
  165. Procedure WriteField(aPair : TRestFieldPair); virtual; abstract;
  166. Procedure EndRow; virtual; abstract;
  167. Procedure EndData; virtual; abstract;
  168. Procedure FinalizeOutput; virtual; abstract;
  169. // Set before InitStreaming is called;
  170. Property OutputOptions : TRestOutputOptions Read FOutputOptions Write SetOutputOptions;
  171. end;
  172. TRestOutputStreamerClass = class of TRestOutputStreamer;
  173. { TRestIO }
  174. TRestIO = Class
  175. private
  176. FConn: TSQLConnection;
  177. FCOnnection: UTF8String;
  178. FInput: TRestInputStreamer;
  179. FOperation: TRestOperation;
  180. FOutput: TRestOutputStreamer;
  181. FRequest: TRequest;
  182. FResource: TSQLDBRestResource;
  183. FResourceName: UTF8String;
  184. FResponse: TResponse;
  185. FRestStrings: TRestStringsConfig;
  186. FSchema: UTF8String;
  187. FTrans: TSQLTransaction;
  188. FContentStream : TStream;
  189. FUserID: String;
  190. Protected
  191. Public
  192. Constructor Create(aRequest : TRequest; aResponse : TResponse); virtual;
  193. Destructor Destroy; override;
  194. // Set things.
  195. Procedure SetIO(aInput : TRestInputStreamer;aOutput : TRestOutputStreamer);
  196. Procedure SetConn(aConn : TSQLConnection; ATrans : TSQLTransaction);
  197. Procedure SetResource(aResource : TSQLDBRestResource);
  198. procedure SetOperation(aOperation : TRestOperation);
  199. Procedure SetRestStrings(aValue : TRestStringsConfig);
  200. // Get things
  201. class function StrToNullBoolean(S: String; Strict: Boolean): TNullBoolean;
  202. Procedure DoGetVariable(Sender : TObject; Const aName : UTF8String; Out aVal : UTF8String);
  203. Function GetVariable (Const aName : UTF8String; Out aVal : UTF8String; AllowedSources : TVAriableSources = AllVariableSources) : TVariableSource; virtual;
  204. function GetFilterVariable(const aName: UTF8String; AFilter: TRestFieldFilter; out aValue: UTF8String): TVariableSource;
  205. Function GetBooleanVar(Const aName : UTF8String; aStrict : Boolean = False) : TNullBoolean;
  206. function GetRequestOutputOptions(aDefault: TRestOutputOptions): TRestOutputOptions;
  207. function GetLimitOffset(aEnforceLimit: Int64; out aLimit, aOffset: Int64): boolean;
  208. // Create error response in output
  209. Procedure CreateErrorResponse;
  210. Property Operation : TRestOperation Read FOperation;
  211. // Not owned by TRestIO
  212. Property Request : TRequest read FRequest;
  213. Property Response : TResponse read FResponse;
  214. Property Connection : TSQLConnection Read FConn Write FConn;
  215. Property Transaction : TSQLTransaction Read FTrans Write FTrans;
  216. Property Resource : TSQLDBRestResource Read FResource;
  217. Property RestStrings : TRestStringsConfig Read FRestStrings;
  218. // owned by TRestIO
  219. Property RESTInput : TRestInputStreamer read FInput;
  220. Property RESTOutput : TRestOutputStreamer read FOutput;
  221. Property RequestContentStream : TStream Read FContentStream;
  222. // For informative purposes
  223. Property ResourceName : UTF8String Read FResourceName;
  224. Property Schema : UTF8String Read FSchema;
  225. Property ConnectionName : UTF8String Read FCOnnection;
  226. Property UserID : String Read FUserID Write FUserID;
  227. end;
  228. TRestIOClass = Class of TRestIO;
  229. { TStreamerDef }
  230. TStreamerDef = Class (TCollectionItem)
  231. private
  232. FClass: TRestStreamerClass;
  233. FName: String;
  234. Public
  235. Property MyClass : TRestStreamerClass Read FClass Write FClass;
  236. Property MyName : String Read FName Write Fname;
  237. end;
  238. { TStreamerDefList }
  239. TStreamerDefList = Class(TCollection)
  240. private
  241. function GetD(aIndex : integer): TStreamerDef;
  242. Public
  243. Function IndexOfStreamer(const aName : string) : Integer;
  244. Function IndexOfStreamerContentType(const aContentType : string) : Integer;
  245. Property Defs[aIndex : integer] : TStreamerDef Read GetD; default;
  246. end;
  247. { TStreamerFactory }
  248. TRestStreamerType = (rstInput,rstOutput);
  249. TStreamerFactory = Class (TObject)
  250. Private
  251. class var FGlobal : TStreamerFactory;
  252. Private
  253. FDefs : Array[TRestStreamerType] of TStreamerDefList;
  254. Protected
  255. Function FindDefByName(aType : TRestStreamerType; aName : String) : TStreamerDef;
  256. Function FindDefByContentType(aType : TRestStreamerType; aContentType : String) : TStreamerDef;
  257. Function IndexOfStreamer(aType : TRestStreamerType; const aName : string) : Integer;
  258. Function IndexOfStreamerContentType(aType : TRestStreamerType; const aContentType : string) : Integer;
  259. Procedure RegisterStreamer(aType : TRestStreamerType; Const aName : String; aClass : TRestStreamerClass);
  260. Procedure UnRegisterStreamer(aType : TRestStreamerType; Const aName : String);
  261. Public
  262. Constructor Create;
  263. Destructor Destroy; override;
  264. Class Function Instance : TStreamerFactory;
  265. Class Procedure GetStreamerList(aList : TStrings; atype : TRestStreamerType);
  266. Procedure GetStreamerDefNames(aList : TStrings; atype : TRestStreamerType);
  267. Function FindStreamerByName(aType : TRestStreamerType; const aName : string) : TStreamerDef;
  268. Function FindStreamerByContentType(aType : TRestStreamerType; const aContentType : string) : TStreamerDef;
  269. end;
  270. implementation
  271. uses base64, dateutils, sqldbrestconst;
  272. Const
  273. DefaultPropertyNames : Array[TRestStringProperty] of UTF8String = (
  274. ISODateFormat, { rpDateFormat }
  275. ISODateTimeFormat, { rpDateTimeFormat }
  276. ISOTimeFormat, { rpTimeFormat }
  277. 'data', { rpDataRoot}
  278. 'metaData', { rpMetaDataRoot }
  279. 'error', { rpErrorRoot }
  280. 'name', { rpFieldNameProp }
  281. 'type', { rpFieldTypeProp }
  282. 'format', { rpFieldDateFormatProp }
  283. 'maxLen', { rpFieldMaxLenProp }
  284. 'humanreadable', { rpHumanReadable }
  285. 'fl', { rpFieldList }
  286. 'xl', { rpExcludeFieldList }
  287. 'Connection', { rpConnection }
  288. 'Resource', { rpResource }
  289. 'metadata', { rpIncludeMetadata }
  290. 'sparse', { rpSparse }
  291. 'row', { rpRowName }
  292. 'fields', { rpMetaDataFields }
  293. 'field', { rpMetaDataField }
  294. 'code', { rpErrorCode }
  295. 'message', { rpErrorMessage }
  296. '', { rpFilterEqual }
  297. '_lt', { rpFilterLessThan }
  298. '_gt', { rpFilterGreaterThan }
  299. '_lte', { rpFilterLessThanEqual }
  300. '_gte', { rpFilterGreaterThanEqual }
  301. '_null', { rpFilterIsNull }
  302. 'limit', { rpLimit }
  303. 'offset', { rpOffset }
  304. 'sort', { rpOrderBy }
  305. 'metadata', { rpMetadataResourceName }
  306. 'fmtin', { rpInputFormat }
  307. 'fmt', { rpOutputFormat }
  308. 'customview', { rpCustomViewResourceName }
  309. 'sql', { rpCustomViewSQLParam }
  310. 'datapacket' { rpXMLDocumentRoot}
  311. );
  312. { TStreamerDefList }
  313. function TStreamerDefList.GetD(aIndex : integer): TStreamerDef;
  314. begin
  315. Result:=TStreamerDef(Items[aIndex])
  316. end;
  317. function TStreamerDefList.IndexOfStreamer(const aName: string): Integer;
  318. begin
  319. Result:=Count-1;
  320. While (Result>=0) and Not SameText(GetD(Result).MyName,aName) do
  321. Dec(Result);
  322. end;
  323. function TStreamerDefList.IndexOfStreamerContentType(const aContentType: string): Integer;
  324. begin
  325. Result:=Count-1;
  326. While (Result>=0) and Not SameText(GetD(Result).MyClass.GetContentType, aContentType) do
  327. Dec(Result);
  328. end;
  329. { TStreamerFactory }
  330. function TStreamerFactory.FindDefByName(aType : TRestStreamerType; aName: String): TStreamerDef;
  331. Var
  332. Idx : integer;
  333. begin
  334. Idx:=FDefs[aType].IndexOfStreamer(aName);
  335. if Idx=-1 then
  336. Result:=Nil
  337. else
  338. Result:=FDefs[aType][Idx];
  339. end;
  340. function TStreamerFactory.FindDefByContentType(aType : TRestStreamerType; aContentType: String): TStreamerDef;
  341. Var
  342. Idx : integer;
  343. begin
  344. Idx:=FDefs[aType].IndexOfStreamerContentType(aContentType);
  345. if Idx=-1 then
  346. Result:=Nil
  347. else
  348. Result:=FDefs[aType][Idx];
  349. end;
  350. procedure TStreamerFactory.RegisterStreamer(aType : TRestStreamerType; const aName: String; aClass: TRestStreamerClass);
  351. Var
  352. D : TStreamerDef;
  353. begin
  354. D:=FindDefByName(atype,aName);
  355. if D=Nil then
  356. begin
  357. D:=FDefs[atype].Add as TStreamerDef;
  358. D.MyName:=aName;
  359. end;
  360. D.MyClass:=aClass;
  361. end;
  362. procedure TStreamerFactory.UnRegisterStreamer(aType : TRestStreamerType; const aName: String);
  363. begin
  364. FindDefByName(aType,aName).Free;
  365. end;
  366. constructor TStreamerFactory.Create;
  367. Var
  368. T : TRestStreamerType;
  369. begin
  370. for T in TRestStreamerType do
  371. FDefs[T]:=TStreamerDefList.Create(TStreamerDef);
  372. end;
  373. destructor TStreamerFactory.Destroy;
  374. Var
  375. T : TRestStreamerType;
  376. begin
  377. for T in TRestStreamerType do
  378. FreeAndNil(FDefs[T]);
  379. inherited Destroy;
  380. end;
  381. class function TStreamerFactory.Instance: TStreamerFactory;
  382. begin
  383. if FGlobal=Nil then
  384. FGlobal:=TStreamerFactory.Create;
  385. Result:=FGlobal;
  386. end;
  387. class procedure TStreamerFactory.GetStreamerList(aList: TStrings;
  388. atype: TRestStreamerType);
  389. begin
  390. TStreamerFactory.Instance.GetStreamerDefNames(aList,aType);
  391. end;
  392. procedure TStreamerFactory.GetStreamerDefNames(aList: TStrings; atype: TRestStreamerType);
  393. var
  394. I : Integer;
  395. begin
  396. aList.Clear;
  397. For I:=0 to FDefs[aType].Count-1 do
  398. aList.Add(FDefs[aType][I].MyName);
  399. end;
  400. function TStreamerFactory.IndexOfStreamer(aType : TRestStreamerType; const aName: string): Integer;
  401. begin
  402. Result:=FDefs[aType].IndexOfStreamer(aName);
  403. end;
  404. function TStreamerFactory.IndexOfStreamerContentType(aType : TRestStreamerType; const aContentType: string): Integer;
  405. begin
  406. Result:=FDefs[aType].IndexOfStreamerContentType(aContentType);
  407. end;
  408. function TStreamerFactory.FindStreamerByName(aType : TRestStreamerType; const aName: string): TStreamerDef;
  409. begin
  410. Result:=FindDefByName(aType,aName);
  411. end;
  412. function TStreamerFactory.FindStreamerByContentType(aType : TRestStreamerType; const aContentType: string): TStreamerDef;
  413. begin
  414. Result:=FindDefByContentType(aType,aContentType);
  415. end;
  416. { TRestStringsConfig }
  417. function TRestStringsConfig.GetRestPropName(AIndex: Integer): UTF8String;
  418. begin
  419. Result:=FValues[TRestStringProperty(AIndex)];
  420. if (Result='') then
  421. Result:=DefaultPropertyNames[TRestStringProperty(AIndex)]
  422. end;
  423. function TRestStringsConfig.IsRestStringStored(AIndex: Integer): Boolean;
  424. Var
  425. V : UTF8String;
  426. begin
  427. V:=FValues[TRestStringProperty(AIndex)];
  428. Result:=(V<>'') and (V<>DefaultPropertyNames[TRestStringProperty(AIndex)]);
  429. end;
  430. procedure TRestStringsConfig.SetRestPropName(AIndex: Integer; AValue: UTF8String);
  431. begin
  432. FValues[TRestStringProperty(AIndex)]:=aValue;
  433. end;
  434. class function TRestStringsConfig.GetDefaultString(aString: TRestStringProperty): UTF8String;
  435. begin
  436. Result:=DefaultPropertyNames[aString]
  437. end;
  438. function TRestStringsConfig.GetRestString(aString: TRestStringProperty): UTF8String;
  439. begin
  440. Result:=FValues[aString];
  441. if (Result='') then
  442. Result:=GetDefaultString(aString);
  443. end;
  444. procedure TRestStringsConfig.SetRestString(aString: TRestStringProperty; AValue: UTF8String);
  445. begin
  446. FValues[AString]:=aValue;
  447. end;
  448. procedure TRestStringsConfig.Assign(aSource: TPersistent);
  449. Var
  450. R : TRestStringsConfig;
  451. S : TRestStringProperty;
  452. begin
  453. if (aSource is TRestStringsConfig) then
  454. begin
  455. R:=aSource as TRestStringsConfig;
  456. For S in TRestStringProperty do
  457. FValues[S]:=R.FValues[S];
  458. end;
  459. inherited Assign(aSource);
  460. end;
  461. { TRestOutputStreamer }
  462. procedure TRestOutputStreamer.SetOutputOptions(AValue: TRestOutputOptions);
  463. begin
  464. if FOutputOptions=AValue then Exit;
  465. FOutputOptions:=AValue;
  466. end;
  467. procedure TRestOutputStreamer.CreateErrorContent(aCode: Integer;
  468. const Fmt: String; const Args: array of const);
  469. Var
  470. S : String;
  471. begin
  472. Try
  473. S:=Format(Fmt,Args);
  474. except
  475. On E : Exception do
  476. begin
  477. S:=Format('Error formatting string "%s" with %d arguments. Original code: %d',[Fmt,Length(Args),aCode]);
  478. aCode:=500;
  479. end;
  480. end;
  481. CreateErrorContent(aCode,S);
  482. end;
  483. function TRestOutputStreamer.HasOption(aOption: TRestOutputOption): Boolean;
  484. begin
  485. Result:=aOption in OutputOptions;
  486. end;
  487. Function TRestOutputStreamer.FieldToBase64(F : TField) : UTF8String;
  488. var
  489. BF : TBlobField absolute F;
  490. Src : TStream;
  491. Dest : TStringStream;
  492. E : TBase64EncodingStream;
  493. begin
  494. Src:=Nil;
  495. Dest:=nil;
  496. E:=Nil;
  497. Try
  498. if f is TBlobField then
  499. begin
  500. Src:=TMemoryStream.Create;
  501. Src.Size:=BF.DataSize;
  502. BF.SaveToStream(Src);
  503. end
  504. else
  505. Src:=TStringStream.Create(F.AsString);
  506. Src.Position:=0;
  507. Dest:=TStringStream.Create(''{,CP_UTF8});
  508. E:=TBase64EncodingStream.Create(Dest);
  509. E.CopyFrom(Src,0);
  510. FreeAndNil(E); // Will flush
  511. Result:=Dest.DataString;
  512. Finally
  513. Src.Free;
  514. Dest.Free;
  515. end;
  516. end;
  517. { TRestStreamer }
  518. constructor TRestStreamer.Create(aStream: TStream; aStrings: TRestStringsConfig; aOnGetVar: TRestGetVariableEvent);
  519. begin
  520. FStream:=aStream;
  521. FOnGetVar:=aOnGetVar;
  522. FStrings:=aStrings;
  523. end;
  524. function TRestStreamer.GetString(aString: TRestStringProperty): UTF8String;
  525. begin
  526. If Assigned(FStrings) then
  527. Result:=FStrings.GetRestString(aString)
  528. else
  529. Result:=DefaultPropertyNames[aString];
  530. end;
  531. function TRestStreamer.GetVariable(const aName: UTF8String): UTF8String;
  532. begin
  533. Result:='';
  534. if Assigned(FOnGetVar) then
  535. FOnGetVar(Self,aName,Result);
  536. end;
  537. Class function TRestStreamer.GetContentType: String;
  538. begin
  539. Result:='text/html';
  540. end;
  541. class procedure TRestInputStreamer.RegisterStreamer(const aName: String);
  542. begin
  543. TStreamerFactory.Instance.RegisterStreamer(rstInput,aName,Self)
  544. end;
  545. class procedure TRestInputStreamer.UnRegisterStreamer(const aName: String);
  546. begin
  547. TStreamerFactory.Instance.UnRegisterStreamer(rstInput,aName);
  548. end;
  549. class procedure TRestOutputStreamer.RegisterStreamer(const aName: String);
  550. begin
  551. TStreamerFactory.Instance.RegisterStreamer(rstOutput,aName,Self)
  552. end;
  553. class procedure TRestOutPutStreamer.UnRegisterStreamer(const aName: String);
  554. begin
  555. TStreamerFactory.Instance.UnRegisterStreamer(rstOutput,aName)
  556. end;
  557. function TRestOutputStreamer.RequireMetadata: Boolean;
  558. begin
  559. Result:=False;
  560. end;
  561. function TRestOutputStreamer.FieldToString(aFieldType : TRestFieldType; F: TField): UTF8string;
  562. begin
  563. Case aFieldType of
  564. rftInteger : Result:=F.AsString;
  565. rftLargeInt : Result:=F.AsString;
  566. rftFloat : Result:=F.AsString;
  567. rftDate : Result:=FormatDateTime(GetString(rpDateFormat),DateOf(F.AsDateTime));
  568. rftTime : Result:=FormatDateTime(GetString(rpTimeFormat),TimeOf(F.AsDateTime));
  569. rftDateTime : Result:=FormatDateTime(GetString(rpDateTimeFormat),F.AsDateTime);
  570. rftString : Result:=F.AsString;
  571. rftBoolean : Result:=BoolToStr(F.AsBoolean,'true','false');
  572. rftBlob : Result:=FieldToBase64(F);
  573. end;
  574. end;
  575. { TRestIO }
  576. procedure TRestIO.SetIO(aInput: TRestInputStreamer; aOutput: TRestOutputStreamer);
  577. begin
  578. Finput:=aInput;
  579. Finput.FOnGetVar:=@DoGetVariable;
  580. Foutput:=aOutput;
  581. FOutput.FOnGetVar:=@DoGetVariable;
  582. end;
  583. procedure TRestIO.SetConn(aConn: TSQLConnection; ATrans: TSQLTransaction);
  584. begin
  585. FConn:=aConn;
  586. FTrans:=aTrans;
  587. end;
  588. procedure TRestIO.SetResource(aResource: TSQLDBRestResource);
  589. begin
  590. Fresource:=AResource;
  591. end;
  592. procedure TRestIO.SetOperation(aOperation: TRestOperation);
  593. begin
  594. FOperation:=aOperation;
  595. end;
  596. procedure TRestIO.SetRestStrings(aValue: TRestStringsConfig);
  597. begin
  598. FRestStrings:=aValue;
  599. end;
  600. procedure TRestIO.DoGetVariable(Sender: TObject; const aName: UTF8String; out
  601. aVal: UTF8String);
  602. begin
  603. GetVariable(aName,aVal);
  604. end;
  605. constructor TRestIO.Create(aRequest: TRequest; aResponse: TResponse);
  606. begin
  607. FRequest:=aRequest;
  608. FResponse:=aResponse;
  609. FContentStream:=TStringStream.Create(aRequest.Content);
  610. end;
  611. destructor TRestIO.Destroy;
  612. begin
  613. if Assigned(FInput) then
  614. Finput.FOnGetVar:=Nil;
  615. if Assigned(Foutput) then
  616. FOutput.FOnGetVar:=Nil;
  617. FreeAndNil(FContentStream) ;
  618. FreeAndNil(Finput);
  619. FreeAndNil(Foutput);
  620. inherited Destroy;
  621. end;
  622. function TRestIO.GetVariable(const aName: UTF8String; out aVal: UTF8String;
  623. AllowedSources: TVAriableSources): TVariableSource;
  624. Function FindInList(aSource : TVariableSource;L : TStrings) : Boolean;
  625. Var
  626. I : Integer;
  627. N,V : String;
  628. begin
  629. Result:=(aSource in AllowedSources);
  630. if Result then
  631. begin
  632. I:=L.IndexOfName(aName);
  633. Result:=I<>-1;
  634. if Result then
  635. begin
  636. L.GetNameValue(I,N,V);
  637. aVal:=V;
  638. GetVariable:=aSource;
  639. end;
  640. end;
  641. end;
  642. begin
  643. Result:=vsNone;
  644. With Request do
  645. if not FIndInList(vsQuery,QueryFields) then
  646. if not FindInList(vsContent,ContentFields) then
  647. begin
  648. aVal:=RouteParams[aName];
  649. if (aVal<>'') then
  650. result:=vsRoute
  651. else
  652. FindInList(vsHeader,CustomHeaders);
  653. end;
  654. end;
  655. function TRestIO.GetFilterVariable(const aName: UTF8String; AFilter: TRestFieldFilter;out aValue: UTF8String) : TVariableSource;
  656. Const
  657. FilterStrings : Array[TRestFieldFilter] of TRestStringProperty =
  658. (rpFilterEqual,rpFilterLessThan,rpFilterGreaterThan,rpFilterLessThanEqual,rpFilterGreaterThanEqual,rpFilterIsNull);
  659. begin
  660. aValue:='';
  661. Result:=GetVariable(aName+FRestStrings.GetRestString(FilterStrings[aFilter]),aValue,[vsQuery]);
  662. end;
  663. Class function TRestIO.StrToNullBoolean(S: String; Strict: Boolean): TNullBoolean;
  664. begin
  665. result:=nbNone;
  666. s:=lowercase(s);
  667. if (s<>'') then
  668. if (s='1') or (s='t') or (s='true') or (s='y') then
  669. Result:=nbTrue
  670. else
  671. if (s='0') or (s='f') or (s='false') or (s='n') then
  672. Result:=nbFalse
  673. else if not Strict then
  674. Result:=nbNone
  675. else
  676. Raise EConvertError.CreateFmt('Not a correct boolean value: "%s"',[S])
  677. end;
  678. function TRestIO.GetBooleanVar(const aName: UTF8String; aStrict : Boolean = False): TNullBoolean;
  679. Var
  680. S : UTF8String;
  681. begin
  682. result:=nbNone;
  683. if GetVariable(aName,S)=vsNone then
  684. Result:=nbNone
  685. else
  686. Result:=StrToNullBoolean(S,aStrict);
  687. end;
  688. Function TRestIO.GetRequestOutputOptions(aDefault : TRestOutputOptions) : TRestOutputOptions;
  689. Procedure CheckParam(aName : String; aOption: TRestOutputOption);
  690. begin
  691. Case GetBooleanVar(aName) of
  692. nbFalse : Exclude(Result,aOption);
  693. nbTrue : Include(Result,aOption);
  694. else
  695. // nbNull: keep default
  696. end
  697. end;
  698. begin
  699. Result:=aDefault;
  700. CheckParam(FRestStrings.GetRestString(rpHumanReadable),ooHumanReadable);
  701. CheckParam(FRestStrings.GetRestString(rpSparse),ooSparse);
  702. CheckParam(FRestStrings.GetRestString(rpIncludeMetadata),ooMetadata);
  703. end;
  704. function TRestIO.GetLimitOffset(aEnforceLimit : Int64; out aLimit, aOffset: Int64): boolean;
  705. Var
  706. P,S : UTF8String;
  707. begin
  708. aLimit:=0;
  709. aOffset:=0;
  710. P:=RestStrings.GetRestString(rpLimit);
  711. Result:=GetVariable(P,S,[vsQuery])<>vsNone;
  712. if Not Result then
  713. Exit;
  714. if (S<>'') and not TryStrToInt64(S,aLimit) then
  715. Raise ESQLDBRest.CreateFmt(400,SErrInvalidParam,[P]);
  716. P:=RestStrings.GetRestString(rpOffset);
  717. if GetVariable(P,S,[vsQuery])<>vsNone then
  718. if (S<>'') and not TryStrToInt64(S,aOffset) then
  719. Raise ESQLDBRest.CreateFmt(400,SErrInvalidParam,[P]);
  720. if (aEnforceLimit>0) and (aLimit>aEnforceLimit) then
  721. aLimit:=aEnforceLimit;
  722. end;
  723. procedure TRestIO.CreateErrorResponse;
  724. begin
  725. RestOutput.CreateErrorContent(Response.Code,Response.CodeText);
  726. end;
  727. finalization
  728. FreeAndNil(TStreamerFactory.Fglobal);
  729. end.