sqldbrestschema.pp 53 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2019 by the Free Pascal development team
  4. SQLDB REST bridge : REST Schema.
  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 sqldbrestschema;
  13. {$ENDIF FPC_DOTTEDUNITS}
  14. {$mode objfpc}
  15. {$H+}
  16. {$modeswitch typehelpers}
  17. {$modeswitch advancedrecords}
  18. interface
  19. {$IFDEF FPC_DOTTEDUNITS}
  20. uses
  21. System.Classes, System.SysUtils, System.Contnrs, Data.Db, Data.Sqldb, FpJson.Data;
  22. {$ELSE FPC_DOTTEDUNITS}
  23. uses
  24. Classes, SysUtils, contnrs, db, sqldb, fpjson;
  25. {$ENDIF FPC_DOTTEDUNITS}
  26. Type
  27. TRestFieldType = (rftUnknown,rftInteger,rftLargeInt,rftFloat,rftDate,rftTime,rftDateTime,rftString,rftBoolean,rftBlob);
  28. TRestFieldTypes = set of TRestFieldType;
  29. TRestFieldOption = (foInKey,foInInsert, foInUpdate,foRequired,foFilter,foOrderBy,foOrderByDesc);
  30. TRestFieldOptions = Set of TRestFieldOption;
  31. TRestFieldFilter = (rfEqual,rfLessThan,rfGreaterThan,rfLessThanEqual,rfGreaterThanEqual,rfNull);
  32. TRestFieldFilters = set of TRestFieldFilter;
  33. TSQLKind = (skSelect,skInsert,skUpdate,skDelete); // Must follow Index used below.
  34. TSQLKinds = set of TSQLKind;
  35. TRestOperation = (roUnknown,roGet,roPost,roPut,roDelete,roOptions,roHead,roPatch);
  36. TRestOperations = Set of TRestOperation;
  37. TFieldListKind = (flSelect,flInsert,flInsertParams,flUpdate,flWhereKey,flFilter,flOrderby);
  38. TFieldListKinds = set of TFieldListKind;
  39. TVariableSource = (vsNone,vsQuery,vsContent,vsRoute,vsHeader,vsData,vsParam);
  40. TVariableSources = Set of TVariableSource;
  41. Const
  42. AllRestOperations = [Succ(Low(TRestOperation))..High(TRestOperation)];
  43. AllFieldFilters = [Low(TRestFieldFilter)..High(TRestFieldFilter)];
  44. JSONSchemaRoot = 'schema';
  45. JSONResourcesRoot = 'resources';
  46. JSONConnectionsRoot = 'connections';
  47. JSONConnectionName = 'connectionName';
  48. Type
  49. { TBaseRestContext }
  50. TBaseRestContext = Class(TObject)
  51. private
  52. FData: TObject;
  53. FUserID: UTF8String;
  54. FFreeList : TFPObjectList;
  55. Protected
  56. Procedure AddToFreeList(aData : TJSONData);
  57. // The result of this function will be freed.
  58. function DoGetInputData(const aName: UTF8string): TJSONData; virtual; abstract;
  59. Procedure DoSetInputData(aName: UTF8string; aValue: TJSONData); virtual; abstract;
  60. Function GetConnection : TSQLConnection; virtual; abstract;
  61. Function GetTransaction : TSQLTransaction; virtual; abstract;
  62. Function GetUpdateData : TDataset; virtual; abstract;
  63. Public
  64. Destructor Destroy; override;
  65. // Call this to get a HTTP Query variable, header,...
  66. Function GetVariable(Const aName : UTF8String; aSources : TVariableSources; Out aValue : UTF8String) : Boolean; virtual; abstract;
  67. // Get data from input data. Do not free the result !
  68. Function GetInputData(aName : UTF8string) : TJSONData;
  69. // Set data from input data. Do not free the result !
  70. Procedure SetInputData(aName : UTF8string; aValue : TJSONData);
  71. // This will be set when calling.
  72. Property UserID : UTF8String Read FUserID Write FUserID;
  73. // You can attach data to this if you want to. It will be kept for the duration of the request.
  74. // You are responsible for freeing this data, though.
  75. Property Data : TObject Read FData Write FData;
  76. // Get connection in use
  77. Property Connection : TSQLConnection Read GetConnection;
  78. // Get transaction in use
  79. Property Transaction : TSQLTransaction Read GetTransaction;
  80. // Updated data after PUT/POST/PATCH
  81. Property UpdatedData : TDataset Read GetUpdateData;
  82. // Property access to input data. You can set this as well in before update handlers.
  83. // The value you set will be set
  84. Property InputData[aName : UTF8String] : TJSONData Read GetInputData Write SetInputData;
  85. end;
  86. { ESQLDBRest }
  87. ESQLDBRest = Class(Exception)
  88. private
  89. FResponseCode: Integer;
  90. Public
  91. Constructor Create(aCode : Integer; Const aMessage : String);
  92. Constructor CreateFmt(aCode : Integer; Const Fmt : String; COnst Args: Array of const);
  93. Property ResponseCode : Integer Read FResponseCode Write FResponseCode;
  94. end;
  95. TRestSQLQuery = Class(TSQLQuery)
  96. Public
  97. Property TableName;
  98. end;
  99. TSQLDBRestSchema = Class;
  100. TSQLDBRestCustomBusinessProcessor = Class;
  101. TSQLDBRestBusinessProcessor = Class;
  102. { TSQLDBRestField }
  103. TSQLDBRestField = class(TCollectionItem)
  104. private
  105. FFieldName: UTF8String;
  106. FFieldType: TRestFieldType;
  107. FFilters: TRestFieldFilters;
  108. fGeneratorName: String;
  109. FMaxLen: Integer;
  110. FNativeFieldType: TFieldType;
  111. FOptions: TRestFieldOptions;
  112. FPublicName: UTF8String;
  113. function GetPublicName: UTF8String;
  114. Protected
  115. Function GetDisplayName: string; override;
  116. Public
  117. Constructor Create(ACollection: TCollection); override;
  118. Procedure Assign(Source: TPersistent); override;
  119. Function UseInFieldList(aListKind : TFieldListKind) : Boolean; virtual;
  120. Published
  121. Property FieldName : UTF8String Read FFieldName Write FFieldName;
  122. Property PublicName : UTF8String Read GetPublicName Write FPublicName;
  123. Property GeneratorName : String Read fGeneratorName Write FGeneratorName;
  124. Property FieldType : TRestFieldType Read FFieldType Write FFieldType;
  125. Property NativeFieldType : TFieldType Read FNativeFieldType Write FNativeFieldType;
  126. Property Options : TRestFieldOptions Read FOptions Write FOptions;
  127. Property Filters : TRestFieldFilters Read FFilters Write FFilters default AllFieldFilters;
  128. Property MaxLen : Integer Read FMaxLen Write FMaxLen;
  129. end;
  130. TSQLDBRestFieldClass = Class of TSQLDBRestField;
  131. TSQLDBRestFieldArray = Array of TSQLDBRestField;
  132. { TSQLDBRestFieldArrayHelper }
  133. TSQLDBRestFieldArrayHelper = type helper for TSQLDBRestFieldArray
  134. Function IndexOf(aField : TSQLDBRestField) : Integer;
  135. Function Has(aField : TSQLDBRestField) : Boolean;
  136. end;
  137. TRestFieldPair = Record
  138. DBField : TField;
  139. RestField :TSQLDBRestField;
  140. end;
  141. TRestFieldPairArray = Array of TRestFieldPair;
  142. TRestFieldOrderPair = Record
  143. RestField :TSQLDBRestField;
  144. Desc : Boolean;
  145. end;
  146. TRestFieldOrderPairArray = Array of TRestFieldOrderPair;
  147. { TSQLDBRestFieldList }
  148. { TSQLDBRestFieldListEnumerator }
  149. TSQLDBRestFieldListEnumerator = Class(TCollectionEnumerator)
  150. Public
  151. function GetCurrent: TSQLDBRestField; reintroduce;
  152. property Current: TSQLDBRestField read GetCurrent;
  153. end;
  154. TSQLDBRestFieldList = class(TCollection)
  155. private
  156. function GetFields(aIndex : Integer): TSQLDBRestField;
  157. procedure SetFields(aIndex : Integer; AValue: TSQLDBRestField);
  158. Public
  159. Function GetEnumerator: TSQLDBRestFieldListEnumerator;
  160. Function AddField(Const aFieldName : UTF8String; aFieldType : TRestFieldType; aOptions : TRestFieldOptions) : TSQLDBRestField;
  161. function indexOfFieldName(const aFieldName: UTF8String): Integer;
  162. Function FindByFieldName(const aFieldName: UTF8String):TSQLDBRestField;
  163. function indexOfPublicName(const aPublicName: UTF8String): Integer;
  164. Function FindByPublicName(const aFieldName: UTF8String):TSQLDBRestField;
  165. Property Fields[aIndex : Integer] : TSQLDBRestField read GetFields write SetFields; default;
  166. end;
  167. TSQLDBRestFieldListClass = Class of TSQLDBRestFieldList;
  168. { TSQLDBRestParam }
  169. TSQLDBRestParam = class(TCollectionItem)
  170. private
  171. FName: UTF8String;
  172. FDefault: UTF8String;
  173. FDataType : TFieldType;
  174. Protected
  175. Function GetDisplayName: string; override;
  176. Public
  177. Procedure Assign(Source: TPersistent); override;
  178. Published
  179. Property Name : UTF8String Read FName Write FName;
  180. Property DataType : TFieldType Read FDataType Write FDataType;
  181. Property DefaultValue : UTF8String Read FDefault Write FDefault;
  182. end;
  183. TSQLDBRestParamClass = Class of TSQLDBRestParam;
  184. TSQLDBRestParamArray = Array of TSQLDBRestParam;
  185. { TSQLDBRestParamListEnumerator }
  186. TSQLDBRestParamListEnumerator = Class(TCollectionEnumerator)
  187. Public
  188. function GetCurrent: TSQLDBRestParam; reintroduce;
  189. property Current: TSQLDBRestParam read GetCurrent;
  190. end;
  191. { TSQLDBRestParameterList }
  192. TSQLDBRestParameterList = class(TCollection)
  193. private
  194. function GetParam(aIndex : Integer): TSQLDBRestParam;
  195. procedure SetParam(aIndex : Integer; AValue: TSQLDBRestParam);
  196. Public
  197. Function GetEnumerator: TSQLDBRestParamListEnumerator;
  198. Function IndexOf(Const aName : string) : Integer;
  199. Function Find(Const aName : string) : TSQLDBRestParam;
  200. Function ParamByName(Const aName : string) : TSQLDBRestParam;
  201. Function AddParam(Const aName : string) : TSQLDBRestParam;
  202. Property Params[aIndex : Integer] : TSQLDBRestParam Read GetParam Write SetParam;default;
  203. end;
  204. TSQLDBRestParameterListClass = Class of TSQLDBRestParameterList;
  205. { TSQLDBRestResource }
  206. TSQLDBRestGetDatasetEvent = Procedure (aSender : TObject; aContext : TBaseRestContext; aFieldList : TRestFieldPairArray; aOrderBy : TRestFieldOrderPairArray; aLimit, aOffset : Int64; Var aDataset : TDataset) of object;
  207. TSQLDBRestCheckParamsEvent = Procedure (aSender : TObject; aContext : TBaseRestContext; aOperation : TRestOperation; Params : TParams) of object;
  208. TSQLDBRestAllowRecordEvent = Procedure (aSender : TObject; aContext : TBaseRestContext; aDataSet : TDataset; var allowRecord : Boolean) of object;
  209. TSQLDBRestAllowResourceEvent = Procedure (aSender : TObject; aContext : TBaseRestContext; var allowResource : Boolean) of object;
  210. TSQLDBRestAllowedOperationsEvent = Procedure (aSender : TObject; aContext : TBaseRestContext; var aOperations : TRestOperations) of object;
  211. TSQLDBRestOnGetWhere = Procedure(Sender : TObject; aContext : TBaseRestContext; aKind : TSQLKind; var aWhere : UTF8String) of object;
  212. TProcessIdentifier = Function (const S: UTF8String): UTF8String of object;
  213. TSQLDBRestResource = class(TCollectionItem)
  214. private
  215. FBusinessProcessor: TSQLDBRestCustomBusinessProcessor;
  216. FAllowedOperations: TRestOperations;
  217. FConnectionName: UTF8String;
  218. FEnabled: Boolean;
  219. FFields: TSQLDBRestFieldList;
  220. FInMetadata: Boolean;
  221. FOnAllowedOperations: TSQLDBRestAllowedOperationsEvent;
  222. FOnAllowRecord: TSQLDBRestAllowRecordEvent;
  223. FOnCheckParams: TSQLDBRestCheckParamsEvent;
  224. FOnGetDataset: TSQLDBRestGetDatasetEvent;
  225. FOnGetWhere: TSQLDBRestOnGetWhere;
  226. FOnResourceAllowed: TSQLDBRestAllowResourceEvent;
  227. FParameters: TSQLDBRestParameterList;
  228. FResourceName: UTF8String;
  229. FTableName: UTF8String;
  230. FSQL : Array[TSQLKind] of TStrings;
  231. function GetResourceName: UTF8String;
  232. function GetSQL(AIndex: Integer): TStrings;
  233. function GetSQLTyped(aKind : TSQLKind): TStrings;
  234. procedure SetAllowedOperations(AValue: TRestOperations);
  235. procedure SetFields(AValue: TSQLDBRestFieldList);
  236. procedure SetParameters(AValue: TSQLDBRestParameterList);
  237. procedure SetSQL(AIndex: Integer; AValue: TStrings);
  238. Protected
  239. Function GetDisplayName: string; override;
  240. Public
  241. Class var
  242. DefaultFieldListClass : TSQLDBRestFieldListClass;
  243. DefaultFieldClass: TSQLDBRestFieldClass;
  244. DefaultParameterListClass : TSQLDBRestParameterListClass;
  245. DefaultParamClass : TSQLDBRestParamClass;
  246. Class function CreateFieldList : TSQLDBRestFieldList; virtual;
  247. Class function CreateParamList : TSQLDBRestParameterList; virtual;
  248. Class function FieldTypeToRestFieldType(aFieldType: TFieldType): TRestFieldType; virtual;
  249. Class Constructor Init;
  250. Public
  251. Constructor Create(ACollection: TCollection); override;
  252. Destructor Destroy; override;
  253. Procedure CheckParams(aContext : TBaseRestContext; aOperation : TRestoperation; P : TParams);
  254. Function GetDataset(aContext : TBaseRestContext; aFieldList : TRestFieldPairArray; aOrderBy : TRestFieldOrderPairArray; aLimit, aOffset : Int64) : TDataset;
  255. Function GetSchema : TSQLDBRestSchema;
  256. function GenerateDefaultSQL(aKind: TSQLKind; OnlyFields: TSQLDBRestFieldArray = nil): UTF8String; virtual;
  257. Procedure Assign(Source: TPersistent); override;
  258. Function AllowRecord(aContext : TBaseRestContext; aDataset : TDataset) : Boolean;
  259. Function AllowResource(aContext : TBaseRestContext) : Boolean;
  260. Function GetAllowedOperations(aContext : TBaseRestContext) : TRestOperations;
  261. Function GetHTTPAllow : String; virtual;
  262. function GetFieldList(aListKind: TFieldListKind; const ASep : String = ''; OnlyFields : TSQLDBRestFieldArray = Nil): UTF8String;
  263. function GetFieldArray(aListKind: TFieldListKind): TSQLDBRestFieldArray;
  264. Function GetResolvedSQl(aKind : TSQLKind; Const AWhere : UTF8String; Const aOrderBy : UTF8String = ''; const aLimit : UTF8String = ''; OnlyFields : TSQLDBRestFieldArray = nil) : UTF8String;
  265. Function ProcessSQl(const aSQL : String; Const AWhere : UTF8String; Const aOrderBy : UTF8String = ''; const aLimit : UTF8String = '') : UTF8String;
  266. Procedure PopulateFieldsFromFieldDefs(Defs : TFieldDefs; aIndexFields : TStringArray; aProcessIdentifier : TProcessIdentifier; aMinFieldOpts : TRestFieldOptions);
  267. Procedure PopulateParametersFromSQL(const SQL : String; DoClear : Boolean = True);
  268. function DoCompleteWhere(aContext : TBaseRestContext; aKind: TSQLKind; const aWhere: UTF8String ): UTF8String;
  269. Property SQL [aKind : TSQLKind] : TStrings Read GetSQLTyped;
  270. Property BusinessProcessor : TSQLDBRestCustomBusinessProcessor Read FBusinessProcessor;
  271. Published
  272. Property Fields : TSQLDBRestFieldList Read FFields Write SetFields;
  273. Property Parameters : TSQLDBRestParameterList Read FParameters Write SetParameters;
  274. Property Enabled : Boolean Read FEnabled Write FEnabled default true;
  275. Property InMetadata : Boolean Read FInMetadata Write FInMetadata default true;
  276. Property ConnectionName : UTF8String read FConnectionName Write FConnectionName;
  277. Property TableName : UTF8String read FTableName Write FTableName;
  278. Property ResourceName : UTF8String read GetResourceName Write FResourceName;
  279. Property AllowedOperations : TRestOperations Read FAllowedOperations Write SetAllowedOperations;
  280. Property SQLSelect : TStrings Index 0 Read GetSQL Write SetSQL;
  281. Property SQLInsert : TStrings Index 1 Read GetSQL Write SetSQL;
  282. Property SQLUpdate : TStrings Index 2 Read GetSQL Write SetSQL;
  283. Property SQLDelete : TStrings Index 3 Read GetSQL Write SetSQL;
  284. Property OnResourceAllowed : TSQLDBRestAllowResourceEvent Read FOnResourceAllowed Write FOnResourceAllowed;
  285. Property OnAllowedOperations : TSQLDBRestAllowedOperationsEvent Read FOnAllowedOperations Write FOnAllowedOperations;
  286. Property OnGetDataset : TSQLDBRestGetDatasetEvent Read FOnGetDataset Write FOnGetDataset;
  287. Property OnCheckParams : TSQLDBRestCheckParamsEvent Read FOnCheckParams Write FOnCheckParams;
  288. Property OnAllowRecord : TSQLDBRestAllowRecordEvent Read FOnAllowRecord Write FOnAllowRecord;
  289. Property OnGetWhere : TSQLDBRestOnGetWhere Read FOnGetWhere Write FOnGetWhere;
  290. end;
  291. { TSQLDBRestResourceList }
  292. TSQLDBRestResourceList = Class(TOwnedCollection)
  293. private
  294. function GetResource(aIndex : Integer): TSQLDBRestResource;
  295. procedure SetResource(aIndex : Integer; AValue: TSQLDBRestResource);
  296. Public
  297. Function Schema : TSQLDBRestSchema;
  298. Function AddResource(Const aTableName : UTF8String; Const aResourceName : UTF8String) : TSQLDBRestResource;
  299. Function indexOfTableName(Const aTableName : UTF8String) : Integer;
  300. Function indexOfResourceName(Const aResourceName : UTF8String) : Integer;
  301. Function FindResourceByName(Const aResourceName : UTF8String) : TSQLDBRestResource;
  302. Function FindResourceByTableName(Const aTableName : UTF8String) : TSQLDBRestResource;
  303. Procedure SaveToFile(Const aFileName : UTF8String);
  304. Procedure SaveToStream(Const aStream : TStream);
  305. function AsJSON(const aPropName: UTF8String=''): TJSONData;
  306. Procedure LoadFromFile(Const aFileName : UTF8String);
  307. Procedure LoadFromStream(Const aStream : TStream);
  308. Procedure FromJSON(aData: TJSONData;const aPropName: UTF8String='');
  309. Property Resources[aIndex : Integer] : TSQLDBRestResource read GetResource write SetResource; default;
  310. end;
  311. { TSQLDBRestSchema }
  312. TSQLDBRestSchema = Class(TComponent)
  313. private
  314. FConnectionName: UTF8String;
  315. FResources: TSQLDBRestResourceList;
  316. FProcessors : TFPList;
  317. procedure SetResources(AValue: TSQLDBRestResourceList);
  318. Protected
  319. function CreateResourceList: TSQLDBRestResourceList; virtual;
  320. function ProcessIdentifier(const S: UTF8String): UTF8String; virtual;
  321. Function AttachProcessor(aProcessor : TSQLDBRestCustomBusinessProcessor) : Boolean; Virtual;
  322. Function DetachProcessor(aProcessor : TSQLDBRestCustomBusinessProcessor) : Boolean; Virtual;
  323. Procedure AttachAllProcessors; virtual;
  324. Procedure DetachAllProcessors; virtual;
  325. Public
  326. Constructor Create(AOwner: TComponent); override;
  327. Destructor Destroy; override;
  328. Procedure RemoveBusinessProcessor(aProcessor : TSQLDBRestCustomBusinessProcessor);
  329. Procedure AddBusinessProcessor(aProcessor : TSQLDBRestCustomBusinessProcessor);
  330. Procedure SaveToFile(Const aFileName : UTF8String);
  331. Procedure SaveToStream(Const aStream : TStream);
  332. function AsJSON(const aPropName: UTF8String=''): TJSONData;
  333. Procedure LoadFromFile(Const aFileName : UTF8String);
  334. Procedure LoadFromStream(Const aStream : TStream);
  335. Procedure FromJSON(aData: TJSONData;const aPropName: UTF8String='');
  336. Class function GetPrimaryIndexFields(Q: TSQLQuery): TStringArray; virtual;
  337. procedure PopulateResourceFields(aConn: TSQLConnection; aRes: TSQLDBRestResource; aMinFieldOpts : TRestFieldOptions = []); virtual;
  338. procedure PopulateResources(aConn: TSQLConnection; aTables: array of string; aMinFieldOpts: TRestFieldOptions= []);
  339. Procedure PopulateResources(aConn : TSQLConnection; aTables : TStrings = Nil; aMinFieldOpts : TRestFieldOptions = []);
  340. Published
  341. Property Resources : TSQLDBRestResourceList Read FResources Write SetResources;
  342. Property ConnectionName : UTF8String Read FConnectionName Write FConnectionName;
  343. end;
  344. TCustomViewResource = Class(TSQLDBRestResource)
  345. end;
  346. { TSQLDBRestCustomBusinessProcessor }
  347. TSQLDBRestCustomBusinessProcessor = Class(TComponent)
  348. private
  349. FResource: TSQLDBRestResource;
  350. FResourceName: UTF8String;
  351. procedure SetResourceName(AValue: UTF8String);
  352. Protected
  353. Function GetSchema : TSQLDBRestSchema; virtual;
  354. Function GetAllowedOperations(aContext : TBaseRestContext; aDefault : TRestOperations) : TRestOperations; virtual; abstract;
  355. Function AllowResource(aContext : TBaseRestContext) : Boolean; virtual; abstract;
  356. Procedure CheckParams(aContext : TBaseRestContext; aOperation : TRestoperation; P : TParams); virtual; abstract;
  357. Function GetDataset(aContext : TBaseRestContext; aFieldList : TRestFieldPairArray; aOrderBy : TRestFieldOrderPairArray; aLimit, aOffset : Int64) : TDataset; virtual;abstract;
  358. Function AllowRecord(aContext : TBaseRestContext;aDataset : TDataset) : Boolean; virtual; abstract;
  359. Function ProcessWhereSQL(aContext : TBaseRestContext; aKind : TSQLKind; const aWhere : UTF8String) : UTF8String; virtual;
  360. Public
  361. Property Resource : TSQLDBRestResource Read FResource;
  362. Property ResourceName : UTF8String Read FResourceName Write SetResourceName;
  363. end;
  364. { TSQLDBRestBusinessProcessor }
  365. TOnGetHTTPAllow = Procedure(Sender : TObject; Var aHTTPAllow) of object;
  366. TRestDatabaseEvent = Procedure(Sender : TObject; aOperation : TRestOperation; aContext: TBaseRestContext; aResource : TSQLDBRestResource) of object;
  367. TSQLDBRestBusinessProcessor = class(TSQLDBRestCustomBusinessProcessor)
  368. private
  369. FOnAllowedOperations: TSQLDBRestAllowedOperationsEvent;
  370. FOnAllowRecord: TSQLDBRestAllowRecordEvent;
  371. FOnCheckParams: TSQLDBRestCheckParamsEvent;
  372. FOnGetDataset: TSQLDBRestGetDatasetEvent;
  373. FOnGetWhere: TSQLDBRestOnGetWhere;
  374. FOnResourceAllowed: TSQLDBRestAllowResourceEvent;
  375. FSchema: TSQLDBRestSchema;
  376. FAfterDatabaseRead: TRestDatabaseEvent;
  377. FAfterDatabaseUpdate: TRestDatabaseEvent;
  378. FBeforeDatabaseRead: TRestDatabaseEvent;
  379. FBeforeDatabaseUpdate: TRestDatabaseEvent;
  380. procedure SetSchema(AValue: TSQLDBRestSchema);
  381. Protected
  382. Function GetSchema : TSQLDBRestSchema; override;
  383. Function AllowResource(aContext : TBaseRestContext) : Boolean; override;
  384. Function GetAllowedOperations(aContext : TBaseRestContext; aDefault : TRestOperations) : TRestOperations; override;
  385. Procedure CheckParams(aContext : TBaseRestContext; aOperation : TRestoperation; P : TParams); override;
  386. Function GetDataset(aContext : TBaseRestContext; aFieldList : TRestFieldPairArray; aOrderBy : TRestFieldOrderPairArray; aLimit, aOffset : Int64) : TDataset; override;
  387. Function AllowRecord(aContext : TBaseRestContext; aDataset : TDataset) : Boolean; override;
  388. Function ProcessWhereSQL(aContext : TBaseRestContext; aKind : TSQLKind; const aWhere : UTF8String) : UTF8String; override;
  389. Published
  390. Property Schema : TSQLDBRestSchema Read GetSchema Write SetSchema;
  391. Property ResourceName;
  392. Property OnGetDataset : TSQLDBRestGetDatasetEvent Read FOnGetDataset Write FOnGetDataset;
  393. Property OnCheckParams : TSQLDBRestCheckParamsEvent Read FOnCheckParams Write FOnCheckParams;
  394. Property OnAllowResource : TSQLDBRestAllowResourceEvent Read FOnResourceAllowed Write FOnResourceAllowed;
  395. Property OnAllowedOperations : TSQLDBRestAllowedOperationsEvent Read FOnAllowedOperations Write FOnAllowedOperations;
  396. Property OnAllowRecord : TSQLDBRestAllowRecordEvent Read FOnAllowRecord Write FOnAllowRecord;
  397. Property OnGetWhere : TSQLDBRestOnGetWhere Read FOnGetWhere Write FOnGetWhere;
  398. Published
  399. Property BeforeDatabaseUpdate : TRestDatabaseEvent Read FBeforeDatabaseUpdate Write FBeforeDatabaseUpdate;
  400. Property AfterDatabaseUpdate : TRestDatabaseEvent Read FAfterDatabaseUpdate Write FAfterDatabaseUpdate;
  401. Property BeforeDatabaseRead: TRestDatabaseEvent Read FBeforeDatabaseRead Write FBeforeDatabaseRead;
  402. Property AfterDatabaseRead : TRestDatabaseEvent Read FAfterDatabaseRead Write FAfterDatabaseRead;
  403. end;
  404. Const
  405. TypeNames : Array[TRestFieldType] of string = ('?','int','bigint','float','date','time','datetime','string','bool','blob');
  406. RestMethods : Array[TRestOperation] of string = ('','GET','POST','PUT','DELETE','OPTIONS','HEAD','PATCH');
  407. implementation
  408. {$IFDEF FPC_DOTTEDUNITS}
  409. uses System.StrUtils, FpJson.Rtti,Data.Consts, FpWeb.RestBridge.Consts;
  410. {$ELSE FPC_DOTTEDUNITS}
  411. uses strutils, fpjsonrtti,dbconst, sqldbrestconst;
  412. {$ENDIF FPC_DOTTEDUNITS}
  413. { TSQLDBRestParam }
  414. function TSQLDBRestParam.GetDisplayName: string;
  415. begin
  416. Result:=Name;
  417. if Result='' then
  418. Result:=inherited GetDisplayName;
  419. end;
  420. procedure TSQLDBRestParam.Assign(Source: TPersistent);
  421. var
  422. P : TSQLDBRestParam absolute Source;
  423. begin
  424. if Source is TSQLDBRestParam then
  425. begin
  426. FName:=P.Name;
  427. FDataType:=P.DataType;
  428. FDefault:=P.DefaultValue;
  429. end
  430. else
  431. inherited Assign(Source);
  432. end;
  433. { TSQLDBRestParamListEnumerator }
  434. function TSQLDBRestParamListEnumerator.GetCurrent: TSQLDBRestParam;
  435. begin
  436. Result:=TSQLDBRestParam(Inherited GetCurrent);
  437. end;
  438. { TSQLDBRestParameterList }
  439. function TSQLDBRestParameterList.GetParam(aIndex : Integer): TSQLDBRestParam;
  440. begin
  441. Result:=Items[aIndex] as TSQLDBRestParam;
  442. end;
  443. procedure TSQLDBRestParameterList.SetParam(aIndex : Integer; AValue: TSQLDBRestParam);
  444. begin
  445. Items[aIndex]:=aValue;
  446. end;
  447. function TSQLDBRestParameterList.GetEnumerator: TSQLDBRestParamListEnumerator;
  448. begin
  449. Result:=TSQLDBRestParamListEnumerator.Create(Self);
  450. end;
  451. function TSQLDBRestParameterList.IndexOf(const aName: string): Integer;
  452. begin
  453. Result:=Count-1;
  454. While (Result>=0) and Not SameText(aName,GetParam(Result).Name) do
  455. Dec(Result);
  456. end;
  457. function TSQLDBRestParameterList.Find(const aName: string): TSQLDBRestParam;
  458. var
  459. Idx : Integer;
  460. begin
  461. Result:=Nil;
  462. Idx:=IndexOf(aName);
  463. if (Idx<>-1) then
  464. Result:=GetParam(Idx);
  465. end;
  466. function TSQLDBRestParameterList.ParamByName(const aName: string): TSQLDBRestParam;
  467. begin
  468. Result:=Find(aName);
  469. if Result=Nil then
  470. Raise ESQLDBRest.CreateFmt(500,SErrUnknownParam,[aName]);
  471. end;
  472. function TSQLDBRestParameterList.AddParam(const aName: string): TSQLDBRestParam;
  473. begin
  474. if IndexOf(aName)<>-1 then
  475. Raise ESQLDBRest.CreateFmt(500,SErrDuplicateParam,[aName]);
  476. Result:=Add as TSQLDBRestParam;
  477. Result.Name:=aName;
  478. Result.DataType:=ftString;
  479. end;
  480. { TSQLDBRestFieldListEnumerator }
  481. function TSQLDBRestFieldListEnumerator.GetCurrent: TSQLDBRestField;
  482. begin
  483. Result:=TSQLDBRestField(Inherited GetCurrent);
  484. end;
  485. { TSQLDBRestFieldArrayHelper }
  486. function TSQLDBRestFieldArrayHelper.IndexOf(aField: TSQLDBRestField): Integer;
  487. begin
  488. Result:=Length(Self)-1;
  489. While (Result>=0) and (Self[Result]<>aField) do
  490. Dec(Result);
  491. end;
  492. function TSQLDBRestFieldArrayHelper.Has(aField: TSQLDBRestField): Boolean;
  493. begin
  494. Result:=IndexOf(aField)<>-1;
  495. end;
  496. { TBaseRestContext }
  497. destructor TBaseRestContext.Destroy;
  498. begin
  499. FreeAndNil(FFreeList);
  500. inherited Destroy;
  501. end;
  502. procedure TBaseRestContext.AddToFreeList(aData: TJSONData);
  503. begin
  504. If Not Assigned(FFreeList) then
  505. FFreeList:=TFPObjectList.Create(True);
  506. FFreeList.Add(aData)
  507. end;
  508. function TBaseRestContext.GetInputData(aName: UTF8string): TJSONData;
  509. begin
  510. Result:=DoGetInputData(aName);
  511. // Don't burden the user with freeing this.
  512. if Assigned(Result) then
  513. AddToFreeList(Result);
  514. end;
  515. procedure TBaseRestContext.SetInputData(aName: UTF8string; aValue: TJSONData);
  516. begin
  517. DoSetInputData(aName,aValue);
  518. end;
  519. { TSQLDBRestCustomBusinessProcessor }
  520. procedure TSQLDBRestCustomBusinessProcessor.SetResourceName(AValue: UTF8String);
  521. Var
  522. S : TSQLDBRestSchema;
  523. begin
  524. if FResourceName=AValue then Exit;
  525. // Reregister, so the attachment happens to the correct resource
  526. S:=GetSchema;
  527. If (FResourceName<>'') and Assigned(S) then
  528. S.RemoveBusinessProcessor(Self);
  529. FResourceName:=AValue;
  530. S:=GetSchema;
  531. If (FResourceName<>'') and Assigned(S) then
  532. S.AddBusinessProcessor(Self);
  533. end;
  534. function TSQLDBRestCustomBusinessProcessor.GetSchema: TSQLDBRestSchema;
  535. begin
  536. Result:=Nil;
  537. end;
  538. function TSQLDBRestCustomBusinessProcessor.ProcessWhereSQL(aContext : TBaseRestContext; aKind : TSQLKind; const aWhere: UTF8String
  539. ): UTF8String;
  540. begin
  541. Result:=aWhere;
  542. // Silence compiler
  543. if aKind<>skSelect then
  544. ;
  545. end;
  546. { TSQLDBRestBusinessProcessor }
  547. procedure TSQLDBRestBusinessProcessor.SetSchema(AValue: TSQLDBRestSchema);
  548. begin
  549. if FSchema=AValue then Exit;
  550. if Assigned(FSchema) and (ResourceName<>'') then
  551. begin
  552. FSchema.RemoveBusinessProcessor(Self);
  553. FSchema.RemoveFreeNotification(Self);
  554. end;
  555. FSchema:=AValue;
  556. if Assigned(FSchema) and (ResourceName<>'') then
  557. begin
  558. FSchema.AddBusinessProcessor(Self);
  559. FSchema.FreeNotification(Self);
  560. end
  561. end;
  562. function TSQLDBRestBusinessProcessor.GetSchema: TSQLDBRestSchema;
  563. begin
  564. Result:=FSchema;
  565. end;
  566. function TSQLDBRestBusinessProcessor.AllowResource(aContext: TBaseRestContext
  567. ): Boolean;
  568. begin
  569. Result:=True;
  570. if Assigned(FOnResourceAllowed) then
  571. FOnResourceAllowed(Self,aContext,Result);
  572. end;
  573. function TSQLDBRestBusinessProcessor.GetAllowedOperations(
  574. aContext: TBaseRestContext; aDefault: TRestOperations): TRestOperations;
  575. begin
  576. Result:=aDefault;
  577. if Assigned(FOnAllowedOperations) then
  578. FOnAllowedOperations(Self,aContext,Result);
  579. end;
  580. procedure TSQLDBRestBusinessProcessor.CheckParams(aContext: TBaseRestContext;
  581. aOperation: TRestoperation; P: TParams);
  582. begin
  583. if Assigned(FOnCheckParams) then
  584. FOnCheckParams(Self,aContext,aOperation,P);
  585. end;
  586. function TSQLDBRestBusinessProcessor.GetDataset(aContext : TBaseRestContext;
  587. aFieldList: TRestFieldPairArray; aOrderBy: TRestFieldOrderPairArray; aLimit,
  588. aOffset: Int64): TDataset;
  589. begin
  590. Result:=nil;
  591. if Assigned(FOnGetDataset) then
  592. FOnGetDataset(Self,aContext,aFieldList,aOrderBy,aLimit,aOffset,Result);
  593. end;
  594. function TSQLDBRestBusinessProcessor.AllowRecord(aContext : TBaseRestContext; aDataset: TDataset): Boolean;
  595. begin
  596. Result:=True;
  597. if Assigned(FOnAllowRecord) then
  598. FOnAllowRecord(Self,acontext,aDataset,Result);
  599. end;
  600. function TSQLDBRestBusinessProcessor.ProcessWhereSQL(aContext : TBaseRestContext; aKind: TSQLKind;
  601. const aWhere: UTF8String): UTF8String;
  602. begin
  603. Result:=inherited ProcessWhereSQL(aContext, aKind, aWhere);
  604. if Assigned(FOnGetWhere) then
  605. FOnGetWhere(Self,aContext,aKind,Result);
  606. end;
  607. { ESQLDBRest }
  608. constructor ESQLDBRest.Create(aCode: Integer; const aMessage: String);
  609. begin
  610. FResponseCode:=aCode;
  611. HelpContext:=aCode;
  612. Inherited create(aMessage);
  613. end;
  614. constructor ESQLDBRest.CreateFmt(aCode: Integer; const Fmt: String;
  615. const Args: array of const);
  616. begin
  617. FResponseCode:=aCode;
  618. HelpContext:=aCode;
  619. Inherited CreateFmt(Fmt,Args);
  620. end;
  621. { TSQLDBRestSchema }
  622. procedure TSQLDBRestSchema.SetResources(AValue: TSQLDBRestResourceList);
  623. begin
  624. if FResources=AValue then Exit;
  625. FResources.Assign(AValue);
  626. end;
  627. constructor TSQLDBRestSchema.Create(AOwner: TComponent);
  628. begin
  629. inherited Create(AOwner);
  630. FResources:=CreateResourceList;
  631. FProcessors:=TFPList.Create;
  632. end;
  633. function TSQLDBRestSchema.CreateResourceList: TSQLDBRestResourceList;
  634. begin
  635. Result:=TSQLDBRestResourceList.Create(Self,TSQLDBRestResource);
  636. end;
  637. destructor TSQLDBRestSchema.Destroy;
  638. begin
  639. FreeAndNil(FProcessors);
  640. FreeAndNil(FResources);
  641. inherited Destroy;
  642. end;
  643. procedure TSQLDBRestSchema.RemoveBusinessProcessor(
  644. aProcessor: TSQLDBRestCustomBusinessProcessor);
  645. begin
  646. DetachProcessor(aProcessor);
  647. FProcessors.Remove(aProcessor);
  648. end;
  649. procedure TSQLDBRestSchema.AddBusinessProcessor(
  650. aProcessor: TSQLDBRestCustomBusinessProcessor);
  651. begin
  652. FProcessors.Remove(aProcessor);
  653. AttachProcessor(aProcessor);
  654. end;
  655. procedure TSQLDBRestSchema.SaveToFile(const aFileName: UTF8String);
  656. Var
  657. F : TFileStream;
  658. begin
  659. F:=TFileStream.Create(aFileName,fmCreate);
  660. try
  661. SaveToStream(F);
  662. finally
  663. F.Free;
  664. end;
  665. end;
  666. procedure TSQLDBRestSchema.SaveToStream(const aStream: TStream);
  667. Var
  668. D : TJSONData;
  669. S : TJSONStringType;
  670. begin
  671. D:=asJSON(JSONSchemaRoot);
  672. try
  673. S:=D.FormatJSON();
  674. finally
  675. D.Free;
  676. end;
  677. aStream.WriteBuffer(S[1],Length(S)*SizeOf(TJSONCharType));
  678. end;
  679. function TSQLDBRestSchema.AsJSON(const aPropName: UTF8String): TJSONData;
  680. begin
  681. Result:=TJSONObject.Create([JSONResourcesRoot,Resources.AsJSON(),JSONConnectionName,ConnectionName]);
  682. if (aPropName<>'') then
  683. Result:=TJSONObject.Create([aPropName,Result]);
  684. end;
  685. procedure TSQLDBRestSchema.LoadFromFile(const aFileName: UTF8String);
  686. Var
  687. F : TFileStream;
  688. begin
  689. F:=TFileStream.Create(aFileName,fmOpenRead or fmShareDenyWrite);
  690. try
  691. LoadFromStream(F);
  692. finally
  693. F.Free;
  694. end;
  695. end;
  696. procedure TSQLDBRestSchema.LoadFromStream(const aStream: TStream);
  697. Var
  698. D : TJSONData;
  699. begin
  700. D:=GetJSON(aStream);
  701. try
  702. FromJSON(D,JSONSchemaRoot);
  703. finally
  704. D.Free;
  705. end;
  706. end;
  707. procedure TSQLDBRestSchema.FromJSON(aData: TJSONData; const aPropName: UTF8String);
  708. Var
  709. J : TJSONObject;
  710. begin
  711. J:=aData as TJSONObject;
  712. if (aPropName<>'') then
  713. J:=J.Objects[aPropName];
  714. Resources.FromJSON(J,JSONResourcesRoot);
  715. ConnectionName:=J.Get(JSONConnectionName,'');
  716. AttachAllProcessors;
  717. end;
  718. function TSQLDBRestSchema.ProcessIdentifier(const S: UTF8String): UTF8String;
  719. begin
  720. Result:=S;
  721. end;
  722. function TSQLDBRestSchema.AttachProcessor(aProcessor: TSQLDBRestCustomBusinessProcessor): Boolean;
  723. Var
  724. Res : TSQLDBRestResource;
  725. begin
  726. if aProcessor.ResourceName='' then
  727. exit;
  728. Res:=FResources.FindResourceByName(aProcessor.ResourceName);
  729. Result:=Assigned(Res);
  730. if Result then
  731. begin
  732. Res.FBusinessProcessor:=aProcessor;
  733. aProcessor.FResource:=Res;
  734. end;
  735. end;
  736. function TSQLDBRestSchema.DetachProcessor(aProcessor: TSQLDBRestCustomBusinessProcessor): Boolean;
  737. Var
  738. Res : TSQLDBRestResource;
  739. begin
  740. if aProcessor.ResourceName='' then
  741. exit;
  742. Res:=FResources.FindResourceByName(aProcessor.ResourceName);
  743. Result:=Assigned(Res);
  744. if Result then
  745. begin
  746. Res.FBusinessProcessor:=Nil;
  747. aProcessor.FResource:=Nil;
  748. end;
  749. end;
  750. procedure TSQLDBRestSchema.AttachAllProcessors;
  751. Var
  752. I : integer;
  753. begin
  754. For I:=0 to FProcessors.Count-1 do
  755. AttachProcessor(TSQLDBRestCustomBusinessProcessor(FProcessors[i]));
  756. end;
  757. procedure TSQLDBRestSchema.DetachAllProcessors;
  758. Var
  759. I : integer;
  760. begin
  761. For I:=0 to FProcessors.Count-1 do
  762. DetachProcessor(TSQLDBRestCustomBusinessProcessor(FProcessors[i]));
  763. end;
  764. class function TSQLDBRestSchema.GetPrimaryIndexFields(Q: TSQLQuery): TStringArray;
  765. Var
  766. C,I : Integer;
  767. Fields : UTF8String;
  768. begin
  769. Result:=Default(TStringArray);
  770. Q.ServerIndexDefs.Update;
  771. I:=0;
  772. Fields:='';
  773. With Q.ServerIndexDefs do
  774. While (Fields='') and (i<Count) do
  775. begin
  776. if (ixPrimary in Items[i].Options) then
  777. Fields:=Items[i].Fields;
  778. Inc(I);
  779. end;
  780. C:=WordCount(Fields,[';',' ']);
  781. SetLength(Result,C);
  782. For I:=1 to C do
  783. Result[I-1]:=ExtractWord(I,Fields,[';',' ']);
  784. end;
  785. procedure TSQLDBRestSchema.PopulateResourceFields(aConn : TSQLConnection; aRes : TSQLDBRestResource; aMinFieldOpts : TRestFieldOptions = []);
  786. Var
  787. Q : TRestSQLQuery;
  788. IndexFields : TStringArray;
  789. begin
  790. IndexFields:=Default(TStringArray);
  791. Q:=TRestSQLQuery.Create(Self);
  792. try
  793. Q.Database:=aConn;
  794. Q.ParseSQL:=True; // we want the table name
  795. if (aRes.SQLSelect.Count=0) then
  796. Q.SQL.Text:='SELECT * FROM '+aRes.TableName+' WHERE (1=0)' // Not very efficient :(
  797. else
  798. Q.SQL.Text:=aRes.GetResolvedSQL(skSelect,'(1=0)','');
  799. Q.TableName:=aRes.TableName;
  800. Q.UniDirectional:=True;
  801. Q.UsePrimaryKeyAsKey:=False;
  802. Q.Open;
  803. if (Q.TableName<>'') then
  804. IndexFields:=GetPrimaryIndexFields(Q);
  805. aRes.PopulateFieldsFromFieldDefs(Q.FieldDefs,IndexFields,@ProcessIdentifier,aMinFieldOpts)
  806. finally
  807. Q.Free;
  808. end;
  809. end;
  810. procedure TSQLDBRestSchema.PopulateResources(aConn: TSQLConnection;
  811. aTables: array of string; aMinFieldOpts: TRestFieldOptions);
  812. Var
  813. L : TStringList;
  814. S : String;
  815. begin
  816. L:=TStringList.Create;
  817. try
  818. L.Capacity:=Length(aTables);
  819. For S in aTables do
  820. L.Add(S);
  821. L.Sorted:=True;
  822. PopulateResources(aConn,L,aMinFieldOpts);
  823. finally
  824. l.Free;
  825. end;
  826. end;
  827. procedure TSQLDBRestSchema.PopulateResources(aConn: TSQLConnection; aTables : TStrings = Nil; aMinFieldOpts : TRestFieldOptions = []);
  828. Var
  829. L : TStrings;
  830. S,N : UTF8String;
  831. R : TSQLDBRestResource;
  832. begin
  833. L:=TStringList.Create;
  834. try
  835. aConn.Connected:=True;
  836. aConn.GetTableNames(L);
  837. For S in L do
  838. begin
  839. N:=ProcessIdentifier(S);
  840. if SameStr(N,S) then // No SameText, Allow to change case
  841. N:='';
  842. if (aTables=Nil) or (aTables.IndexOf(S)=-1) then
  843. begin
  844. R:=Resources.AddResource(S,N);
  845. PopulateResourceFields(aConn,R,aMinFieldOpts);
  846. end;
  847. end;
  848. finally
  849. L.Free;
  850. end;
  851. end;
  852. { TSQLDBRestResourceList }
  853. function TSQLDBRestResourceList.GetResource(aIndex : Integer): TSQLDBRestResource;
  854. begin
  855. Result:=TSQLDBRestResource(Items[aIndex])
  856. end;
  857. procedure TSQLDBRestResourceList.SetResource(aIndex : Integer; AValue: TSQLDBRestResource);
  858. begin
  859. Items[aIndex]:=aValue;
  860. end;
  861. function TSQLDBRestResourceList.Schema: TSQLDBRestSchema;
  862. begin
  863. If (Owner is TSQLDBRestSchema) then
  864. Result:=Owner as TSQLDBRestSchema
  865. else
  866. Result:=Nil;
  867. end;
  868. function TSQLDBRestResourceList.AddResource(const aTableName: UTF8String; const aResourceName: UTF8String): TSQLDBRestResource;
  869. Var
  870. N : UTF8String;
  871. begin
  872. N:=aResourceName;
  873. if N='' then
  874. N:=aTableName;
  875. if (N='') then
  876. Raise ESQLDBRest.Create(500,SErrResourceNameEmpty);
  877. if indexOfResourceName(N)<>-1 then
  878. Raise ESQLDBRest.CreateFmt(500,SErrDuplicateResource,[N]);
  879. Result:=add as TSQLDBRestResource;
  880. Result.TableName:=aTableName;
  881. Result.ResourceName:=aResourceName;
  882. end;
  883. function TSQLDBRestResourceList.indexOfTableName(const aTableName: UTF8String): Integer;
  884. begin
  885. Result:=Count-1;
  886. While (Result>=0) and not SameText(aTableName,GetResource(Result).TableName) do
  887. Dec(Result);
  888. end;
  889. function TSQLDBRestResourceList.indexOfResourceName(const aResourceName: UTF8String): Integer;
  890. begin
  891. Result:=Count-1;
  892. While (Result>=0) and not SameText(aResourceName,GetResource(Result).ResourceName) do
  893. Dec(Result);
  894. end;
  895. function TSQLDBRestResourceList.FindResourceByName(const aResourceName: UTF8String): TSQLDBRestResource;
  896. Var
  897. Idx : Integer;
  898. begin
  899. idx:=indexOfResourceName(aResourceName);
  900. if Idx=-1 then
  901. Result:=nil
  902. else
  903. Result:=GetResource(Idx);
  904. end;
  905. function TSQLDBRestResourceList.FindResourceByTableName(const aTableName: UTF8String): TSQLDBRestResource;
  906. Var
  907. Idx : Integer;
  908. begin
  909. idx:=indexOfTableName(aTableName);
  910. if Idx=-1 then
  911. Result:=nil
  912. else
  913. Result:=GetResource(Idx);
  914. end;
  915. procedure TSQLDBRestResourceList.SaveToFile(const aFileName: UTF8String);
  916. Var
  917. F : TFileStream;
  918. begin
  919. F:=TFileStream.Create(aFileName,fmCreate);
  920. try
  921. SaveToStream(F);
  922. finally
  923. F.Free;
  924. end;
  925. end;
  926. procedure TSQLDBRestResourceList.SaveToStream(const aStream: TStream);
  927. Var
  928. D : TJSONData;
  929. S : TJSONStringType;
  930. begin
  931. D:=asJSON(JSONResourcesRoot);
  932. try
  933. S:=D.FormatJSON();
  934. finally
  935. D.Free;
  936. end;
  937. aStream.WriteBuffer(S[1],Length(S)*SizeOf(TJSONCharType));
  938. end;
  939. function TSQLDBRestResourceList.AsJSON(const aPropName: UTF8String = ''): TJSONData;
  940. Var
  941. S : TJSONStreamer;
  942. A : TJSONArray;
  943. begin
  944. S:=TJSONStreamer.Create(Nil);
  945. try
  946. A:=S.StreamCollection(Self);
  947. finally
  948. S.Free;
  949. end;
  950. if aPropName='' then
  951. Result:=A
  952. else
  953. Result:=TJSONObject.Create([aPropName,A]);
  954. end;
  955. procedure TSQLDBRestResourceList.LoadFromFile(const aFileName: UTF8String);
  956. Var
  957. F : TFileStream;
  958. begin
  959. F:=TFileStream.Create(aFileName,fmOpenRead or fmShareDenyWrite);
  960. try
  961. LoadFromStream(F);
  962. finally
  963. F.Free;
  964. end;
  965. end;
  966. procedure TSQLDBRestResourceList.LoadFromStream(const aStream: TStream);
  967. Var
  968. D : TJSONData;
  969. begin
  970. D:=GetJSON(aStream);
  971. try
  972. FromJSON(D,JSONResourcesRoot);
  973. finally
  974. D.Free;
  975. end;
  976. end;
  977. procedure TSQLDBRestResourceList.FromJSON(aData: TJSONData; const aPropName: UTF8String);
  978. Var
  979. A : TJSONArray;
  980. D : TJSONDestreamer;
  981. begin
  982. if (aPropName<>'') then
  983. A:=(aData as TJSONObject).Arrays[aPropName]
  984. else
  985. A:=aData as TJSONArray;
  986. D:=TJSONDestreamer.Create(Nil);
  987. try
  988. Clear;
  989. D.JSONToCollection(A,Self);
  990. finally
  991. D.Free;
  992. end;
  993. end;
  994. { TSQLDBRestResource }
  995. function TSQLDBRestResource.GetResourceName: UTF8String;
  996. begin
  997. Result:=FResourceName;
  998. if Result='' then
  999. Result:=FTableName;
  1000. end;
  1001. function TSQLDBRestResource.GetSQL(AIndex: Integer): TStrings;
  1002. begin
  1003. Result:=FSQL[TSQLKind(aIndex)];
  1004. end;
  1005. function TSQLDBRestResource.GetSQLTyped(aKind : TSQLKind): TStrings;
  1006. begin
  1007. Result:=FSQL[aKind];
  1008. end;
  1009. procedure TSQLDBRestResource.SetAllowedOperations(AValue: TRestOperations);
  1010. begin
  1011. if FAllowedOperations=AValue then Exit;
  1012. FAllowedOperations:=AValue;
  1013. end;
  1014. procedure TSQLDBRestResource.SetFields(AValue: TSQLDBRestFieldList);
  1015. begin
  1016. if FFields=AValue then Exit;
  1017. FFields.Assign(AValue);
  1018. end;
  1019. procedure TSQLDBRestResource.SetParameters(AValue: TSQLDBRestParameterList);
  1020. begin
  1021. if FParameters=AValue then Exit;
  1022. FParameters.Assign(AValue);
  1023. end;
  1024. procedure TSQLDBRestResource.SetSQL(AIndex: Integer; AValue: TStrings);
  1025. begin
  1026. FSQL[TSQLKind(aIndex)].Assign(aValue);
  1027. end;
  1028. function TSQLDBRestResource.GetDisplayName: string;
  1029. begin
  1030. Result:=ResourceName;
  1031. end;
  1032. constructor TSQLDBRestResource.Create(ACollection: TCollection);
  1033. Var
  1034. K : TSQLKind;
  1035. begin
  1036. inherited Create(ACollection);
  1037. FFields:=CreateFieldList;
  1038. FParameters:=CreateParamList;
  1039. FEnabled:=True;
  1040. FInMetadata:=True;
  1041. for K in TSQLKind do
  1042. FSQL[K]:=TStringList.Create;
  1043. FAllowedOperations:=AllRestOperations;
  1044. end;
  1045. destructor TSQLDBRestResource.Destroy;
  1046. Var
  1047. K : TSQLKind;
  1048. begin
  1049. If Assigned(FBusinessProcessor) then
  1050. FBusinessProcessor.FResource:=Nil;
  1051. FreeAndNil(FFields);
  1052. for K in TSQLKind do
  1053. FreeAndNil(FSQL[K]);
  1054. inherited Destroy;
  1055. end;
  1056. procedure TSQLDBRestResource.CheckParams(aContext : TBaseRestContext; aOperation: TRestoperation; P: TParams);
  1057. begin
  1058. if Assigned(FOnCheckParams) then
  1059. FOnCheckParams(Self,aContext,aOperation,P)
  1060. else if Assigned(FBusinessProcessor) then
  1061. FBusinessProcessor.CheckParams(aContext,aOperation,P)
  1062. end;
  1063. function TSQLDBRestResource.GetDataset(aContext : TBaseRestContext; aFieldList: TRestFieldPairArray; aOrderBy: TRestFieldOrderPairArray; aLimit, aOffset: Int64): TDataset;
  1064. begin
  1065. Result:=Nil;
  1066. If Assigned(FOnGetDataset) then
  1067. FOnGetDataset(Self,aContext,aFieldList,aOrderBy,aLimit,aOffset,Result)
  1068. else if Assigned(FBusinessProcessor) then
  1069. Result:=FBusinessProcessor.GetDataset(aContext,aFieldList,aOrderBy,aLimit,aOffset);
  1070. end;
  1071. function TSQLDBRestResource.GetSchema: TSQLDBRestSchema;
  1072. begin
  1073. If Assigned(Collection) and (Collection is TSQLDBRestResourceList) then
  1074. Result:=TSQLDBRestResourceList(Collection).Schema
  1075. else
  1076. Result:=Nil;
  1077. end;
  1078. procedure TSQLDBRestResource.Assign(Source: TPersistent);
  1079. Var
  1080. R : TSQLDBRestResource;
  1081. K : TSQLKind;
  1082. begin
  1083. if (Source is TSQLDBRestResource) then
  1084. begin
  1085. R:=Source as TSQLDBRestResource;
  1086. for K in TSQLKind do
  1087. SQL[K].Assign(R.SQL[K]);
  1088. Fields.Assign(R.Fields);
  1089. Parameters.Assign(R.Parameters);
  1090. TableName:=R.TableName;
  1091. FResourceName:=R.FResourceName;
  1092. ConnectionName:=R.ConnectionName;
  1093. Enabled:=R.Enabled;
  1094. InMetadata:=R.InMetadata;
  1095. FAllowedOperations:=R.AllowedOperations;
  1096. OnResourceAllowed:=R.OnResourceAllowed;
  1097. OnAllowedOperations:=R.OnAllowedOperations;
  1098. OnGetDataset:=R.OnGetDataset;
  1099. OnCheckParams:=R.OnCheckParams;
  1100. OnAllowRecord:=R.OnAllowRecord;
  1101. end
  1102. else
  1103. inherited Assign(Source);
  1104. end;
  1105. function TSQLDBRestResource.AllowRecord(aContext : TBaseRestContext; aDataset: TDataset): Boolean;
  1106. begin
  1107. Result:=True;
  1108. if Assigned(FOnAllowRecord) then
  1109. FOnAllowRecord(Self,aContext,aDataset,Result)
  1110. else if Assigned(FBusinessProcessor) then
  1111. Result:=FBusinessProcessor.AllowRecord(aContext,aDataset);
  1112. end;
  1113. function TSQLDBRestResource.AllowResource(aContext : TBaseRestContext): Boolean;
  1114. begin
  1115. Result:=True;
  1116. If Assigned(FOnResourceAllowed) then
  1117. FOnResourceAllowed(Self,aContext,Result)
  1118. else If Assigned(FBusinessProcessor) then
  1119. Result:=FBusinessProcessor.AllowResource(aContext);
  1120. end;
  1121. function TSQLDBRestResource.GetAllowedOperations(aContext: TBaseRestContext
  1122. ): TRestOperations;
  1123. begin
  1124. Result:=AllowedOperations;
  1125. if Assigned(FOnAllowedOperations) then
  1126. FOnAllowedOperations(Self,aContext,Result)
  1127. else if Assigned(FBusinessProcessor) then
  1128. Result:=FBusinessProcessor.GetAllowedOperations(aContext,Result);
  1129. end;
  1130. function TSQLDBRestResource.GetHTTPAllow: String;
  1131. Procedure AddR(const s : String);
  1132. begin
  1133. if (Result<>'') then
  1134. Result:=Result+', ';
  1135. Result:=Result+S;
  1136. end;
  1137. Var
  1138. O : TRestOperation;
  1139. begin
  1140. Result:='';
  1141. For O in TRestOperation do
  1142. if (O<>roUnknown) and (O in AllowedOperations) then
  1143. AddR(RestMethods[O]);
  1144. end;
  1145. function TSQLDBRestResource.GetFieldList(aListKind: TFieldListKind;
  1146. const ASep: String; OnlyFields: TSQLDBRestFieldArray): UTF8String;
  1147. Const
  1148. SepComma = ', ';
  1149. SepAND = ' AND ';
  1150. SepSpace = ' ';
  1151. Const
  1152. DefaultSeps : Array[TFieldListKind] of string = (sepComma,sepComma,sepComma,sepComma,sepAnd,sepSpace,sepComma);
  1153. Const
  1154. Wheres = [flWhereKey];
  1155. Colons = Wheres + [flInsertParams,flUpdate];
  1156. UseEqual = Wheres+[flUpdate];
  1157. Function AllowField (F :TSQLDBRestField) : Boolean; inline;
  1158. begin
  1159. Result:=F.UseInFieldList(aListKind) and ((Length(OnlyFields)=0) or (OnlyFields.Has(F)));
  1160. end;
  1161. Var
  1162. Sep,Term,Res,Prefix : UTF8String;
  1163. I : Integer;
  1164. F : TSQLDBRestField;
  1165. begin
  1166. Prefix:='';
  1167. Sep:=aSep;
  1168. if Sep='' then
  1169. begin
  1170. Sep:=DefaultSeps[aListKind];
  1171. If aListKind in Colons then
  1172. Prefix:=':';
  1173. end;
  1174. Res:='';
  1175. For I:=0 to Fields.Count-1 do
  1176. begin
  1177. Term:='';
  1178. F:=Fields[i];
  1179. if allowfield(F) then
  1180. begin
  1181. Term:=Prefix+F.FieldName;
  1182. if (aSep='') and (aListKind in UseEqual) then
  1183. begin
  1184. Term := F.FieldName+' = '+Term;
  1185. if (aListKind in Wheres) then
  1186. Term:='('+Term+')';
  1187. end;
  1188. end;
  1189. if (Term<>'') then
  1190. begin
  1191. If (Res<>'') then
  1192. Res:=Res+Sep;
  1193. Res:=Res+Term;
  1194. end;
  1195. end;
  1196. Result:=Res;
  1197. end;
  1198. function TSQLDBRestResource.GetFieldArray(aListKind: TFieldListKind
  1199. ): TSQLDBRestFieldArray;
  1200. Var
  1201. I,aCount : Integer;
  1202. F : TSQLDBRestField;
  1203. begin
  1204. Result:=Default(TSQLDBRestFieldArray);
  1205. aCount:=0;
  1206. SetLength(Result,Fields.Count);
  1207. For I:=0 to Fields.Count-1 do
  1208. begin
  1209. F:=Fields[i];
  1210. if F.UseInFieldList(aListKind) then
  1211. begin
  1212. Result[aCount]:=F;
  1213. Inc(aCount);
  1214. end;
  1215. end;
  1216. SetLength(Result,aCount);
  1217. end;
  1218. function TSQLDBRestResource.GenerateDefaultSQL(aKind: TSQLKind; OnlyFields : TSQLDBRestFieldArray = nil) : UTF8String;
  1219. begin
  1220. Case aKind of
  1221. skSelect :
  1222. Result:='SELECT '+GetFieldList(flSelect,'',OnlyFields)+' FROM '+TableName+' %FULLWHERE% %FULLORDERBY% %LIMIT%';
  1223. skInsert :
  1224. Result:='INSERT INTO '+TableName+' ('+GetFieldList(flInsert,'',OnlyFields)+') VALUES ('+GetFieldList(flInsertParams)+')';
  1225. skUpdate :
  1226. Result:='UPDATE '+TableName+' SET '+GetFieldList(flUpdate,'',OnlyFields)+' %FULLWHERE%';
  1227. skDelete :
  1228. Result:='DELETE FROM '+TableName+' %FULLWHERE%';
  1229. else
  1230. Raise ESQLDBRest.CreateFmt(500,SErrUnknownStatement,[Ord(aKind)]);
  1231. end;
  1232. end;
  1233. function TSQLDBRestResource.GetResolvedSQl(aKind: TSQLKind;
  1234. const AWhere: UTF8String; const aOrderBy: UTF8String; const aLimit: UTF8String;
  1235. OnlyFields: TSQLDBRestFieldArray): UTF8String;
  1236. begin
  1237. Result:=SQL[aKind].Text;
  1238. if (Result='') then
  1239. Result:=GenerateDefaultSQL(aKind,OnlyFields);
  1240. Result:=ProcessSQL(Result,aWhere,aOrderBy,aLimit);
  1241. end;
  1242. function TSQLDBRestResource.DoCompleteWhere(aContext : TBaseRestContext; aKind: TSQLKind;const aWhere : UTF8String) : UTF8String;
  1243. begin
  1244. Result:=aWhere;
  1245. if Assigned(OnGetWhere) then
  1246. FOnGetWhere(Self,aContext, aKind,Result);
  1247. if Assigned(BusinessProcessor) then
  1248. Result:=BusinessProcessor.ProcessWhereSQL(aContext, aKind, Result);
  1249. end;
  1250. function TSQLDBRestResource.ProcessSQl(const aSQL: String; const AWhere: UTF8String;
  1251. const aOrderBy: UTF8String; const aLimit: UTF8String): UTF8String;
  1252. Var
  1253. S : UTF8String;
  1254. begin
  1255. Result:=aSQL;
  1256. // from tables %FULLWHERE%
  1257. if (aWhere<>'') then
  1258. S:='WHERE '+aWhere
  1259. else
  1260. S:='';
  1261. Result:=StringReplace(Result,'%FULLWHERE%',S,[rfReplaceAll]);
  1262. // from tables WHERE %REQUIREDWHERE%
  1263. if (aWhere<>'') then
  1264. S:=aWhere
  1265. else
  1266. S:='(1=0)';
  1267. Result:=StringReplace(Result,'%REQUIREDWHERE%',S,[rfReplaceAll]);
  1268. // from tables WHERE X=Y %OPTIONALWHERE%
  1269. if (aWhere<>'') then
  1270. S:='AND ('+aWhere+')'
  1271. else
  1272. S:='';
  1273. Result:=StringReplace(Result,'%OPTIONALWHERE%',S,[rfReplaceAll]);
  1274. // from tables WHERE X=Y AND %WHERE%
  1275. if (aWhere<>'') then
  1276. S:='('+aWhere+')'
  1277. else
  1278. S:='';
  1279. Result:=StringReplace(Result,'%WHERE%',S,[rfReplaceAll]);
  1280. if (aOrderBy<>'') then
  1281. S:='ORDER BY '+AOrderBy
  1282. else
  1283. S:='';
  1284. Result:=StringReplace(Result,'%FULLORDERBY%',S,[rfReplaceAll]);
  1285. Result:=StringReplace(Result,'%ORDERBY%',aOrderBy,[rfReplaceAll]);
  1286. Result:=StringReplace(Result,'%LIMIT%',aLimit,[rfReplaceAll]);
  1287. end;
  1288. class function TSQLDBRestResource.FieldTypeToRestFieldType(
  1289. aFieldType: TFieldType): TRestFieldType;
  1290. Const
  1291. Map : Array[TFieldType] of TRestFieldType =
  1292. (rftUnknown, rftString, rftInteger, rftInteger, rftInteger, // ftUnknown, ftString, ftSmallint, ftInteger, ftWord,
  1293. rftBoolean, rftFloat, rftFloat, rftFloat, rftDate, rftTime, rftDateTime, // ftBoolean, ftFloat, ftCurrency, ftBCD, ftDate, ftTime, ftDateTime,
  1294. rftBlob, rftBlob, rftInteger, rftBlob, rftString, rftUnknown, rftString, // ftBytes, ftVarBytes, ftAutoInc, ftBlob, ftMemo, ftGraphic, ftFmtMemo,
  1295. rftUnknown, rftUnknown, rftUnknown, rftUnknown, rftString, // ftParadoxOle, ftDBaseOle, ftTypedBinary, ftCursor, ftFixedChar,
  1296. rftString, rftLargeInt, rftUnknown, rftUnknown, rftUnknown, // ftWideString, ftLargeint, ftADT, ftArray, ftReference,
  1297. rftUnknown, rftBlob, rftBlob, rftUnknown, rftUnknown, // ftDataSet, ftOraBlob, ftOraClob, ftVariant, ftInterface,
  1298. rftUnknown, rftString, rftDateTime, rftFloat, rftString, rftString // ftIDispatch, ftGuid, ftTimeStamp, ftFMTBcd, ftFixedWideChar, ftWideMemo
  1299. {$IFNDEF VER3_2_2}
  1300. ,rftDateTime, rftDateTime, rftInteger, rftInteger, rftInteger, rftFloat, // ftOraTimeStamp, ftOraInterval, ftLongWord, ftShortint, ftByte, ftExtended
  1301. rftFloat // Single
  1302. {$ENDIF}
  1303. );
  1304. begin
  1305. Result:=Map[aFieldType];
  1306. end;
  1307. class constructor TSQLDBRestResource.Init;
  1308. begin
  1309. DefaultFieldListClass:=TSQLDBRestFieldList;
  1310. DefaultFieldClass:=TSQLDBRestField;
  1311. DefaultParameterListClass:=TSQLDBRestParameterList;
  1312. DefaultParamClass:=TSQLDBRestParam;
  1313. end;
  1314. procedure TSQLDBRestResource.PopulateFieldsFromFieldDefs(Defs: TFieldDefs; aIndexFields: TStringArray;
  1315. aProcessIdentifier: TProcessIdentifier; aMinFieldOpts: TRestFieldOptions);
  1316. Var
  1317. I : Integer;
  1318. F : TSQLDBRestField;
  1319. FN,PN : UTF8String;
  1320. O : TRestFieldOptions;
  1321. RFT : TRestFieldType;
  1322. FD : TFieldDef;
  1323. begin
  1324. For I:=0 to Defs.Count-1 do
  1325. begin
  1326. FD:=Defs[i];
  1327. RFT:=FieldTypeToRestFieldType(FD.DataType);
  1328. if RFT=rftUnknown then
  1329. Continue;
  1330. FN:=FD.Name;
  1331. if Assigned(aProcessIdentifier) then
  1332. PN:=aProcessIdentifier(FN);
  1333. if SameStr(PN,FN) then // No SameText, Allow to change case
  1334. PN:='';
  1335. O:=aMinFieldOpts;
  1336. if FD.Required then
  1337. Include(O,foRequired);
  1338. If IndexStr(FN,aIndexFields)<>-1 then
  1339. begin
  1340. Include(O,foInKey);
  1341. Exclude(O,foFilter);
  1342. end;
  1343. F:=Fields.AddField(FN,RFT,O);
  1344. F.NativeFieldType:=FD.DataType;
  1345. if F.FieldType=rftString then
  1346. F.MaxLen:=FD.Size;
  1347. F.PublicName:=PN;
  1348. end;
  1349. end;
  1350. procedure TSQLDBRestResource.PopulateParametersFromSQL(const SQL: String;
  1351. DoClear: Boolean);
  1352. Var
  1353. Parms : TParams;
  1354. P : TParam;
  1355. SRP : TSQLDBRestParam;
  1356. begin
  1357. if DoClear then
  1358. Parameters.Clear;
  1359. Parms:=TParams.Create(Nil);
  1360. try
  1361. Parms.ParseSQL(SQL,True);
  1362. for P in Parms do
  1363. If Parameters.IndexOf(P.Name)=-1 then
  1364. begin
  1365. SRP:=Parameters.AddParam(P.Name);
  1366. SRP.DataType:=ftString;
  1367. end;
  1368. finally
  1369. Parms.Free;
  1370. end;
  1371. end;
  1372. class function TSQLDBRestResource.CreateFieldList: TSQLDBRestFieldList;
  1373. begin
  1374. Result:=DefaultFieldListClass.Create(DefaultFieldClass);
  1375. end;
  1376. class function TSQLDBRestResource.CreateParamList: TSQLDBRestParameterList;
  1377. begin
  1378. Result:=DefaultParameterListClass.Create(DefaultParamClass);
  1379. end;
  1380. { TSQLDBRestFieldList }
  1381. function TSQLDBRestFieldList.GetFields(aIndex: Integer): TSQLDBRestField;
  1382. begin
  1383. Result:=TSQLDBRestField(Items[aIndex])
  1384. end;
  1385. procedure TSQLDBRestFieldList.SetFields(aIndex : Integer; AValue: TSQLDBRestField);
  1386. begin
  1387. Items[aIndex]:=aValue;
  1388. end;
  1389. function TSQLDBRestFieldList.GetEnumerator: TSQLDBRestFieldListEnumerator;
  1390. begin
  1391. Result:=TSQLDBRestFieldListEnumerator.Create(Self);
  1392. end;
  1393. function TSQLDBRestFieldList.AddField(const aFieldName: UTF8String; aFieldType: TRestFieldType; aOptions: TRestFieldOptions
  1394. ): TSQLDBRestField;
  1395. begin
  1396. if IndexOfFieldName(aFieldName)<>-1 then
  1397. Raise ESQLDBRest.CreateFmt(500,SDuplicateFieldName,[aFieldName]);
  1398. Result:=Add as TSQLDBRestField;
  1399. Result.FieldName:=aFieldName;
  1400. Result.FieldType:=aFieldType;
  1401. Result.Options:=aOptions;
  1402. end;
  1403. function TSQLDBRestFieldList.indexOfFieldName(const aFieldName : UTF8String): Integer;
  1404. begin
  1405. Result:=Count-1;
  1406. While (Result>=0) and not SameText(aFieldName,GetFields(Result).FieldName) do
  1407. Dec(Result);
  1408. end;
  1409. function TSQLDBRestFieldList.FindByFieldName(const aFieldName: UTF8String
  1410. ): TSQLDBRestField;
  1411. Var
  1412. I : Integer;
  1413. begin
  1414. I:=indexOfFieldName(aFieldName);
  1415. if (I=-1) then
  1416. Result:=Nil
  1417. else
  1418. Result:=GetFields(I);
  1419. end;
  1420. function TSQLDBRestFieldList.indexOfPublicName(const aPublicName : UTF8String): Integer;
  1421. begin
  1422. Result:=Count-1;
  1423. While (Result>=0) and not SameText(aPublicName,GetFields(Result).PublicName) do
  1424. Dec(Result);
  1425. end;
  1426. function TSQLDBRestFieldList.FindByPublicName(const aFieldName: UTF8String
  1427. ): TSQLDBRestField;
  1428. Var
  1429. I : Integer;
  1430. begin
  1431. I:=indexOfPublicName(aFieldName);
  1432. if (I=-1) then
  1433. Result:=Nil
  1434. else
  1435. Result:=GetFields(I);
  1436. end;
  1437. { TSQLDBRestField }
  1438. function TSQLDBRestField.GetPublicName: UTF8String;
  1439. begin
  1440. Result:=FPublicName;
  1441. if (Result='') then
  1442. Result:=FFieldName;
  1443. end;
  1444. constructor TSQLDBRestField.Create(ACollection: TCollection);
  1445. begin
  1446. inherited Create(ACollection);
  1447. FFilters:=AllFieldFilters;
  1448. end;
  1449. procedure TSQLDBRestField.Assign(Source: TPersistent);
  1450. Var
  1451. F : TSQLDBRestField;
  1452. begin
  1453. if (Source is TSQLDBRestField) then
  1454. begin
  1455. F:=source as TSQLDBRestField;
  1456. FieldName:=F.FieldName;
  1457. FPublicName:=F.FPublicName;
  1458. FieldType:=F.FieldType;
  1459. NativeFieldType:=F.NativeFieldType;
  1460. Options:=F.Options;
  1461. Filters:=F.Filters;
  1462. MaxLen:=F.MaxLen;
  1463. GeneratorName:=F.GeneratorName;
  1464. end
  1465. else
  1466. inherited Assign(Source);
  1467. end;
  1468. function TSQLDBRestField.GetDisplayName: string;
  1469. begin
  1470. Result:=PublicName;
  1471. end;
  1472. function TSQLDBRestField.UseInFieldList(aListKind: TFieldListKind): Boolean;
  1473. begin
  1474. Result:=True;
  1475. Case aListKind of
  1476. flSelect : Result:=True;
  1477. flInsert : Result:=foInInsert in Options;
  1478. flInsertParams : Result:=(foInInsert in Options) and not (NativeFieldType=ftAutoInc);
  1479. flUpdate : Result:=foInUpdate in Options;
  1480. flWhereKey : Result:=foInKey in Options;
  1481. flFilter : Result:=foFilter in Options;
  1482. flOrderby : Result:=([foOrderBy,foOrderByDesc]*options)<>[];
  1483. end;
  1484. end;
  1485. end.