sqldbrestio.pp 38 KB

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