12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187 |
- {
- This file is part of the Free Pascal run time library.
- Copyright (c) 2019 by the Free Pascal development team
- SQLDB REST Dispatcher basic I/O environment.
- See the file COPYING.FPC, included in this distribution,
- for details about the copyright.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- **********************************************************************}
- {$IFNDEF FPC_DOTTEDUNITS}
- unit sqldbrestio;
- {$ENDIF FPC_DOTTEDUNITS}
- {$mode objfpc}{$H+}
- interface
- {$IFDEF FPC_DOTTEDUNITS}
- uses
- System.Classes, System.SysUtils, FpJson.Data, Data.BufDataset, Data.Sqldb, Data.Db, FpWeb.Http.Defs, FpWeb.RestBridge.Schema;
- {$ELSE FPC_DOTTEDUNITS}
- uses
- Classes, SysUtils, fpjson, bufdataset, sqldb, db, httpdefs, sqldbrestschema;
- {$ENDIF FPC_DOTTEDUNITS}
- Type
- TRestOutputOption = (ooMetadata,ooSparse,ooHumanReadable);
- TRestOutputOptions = Set of TRestOutputOption;
- TNullBoolean = (nbNone,nbFalse,nbTrue);
- TNullBooleans = set of TNullBoolean;
- Const
- AllVariableSources = [Low(TVariableSource)..High(TVariableSource)];
- allOutputOptions = [Low(TRestOutputOption)..High(TRestOutputOption)];
- Type
- TRestIO = Class;
- TRestStringProperty = (rpDateFormat,
- rpDateTimeFormat,
- rpTimeFormat,
- rpDataRoot,
- rpMetaDataRoot,
- rpErrorRoot,
- rpFieldNameProp,
- rpFieldTypeProp,
- rpFieldDateFormatProp,
- rpFieldMaxLenProp,
- rpHumanReadable,
- rpFieldList,
- rpExcludeFieldList,
- rpConnection,
- rpResource,
- rpIncludeMetadata,
- rpSparse,
- rpRowName,
- rpMetaDataFields,
- rpMetaDataField,
- rpErrorCode,
- rpErrorMessage,
- rpFilterEqual,
- rpFilterLessThan,
- rpFilterGreaterThan,
- rpFilterLessThanEqual,
- rpFilterGreaterThanEqual,
- rpFilterIsNull,
- rpLimit,
- rpOffset,
- rpOrderBy,
- rpMetadataResourceName,
- rpInputFormat,
- rpOutputFormat,
- rpCustomViewResourceName,
- rpCustomViewSQLParam,
- rpXMLDocumentRoot,
- rpConnectionResourceName,
- rpParametersResourceName,
- rpParametersRoutePart,
- rpAttachment
- );
- TRestStringProperties = Set of TRestStringProperty;
- TRestGetVariableEvent = Procedure (Sender : TObject; Const aName : UTF8String; Out aVal : UTF8String) of object;
- { TRestStringsConfig }
- TRestStringsConfig = Class(TPersistent)
- private
- FValues : Array[TRestStringProperty] of UTF8String;
- function GetRestPropName(AIndex: Integer): UTF8String;
- function IsRestStringStored(AIndex: Integer): Boolean;
- procedure SetRestPropName(AIndex: Integer; AValue: UTF8String);
- Public
- Class Function GetDefaultString(aString : TRestStringProperty) :UTF8String;
- Function GetRestString(aString : TRestStringProperty) :UTF8String;
- Procedure SetRestString(aString : TRestStringProperty; AValue :UTF8String);
- Procedure Assign(aSource : TPersistent); override;
- Published
- // Indexes here MUST match TRestProperty
- Property RESTDateFormat : UTF8String Index ord(rpDateFormat) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
- Property RESTDateTimeFormat : UTF8String Index ord(rpDateTimeFormat) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
- Property RESTTimeFormat : UTF8String Index ord(rpTimeFormat) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
- Property DataProperty : UTF8String Index ord(rpDataRoot) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
- Property MetaDataRoot : UTF8String Index ord(rpMetaDataRoot) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
- Property ErrorProperty : UTF8String Index ord(rpErrorRoot) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
- Property FieldNameProperty : UTF8String Index ord(rpFieldNameProp) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
- Property FieldTypeProperty : UTF8String Index ord(rpFieldTypeProp) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
- Property DateFormatProperty : UTF8String Index ord(rpFieldDateFormatProp) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
- Property MaxLenProperty : UTF8String Index ord(rpFieldMaxLenProp) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
- Property HumanReadableParam : UTF8String Index ord(rpHumanReadable) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
- Property FieldListParam : UTF8String Index ord(rpFieldList) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
- Property ExcludeFieldListParam : UTF8String Index ord(rpExcludeFieldList) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
- Property ConnectionParam : UTF8String Index Ord(rpConnection) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
- Property ResourceParam : UTF8String Index ord(rpResource) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
- Property IncludeMetadataParam : UTF8String Index ord(rpIncludeMetadata) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
- Property SparseParam : UTF8String Index Ord(rpSparse) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
- Property RowName : UTF8String Index Ord(rpRowName) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
- Property MetadataFields : UTF8String Index Ord(rpMetadataFields) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
- Property MetadataField : UTF8String Index Ord(rpMetadataField) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
- Property ErrorCode : UTF8String Index ord(rpErrorCode) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
- Property ErrorMessage : UTF8String Index ord(rpErrorMessage) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
- Property FilterParamEqual : UTF8String Index ord(rpFilterEqual) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
- Property FilterParamLessThan : UTF8String Index ord(rpFilterLessThan) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
- Property FilterParamGreaterThan : UTF8String Index ord(rpFilterGreaterThan) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
- Property FilterParamLessThanEqual : UTF8String Index ord(rpFilterLessThanEqual) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
- Property FilterParamGreaterThanEqual : UTF8String Index ord(rpFilterGreaterThanEqual) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
- Property FilterParamIsNull : UTF8String Index ord(rpFilterIsNull) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
- Property LimitParam : UTF8string Index ord(rpLimit) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
- Property OffsetParam : UTF8string Index ord(rpOffset) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
- Property SortParam : UTF8string Index ord(rpOrderBy) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
- Property MetadataResourceName : UTF8string Index ord(rpMetadataResourceName) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
- Property MetadataParametersName : UTF8string Index ord(rpParametersResourceName) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
- Property MetadataParametersRoutePart : UTF8string Index ord(rpParametersRoutePart) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
- Property InputFormatParam : UTF8string Index ord(rpInputFormat) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
- Property OutputFormatParam : UTF8string Index ord(rpOutputFormat) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
- Property CustomViewResourceName : UTF8string Index ord(rpCustomViewResourceName) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
- Property CustomViewSQLParam : UTF8string Index ord(rpCustomViewSQLParam) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
- Property XMLDocumentRoot : UTF8string Index ord(rpXMLDocumentRoot) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
- Property ConnectionResourceName : UTF8string Index ord(rpConnectionResourceName) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
- Property AttachmentParam : UTF8String Index ord(rpAttachment) Read GetRestPropName Write SetRestPropName Stored IsRestStringStored;
- end;
- TRestStatus = (rsError, // Internal logic/unexpected error (500)
- rsGetOK, // GET command completed OK (200)
- rsPostOK, // POST command completed OK (204)
- rsPutOK, // PUT command completed OK (200)
- rsDeleteOK, // DELETE command completed OK (204)
- rsInvalidParam, // Something wrong/missing in Query parameters (400)
- rsCORSOK, // CORS request completed OK (200)
- rsCORSNotAllowed, // CORS request not allowed (403)
- rsUnauthorized, // Authentication failed (401)
- rsResourceNotAllowed, // Resource request not allowed (403)
- rsRestOperationNotAllowed, // Resource operation (method) not allowed (405)
- rsInvalidMethod, // Invalid HTTP method (400)
- rsUnknownResource, // Unknown resource (404)
- rsNoResourceSpecified, // Unable to determine resource (404)
- rsNoConnectionSpecified, // Unable to determine connection for (400)
- rsRecordNotFound, // Query did not return record for single resource (404)
- rsInvalidContent, // Invalid content for POST/PUT operation (400)
- rsPatchOK // PATCH command completed OK (200)
- );
- TRestStatuses = set of TRestStatus;
- { TRestStatusConfig }
- TRestStatusConfig = Class(TPersistent)
- private
- FStatus : Array[TRestStatus] of Word;
- function GetStatus(AIndex: Integer): Word;
- function IsStatusStored(AIndex: Integer): Boolean;
- procedure SetStatus(AIndex: Integer; AValue: Word);
- Public
- Procedure Assign(aSource : TPersistent); override;
- function GetStatusCode(aStatus : TRestStatus): Word;
- Published
- // Internal logic/unexpected error (500)
- Property Error : Word Index Ord(rsError) Read GetStatus Write SetStatus Stored IsStatusStored;
- // GET command completed OK (200)
- Property GetOK : Word Index Ord(rsGetOK) Read GetStatus Write SetStatus Stored IsStatusStored;
- // POST command completed OK (204)
- Property PostOK : Word Index Ord(rsPostOK) Read GetStatus Write SetStatus Stored IsStatusStored;
- // PUT command completed OK (200)
- Property PutOK : Word Index Ord(rsPutOK) Read GetStatus Write SetStatus Stored IsStatusStored;
- // DELETE command completed OK (204)
- Property DeleteOK : Word Index Ord(rsDeleteOK) Read GetStatus Write SetStatus Stored IsStatusStored;
- // Something wrong/missing in Query parameters (400)
- Property InvalidParam : Word Index Ord(rsInvalidParam) Read GetStatus Write SetStatus Stored IsStatusStored;
- // CORS request completed OK (200)
- Property CORSOK : Word Index Ord(rsCORSOK) Read GetStatus Write SetStatus Stored IsStatusStored;
- // CORS request not allowed (403)
- Property CORSNotAllowed : Word Index Ord(rsCORSNotAllowed) Read GetStatus Write SetStatus Stored IsStatusStored;
- // Authentication failed (401)
- Property Unauthorized : Word Index Ord(rsUnauthorized) Read GetStatus Write SetStatus Stored IsStatusStored;
- // Resource request not allowed (403)
- Property ResourceNotAllowed : Word Index Ord(rsResourceNotAllowed) Read GetStatus Write SetStatus Stored IsStatusStored;
- // Resource operation (method) not allowed (405)
- Property RestOperationNotAllowed : Word Index Ord(rsRestOperationNotAllowed) Read GetStatus Write SetStatus Stored IsStatusStored;
- // Invalid HTTP method (400)
- Property InvalidMethod : Word Index Ord(rsInvalidMethod) Read GetStatus Write SetStatus Stored IsStatusStored;
- // Unknown resource (404)
- Property UnknownResource : Word Index Ord(rsUnknownResource) Read GetStatus Write SetStatus Stored IsStatusStored;
- // Unable to determine resource (404)
- Property NoResourceSpecified : Word Index Ord(rsNoResourceSpecified) Read GetStatus Write SetStatus Stored IsStatusStored;
- // Unable to determine connection for (400)
- Property NoConnectionSpecified : Word Index Ord(rsNoConnectionSpecified) Read GetStatus Write SetStatus Stored IsStatusStored;
- // Query did not return record for single resource (404)
- Property RecordNotFound : Word Index Ord(rsRecordNotFound) Read GetStatus Write SetStatus Stored IsStatusStored;
- // Invalid content for POST/PUT operation (400)
- Property InvalidContent : Word Index Ord(rsInvalidContent) Read GetStatus Write SetStatus Stored IsStatusStored;
- end;
- { TRestStreamer }
- TRestStreamer = Class(TObject)
- private
- FStream: TStream;
- FOnGetVar : TRestGetVariableEvent;
- FStrings: TRestStringsConfig;
- FStatuses : TRestStatusConfig;
- Public
- // Registry
- Class Function GetContentType : String; virtual;
- Constructor Create(aStream : TStream;aStrings : TRestStringsConfig;aStatus : TRestStatusConfig; aOnGetVar : TRestGetVariableEvent);
- Function GetString(aString : TRestStringProperty) : UTF8String;
- Property Strings : TRestStringsConfig Read FStrings;
- Property Statuses : TRestStatusConfig Read FStatuses;
- procedure InitStreaming; virtual; abstract;
- Function GetVariable(const aName : UTF8String) : UTF8String;
- Property Stream : TStream Read FStream;
- end;
- TRestStreamerClass = Class of TRestStreamer;
- { TRestInputStreamer }
- TRestInputStreamer = Class(TRestStreamer)
- Public
- // Select input object aIndex. Must return False if no such object in input
- // Currently aIndex=0, but for batch operations this may later become nonzero.
- Function SelectObject(aIndex : Integer) : Boolean; virtual; abstract;
- // Return Nil if none found. If result is non-nil, caller will free.
- Function GetContentField(aName : UTF8string) : TJSONData; virtual; abstract;
- Function HaveInputData(aName : UTF8string) : Boolean; virtual;
- Class Procedure RegisterStreamer(Const aName : String);
- Class Procedure UnRegisterStreamer(Const aName : String);
- end;
- TRestInputStreamerClass = Class of TRestInputStreamer;
- { TRestOutputStreamer }
- TRestOutputStreamer = Class(TRestStreamer)
- private
- FOutputOptions: TRestOutputOptions;
- Protected
- procedure SetOutputOptions(AValue: TRestOutputOptions); virtual;
- Public
- Class Procedure RegisterStreamer(Const aName : String);
- Class Procedure UnRegisterStreamer(Const aName : String);
- Class Function FileExtension : String; virtual;
- function RequireMetadata : Boolean; virtual;
- Function FieldToString(aFieldType : TRestFieldType; F : TField) : UTF8string; virtual;
- function FieldToBase64(F: TField): UTF8String; virtual;
- Function HasOption(aOption : TRestOutputOption) : Boolean;
- Procedure CreateErrorContent(aCode : Integer; Const aMessage: String); virtual; abstract;
- Procedure CreateErrorContent(aCode : Integer; Const Fmt: String; Const Args : Array of const);
- Procedure WriteMetadata(aFieldList : TRestFieldPairArray); virtual; abstract;
- Procedure StartData; virtual; abstract;
- Procedure StartRow; virtual; abstract;
- Procedure WriteField(aPair : TRestFieldPair); virtual; abstract;
- Procedure EndRow; virtual; abstract;
- Procedure EndData; virtual; abstract;
- Procedure FinalizeOutput; virtual; abstract;
- // Set before InitStreaming is called;
- Property OutputOptions : TRestOutputOptions Read FOutputOptions Write SetOutputOptions;
- end;
- TRestOutputStreamerClass = class of TRestOutputStreamer;
- { TRestContext }
- TRestContext = Class(TBaseRestContext)
- Private
- FIO : TRestIO;
- Protected
- function GetConnection: TSQLConnection; override;
- function GetTransaction: TSQLTransaction; override;
- Function DoGetInputData(const aName : UTF8string) : TJSONData; override;
- Function GetUpdateData : TDataset; override;
- property IO : TRestIO Read FIO;
- Public
- Function GetVariable(Const aName : UTF8String; aSources : TVariableSources; Out aValue : UTF8String) : Boolean; override;
- end;
- { TRestIO }
- TSQLLogNotifyEvent = Procedure (Sender : TObject; EventType : TDBEventType; Const Msg : String) of object;
- TRestIO = Class
- private
- FConn: TSQLConnection;
- FCOnnection: UTF8String;
- FInput: TRestInputStreamer;
- FOnSQLLog: TSQLLogNotifyEvent;
- FOperation: TRestOperation;
- FOutput: TRestOutputStreamer;
- FRequest: TRequest;
- FResource: TSQLDBRestResource;
- FResponse: TResponse;
- FRestContext: TRestContext;
- FRestStatuses: TRestStatusConfig;
- FRestStrings: TRestStringsConfig;
- FSchema: UTF8String;
- FTrans: TSQLTransaction;
- FContentStream : TStream;
- FUpdatedData: TBufDataset;
- function GetResourceName: UTF8String;
- function GetUserID: String;
- procedure SetUserID(const AValue: String);
- Protected
- Public
- Constructor Create(aRequest : TRequest; aResponse : TResponse); virtual;
- Destructor Destroy; override;
- // Log callback for SQL. Rerouted here, because we need IO
- procedure DoSQLLog(Sender: TSQLConnection; EventType: TDBEventType; const Msg: String);
- // Set things.
- Procedure SetIO(aInput : TRestInputStreamer;aOutput : TRestOutputStreamer);
- Procedure SetConn(aConn : TSQLConnection; ATrans : TSQLTransaction);
- Procedure SetResource(aResource : TSQLDBRestResource);
- procedure SetOperation(aOperation : TRestOperation);
- Procedure SetRestStrings(aValue : TRestStringsConfig);
- Procedure SetRestStatuses(aValue : TRestStatusConfig);
- // Get things
- class function StrToNullBoolean(const S: String; Strict: Boolean): TNullBoolean;
- Procedure DoGetVariable(Sender : TObject; Const aName : UTF8String; Out aVal : UTF8String);
- Function GetVariable (Const aName : UTF8String; Out aVal : UTF8String; AllowedSources : TVAriableSources = AllVariableSources) : TVariableSource; virtual;
- function GetFilterVariable(const aName: UTF8String; AFilter: TRestFieldFilter; out aValue: UTF8String): TVariableSource;
- Function GetBooleanVar(Const aName : UTF8String; aStrict : Boolean = False) : TNullBoolean;
- function GetRequestOutputOptions(aDefault: TRestOutputOptions): TRestOutputOptions;
- function GetLimitOffset(aEnforceLimit: Int64; out aLimit, aOffset: Int64): boolean;
- // Create error response in output
- function CreateRestContext: TRestContext; virtual;
- Procedure CreateErrorResponse;
- Property Operation : TRestOperation Read FOperation;
- // Not owned by TRestIO
- Property Request : TRequest read FRequest;
- Property Response : TResponse read FResponse;
- Property Connection : TSQLConnection Read FConn Write FConn;
- Property Transaction : TSQLTransaction Read FTrans Write FTrans;
- Property Resource : TSQLDBRestResource Read FResource;
- Property RestStrings : TRestStringsConfig Read FRestStrings;
- Property RestStatuses : TRestStatusConfig Read FRestStatuses;
- // owned by TRestIO
- Property UpdatedData : TBufDataset Read FUpdatedData;
- Property RESTInput : TRestInputStreamer read FInput;
- Property RESTOutput : TRestOutputStreamer read FOutput;
- Property RequestContentStream : TStream Read FContentStream;
- Property RestContext : TRestContext Read FRestContext;
- // For informative purposes
- Property ResourceName : UTF8String Read GetResourceName;
- Property Schema : UTF8String Read FSchema;
- Property ConnectionName : UTF8String Read FCOnnection;
- Property UserID : String Read GetUserID Write SetUserID;
- // For logging
- Property OnSQLLog :TSQLLogNotifyEvent Read FOnSQLLog Write FOnSQLLog;
- end;
- TRestIOClass = Class of TRestIO;
- { TStreamerDef }
- TStreamerDef = Class (TCollectionItem)
- private
- FClass: TRestStreamerClass;
- FName: String;
- Public
- Property MyClass : TRestStreamerClass Read FClass Write FClass;
- Property MyName : String Read FName Write Fname;
- end;
- { TStreamerDefList }
- TStreamerDefList = Class(TCollection)
- private
- function GetD(aIndex : integer): TStreamerDef;
- Public
- Function IndexOfStreamer(const aName : string) : Integer;
- Function IndexOfStreamerContentType(const aContentType : string) : Integer;
- Property Defs[aIndex : integer] : TStreamerDef Read GetD; default;
- end;
- { TStreamerFactory }
- TRestStreamerType = (rstInput,rstOutput);
- TStreamerFactory = Class (TObject)
- Private
- class var FGlobal : TStreamerFactory;
- Private
- FDefs : Array[TRestStreamerType] of TStreamerDefList;
- Protected
- Function FindDefByName(aType : TRestStreamerType; const aName : String) : TStreamerDef;
- Function FindDefByContentType(aType : TRestStreamerType; const aContentType : String) : TStreamerDef;
- Function IndexOfStreamer(aType : TRestStreamerType; const aName : string) : Integer;
- Function IndexOfStreamerContentType(aType : TRestStreamerType; const aContentType : string) : Integer;
- Procedure RegisterStreamer(aType : TRestStreamerType; Const aName : String; aClass : TRestStreamerClass);
- Procedure UnRegisterStreamer(aType : TRestStreamerType; Const aName : String);
- Public
- Constructor Create;
- Destructor Destroy; override;
- Class Function Instance : TStreamerFactory;
- Class Procedure GetStreamerList(aList : TStrings; atype : TRestStreamerType);
- Procedure GetStreamerDefNames(aList : TStrings; atype : TRestStreamerType);
- Function FindStreamerByName(aType : TRestStreamerType; const aName : string) : TStreamerDef;
- Function FindStreamerByContentType(aType : TRestStreamerType; const aContentType : string) : TStreamerDef;
- end;
- { TRestBufDataset }
- TRestBufDataset = class (TBufDataset)
- protected
- procedure LoadBlobIntoBuffer(FieldDef: TFieldDef; ABlobBuf: PBufBlobField); override;
- end;
- implementation
- {$IFDEF FPC_DOTTEDUNITS}
- uses System.Hash.Base64, System.DateUtils, FpWeb.RestBridge.Consts;
- {$ELSE FPC_DOTTEDUNITS}
- uses base64, dateutils, sqldbrestconst;
- {$ENDIF FPC_DOTTEDUNITS}
- Const
- DefaultPropertyNames : Array[TRestStringProperty] of UTF8String = (
- ISODateFormat, { rpDateFormat }
- ISODateTimeFormat, { rpDateTimeFormat }
- ISOTimeFormat, { rpTimeFormat }
- 'data', { rpDataRoot}
- 'metaData', { rpMetaDataRoot }
- 'error', { rpErrorRoot }
- 'name', { rpFieldNameProp }
- 'type', { rpFieldTypeProp }
- 'format', { rpFieldDateFormatProp }
- 'maxLen', { rpFieldMaxLenProp }
- 'humanreadable', { rpHumanReadable }
- 'fl', { rpFieldList }
- 'xl', { rpExcludeFieldList }
- 'Connection', { rpConnection }
- 'Resource', { rpResource }
- 'metadata', { rpIncludeMetadata }
- 'sparse', { rpSparse }
- 'row', { rpRowName }
- 'fields', { rpMetaDataFields }
- 'field', { rpMetaDataField }
- 'code', { rpErrorCode }
- 'message', { rpErrorMessage }
- '', { rpFilterEqual }
- '_lt', { rpFilterLessThan }
- '_gt', { rpFilterGreaterThan }
- '_lte', { rpFilterLessThanEqual }
- '_gte', { rpFilterGreaterThanEqual }
- '_null', { rpFilterIsNull }
- 'limit', { rpLimit }
- 'offset', { rpOffset }
- 'sort', { rpOrderBy }
- 'metadata', { rpMetadataResourceName }
- 'fmtin', { rpInputFormat }
- 'fmt', { rpOutputFormat }
- 'customview', { rpCustomViewResourceName }
- 'sql', { rpCustomViewSQLParam }
- 'datapacket', { rpXMLDocumentRoot}
- '_connection', { rpConnectionResourceName }
- '_parameters', { rpParametersResourceName }
- 'parameters', { rpParametersRoutePart }
- 'att' { rpAttachment }
- );
- DefaultStatuses : Array[TRestStatus] of Word = (
- 500, { rsError }
- 200, { rsGetOK }
- 201, { rsPostOK }
- 200, { rsPutOK }
- 204, { rsDeleteOK }
- 400, { rsInvalidParam }
- 200, { rsCORSOK}
- 403, { rsCORSNotallowed}
- 401, { rsUnauthorized }
- 403, { rsResourceNotAllowed }
- 405, { rsRestOperationNotAllowed }
- 400, { rsInvalidMethod }
- 404, { rsUnknownResource }
- 404, { rsNoResourceSpecified }
- 400, { rsNoConnectionSpecified }
- 404, { rsRecordNotFound }
- 400, { rsInvalidContent }
- 200 { rsPatchOK }
- );
- { TRestBufDataset }
- procedure TRestBufDataset.LoadBlobIntoBuffer(FieldDef: TFieldDef; ABlobBuf: PBufBlobField);
- begin
- If (FieldDef=Nil) or (aBlobBuf=Nil) then
- exit;
- end;
- { TRestStatusConfig }
- function TRestStatusConfig.GetStatus(AIndex: Integer): Word;
- begin
- Result:=GetStatusCode(TRestStatus(aIndex));
- end;
- function TRestStatusConfig.IsStatusStored(AIndex: Integer): Boolean;
- Var
- W : Word;
- begin
- W:=FStatus[TRestStatus(aIndex)];
- Result:=(W<>0) and (W<>DefaultStatuses[TRestStatus(aIndex)]);
- end;
- procedure TRestStatusConfig.SetStatus(AIndex: Integer; AValue: Word);
- begin
- if (aValue<>DefaultStatuses[TRestStatus(aIndex)]) then
- aValue:=0;
- FStatus[TRestStatus(aIndex)]:=aValue;
- end;
- procedure TRestStatusConfig.Assign(aSource: TPersistent);
- Var
- C : TRestStatusConfig;
- S : TRestStatus;
- begin
- if aSource is TRestStatusConfig then
- begin
- C:=aSource as TRestStatusConfig;
- for S in TRestStatus do
- FStatus[S]:=C.FStatus[S];
- end
- else
- inherited Assign(aSource);
- end;
- function TRestStatusConfig.GetStatusCode(aStatus: TRestStatus): Word;
- begin
- Result:=FStatus[aStatus];
- if Result=0 then
- Result:=DefaultStatuses[aStatus];
- end;
- { TRestContext }
- function TRestContext.GetVariable(const aName: UTF8String; aSources : TVariableSources; out aValue: UTF8String): Boolean;
- Var
- D : TJSONData;
- begin
- Result:=FIO.GetVariable(aName,aValue,aSources)<>vsNone;
- if Not Result and (vsData in aSources) then
- begin
- // Will be freed.
- D:=GetInputData(aName);
- Result:=Assigned(D);
- if Result then
- if D.JSONType in StructuredJSONTypes then
- aValue:=D.AsJSON
- else
- aValue:=D.AsString;
- end;
- end;
- function TRestContext.GetConnection: TSQLConnection;
- begin
- Result:=IO.Connection;
- end;
- function TRestContext.GetTransaction: TSQLTransaction;
- begin
- Result:=IO.Transaction;
- end;
- function TRestContext.DoGetInputData(const aName: UTF8string): TJSONData;
- begin
- Result:=IO.RESTInput.GetContentField(aName);
- end;
- function TRestContext.GetUpdateData: TDataset;
- begin
- Result:=IO.UpdatedData;
- end;
- { TStreamerDefList }
- function TStreamerDefList.GetD(aIndex : integer): TStreamerDef;
- begin
- Result:=TStreamerDef(Items[aIndex])
- end;
- function TStreamerDefList.IndexOfStreamer(const aName: string): Integer;
- begin
- Result:=Count-1;
- While (Result>=0) and Not SameText(GetD(Result).MyName,aName) do
- Dec(Result);
- end;
- function TStreamerDefList.IndexOfStreamerContentType(const aContentType: string): Integer;
- begin
- Result:=Count-1;
- While (Result>=0) and Not SameText(GetD(Result).MyClass.GetContentType, aContentType) do
- Dec(Result);
- end;
- { TStreamerFactory }
- function TStreamerFactory.FindDefByName(aType : TRestStreamerType; const aName: String): TStreamerDef;
- Var
- Idx : integer;
- begin
- Idx:=FDefs[aType].IndexOfStreamer(aName);
- if Idx=-1 then
- Result:=Nil
- else
- Result:=FDefs[aType][Idx];
- end;
- function TStreamerFactory.FindDefByContentType(aType : TRestStreamerType; Const aContentType: String): TStreamerDef;
- Var
- Idx : integer;
- begin
- Idx:=FDefs[aType].IndexOfStreamerContentType(aContentType);
- if Idx=-1 then
- Result:=Nil
- else
- Result:=FDefs[aType][Idx];
- end;
- procedure TStreamerFactory.RegisterStreamer(aType : TRestStreamerType; const aName: String; aClass: TRestStreamerClass);
- Var
- D : TStreamerDef;
- begin
- D:=FindDefByName(atype,aName);
- if D=Nil then
- begin
- D:=FDefs[atype].Add as TStreamerDef;
- D.MyName:=aName;
- end;
- D.MyClass:=aClass;
- end;
- procedure TStreamerFactory.UnRegisterStreamer(aType : TRestStreamerType; const aName: String);
- begin
- FindDefByName(aType,aName).Free;
- end;
- constructor TStreamerFactory.Create;
- Var
- T : TRestStreamerType;
- begin
- for T in TRestStreamerType do
- FDefs[T]:=TStreamerDefList.Create(TStreamerDef);
- end;
- destructor TStreamerFactory.Destroy;
- Var
- T : TRestStreamerType;
- begin
- for T in TRestStreamerType do
- FreeAndNil(FDefs[T]);
- inherited Destroy;
- end;
- class function TStreamerFactory.Instance: TStreamerFactory;
- begin
- if FGlobal=Nil then
- FGlobal:=TStreamerFactory.Create;
- Result:=FGlobal;
- end;
- class procedure TStreamerFactory.GetStreamerList(aList: TStrings;
- atype: TRestStreamerType);
- begin
- TStreamerFactory.Instance.GetStreamerDefNames(aList,aType);
- end;
- procedure TStreamerFactory.GetStreamerDefNames(aList: TStrings; atype: TRestStreamerType);
- var
- I : Integer;
- begin
- aList.Clear;
- For I:=0 to FDefs[aType].Count-1 do
- aList.Add(FDefs[aType][I].MyName);
- end;
- function TStreamerFactory.IndexOfStreamer(aType : TRestStreamerType; const aName: string): Integer;
- begin
- Result:=FDefs[aType].IndexOfStreamer(aName);
- end;
- function TStreamerFactory.IndexOfStreamerContentType(aType : TRestStreamerType; const aContentType: string): Integer;
- begin
- Result:=FDefs[aType].IndexOfStreamerContentType(aContentType);
- end;
- function TStreamerFactory.FindStreamerByName(aType : TRestStreamerType; const aName: string): TStreamerDef;
- begin
- Result:=FindDefByName(aType,aName);
- end;
- function TStreamerFactory.FindStreamerByContentType(aType : TRestStreamerType; const aContentType: string): TStreamerDef;
- begin
- Result:=FindDefByContentType(aType,aContentType);
- end;
- { TRestStringsConfig }
- function TRestStringsConfig.GetRestPropName(AIndex: Integer): UTF8String;
- begin
- Result:=FValues[TRestStringProperty(AIndex)];
- if (Result='') then
- Result:=DefaultPropertyNames[TRestStringProperty(AIndex)]
- end;
- function TRestStringsConfig.IsRestStringStored(AIndex: Integer): Boolean;
- Var
- V : UTF8String;
- begin
- V:=FValues[TRestStringProperty(AIndex)];
- Result:=(V<>'') and (V<>DefaultPropertyNames[TRestStringProperty(AIndex)]);
- end;
- procedure TRestStringsConfig.SetRestPropName(AIndex: Integer; AValue: UTF8String);
- begin
- FValues[TRestStringProperty(AIndex)]:=aValue;
- end;
- class function TRestStringsConfig.GetDefaultString(aString: TRestStringProperty): UTF8String;
- begin
- Result:=DefaultPropertyNames[aString]
- end;
- function TRestStringsConfig.GetRestString(aString: TRestStringProperty): UTF8String;
- begin
- Result:=FValues[aString];
- if (Result='') then
- Result:=GetDefaultString(aString);
- end;
- procedure TRestStringsConfig.SetRestString(aString: TRestStringProperty; AValue: UTF8String);
- begin
- FValues[AString]:=aValue;
- end;
- procedure TRestStringsConfig.Assign(aSource: TPersistent);
- Var
- R : TRestStringsConfig;
- S : TRestStringProperty;
- begin
- if (aSource is TRestStringsConfig) then
- begin
- R:=aSource as TRestStringsConfig;
- For S in TRestStringProperty do
- FValues[S]:=R.FValues[S];
- end;
- inherited Assign(aSource);
- end;
- { TRestOutputStreamer }
- procedure TRestOutputStreamer.SetOutputOptions(AValue: TRestOutputOptions);
- begin
- if FOutputOptions=AValue then Exit;
- FOutputOptions:=AValue;
- if RequireMetadata then
- Include(FOutputOptions,ooMetadata);
- end;
- procedure TRestOutputStreamer.CreateErrorContent(aCode: Integer;
- const Fmt: String; const Args: array of const);
- Var
- S : String;
- begin
- Try
- S:=Format(Fmt,Args);
- except
- On E : Exception do
- begin
- S:=Format('Error formatting string "%s" with %d arguments. Original code: %d',[Fmt,Length(Args),aCode]);
- aCode:=Statuses.GetStatusCode(rsError);
- end;
- end;
- CreateErrorContent(aCode,S);
- end;
- function TRestOutputStreamer.HasOption(aOption: TRestOutputOption): Boolean;
- begin
- Result:=aOption in OutputOptions;
- end;
- Function TRestOutputStreamer.FieldToBase64(F : TField) : UTF8String;
- var
- BF : TBlobField absolute F;
- Src : TStream;
- Dest : TStringStream;
- E : TBase64EncodingStream;
- begin
- Src:=Nil;
- Dest:=nil;
- E:=Nil;
- Try
- if f is TBlobField then
- begin
- Src:=TMemoryStream.Create;
- Src.Size:=BF.DataSize;
- BF.SaveToStream(Src);
- end
- else
- Src:=TStringStream.Create(F.AsString);
- Src.Position:=0;
- Dest:=TStringStream.Create(''{,CP_UTF8});
- E:=TBase64EncodingStream.Create(Dest);
- E.CopyFrom(Src,0);
- FreeAndNil(E); // Will flush
- Result:=Dest.DataString;
- Finally
- Src.Free;
- Dest.Free;
- end;
- end;
- { TRestStreamer }
- constructor TRestStreamer.Create(aStream: TStream; aStrings: TRestStringsConfig; aStatus : TRestStatusConfig; aOnGetVar: TRestGetVariableEvent);
- begin
- FStream:=aStream;
- FOnGetVar:=aOnGetVar;
- FStrings:=aStrings;
- FStatuses:=aStatus;
- end;
- function TRestStreamer.GetString(aString: TRestStringProperty): UTF8String;
- begin
- If Assigned(FStrings) then
- Result:=FStrings.GetRestString(aString)
- else
- Result:=DefaultPropertyNames[aString];
- end;
- function TRestStreamer.GetVariable(const aName: UTF8String): UTF8String;
- begin
- Result:='';
- if Assigned(FOnGetVar) then
- FOnGetVar(Self,aName,Result);
- end;
- Class function TRestStreamer.GetContentType: String;
- begin
- Result:='text/html';
- end;
- function TRestInputStreamer.HaveInputData(aName: UTF8string): Boolean;
- Var
- D : TJSONData;
- begin
- D:=GetContentField(aName);
- Result:=D<>Nil;
- D.Free;
- end;
- class procedure TRestInputStreamer.RegisterStreamer(const aName: String);
- begin
- TStreamerFactory.Instance.RegisterStreamer(rstInput,aName,Self)
- end;
- class procedure TRestInputStreamer.UnRegisterStreamer(const aName: String);
- begin
- TStreamerFactory.Instance.UnRegisterStreamer(rstInput,aName);
- end;
- class procedure TRestOutputStreamer.RegisterStreamer(const aName: String);
- begin
- TStreamerFactory.Instance.RegisterStreamer(rstOutput,aName,Self)
- end;
- class procedure TRestOutputStreamer.UnRegisterStreamer(const aName: String);
- begin
- TStreamerFactory.Instance.UnRegisterStreamer(rstOutput,aName)
- end;
- class function TRestOutputStreamer.FileExtension: String;
- begin
- Result:='';
- end;
- function TRestOutputStreamer.RequireMetadata: Boolean;
- begin
- Result:=False;
- end;
- function TRestOutputStreamer.FieldToString(aFieldType : TRestFieldType; F: TField): UTF8string;
- begin
- Case aFieldType of
- rftInteger : Result:=F.AsString;
- rftLargeInt : Result:=F.AsString;
- rftFloat : Result:=F.AsString;
- rftDate : Result:=FormatDateTime(GetString(rpDateFormat),DateOf(F.AsDateTime));
- rftTime : Result:=FormatDateTime(GetString(rpTimeFormat),TimeOf(F.AsDateTime));
- rftDateTime : Result:=FormatDateTime(GetString(rpDateTimeFormat),F.AsDateTime);
- rftString : Result:=F.AsString;
- rftBoolean : Result:=BoolToStr(F.AsBoolean,'true','false');
- rftBlob : Result:=FieldToBase64(F);
- else
- Result:='';
- end;
- end;
- { TRestIO }
- procedure TRestIO.SetIO(aInput: TRestInputStreamer; aOutput: TRestOutputStreamer);
- begin
- Finput:=aInput;
- Finput.FOnGetVar:=@DoGetVariable;
- Foutput:=aOutput;
- FOutput.FOnGetVar:=@DoGetVariable;
- end;
- procedure TRestIO.SetConn(aConn: TSQLConnection; ATrans: TSQLTransaction);
- begin
- FConn:=aConn;
- FTrans:=aTrans;
- end;
- procedure TRestIO.SetResource(aResource: TSQLDBRestResource);
- begin
- Fresource:=AResource;
- end;
- procedure TRestIO.SetOperation(aOperation: TRestOperation);
- begin
- FOperation:=aOperation;
- end;
- procedure TRestIO.SetRestStrings(aValue: TRestStringsConfig);
- begin
- FRestStrings:=aValue;
- end;
- procedure TRestIO.SetRestStatuses(aValue: TRestStatusConfig);
- begin
- FRestStatuses:=aValue;
- end;
- procedure TRestIO.DoGetVariable(Sender: TObject; const aName: UTF8String; out
- aVal: UTF8String);
- begin
- GetVariable(aName,aVal);
- end;
- procedure TRestIO.SetUserID(const AValue: String);
- begin
- if (UserID=AValue) then Exit;
- FRestContext.UserID:=AValue;
- end;
- function TRestIO.GetUserID: String;
- begin
- Result:=FRestContext.UserID;
- end;
- function TRestIO.GetResourceName: UTF8String;
- begin
- if Assigned(FResource) then
- Result:=FResource.ResourceName
- else
- Result:='?';
- end;
- constructor TRestIO.Create(aRequest: TRequest; aResponse: TResponse);
- begin
- FRequest:=aRequest;
- FResponse:=aResponse;
- FContentStream:=TStringStream.Create(aRequest.Content);
- FRestContext:=CreateRestContext;
- FRestContext.FIO:=Self;
- FUpdatedData:=TRestBufDataset.Create(Nil);
- end;
- destructor TRestIO.Destroy;
- begin
- FreeAndNil(FUpdatedData);
- FreeAndNil(FRestContext);
- if Assigned(FInput) then
- Finput.FOnGetVar:=Nil;
- if Assigned(Foutput) then
- FOutput.FOnGetVar:=Nil;
- FreeAndNil(FContentStream) ;
- FreeAndNil(Finput);
- FreeAndNil(Foutput);
- inherited Destroy;
- end;
- procedure TRestIO.DoSQLLog(Sender: TSQLConnection; EventType: TDBEventType; const Msg: String);
- begin
- If Assigned(OnSQLLog) then
- FOnSQLLog(Self,EventType,Msg);
- end;
- function TRestIO.CreateRestContext : TRestContext;
- begin
- Result:=TRestContext.Create;
- end;
- function TRestIO.GetVariable(const aName: UTF8String; out aVal: UTF8String;
- AllowedSources: TVAriableSources): TVariableSource;
- Function FindInList(aSource : TVariableSource;L : TStrings) : Boolean;
- Var
- I : Integer;
- N,V : String;
- begin
- Result:=(aSource in AllowedSources);
- if Result then
- begin
- I:=L.IndexOfName(aName);
- Result:=I<>-1;
- if Result then
- begin
- L.GetNameValue(I,N,V);
- aVal:=V;
- GetVariable:=aSource;
- end;
- end;
- end;
- begin
- Result:=vsNone;
- With Request do
- if not FIndInList(vsQuery,QueryFields) then
- if not FindInList(vsContent,ContentFields) then
- begin
- aVal:=RouteParams[aName];
- if (aVal<>'') then
- result:=vsRoute
- else
- FindInList(vsHeader,CustomHeaders);
- end;
- end;
- function TRestIO.GetFilterVariable(const aName: UTF8String; AFilter: TRestFieldFilter;out aValue: UTF8String) : TVariableSource;
- Const
- FilterStrings : Array[TRestFieldFilter] of TRestStringProperty =
- (rpFilterEqual,rpFilterLessThan,rpFilterGreaterThan,rpFilterLessThanEqual,rpFilterGreaterThanEqual,rpFilterIsNull);
- begin
- aValue:='';
- Result:=GetVariable(aName+FRestStrings.GetRestString(FilterStrings[aFilter]),aValue,[vsQuery]);
- end;
- class function TRestIO.StrToNullBoolean(const S: String; Strict: Boolean): TNullBoolean;
- var
- ls : string;
- begin
- result:=nbNone;
- ls:=lowercase(s);
- if (ls<>'') then
- if (ls='1') or (ls='t') or (ls='true') or (ls='y') then
- Result:=nbTrue
- else
- if (ls='0') or (ls='f') or (ls='false') or (ls='n') then
- Result:=nbFalse
- else if not Strict then
- Result:=nbNone
- else
- Raise EConvertError.CreateFmt('Not a correct boolean value: "%s"',[S])
- end;
- function TRestIO.GetBooleanVar(const aName: UTF8String; aStrict : Boolean = False): TNullBoolean;
- Var
- S : UTF8String;
- begin
- result:=nbNone;
- if GetVariable(aName,S)=vsNone then
- Result:=nbNone
- else
- Result:=StrToNullBoolean(S,aStrict);
- end;
- function TRestIO.GetRequestOutputOptions(aDefault: TRestOutputOptions
- ): TRestOutputOptions;
- Procedure CheckParam(aName : String; aOption: TRestOutputOption);
- begin
- Case GetBooleanVar(aName) of
- nbFalse : Exclude(Result,aOption);
- nbTrue : Include(Result,aOption);
- else
- // nbNull: keep default
- end
- end;
- begin
- Result:=aDefault;
- CheckParam(FRestStrings.GetRestString(rpHumanReadable),ooHumanReadable);
- CheckParam(FRestStrings.GetRestString(rpSparse),ooSparse);
- CheckParam(FRestStrings.GetRestString(rpIncludeMetadata),ooMetadata);
- end;
- function TRestIO.GetLimitOffset(aEnforceLimit : Int64; out aLimit, aOffset: Int64): boolean;
- Var
- P,S : UTF8String;
- begin
- aLimit:=0;
- aOffset:=0;
- P:=RestStrings.GetRestString(rpLimit);
- Result:=GetVariable(P,S,[vsQuery])<>vsNone;
- if Not Result then
- Exit;
- if (S<>'') and not TryStrToInt64(S,aLimit) then
- Raise ESQLDBRest.CreateFmt(RestStatuses.GetStatusCode(rsInvalidParam),SErrInvalidParam,[P]);
- P:=RestStrings.GetRestString(rpOffset);
- if GetVariable(P,S,[vsQuery])<>vsNone then
- if (S<>'') and not TryStrToInt64(S,aOffset) then
- Raise ESQLDBRest.CreateFmt(RestStatuses.GetStatusCode(rsInvalidParam),SErrInvalidParam,[P]);
- if (aEnforceLimit>0) and (aLimit>aEnforceLimit) then
- aLimit:=aEnforceLimit;
- end;
- procedure TRestIO.CreateErrorResponse;
- begin
- RestOutput.CreateErrorContent(Response.Code,Response.CodeText);
- end;
- finalization
- FreeAndNil(TStreamerFactory.Fglobal);
- end.
|