sqldbrestio.pp 41 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187
  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. {$IFNDEF FPC_DOTTEDUNITS}
  12. unit sqldbrestio;
  13. {$ENDIF FPC_DOTTEDUNITS}
  14. {$mode objfpc}{$H+}
  15. interface
  16. {$IFDEF FPC_DOTTEDUNITS}
  17. uses
  18. System.Classes, System.SysUtils, FpJson.Data, Data.BufDataset, Data.Sqldb, Data.Db, FpWeb.Http.Defs, FpWeb.RestBridge.Schema;
  19. {$ELSE FPC_DOTTEDUNITS}
  20. uses
  21. Classes, SysUtils, fpjson, bufdataset, sqldb, db, httpdefs, sqldbrestschema;
  22. {$ENDIF FPC_DOTTEDUNITS}
  23. Type
  24. TRestOutputOption = (ooMetadata,ooSparse,ooHumanReadable);
  25. TRestOutputOptions = Set of TRestOutputOption;
  26. TNullBoolean = (nbNone,nbFalse,nbTrue);
  27. TNullBooleans = set of TNullBoolean;
  28. Const
  29. AllVariableSources = [Low(TVariableSource)..High(TVariableSource)];
  30. allOutputOptions = [Low(TRestOutputOption)..High(TRestOutputOption)];
  31. Type
  32. TRestIO = Class;
  33. TRestStringProperty = (rpDateFormat,
  34. rpDateTimeFormat,
  35. rpTimeFormat,
  36. rpDataRoot,
  37. rpMetaDataRoot,
  38. rpErrorRoot,
  39. rpFieldNameProp,
  40. rpFieldTypeProp,
  41. rpFieldDateFormatProp,
  42. rpFieldMaxLenProp,
  43. rpHumanReadable,
  44. rpFieldList,
  45. rpExcludeFieldList,
  46. rpConnection,
  47. rpResource,
  48. rpIncludeMetadata,
  49. rpSparse,
  50. rpRowName,
  51. rpMetaDataFields,
  52. rpMetaDataField,
  53. rpErrorCode,
  54. rpErrorMessage,
  55. rpFilterEqual,
  56. rpFilterLessThan,
  57. rpFilterGreaterThan,
  58. rpFilterLessThanEqual,
  59. rpFilterGreaterThanEqual,
  60. rpFilterIsNull,
  61. rpLimit,
  62. rpOffset,
  63. rpOrderBy,
  64. rpMetadataResourceName,
  65. rpInputFormat,
  66. rpOutputFormat,
  67. rpCustomViewResourceName,
  68. rpCustomViewSQLParam,
  69. rpXMLDocumentRoot,
  70. rpConnectionResourceName,
  71. rpParametersResourceName,
  72. rpParametersRoutePart,
  73. rpAttachment
  74. );
  75. TRestStringProperties = Set of TRestStringProperty;
  76. TRestGetVariableEvent = Procedure (Sender : TObject; Const aName : UTF8String; Out aVal : UTF8String) of object;
  77. { TRestStringsConfig }
  78. TRestStringsConfig = Class(TPersistent)
  79. private
  80. FValues : Array[TRestStringProperty] of UTF8String;
  81. function GetRestPropName(AIndex: Integer): UTF8String;
  82. function IsRestStringStored(AIndex: Integer): Boolean;
  83. procedure SetRestPropName(AIndex: Integer; AValue: UTF8String);
  84. Public
  85. Class Function GetDefaultString(aString : TRestStringProperty) :UTF8String;
  86. Function GetRestString(aString : TRestStringProperty) :UTF8String;
  87. Procedure SetRestString(aString : TRestStringProperty; AValue :UTF8String);
  88. Procedure Assign(aSource : TPersistent); override;
  89. Published
  90. // Indexes here MUST match TRestProperty
  91. Property RESTDateFormat : UTF8String Index ord(rpDateFormat) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  92. Property RESTDateTimeFormat : UTF8String Index ord(rpDateTimeFormat) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  93. Property RESTTimeFormat : UTF8String Index ord(rpTimeFormat) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  94. Property DataProperty : UTF8String Index ord(rpDataRoot) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  95. Property MetaDataRoot : UTF8String Index ord(rpMetaDataRoot) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  96. Property ErrorProperty : UTF8String Index ord(rpErrorRoot) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  97. Property FieldNameProperty : UTF8String Index ord(rpFieldNameProp) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  98. Property FieldTypeProperty : UTF8String Index ord(rpFieldTypeProp) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  99. Property DateFormatProperty : UTF8String Index ord(rpFieldDateFormatProp) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  100. Property MaxLenProperty : UTF8String Index ord(rpFieldMaxLenProp) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  101. Property HumanReadableParam : UTF8String Index ord(rpHumanReadable) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  102. Property FieldListParam : UTF8String Index ord(rpFieldList) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  103. Property ExcludeFieldListParam : UTF8String Index ord(rpExcludeFieldList) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  104. Property ConnectionParam : UTF8String Index Ord(rpConnection) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  105. Property ResourceParam : UTF8String Index ord(rpResource) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  106. Property IncludeMetadataParam : UTF8String Index ord(rpIncludeMetadata) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  107. Property SparseParam : UTF8String Index Ord(rpSparse) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  108. Property RowName : UTF8String Index Ord(rpRowName) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  109. Property MetadataFields : UTF8String Index Ord(rpMetadataFields) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  110. Property MetadataField : UTF8String Index Ord(rpMetadataField) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  111. Property ErrorCode : UTF8String Index ord(rpErrorCode) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  112. Property ErrorMessage : UTF8String Index ord(rpErrorMessage) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  113. Property FilterParamEqual : UTF8String Index ord(rpFilterEqual) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  114. Property FilterParamLessThan : UTF8String Index ord(rpFilterLessThan) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  115. Property FilterParamGreaterThan : UTF8String Index ord(rpFilterGreaterThan) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  116. Property FilterParamLessThanEqual : UTF8String Index ord(rpFilterLessThanEqual) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  117. Property FilterParamGreaterThanEqual : UTF8String Index ord(rpFilterGreaterThanEqual) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  118. Property FilterParamIsNull : UTF8String Index ord(rpFilterIsNull) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  119. Property LimitParam : UTF8string Index ord(rpLimit) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  120. Property OffsetParam : UTF8string Index ord(rpOffset) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  121. Property SortParam : UTF8string Index ord(rpOrderBy) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  122. Property MetadataResourceName : UTF8string Index ord(rpMetadataResourceName) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  123. Property MetadataParametersName : UTF8string Index ord(rpParametersResourceName) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  124. Property MetadataParametersRoutePart : UTF8string Index ord(rpParametersRoutePart) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  125. Property InputFormatParam : UTF8string Index ord(rpInputFormat) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  126. Property OutputFormatParam : UTF8string Index ord(rpOutputFormat) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  127. Property CustomViewResourceName : UTF8string Index ord(rpCustomViewResourceName) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  128. Property CustomViewSQLParam : UTF8string Index ord(rpCustomViewSQLParam) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  129. Property XMLDocumentRoot : UTF8string Index ord(rpXMLDocumentRoot) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  130. Property ConnectionResourceName : UTF8string Index ord(rpConnectionResourceName) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  131. Property AttachmentParam : UTF8String Index ord(rpAttachment) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
  132. end;
  133. TRestStatus = (rsError, // Internal logic/unexpected error (500)
  134. rsGetOK, // GET command completed OK (200)
  135. rsPostOK, // POST command completed OK (204)
  136. rsPutOK, // PUT command completed OK (200)
  137. rsDeleteOK, // DELETE command completed OK (204)
  138. rsInvalidParam, // Something wrong/missing in Query parameters (400)
  139. rsCORSOK, // CORS request completed OK (200)
  140. rsCORSNotAllowed, // CORS request not allowed (403)
  141. rsUnauthorized, // Authentication failed (401)
  142. rsResourceNotAllowed, // Resource request not allowed (403)
  143. rsRestOperationNotAllowed, // Resource operation (method) not allowed (405)
  144. rsInvalidMethod, // Invalid HTTP method (400)
  145. rsUnknownResource, // Unknown resource (404)
  146. rsNoResourceSpecified, // Unable to determine resource (404)
  147. rsNoConnectionSpecified, // Unable to determine connection for (400)
  148. rsRecordNotFound, // Query did not return record for single resource (404)
  149. rsInvalidContent, // Invalid content for POST/PUT operation (400)
  150. rsPatchOK // PATCH command completed OK (200)
  151. );
  152. TRestStatuses = set of TRestStatus;
  153. { TRestStatusConfig }
  154. TRestStatusConfig = Class(TPersistent)
  155. private
  156. FStatus : Array[TRestStatus] of Word;
  157. function GetStatus(AIndex: Integer): Word;
  158. function IsStatusStored(AIndex: Integer): Boolean;
  159. procedure SetStatus(AIndex: Integer; AValue: Word);
  160. Public
  161. Procedure Assign(aSource : TPersistent); override;
  162. function GetStatusCode(aStatus : TRestStatus): Word;
  163. Published
  164. // Internal logic/unexpected error (500)
  165. Property Error : Word Index Ord(rsError) Read GetStatus Write SetStatus Stored IsStatusStored;
  166. // GET command completed OK (200)
  167. Property GetOK : Word Index Ord(rsGetOK) Read GetStatus Write SetStatus Stored IsStatusStored;
  168. // POST command completed OK (204)
  169. Property PostOK : Word Index Ord(rsPostOK) Read GetStatus Write SetStatus Stored IsStatusStored;
  170. // PUT command completed OK (200)
  171. Property PutOK : Word Index Ord(rsPutOK) Read GetStatus Write SetStatus Stored IsStatusStored;
  172. // DELETE command completed OK (204)
  173. Property DeleteOK : Word Index Ord(rsDeleteOK) Read GetStatus Write SetStatus Stored IsStatusStored;
  174. // Something wrong/missing in Query parameters (400)
  175. Property InvalidParam : Word Index Ord(rsInvalidParam) Read GetStatus Write SetStatus Stored IsStatusStored;
  176. // CORS request completed OK (200)
  177. Property CORSOK : Word Index Ord(rsCORSOK) Read GetStatus Write SetStatus Stored IsStatusStored;
  178. // CORS request not allowed (403)
  179. Property CORSNotAllowed : Word Index Ord(rsCORSNotAllowed) Read GetStatus Write SetStatus Stored IsStatusStored;
  180. // Authentication failed (401)
  181. Property Unauthorized : Word Index Ord(rsUnauthorized) Read GetStatus Write SetStatus Stored IsStatusStored;
  182. // Resource request not allowed (403)
  183. Property ResourceNotAllowed : Word Index Ord(rsResourceNotAllowed) Read GetStatus Write SetStatus Stored IsStatusStored;
  184. // Resource operation (method) not allowed (405)
  185. Property RestOperationNotAllowed : Word Index Ord(rsRestOperationNotAllowed) Read GetStatus Write SetStatus Stored IsStatusStored;
  186. // Invalid HTTP method (400)
  187. Property InvalidMethod : Word Index Ord(rsInvalidMethod) Read GetStatus Write SetStatus Stored IsStatusStored;
  188. // Unknown resource (404)
  189. Property UnknownResource : Word Index Ord(rsUnknownResource) Read GetStatus Write SetStatus Stored IsStatusStored;
  190. // Unable to determine resource (404)
  191. Property NoResourceSpecified : Word Index Ord(rsNoResourceSpecified) Read GetStatus Write SetStatus Stored IsStatusStored;
  192. // Unable to determine connection for (400)
  193. Property NoConnectionSpecified : Word Index Ord(rsNoConnectionSpecified) Read GetStatus Write SetStatus Stored IsStatusStored;
  194. // Query did not return record for single resource (404)
  195. Property RecordNotFound : Word Index Ord(rsRecordNotFound) Read GetStatus Write SetStatus Stored IsStatusStored;
  196. // Invalid content for POST/PUT operation (400)
  197. Property InvalidContent : Word Index Ord(rsInvalidContent) Read GetStatus Write SetStatus Stored IsStatusStored;
  198. end;
  199. { TRestStreamer }
  200. TRestStreamer = Class(TObject)
  201. private
  202. FStream: TStream;
  203. FOnGetVar : TRestGetVariableEvent;
  204. FStrings: TRestStringsConfig;
  205. FStatuses : TRestStatusConfig;
  206. Public
  207. // Registry
  208. Class Function GetContentType : String; virtual;
  209. Constructor Create(aStream : TStream;aStrings : TRestStringsConfig;aStatus : TRestStatusConfig; aOnGetVar : TRestGetVariableEvent);
  210. Function GetString(aString : TRestStringProperty) : UTF8String;
  211. Property Strings : TRestStringsConfig Read FStrings;
  212. Property Statuses : TRestStatusConfig Read FStatuses;
  213. procedure InitStreaming; virtual; abstract;
  214. Function GetVariable(const aName : UTF8String) : UTF8String;
  215. Property Stream : TStream Read FStream;
  216. end;
  217. TRestStreamerClass = Class of TRestStreamer;
  218. { TRestInputStreamer }
  219. TRestInputStreamer = Class(TRestStreamer)
  220. Public
  221. // Select input object aIndex. Must return False if no such object in input
  222. // Currently aIndex=0, but for batch operations this may later become nonzero.
  223. Function SelectObject(aIndex : Integer) : Boolean; virtual; abstract;
  224. // Return Nil if none found. If result is non-nil, caller will free.
  225. Function GetContentField(aName : UTF8string) : TJSONData; virtual; abstract;
  226. Function HaveInputData(aName : UTF8string) : Boolean; virtual;
  227. Class Procedure RegisterStreamer(Const aName : String);
  228. Class Procedure UnRegisterStreamer(Const aName : String);
  229. end;
  230. TRestInputStreamerClass = Class of TRestInputStreamer;
  231. { TRestOutputStreamer }
  232. TRestOutputStreamer = Class(TRestStreamer)
  233. private
  234. FOutputOptions: TRestOutputOptions;
  235. Protected
  236. procedure SetOutputOptions(AValue: TRestOutputOptions); virtual;
  237. Public
  238. Class Procedure RegisterStreamer(Const aName : String);
  239. Class Procedure UnRegisterStreamer(Const aName : String);
  240. Class Function FileExtension : String; virtual;
  241. function RequireMetadata : Boolean; virtual;
  242. Function FieldToString(aFieldType : TRestFieldType; F : TField) : UTF8string; virtual;
  243. function FieldToBase64(F: TField): UTF8String; virtual;
  244. Function HasOption(aOption : TRestOutputOption) : Boolean;
  245. Procedure CreateErrorContent(aCode : Integer; Const aMessage: String); virtual; abstract;
  246. Procedure CreateErrorContent(aCode : Integer; Const Fmt: String; Const Args : Array of const);
  247. Procedure WriteMetadata(aFieldList : TRestFieldPairArray); virtual; abstract;
  248. Procedure StartData; virtual; abstract;
  249. Procedure StartRow; virtual; abstract;
  250. Procedure WriteField(aPair : TRestFieldPair); virtual; abstract;
  251. Procedure EndRow; virtual; abstract;
  252. Procedure EndData; virtual; abstract;
  253. Procedure FinalizeOutput; virtual; abstract;
  254. // Set before InitStreaming is called;
  255. Property OutputOptions : TRestOutputOptions Read FOutputOptions Write SetOutputOptions;
  256. end;
  257. TRestOutputStreamerClass = class of TRestOutputStreamer;
  258. { TRestContext }
  259. TRestContext = Class(TBaseRestContext)
  260. Private
  261. FIO : TRestIO;
  262. Protected
  263. function GetConnection: TSQLConnection; override;
  264. function GetTransaction: TSQLTransaction; override;
  265. Function DoGetInputData(const aName : UTF8string) : TJSONData; override;
  266. Function GetUpdateData : TDataset; override;
  267. property IO : TRestIO Read FIO;
  268. Public
  269. Function GetVariable(Const aName : UTF8String; aSources : TVariableSources; Out aValue : UTF8String) : Boolean; override;
  270. end;
  271. { TRestIO }
  272. TSQLLogNotifyEvent = Procedure (Sender : TObject; EventType : TDBEventType; Const Msg : String) of object;
  273. TRestIO = Class
  274. private
  275. FConn: TSQLConnection;
  276. FCOnnection: UTF8String;
  277. FInput: TRestInputStreamer;
  278. FOnSQLLog: TSQLLogNotifyEvent;
  279. FOperation: TRestOperation;
  280. FOutput: TRestOutputStreamer;
  281. FRequest: TRequest;
  282. FResource: TSQLDBRestResource;
  283. FResponse: TResponse;
  284. FRestContext: TRestContext;
  285. FRestStatuses: TRestStatusConfig;
  286. FRestStrings: TRestStringsConfig;
  287. FSchema: UTF8String;
  288. FTrans: TSQLTransaction;
  289. FContentStream : TStream;
  290. FUpdatedData: TBufDataset;
  291. function GetResourceName: UTF8String;
  292. function GetUserID: String;
  293. procedure SetUserID(const AValue: String);
  294. Protected
  295. Public
  296. Constructor Create(aRequest : TRequest; aResponse : TResponse); virtual;
  297. Destructor Destroy; override;
  298. // Log callback for SQL. Rerouted here, because we need IO
  299. procedure DoSQLLog(Sender: TSQLConnection; EventType: TDBEventType; const Msg: String);
  300. // Set things.
  301. Procedure SetIO(aInput : TRestInputStreamer;aOutput : TRestOutputStreamer);
  302. Procedure SetConn(aConn : TSQLConnection; ATrans : TSQLTransaction);
  303. Procedure SetResource(aResource : TSQLDBRestResource);
  304. procedure SetOperation(aOperation : TRestOperation);
  305. Procedure SetRestStrings(aValue : TRestStringsConfig);
  306. Procedure SetRestStatuses(aValue : TRestStatusConfig);
  307. // Get things
  308. class function StrToNullBoolean(const S: String; Strict: Boolean): TNullBoolean;
  309. Procedure DoGetVariable(Sender : TObject; Const aName : UTF8String; Out aVal : UTF8String);
  310. Function GetVariable (Const aName : UTF8String; Out aVal : UTF8String; AllowedSources : TVAriableSources = AllVariableSources) : TVariableSource; virtual;
  311. function GetFilterVariable(const aName: UTF8String; AFilter: TRestFieldFilter; out aValue: UTF8String): TVariableSource;
  312. Function GetBooleanVar(Const aName : UTF8String; aStrict : Boolean = False) : TNullBoolean;
  313. function GetRequestOutputOptions(aDefault: TRestOutputOptions): TRestOutputOptions;
  314. function GetLimitOffset(aEnforceLimit: Int64; out aLimit, aOffset: Int64): boolean;
  315. // Create error response in output
  316. function CreateRestContext: TRestContext; virtual;
  317. Procedure CreateErrorResponse;
  318. Property Operation : TRestOperation Read FOperation;
  319. // Not owned by TRestIO
  320. Property Request : TRequest read FRequest;
  321. Property Response : TResponse read FResponse;
  322. Property Connection : TSQLConnection Read FConn Write FConn;
  323. Property Transaction : TSQLTransaction Read FTrans Write FTrans;
  324. Property Resource : TSQLDBRestResource Read FResource;
  325. Property RestStrings : TRestStringsConfig Read FRestStrings;
  326. Property RestStatuses : TRestStatusConfig Read FRestStatuses;
  327. // owned by TRestIO
  328. Property UpdatedData : TBufDataset Read FUpdatedData;
  329. Property RESTInput : TRestInputStreamer read FInput;
  330. Property RESTOutput : TRestOutputStreamer read FOutput;
  331. Property RequestContentStream : TStream Read FContentStream;
  332. Property RestContext : TRestContext Read FRestContext;
  333. // For informative purposes
  334. Property ResourceName : UTF8String Read GetResourceName;
  335. Property Schema : UTF8String Read FSchema;
  336. Property ConnectionName : UTF8String Read FCOnnection;
  337. Property UserID : String Read GetUserID Write SetUserID;
  338. // For logging
  339. Property OnSQLLog :TSQLLogNotifyEvent Read FOnSQLLog Write FOnSQLLog;
  340. end;
  341. TRestIOClass = Class of TRestIO;
  342. { TStreamerDef }
  343. TStreamerDef = Class (TCollectionItem)
  344. private
  345. FClass: TRestStreamerClass;
  346. FName: String;
  347. Public
  348. Property MyClass : TRestStreamerClass Read FClass Write FClass;
  349. Property MyName : String Read FName Write Fname;
  350. end;
  351. { TStreamerDefList }
  352. TStreamerDefList = Class(TCollection)
  353. private
  354. function GetD(aIndex : integer): TStreamerDef;
  355. Public
  356. Function IndexOfStreamer(const aName : string) : Integer;
  357. Function IndexOfStreamerContentType(const aContentType : string) : Integer;
  358. Property Defs[aIndex : integer] : TStreamerDef Read GetD; default;
  359. end;
  360. { TStreamerFactory }
  361. TRestStreamerType = (rstInput,rstOutput);
  362. TStreamerFactory = Class (TObject)
  363. Private
  364. class var FGlobal : TStreamerFactory;
  365. Private
  366. FDefs : Array[TRestStreamerType] of TStreamerDefList;
  367. Protected
  368. Function FindDefByName(aType : TRestStreamerType; const aName : String) : TStreamerDef;
  369. Function FindDefByContentType(aType : TRestStreamerType; const aContentType : String) : TStreamerDef;
  370. Function IndexOfStreamer(aType : TRestStreamerType; const aName : string) : Integer;
  371. Function IndexOfStreamerContentType(aType : TRestStreamerType; const aContentType : string) : Integer;
  372. Procedure RegisterStreamer(aType : TRestStreamerType; Const aName : String; aClass : TRestStreamerClass);
  373. Procedure UnRegisterStreamer(aType : TRestStreamerType; Const aName : String);
  374. Public
  375. Constructor Create;
  376. Destructor Destroy; override;
  377. Class Function Instance : TStreamerFactory;
  378. Class Procedure GetStreamerList(aList : TStrings; atype : TRestStreamerType);
  379. Procedure GetStreamerDefNames(aList : TStrings; atype : TRestStreamerType);
  380. Function FindStreamerByName(aType : TRestStreamerType; const aName : string) : TStreamerDef;
  381. Function FindStreamerByContentType(aType : TRestStreamerType; const aContentType : string) : TStreamerDef;
  382. end;
  383. { TRestBufDataset }
  384. TRestBufDataset = class (TBufDataset)
  385. protected
  386. procedure LoadBlobIntoBuffer(FieldDef: TFieldDef; ABlobBuf: PBufBlobField); override;
  387. end;
  388. implementation
  389. {$IFDEF FPC_DOTTEDUNITS}
  390. uses System.Hash.Base64, System.DateUtils, FpWeb.RestBridge.Consts;
  391. {$ELSE FPC_DOTTEDUNITS}
  392. uses base64, dateutils, sqldbrestconst;
  393. {$ENDIF FPC_DOTTEDUNITS}
  394. Const
  395. DefaultPropertyNames : Array[TRestStringProperty] of UTF8String = (
  396. ISODateFormat, { rpDateFormat }
  397. ISODateTimeFormat, { rpDateTimeFormat }
  398. ISOTimeFormat, { rpTimeFormat }
  399. 'data', { rpDataRoot}
  400. 'metaData', { rpMetaDataRoot }
  401. 'error', { rpErrorRoot }
  402. 'name', { rpFieldNameProp }
  403. 'type', { rpFieldTypeProp }
  404. 'format', { rpFieldDateFormatProp }
  405. 'maxLen', { rpFieldMaxLenProp }
  406. 'humanreadable', { rpHumanReadable }
  407. 'fl', { rpFieldList }
  408. 'xl', { rpExcludeFieldList }
  409. 'Connection', { rpConnection }
  410. 'Resource', { rpResource }
  411. 'metadata', { rpIncludeMetadata }
  412. 'sparse', { rpSparse }
  413. 'row', { rpRowName }
  414. 'fields', { rpMetaDataFields }
  415. 'field', { rpMetaDataField }
  416. 'code', { rpErrorCode }
  417. 'message', { rpErrorMessage }
  418. '', { rpFilterEqual }
  419. '_lt', { rpFilterLessThan }
  420. '_gt', { rpFilterGreaterThan }
  421. '_lte', { rpFilterLessThanEqual }
  422. '_gte', { rpFilterGreaterThanEqual }
  423. '_null', { rpFilterIsNull }
  424. 'limit', { rpLimit }
  425. 'offset', { rpOffset }
  426. 'sort', { rpOrderBy }
  427. 'metadata', { rpMetadataResourceName }
  428. 'fmtin', { rpInputFormat }
  429. 'fmt', { rpOutputFormat }
  430. 'customview', { rpCustomViewResourceName }
  431. 'sql', { rpCustomViewSQLParam }
  432. 'datapacket', { rpXMLDocumentRoot}
  433. '_connection', { rpConnectionResourceName }
  434. '_parameters', { rpParametersResourceName }
  435. 'parameters', { rpParametersRoutePart }
  436. 'att' { rpAttachment }
  437. );
  438. DefaultStatuses : Array[TRestStatus] of Word = (
  439. 500, { rsError }
  440. 200, { rsGetOK }
  441. 201, { rsPostOK }
  442. 200, { rsPutOK }
  443. 204, { rsDeleteOK }
  444. 400, { rsInvalidParam }
  445. 200, { rsCORSOK}
  446. 403, { rsCORSNotallowed}
  447. 401, { rsUnauthorized }
  448. 403, { rsResourceNotAllowed }
  449. 405, { rsRestOperationNotAllowed }
  450. 400, { rsInvalidMethod }
  451. 404, { rsUnknownResource }
  452. 404, { rsNoResourceSpecified }
  453. 400, { rsNoConnectionSpecified }
  454. 404, { rsRecordNotFound }
  455. 400, { rsInvalidContent }
  456. 200 { rsPatchOK }
  457. );
  458. { TRestBufDataset }
  459. procedure TRestBufDataset.LoadBlobIntoBuffer(FieldDef: TFieldDef; ABlobBuf: PBufBlobField);
  460. begin
  461. If (FieldDef=Nil) or (aBlobBuf=Nil) then
  462. exit;
  463. end;
  464. { TRestStatusConfig }
  465. function TRestStatusConfig.GetStatus(AIndex: Integer): Word;
  466. begin
  467. Result:=GetStatusCode(TRestStatus(aIndex));
  468. end;
  469. function TRestStatusConfig.IsStatusStored(AIndex: Integer): Boolean;
  470. Var
  471. W : Word;
  472. begin
  473. W:=FStatus[TRestStatus(aIndex)];
  474. Result:=(W<>0) and (W<>DefaultStatuses[TRestStatus(aIndex)]);
  475. end;
  476. procedure TRestStatusConfig.SetStatus(AIndex: Integer; AValue: Word);
  477. begin
  478. if (aValue<>DefaultStatuses[TRestStatus(aIndex)]) then
  479. aValue:=0;
  480. FStatus[TRestStatus(aIndex)]:=aValue;
  481. end;
  482. procedure TRestStatusConfig.Assign(aSource: TPersistent);
  483. Var
  484. C : TRestStatusConfig;
  485. S : TRestStatus;
  486. begin
  487. if aSource is TRestStatusConfig then
  488. begin
  489. C:=aSource as TRestStatusConfig;
  490. for S in TRestStatus do
  491. FStatus[S]:=C.FStatus[S];
  492. end
  493. else
  494. inherited Assign(aSource);
  495. end;
  496. function TRestStatusConfig.GetStatusCode(aStatus: TRestStatus): Word;
  497. begin
  498. Result:=FStatus[aStatus];
  499. if Result=0 then
  500. Result:=DefaultStatuses[aStatus];
  501. end;
  502. { TRestContext }
  503. function TRestContext.GetVariable(const aName: UTF8String; aSources : TVariableSources; out aValue: UTF8String): Boolean;
  504. Var
  505. D : TJSONData;
  506. begin
  507. Result:=FIO.GetVariable(aName,aValue,aSources)<>vsNone;
  508. if Not Result and (vsData in aSources) then
  509. begin
  510. // Will be freed.
  511. D:=GetInputData(aName);
  512. Result:=Assigned(D);
  513. if Result then
  514. if D.JSONType in StructuredJSONTypes then
  515. aValue:=D.AsJSON
  516. else
  517. aValue:=D.AsString;
  518. end;
  519. end;
  520. function TRestContext.GetConnection: TSQLConnection;
  521. begin
  522. Result:=IO.Connection;
  523. end;
  524. function TRestContext.GetTransaction: TSQLTransaction;
  525. begin
  526. Result:=IO.Transaction;
  527. end;
  528. function TRestContext.DoGetInputData(const aName: UTF8string): TJSONData;
  529. begin
  530. Result:=IO.RESTInput.GetContentField(aName);
  531. end;
  532. function TRestContext.GetUpdateData: TDataset;
  533. begin
  534. Result:=IO.UpdatedData;
  535. end;
  536. { TStreamerDefList }
  537. function TStreamerDefList.GetD(aIndex : integer): TStreamerDef;
  538. begin
  539. Result:=TStreamerDef(Items[aIndex])
  540. end;
  541. function TStreamerDefList.IndexOfStreamer(const aName: string): Integer;
  542. begin
  543. Result:=Count-1;
  544. While (Result>=0) and Not SameText(GetD(Result).MyName,aName) do
  545. Dec(Result);
  546. end;
  547. function TStreamerDefList.IndexOfStreamerContentType(const aContentType: string): Integer;
  548. begin
  549. Result:=Count-1;
  550. While (Result>=0) and Not SameText(GetD(Result).MyClass.GetContentType, aContentType) do
  551. Dec(Result);
  552. end;
  553. { TStreamerFactory }
  554. function TStreamerFactory.FindDefByName(aType : TRestStreamerType; const aName: String): TStreamerDef;
  555. Var
  556. Idx : integer;
  557. begin
  558. Idx:=FDefs[aType].IndexOfStreamer(aName);
  559. if Idx=-1 then
  560. Result:=Nil
  561. else
  562. Result:=FDefs[aType][Idx];
  563. end;
  564. function TStreamerFactory.FindDefByContentType(aType : TRestStreamerType; Const aContentType: String): TStreamerDef;
  565. Var
  566. Idx : integer;
  567. begin
  568. Idx:=FDefs[aType].IndexOfStreamerContentType(aContentType);
  569. if Idx=-1 then
  570. Result:=Nil
  571. else
  572. Result:=FDefs[aType][Idx];
  573. end;
  574. procedure TStreamerFactory.RegisterStreamer(aType : TRestStreamerType; const aName: String; aClass: TRestStreamerClass);
  575. Var
  576. D : TStreamerDef;
  577. begin
  578. D:=FindDefByName(atype,aName);
  579. if D=Nil then
  580. begin
  581. D:=FDefs[atype].Add as TStreamerDef;
  582. D.MyName:=aName;
  583. end;
  584. D.MyClass:=aClass;
  585. end;
  586. procedure TStreamerFactory.UnRegisterStreamer(aType : TRestStreamerType; const aName: String);
  587. begin
  588. FindDefByName(aType,aName).Free;
  589. end;
  590. constructor TStreamerFactory.Create;
  591. Var
  592. T : TRestStreamerType;
  593. begin
  594. for T in TRestStreamerType do
  595. FDefs[T]:=TStreamerDefList.Create(TStreamerDef);
  596. end;
  597. destructor TStreamerFactory.Destroy;
  598. Var
  599. T : TRestStreamerType;
  600. begin
  601. for T in TRestStreamerType do
  602. FreeAndNil(FDefs[T]);
  603. inherited Destroy;
  604. end;
  605. class function TStreamerFactory.Instance: TStreamerFactory;
  606. begin
  607. if FGlobal=Nil then
  608. FGlobal:=TStreamerFactory.Create;
  609. Result:=FGlobal;
  610. end;
  611. class procedure TStreamerFactory.GetStreamerList(aList: TStrings;
  612. atype: TRestStreamerType);
  613. begin
  614. TStreamerFactory.Instance.GetStreamerDefNames(aList,aType);
  615. end;
  616. procedure TStreamerFactory.GetStreamerDefNames(aList: TStrings; atype: TRestStreamerType);
  617. var
  618. I : Integer;
  619. begin
  620. aList.Clear;
  621. For I:=0 to FDefs[aType].Count-1 do
  622. aList.Add(FDefs[aType][I].MyName);
  623. end;
  624. function TStreamerFactory.IndexOfStreamer(aType : TRestStreamerType; const aName: string): Integer;
  625. begin
  626. Result:=FDefs[aType].IndexOfStreamer(aName);
  627. end;
  628. function TStreamerFactory.IndexOfStreamerContentType(aType : TRestStreamerType; const aContentType: string): Integer;
  629. begin
  630. Result:=FDefs[aType].IndexOfStreamerContentType(aContentType);
  631. end;
  632. function TStreamerFactory.FindStreamerByName(aType : TRestStreamerType; const aName: string): TStreamerDef;
  633. begin
  634. Result:=FindDefByName(aType,aName);
  635. end;
  636. function TStreamerFactory.FindStreamerByContentType(aType : TRestStreamerType; const aContentType: string): TStreamerDef;
  637. begin
  638. Result:=FindDefByContentType(aType,aContentType);
  639. end;
  640. { TRestStringsConfig }
  641. function TRestStringsConfig.GetRestPropName(AIndex: Integer): UTF8String;
  642. begin
  643. Result:=FValues[TRestStringProperty(AIndex)];
  644. if (Result='') then
  645. Result:=DefaultPropertyNames[TRestStringProperty(AIndex)]
  646. end;
  647. function TRestStringsConfig.IsRestStringStored(AIndex: Integer): Boolean;
  648. Var
  649. V : UTF8String;
  650. begin
  651. V:=FValues[TRestStringProperty(AIndex)];
  652. Result:=(V<>'') and (V<>DefaultPropertyNames[TRestStringProperty(AIndex)]);
  653. end;
  654. procedure TRestStringsConfig.SetRestPropName(AIndex: Integer; AValue: UTF8String);
  655. begin
  656. FValues[TRestStringProperty(AIndex)]:=aValue;
  657. end;
  658. class function TRestStringsConfig.GetDefaultString(aString: TRestStringProperty): UTF8String;
  659. begin
  660. Result:=DefaultPropertyNames[aString]
  661. end;
  662. function TRestStringsConfig.GetRestString(aString: TRestStringProperty): UTF8String;
  663. begin
  664. Result:=FValues[aString];
  665. if (Result='') then
  666. Result:=GetDefaultString(aString);
  667. end;
  668. procedure TRestStringsConfig.SetRestString(aString: TRestStringProperty; AValue: UTF8String);
  669. begin
  670. FValues[AString]:=aValue;
  671. end;
  672. procedure TRestStringsConfig.Assign(aSource: TPersistent);
  673. Var
  674. R : TRestStringsConfig;
  675. S : TRestStringProperty;
  676. begin
  677. if (aSource is TRestStringsConfig) then
  678. begin
  679. R:=aSource as TRestStringsConfig;
  680. For S in TRestStringProperty do
  681. FValues[S]:=R.FValues[S];
  682. end;
  683. inherited Assign(aSource);
  684. end;
  685. { TRestOutputStreamer }
  686. procedure TRestOutputStreamer.SetOutputOptions(AValue: TRestOutputOptions);
  687. begin
  688. if FOutputOptions=AValue then Exit;
  689. FOutputOptions:=AValue;
  690. if RequireMetadata then
  691. Include(FOutputOptions,ooMetadata);
  692. end;
  693. procedure TRestOutputStreamer.CreateErrorContent(aCode: Integer;
  694. const Fmt: String; const Args: array of const);
  695. Var
  696. S : String;
  697. begin
  698. Try
  699. S:=Format(Fmt,Args);
  700. except
  701. On E : Exception do
  702. begin
  703. S:=Format('Error formatting string "%s" with %d arguments. Original code: %d',[Fmt,Length(Args),aCode]);
  704. aCode:=Statuses.GetStatusCode(rsError);
  705. end;
  706. end;
  707. CreateErrorContent(aCode,S);
  708. end;
  709. function TRestOutputStreamer.HasOption(aOption: TRestOutputOption): Boolean;
  710. begin
  711. Result:=aOption in OutputOptions;
  712. end;
  713. Function TRestOutputStreamer.FieldToBase64(F : TField) : UTF8String;
  714. var
  715. BF : TBlobField absolute F;
  716. Src : TStream;
  717. Dest : TStringStream;
  718. E : TBase64EncodingStream;
  719. begin
  720. Src:=Nil;
  721. Dest:=nil;
  722. E:=Nil;
  723. Try
  724. if f is TBlobField then
  725. begin
  726. Src:=TMemoryStream.Create;
  727. Src.Size:=BF.DataSize;
  728. BF.SaveToStream(Src);
  729. end
  730. else
  731. Src:=TStringStream.Create(F.AsString);
  732. Src.Position:=0;
  733. Dest:=TStringStream.Create(''{,CP_UTF8});
  734. E:=TBase64EncodingStream.Create(Dest);
  735. E.CopyFrom(Src,0);
  736. FreeAndNil(E); // Will flush
  737. Result:=Dest.DataString;
  738. Finally
  739. Src.Free;
  740. Dest.Free;
  741. end;
  742. end;
  743. { TRestStreamer }
  744. constructor TRestStreamer.Create(aStream: TStream; aStrings: TRestStringsConfig; aStatus : TRestStatusConfig; aOnGetVar: TRestGetVariableEvent);
  745. begin
  746. FStream:=aStream;
  747. FOnGetVar:=aOnGetVar;
  748. FStrings:=aStrings;
  749. FStatuses:=aStatus;
  750. end;
  751. function TRestStreamer.GetString(aString: TRestStringProperty): UTF8String;
  752. begin
  753. If Assigned(FStrings) then
  754. Result:=FStrings.GetRestString(aString)
  755. else
  756. Result:=DefaultPropertyNames[aString];
  757. end;
  758. function TRestStreamer.GetVariable(const aName: UTF8String): UTF8String;
  759. begin
  760. Result:='';
  761. if Assigned(FOnGetVar) then
  762. FOnGetVar(Self,aName,Result);
  763. end;
  764. Class function TRestStreamer.GetContentType: String;
  765. begin
  766. Result:='text/html';
  767. end;
  768. function TRestInputStreamer.HaveInputData(aName: UTF8string): Boolean;
  769. Var
  770. D : TJSONData;
  771. begin
  772. D:=GetContentField(aName);
  773. Result:=D<>Nil;
  774. D.Free;
  775. end;
  776. class procedure TRestInputStreamer.RegisterStreamer(const aName: String);
  777. begin
  778. TStreamerFactory.Instance.RegisterStreamer(rstInput,aName,Self)
  779. end;
  780. class procedure TRestInputStreamer.UnRegisterStreamer(const aName: String);
  781. begin
  782. TStreamerFactory.Instance.UnRegisterStreamer(rstInput,aName);
  783. end;
  784. class procedure TRestOutputStreamer.RegisterStreamer(const aName: String);
  785. begin
  786. TStreamerFactory.Instance.RegisterStreamer(rstOutput,aName,Self)
  787. end;
  788. class procedure TRestOutputStreamer.UnRegisterStreamer(const aName: String);
  789. begin
  790. TStreamerFactory.Instance.UnRegisterStreamer(rstOutput,aName)
  791. end;
  792. class function TRestOutputStreamer.FileExtension: String;
  793. begin
  794. Result:='';
  795. end;
  796. function TRestOutputStreamer.RequireMetadata: Boolean;
  797. begin
  798. Result:=False;
  799. end;
  800. function TRestOutputStreamer.FieldToString(aFieldType : TRestFieldType; F: TField): UTF8string;
  801. begin
  802. Case aFieldType of
  803. rftInteger : Result:=F.AsString;
  804. rftLargeInt : Result:=F.AsString;
  805. rftFloat : Result:=F.AsString;
  806. rftDate : Result:=FormatDateTime(GetString(rpDateFormat),DateOf(F.AsDateTime));
  807. rftTime : Result:=FormatDateTime(GetString(rpTimeFormat),TimeOf(F.AsDateTime));
  808. rftDateTime : Result:=FormatDateTime(GetString(rpDateTimeFormat),F.AsDateTime);
  809. rftString : Result:=F.AsString;
  810. rftBoolean : Result:=BoolToStr(F.AsBoolean,'true','false');
  811. rftBlob : Result:=FieldToBase64(F);
  812. else
  813. Result:='';
  814. end;
  815. end;
  816. { TRestIO }
  817. procedure TRestIO.SetIO(aInput: TRestInputStreamer; aOutput: TRestOutputStreamer);
  818. begin
  819. Finput:=aInput;
  820. Finput.FOnGetVar:=@DoGetVariable;
  821. Foutput:=aOutput;
  822. FOutput.FOnGetVar:=@DoGetVariable;
  823. end;
  824. procedure TRestIO.SetConn(aConn: TSQLConnection; ATrans: TSQLTransaction);
  825. begin
  826. FConn:=aConn;
  827. FTrans:=aTrans;
  828. end;
  829. procedure TRestIO.SetResource(aResource: TSQLDBRestResource);
  830. begin
  831. Fresource:=AResource;
  832. end;
  833. procedure TRestIO.SetOperation(aOperation: TRestOperation);
  834. begin
  835. FOperation:=aOperation;
  836. end;
  837. procedure TRestIO.SetRestStrings(aValue: TRestStringsConfig);
  838. begin
  839. FRestStrings:=aValue;
  840. end;
  841. procedure TRestIO.SetRestStatuses(aValue: TRestStatusConfig);
  842. begin
  843. FRestStatuses:=aValue;
  844. end;
  845. procedure TRestIO.DoGetVariable(Sender: TObject; const aName: UTF8String; out
  846. aVal: UTF8String);
  847. begin
  848. GetVariable(aName,aVal);
  849. end;
  850. procedure TRestIO.SetUserID(const AValue: String);
  851. begin
  852. if (UserID=AValue) then Exit;
  853. FRestContext.UserID:=AValue;
  854. end;
  855. function TRestIO.GetUserID: String;
  856. begin
  857. Result:=FRestContext.UserID;
  858. end;
  859. function TRestIO.GetResourceName: UTF8String;
  860. begin
  861. if Assigned(FResource) then
  862. Result:=FResource.ResourceName
  863. else
  864. Result:='?';
  865. end;
  866. constructor TRestIO.Create(aRequest: TRequest; aResponse: TResponse);
  867. begin
  868. FRequest:=aRequest;
  869. FResponse:=aResponse;
  870. FContentStream:=TStringStream.Create(aRequest.Content);
  871. FRestContext:=CreateRestContext;
  872. FRestContext.FIO:=Self;
  873. FUpdatedData:=TRestBufDataset.Create(Nil);
  874. end;
  875. destructor TRestIO.Destroy;
  876. begin
  877. FreeAndNil(FUpdatedData);
  878. FreeAndNil(FRestContext);
  879. if Assigned(FInput) then
  880. Finput.FOnGetVar:=Nil;
  881. if Assigned(Foutput) then
  882. FOutput.FOnGetVar:=Nil;
  883. FreeAndNil(FContentStream) ;
  884. FreeAndNil(Finput);
  885. FreeAndNil(Foutput);
  886. inherited Destroy;
  887. end;
  888. procedure TRestIO.DoSQLLog(Sender: TSQLConnection; EventType: TDBEventType; const Msg: String);
  889. begin
  890. If Assigned(OnSQLLog) then
  891. FOnSQLLog(Self,EventType,Msg);
  892. end;
  893. function TRestIO.CreateRestContext : TRestContext;
  894. begin
  895. Result:=TRestContext.Create;
  896. end;
  897. function TRestIO.GetVariable(const aName: UTF8String; out aVal: UTF8String;
  898. AllowedSources: TVAriableSources): TVariableSource;
  899. Function FindInList(aSource : TVariableSource;L : TStrings) : Boolean;
  900. Var
  901. I : Integer;
  902. N,V : String;
  903. begin
  904. Result:=(aSource in AllowedSources);
  905. if Result then
  906. begin
  907. I:=L.IndexOfName(aName);
  908. Result:=I<>-1;
  909. if Result then
  910. begin
  911. L.GetNameValue(I,N,V);
  912. aVal:=V;
  913. GetVariable:=aSource;
  914. end;
  915. end;
  916. end;
  917. begin
  918. Result:=vsNone;
  919. With Request do
  920. if not FIndInList(vsQuery,QueryFields) then
  921. if not FindInList(vsContent,ContentFields) then
  922. begin
  923. aVal:=RouteParams[aName];
  924. if (aVal<>'') then
  925. result:=vsRoute
  926. else
  927. FindInList(vsHeader,CustomHeaders);
  928. end;
  929. end;
  930. function TRestIO.GetFilterVariable(const aName: UTF8String; AFilter: TRestFieldFilter;out aValue: UTF8String) : TVariableSource;
  931. Const
  932. FilterStrings : Array[TRestFieldFilter] of TRestStringProperty =
  933. (rpFilterEqual,rpFilterLessThan,rpFilterGreaterThan,rpFilterLessThanEqual,rpFilterGreaterThanEqual,rpFilterIsNull);
  934. begin
  935. aValue:='';
  936. Result:=GetVariable(aName+FRestStrings.GetRestString(FilterStrings[aFilter]),aValue,[vsQuery]);
  937. end;
  938. class function TRestIO.StrToNullBoolean(const S: String; Strict: Boolean): TNullBoolean;
  939. var
  940. ls : string;
  941. begin
  942. result:=nbNone;
  943. ls:=lowercase(s);
  944. if (ls<>'') then
  945. if (ls='1') or (ls='t') or (ls='true') or (ls='y') then
  946. Result:=nbTrue
  947. else
  948. if (ls='0') or (ls='f') or (ls='false') or (ls='n') then
  949. Result:=nbFalse
  950. else if not Strict then
  951. Result:=nbNone
  952. else
  953. Raise EConvertError.CreateFmt('Not a correct boolean value: "%s"',[S])
  954. end;
  955. function TRestIO.GetBooleanVar(const aName: UTF8String; aStrict : Boolean = False): TNullBoolean;
  956. Var
  957. S : UTF8String;
  958. begin
  959. result:=nbNone;
  960. if GetVariable(aName,S)=vsNone then
  961. Result:=nbNone
  962. else
  963. Result:=StrToNullBoolean(S,aStrict);
  964. end;
  965. function TRestIO.GetRequestOutputOptions(aDefault: TRestOutputOptions
  966. ): TRestOutputOptions;
  967. Procedure CheckParam(aName : String; aOption: TRestOutputOption);
  968. begin
  969. Case GetBooleanVar(aName) of
  970. nbFalse : Exclude(Result,aOption);
  971. nbTrue : Include(Result,aOption);
  972. else
  973. // nbNull: keep default
  974. end
  975. end;
  976. begin
  977. Result:=aDefault;
  978. CheckParam(FRestStrings.GetRestString(rpHumanReadable),ooHumanReadable);
  979. CheckParam(FRestStrings.GetRestString(rpSparse),ooSparse);
  980. CheckParam(FRestStrings.GetRestString(rpIncludeMetadata),ooMetadata);
  981. end;
  982. function TRestIO.GetLimitOffset(aEnforceLimit : Int64; out aLimit, aOffset: Int64): boolean;
  983. Var
  984. P,S : UTF8String;
  985. begin
  986. aLimit:=0;
  987. aOffset:=0;
  988. P:=RestStrings.GetRestString(rpLimit);
  989. Result:=GetVariable(P,S,[vsQuery])<>vsNone;
  990. if Not Result then
  991. Exit;
  992. if (S<>'') and not TryStrToInt64(S,aLimit) then
  993. Raise ESQLDBRest.CreateFmt(RestStatuses.GetStatusCode(rsInvalidParam),SErrInvalidParam,[P]);
  994. P:=RestStrings.GetRestString(rpOffset);
  995. if GetVariable(P,S,[vsQuery])<>vsNone then
  996. if (S<>'') and not TryStrToInt64(S,aOffset) then
  997. Raise ESQLDBRest.CreateFmt(RestStatuses.GetStatusCode(rsInvalidParam),SErrInvalidParam,[P]);
  998. if (aEnforceLimit>0) and (aLimit>aEnforceLimit) then
  999. aLimit:=aEnforceLimit;
  1000. end;
  1001. procedure TRestIO.CreateErrorResponse;
  1002. begin
  1003. RestOutput.CreateErrorContent(Response.Code,Response.CodeText);
  1004. end;
  1005. finalization
  1006. FreeAndNil(TStreamerFactory.Fglobal);
  1007. end.