Neon.Core.Utils.pas 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387
  1. {******************************************************************************}
  2. { }
  3. { Neon: Serialization Library for Delphi }
  4. { Copyright (c) 2018-2019 Paolo Rossi }
  5. { https://github.com/paolo-rossi/neon-library }
  6. { }
  7. {******************************************************************************}
  8. { }
  9. { Licensed under the Apache License, Version 2.0 (the "License"); }
  10. { you may not use this file except in compliance with the License. }
  11. { You may obtain a copy of the License at }
  12. { }
  13. { http://www.apache.org/licenses/LICENSE-2.0 }
  14. { }
  15. { Unless required by applicable law or agreed to in writing, software }
  16. { distributed under the License is distributed on an "AS IS" BASIS, }
  17. { WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. }
  18. { See the License for the specific language governing permissions and }
  19. { limitations under the License. }
  20. { }
  21. {******************************************************************************}
  22. unit Neon.Core.Utils;
  23. interface
  24. {$I Neon.inc}
  25. uses
  26. System.Classes, System.SysUtils, Data.DB, System.Rtti, System.JSON, System.TypInfo,
  27. {$IFDEF HAS_NET_ENCODING}
  28. System.NetEncoding,
  29. {$ELSE}
  30. IdCoder, IdCoderMIME, IdGlobal,
  31. {$ENDIF}
  32. System.Generics.Collections;
  33. type
  34. TJSONUtils = class
  35. public
  36. class procedure Decode(const ASource: string; ADest: TStream); overload;
  37. class function Encode(const ASource: TStream): string; overload;
  38. class function ToJSON(AJSONValue: TJSONValue): string; static;
  39. class function StringArrayToJsonArray(const AValues: TArray<string>): string; static;
  40. class function DoubleArrayToJsonArray(const AValues: TArray<Double>): string; static;
  41. class function IntegerArrayToJsonArray(const AValues: TArray<Integer>): string; static;
  42. class procedure JSONCopyFrom(ASource, ADestination: TJSONObject); static;
  43. class function BooleanToTJSON(AValue: Boolean): TJSONValue;
  44. class function DateToJSON(ADate: TDateTime; AInputIsUTC: Boolean = True): string; static;
  45. class function JSONToDate(const ADate: string; AReturnUTC: Boolean = True): TDateTime; static;
  46. end;
  47. TRttiUtils = class
  48. private
  49. class var FContext: TRttiContext;
  50. public
  51. // TRttiObject helpers functions
  52. class function FindAttribute<T: TCustomAttribute>(AType: TRttiObject): T; static;
  53. class function HasAttribute<T: TCustomAttribute>(AClass: TClass): Boolean; overload; static;
  54. class function HasAttribute<T: TCustomAttribute>(ARttiObj: TRttiObject): Boolean; overload; static;
  55. class function HasAttribute<T: TCustomAttribute>(ARttiObj: TRttiObject; const ADoSomething: TProc<T>): Boolean; overload; static;
  56. class function ForEachAttribute<T: TCustomAttribute>(
  57. ARttiObj: TRttiObject; const ADoSomething: TProc<T>): Integer; overload; static;
  58. // TRttiType helpers functions
  59. class function ForEachMethodWithAttribute<T: TCustomAttribute>(
  60. ARttiType: TRttiType; const ADoSomething: TFunc<TRttiMethod, T, Boolean>): Integer; static;
  61. class function ForEachFieldWithAttribute<T: TCustomAttribute>(
  62. ARttiType: TRttiType; const ADoSomething: TFunc<TRttiField, T, Boolean>): Integer; overload; static;
  63. class function ForEachPropertyWithAttribute<T: TCustomAttribute>(
  64. ARttiType: TRttiType; const ADoSomething: TFunc<TRttiProperty, T, Boolean>): Integer; overload; static;
  65. class function IsDynamicArrayOf<T: class>(ARttiType: TRttiType;
  66. const AAllowInherithance: Boolean = True): Boolean; overload; static;
  67. class function IsDynamicArrayOf(ARttiType: TRttiType; const AClass: TClass;
  68. const AAllowInherithance: Boolean = True): Boolean; overload; static;
  69. class function IsObjectOfType<T: class>(ARttiType: TRttiType;
  70. const AAllowInherithance: Boolean = True): Boolean; overload; static;
  71. class function IsObjectOfType(ARttiType: TRttiType; const AClass: TClass;
  72. const AAllowInherithance: Boolean = True): Boolean; overload; static;
  73. // Create new value data
  74. class function CreateNewValue(AType: TRttiType): TValue; static;
  75. // Create instance of class with parameterless constructor
  76. class function CreateInstanceValue(AType: TRttiType): TValue; overload;
  77. // Create instance of class with parameterless constructor
  78. class function CreateInstance(AClass: TClass): TObject; overload;
  79. class function CreateInstance(AType: TRttiType): TObject; overload;
  80. class function CreateInstance(const ATypeName: string): TObject; overload;
  81. // Create instance of class with one string parameter
  82. class function CreateInstance(AClass: TClass; const AValue: string): TObject; overload;
  83. class function CreateInstance(AType: TRttiType; const AValue: string): TObject; overload;
  84. class function CreateInstance(const ATypeName, AValue: string): TObject; overload;
  85. // Create instance of class with an array of TValue
  86. class function CreateInstance(AClass: TClass; const Args: array of TValue): TObject; overload;
  87. class function CreateInstance(AType: TRttiType; const Args: array of TValue): TObject; overload;
  88. class function CreateInstance(const ATypeName: string; const Args: array of TValue): TObject; overload;
  89. // Rtti general helper functions
  90. class function IfHasAttribute<T: TCustomAttribute>(AInstance: TObject): Boolean; overload;
  91. class function IfHasAttribute<T: TCustomAttribute>(AInstance: TObject; const ADoSomething: TProc<T>): Boolean; overload;
  92. class function ForEachAttribute<T: TCustomAttribute>(AInstance: TObject; const ADoSomething: TProc<T>): Integer; overload;
  93. class function ForEachFieldWithAttribute<T: TCustomAttribute>(AInstance: TObject; const ADoSomething: TFunc<TRttiField, T, Boolean>): Integer; overload;
  94. class function ForEachField(AInstance: TObject; const ADoSomething: TFunc<TRttiField, Boolean>): Integer;
  95. class function GetType(AObject: TRttiObject): TRttiType;
  96. class function ClassDistanceFromRoot(AClass: TClass): Integer; overload; static;
  97. class function ClassDistanceFromRoot(AInfo: PTypeInfo): Integer; overload; static;
  98. class property Context: TRttiContext read FContext;
  99. end;
  100. TBase64 = class
  101. class function Encode(const ASource: TBytes): string; overload;
  102. class function Encode(const ASource: TStream): string; overload;
  103. class function Decode(const ASource: string): TBytes; overload;
  104. class procedure Decode(const ASource: string; ADest: TStream); overload;
  105. end;
  106. TDataSetUtils = class
  107. private
  108. class function RecordToXML(const ADataSet: TDataSet; const ARootPath: string; AUseUTCDate: Boolean): string; static;
  109. class function RecordToCSV(const ADataSet: TDataSet; AUseUTCDate: Boolean): string; static;
  110. public
  111. class function RecordToJSONSchema(const ADataSet: TDataSet; AUseUTCDate: Boolean): TJSONObject; static;
  112. class function RecordToJSONObject(const ADataSet: TDataSet; AUseUTCDate: Boolean): TJSONObject; static;
  113. class function DataSetToJSONArray(const ADataSet: TDataSet; AUseUTCDate: Boolean): TJSONArray; overload; static;
  114. class function DataSetToJSONArray(const ADataSet: TDataSet; const AAcceptFunc: TFunc<Boolean>; AUseUTCDate: Boolean): TJSONArray; overload; static;
  115. class function DataSetToXML(const ADataSet: TDataSet; AUseUTCDate: Boolean): string; overload; static;
  116. class function DataSetToXML(const ADataSet: TDataSet; const AAcceptFunc: TFunc<Boolean>; AUseUTCDate: Boolean): string; overload; static;
  117. class procedure JSONToRecord(AJSONObject: TJSONObject; ADataSet: TDataSet; AUseUTCDate: Boolean); static;
  118. class procedure JSONToDataSet(AJSONValue: TJSONValue; ADataSet: TDataSet; AUseUTCDate: Boolean); static;
  119. class function DataSetToCSV(const ADataSet: TDataSet; AUseUTCDate: Boolean): string; static;
  120. class function DatasetMetadataToJSONObject(const ADataSet: TDataSet; AUseUTCDate: Boolean): TJSONObject; static;
  121. class function BlobFieldToBase64(ABlobField: TBlobField): string;
  122. class procedure Base64ToBlobField(const ABase64: string; ABlobField: TBlobField);
  123. end;
  124. function ExecuteMethod(const AInstance: TValue; const AMethodName: string; const AArguments: array of TValue;
  125. const ABeforeExecuteProc: TProc{ = nil}; const AAfterExecuteProc: TProc<TValue>{ = nil}): Boolean; overload;
  126. function ExecuteMethod(const AInstance: TValue; AMethod: TRttiMethod; const AArguments: array of TValue;
  127. const ABeforeExecuteProc: TProc{ = nil}; const AAfterExecuteProc: TProc<TValue>{ = nil}): Boolean; overload;
  128. function ReadPropertyValue(AInstance: TObject; const APropertyName: string): TValue;
  129. function TValueToJSONObject(const AName: string; const AValue: TValue): TJSONObject; overload;
  130. function TValueToJSONObject(AObject: TJSONObject; const AName: string; const AValue: TValue): TJSONObject; overload;
  131. implementation
  132. uses
  133. System.StrUtils, System.DateUtils;
  134. type
  135. TJSONFieldType = (NestedObject, NestedArray, SimpleValue);
  136. function TValueToJSONObject(AObject: TJSONObject; const AName: string; const AValue: TValue): TJSONObject;
  137. begin
  138. Result := AObject;
  139. if (AValue.Kind in [tkString]) then
  140. Result.AddPair(AName, AValue.AsString)
  141. else if (AValue.Kind in [tkInteger, tkInt64]) then
  142. Result.AddPair(AName, TJSONNumber.Create(AValue.AsOrdinal))
  143. else if (AValue.Kind in [tkFloat]) then
  144. Result.AddPair(AName, TJSONNumber.Create(AValue.AsExtended))
  145. else if (AValue.IsType<Boolean>) then
  146. Result.AddPair(AName, TJSONUtils.BooleanToTJSON(AValue.AsType<Boolean>))
  147. else if (AValue.IsType<TDateTime>) then
  148. Result.AddPair(AName, TJSONUtils.DateToJSON(AValue.AsType<TDateTime>))
  149. else if (AValue.IsType<TDate>) then
  150. Result.AddPair(AName, TJSONUtils.DateToJSON(AValue.AsType<TDate>))
  151. else if (AValue.IsType<TTime>) then
  152. Result.AddPair(AName, TJSONUtils.DateToJSON(AValue.AsType<TTime>))
  153. else
  154. Result.AddPair(AName, AValue.ToString);
  155. end;
  156. function TValueToJSONObject(const AName: string; const AValue: TValue): TJSONObject;
  157. begin
  158. Result := TValueToJSONObject(TJSONObject.Create(), AName, AValue);
  159. end;
  160. function ReadPropertyValue(AInstance: TObject; const APropertyName: string): TValue;
  161. var
  162. LContext: TRttiContext;
  163. LType: TRttiType;
  164. LProperty: TRttiProperty;
  165. begin
  166. Result := TValue.Empty;
  167. LType := LContext.GetType(AInstance.ClassType);
  168. if Assigned(LType) then
  169. begin
  170. LProperty := LType.GetProperty(APropertyName);
  171. if Assigned(LProperty) then
  172. Result := LProperty.GetValue(AInstance);
  173. end;
  174. end;
  175. function ExecuteMethod(const AInstance: TValue; AMethod: TRttiMethod;
  176. const AArguments: array of TValue; const ABeforeExecuteProc: TProc{ = nil};
  177. const AAfterExecuteProc: TProc<TValue>{ = nil}): Boolean;
  178. var
  179. LResult: TValue;
  180. begin
  181. if Assigned(ABeforeExecuteProc) then
  182. ABeforeExecuteProc();
  183. LResult := AMethod.Invoke(AInstance, AArguments);
  184. Result := True;
  185. if Assigned(AAfterExecuteProc) then
  186. AAfterExecuteProc(LResult);
  187. end;
  188. function ExecuteMethod(const AInstance: TValue; const AMethodName: string;
  189. const AArguments: array of TValue; const ABeforeExecuteProc: TProc{ = nil};
  190. const AAfterExecuteProc: TProc<TValue>{ = nil}): Boolean;
  191. var
  192. LContext: TRttiContext;
  193. LType: TRttiType;
  194. LMethod: TRttiMethod;
  195. begin
  196. Result := False;
  197. LType := LContext.GetType(AInstance.TypeInfo);
  198. if Assigned(LType) then
  199. begin
  200. LMethod := LType.GetMethod(AMethodName);
  201. if Assigned(LMethod) then
  202. Result := ExecuteMethod(AInstance, LMethod, AArguments, ABeforeExecuteProc, AAfterExecuteProc);
  203. end;
  204. end;
  205. class function TRttiUtils.ClassDistanceFromRoot(AClass: TClass): Integer;
  206. var
  207. LClass: TClass;
  208. begin
  209. Result := 0;
  210. LClass := AClass;
  211. while LClass <> TObject do
  212. begin
  213. LClass := LClass.ClassParent;
  214. Inc(Result);
  215. end;
  216. end;
  217. class function TRttiUtils.ClassDistanceFromRoot(AInfo: PTypeInfo): Integer;
  218. var
  219. LType: TRttiType;
  220. begin
  221. Result := -1;
  222. LType := TRttiUtils.Context.GetType(AInfo);
  223. if Assigned(LType) and (LType.TypeKind = tkClass) then
  224. Result := TRttiUtils.ClassDistanceFromRoot(LType.AsInstance.MetaclassType);
  225. end;
  226. { TRttiUtils }
  227. class function TRttiUtils.CreateNewValue(AType: TRttiType): TValue;
  228. var
  229. LAllocatedMem: Pointer;
  230. begin
  231. case AType.TypeKind of
  232. tkInteger: Result := TValue.From<Integer>(0);
  233. tkInt64: Result := TValue.From<Int64>(0);
  234. tkChar: Result := TValue.From<UTF8Char>(#0);
  235. tkWChar: Result := TValue.From<Char>(#0);
  236. tkFloat: Result := TValue.From<Double>(0);
  237. tkString: Result := TValue.From<UTF8String>('');
  238. tkWString: Result := TValue.From<string>('');
  239. tkLString: Result := TValue.From<UTF8String>('');
  240. tkUString: Result := TValue.From<string>('');
  241. tkClass: Result := CreateInstance(AType);
  242. tkRecord:
  243. begin
  244. LAllocatedMem := AllocMem(AType.TypeSize);
  245. try
  246. TValue.Make(LAllocatedMem, AType.Handle, Result);
  247. finally
  248. FreeMem(LAllocatedMem);
  249. end;
  250. end;
  251. else
  252. raise Exception.CreateFmt('Error creating type', [AType.Name]);
  253. end;
  254. end;
  255. class function TRttiUtils.CreateInstance(AClass: TClass): TObject;
  256. var
  257. LType: TRttiType;
  258. begin
  259. LType := FContext.GetType(AClass);
  260. Result := CreateInstanceValue(LType).AsObject;
  261. end;
  262. class function TRttiUtils.CreateInstance(AType: TRttiType): TObject;
  263. begin
  264. Result := CreateInstanceValue(AType).AsObject;
  265. end;
  266. class function TRttiUtils.CreateInstance(const ATypeName: string): TObject;
  267. var
  268. LType: TRttiType;
  269. begin
  270. LType := Context.FindType(ATypeName);
  271. Result := CreateInstanceValue(LType).AsObject;
  272. end;
  273. class function TRttiUtils.CreateInstance(AClass: TClass; const AValue: string): TObject;
  274. var
  275. LType: TRttiType;
  276. begin
  277. LType := FContext.GetType(AClass);
  278. Result := CreateInstance(LType, AValue);
  279. end;
  280. class function TRttiUtils.CreateInstance(AType: TRttiType;
  281. const AValue: string): TObject;
  282. var
  283. LMethod: TRttiMethod;
  284. LMetaClass: TClass;
  285. begin
  286. Result := nil;
  287. if Assigned(AType) then
  288. begin
  289. for LMethod in AType.GetMethods do
  290. begin
  291. if LMethod.HasExtendedInfo and LMethod.IsConstructor then
  292. begin
  293. if Length(LMethod.GetParameters) = 1 then
  294. begin
  295. if LMethod.GetParameters[0].ParamType.TypeKind in [tkLString, tkUString, tkWString, tkString] then
  296. begin
  297. LMetaClass := AType.AsInstance.MetaclassType;
  298. Exit(LMethod.Invoke(LMetaClass, [AValue]).AsObject);
  299. end;
  300. end;
  301. end;
  302. end;
  303. end;
  304. end;
  305. class function TRttiUtils.CreateInstance(const ATypeName, AValue: string): TObject;
  306. var
  307. LType: TRttiType;
  308. begin
  309. LType := Context.FindType(ATypeName);
  310. Result := CreateInstance(LType, AValue);
  311. end;
  312. class function TRttiUtils.CreateInstanceValue(AType: TRttiType): TValue;
  313. var
  314. LMethod: TRTTIMethod;
  315. LMetaClass: TClass;
  316. begin
  317. Result := nil;
  318. if Assigned(AType) then
  319. for LMethod in AType.GetMethods do
  320. begin
  321. if LMethod.HasExtendedInfo and LMethod.IsConstructor then
  322. begin
  323. if Length(LMethod.GetParameters) = 0 then
  324. begin
  325. LMetaClass := AType.AsInstance.MetaclassType;
  326. Exit(LMethod.Invoke(LMetaClass, []));
  327. end;
  328. end;
  329. end;
  330. end;
  331. class function TRttiUtils.ForEachAttribute<T>(AInstance: TObject;
  332. const ADoSomething: TProc<T>): Integer;
  333. var
  334. LContext: TRttiContext;
  335. LType: TRttiType;
  336. begin
  337. Result := 0;
  338. LType := LContext.GetType(AInstance.ClassType);
  339. if Assigned(LType) then
  340. Result := TRttiUtils.ForEachAttribute<T>(LType, ADoSomething);
  341. end;
  342. class function TRttiUtils.ForEachField(AInstance: TObject;
  343. const ADoSomething: TFunc<TRttiField, Boolean>): Integer;
  344. var
  345. LContext: TRttiContext;
  346. LField: TRttiField;
  347. LType: TRttiType;
  348. LBreak: Boolean;
  349. begin
  350. Result := 0;
  351. LType := LContext.GetType(AInstance.ClassType);
  352. for LField in LType.GetFields do
  353. begin
  354. LBreak := False;
  355. if Assigned(ADoSomething) then
  356. begin
  357. if not ADoSomething(LField) then
  358. LBreak := True
  359. else
  360. Inc(Result);
  361. end;
  362. if LBreak then
  363. Break;
  364. end;
  365. end;
  366. class function TRttiUtils.ForEachFieldWithAttribute<T>(AInstance: TObject;
  367. const ADoSomething: TFunc<TRttiField, T, Boolean>): Integer;
  368. var
  369. LContext: TRttiContext;
  370. LType: TRttiType;
  371. begin
  372. Result := 0;
  373. LType := LContext.GetType(AInstance.ClassType);
  374. if Assigned(LType) then
  375. Result := TRttiUtils.ForEachFieldWithAttribute<T>(LType, ADoSomething);
  376. end;
  377. class function TRttiUtils.IfHasAttribute<T>(AInstance: TObject): Boolean;
  378. begin
  379. Result := TRttiUtils.IfHasAttribute<T>(AInstance, nil);
  380. end;
  381. class function TRttiUtils.IfHasAttribute<T>(AInstance: TObject;
  382. const ADoSomething: TProc<T>): Boolean;
  383. var
  384. LContext: TRttiContext;
  385. LType: TRttiType;
  386. begin
  387. Result := False;
  388. LType := LContext.GetType(AInstance.ClassType);
  389. if Assigned(LType) then
  390. Result := TRttiUtils.HasAttribute<T>(LType, ADoSomething);
  391. end;
  392. class function TRttiUtils.ForEachAttribute<T>(ARttiObj: TRttiObject;
  393. const ADoSomething: TProc<T>): Integer;
  394. var
  395. LAttribute: TCustomAttribute;
  396. begin
  397. Result := 0;
  398. for LAttribute in ARttiObj.GetAttributes do
  399. begin
  400. if LAttribute.InheritsFrom(TClass(T)) then
  401. begin
  402. if Assigned(ADoSomething) then
  403. ADoSomething(T(LAttribute));
  404. Inc(Result);
  405. end;
  406. end;
  407. end;
  408. class function TRttiUtils.HasAttribute<T>(ARttiObj: TRttiObject): Boolean;
  409. begin
  410. Result := HasAttribute<T>(ARttiObj, nil);
  411. end;
  412. class function TRttiUtils.HasAttribute<T>(ARttiObj: TRttiObject; const
  413. ADoSomething: TProc<T>): Boolean;
  414. var
  415. LAttribute: TCustomAttribute;
  416. begin
  417. Result := False;
  418. for LAttribute in ARttiObj.GetAttributes do
  419. begin
  420. if LAttribute.InheritsFrom(TClass(T)) then
  421. begin
  422. Result := True;
  423. if Assigned(ADoSomething) then
  424. ADoSomething(T(LAttribute));
  425. Break;
  426. end;
  427. end;
  428. end;
  429. class function TRttiUtils.ForEachFieldWithAttribute<T>(ARttiType: TRttiType;
  430. const ADoSomething: TFunc<TRttiField, T, Boolean>): Integer;
  431. var
  432. LField: TRttiField;
  433. LBreak: Boolean;
  434. begin
  435. for LField in ARttiType.GetFields do
  436. begin
  437. LBreak := False;
  438. if TRttiUtils.HasAttribute<T>(LField,
  439. procedure (AAttrib: T)
  440. begin
  441. if Assigned(ADoSomething) then
  442. begin
  443. if not ADoSomething(LField, AAttrib) then
  444. LBreak := True;
  445. end;
  446. end
  447. )
  448. then
  449. Inc(Result);
  450. if LBreak then
  451. Break;
  452. end;
  453. end;
  454. class function TRttiUtils.ForEachMethodWithAttribute<T>(ARttiType: TRttiType;
  455. const ADoSomething: TFunc<TRttiMethod, T, Boolean>): Integer;
  456. var
  457. LMethod: TRttiMethod;
  458. LBreak: Boolean;
  459. begin
  460. Result := 0;
  461. for LMethod in ARttiType.GetMethods do
  462. begin
  463. LBreak := False;
  464. if TRttiUtils.HasAttribute<T>(LMethod,
  465. procedure (AAttrib: T)
  466. begin
  467. if Assigned(ADoSomething) then
  468. begin
  469. if not ADoSomething(LMethod, AAttrib) then
  470. LBreak := True;
  471. end;
  472. end
  473. )
  474. then
  475. Inc(Result);
  476. if LBreak then
  477. Break;
  478. end;
  479. end;
  480. class function TRttiUtils.ForEachPropertyWithAttribute<T>(ARttiType: TRttiType;
  481. const ADoSomething: TFunc<TRttiProperty, T, Boolean>): Integer;
  482. var
  483. LProperty: TRttiProperty;
  484. LBreak: Boolean;
  485. begin
  486. Result := 0;
  487. for LProperty in ARttiType.GetProperties do
  488. begin
  489. LBreak := False;
  490. if TRttiUtils.HasAttribute<T>(LProperty,
  491. procedure (AAttrib: T)
  492. begin
  493. if Assigned(ADoSomething) then
  494. begin
  495. if not ADoSomething(LProperty, AAttrib) then
  496. LBreak := True;
  497. end;
  498. end
  499. )
  500. then
  501. Inc(Result);
  502. if LBreak then
  503. Break;
  504. end;
  505. end;
  506. class function TRttiUtils.GetType(AObject: TRttiObject): TRttiType;
  507. begin
  508. if AObject is TRttiParameter then
  509. Result := TRttiParameter(AObject).ParamType
  510. else if AObject is TRttiField then
  511. Result := TRttiField(AObject).FieldType
  512. else if AObject is TRttiProperty then
  513. Result := TRttiProperty(AObject).PropertyType
  514. else if AObject is TRttiManagedField then
  515. Result := TRttiManagedField(AObject).FieldType
  516. else
  517. raise Exception.Create('Object doesn''t have a type');
  518. end;
  519. class function TRttiUtils.HasAttribute<T>(AClass: TClass): Boolean;
  520. begin
  521. Result := HasAttribute<T>(Context.GetType(AClass));
  522. end;
  523. class function TRttiUtils.IsDynamicArrayOf(ARttiType: TRttiType;
  524. const AClass: TClass; const AAllowInherithance: Boolean): Boolean;
  525. begin
  526. Result := False;
  527. if ARttiType is TRttiDynamicArrayType then
  528. Result := TRttiUtils.IsObjectOfType(
  529. TRttiDynamicArrayType(ARttiType).ElementType, AClass, AAllowInherithance);
  530. end;
  531. class function TRttiUtils.IsDynamicArrayOf<T>(ARttiType: TRttiType;
  532. const AAllowInherithance: Boolean): Boolean;
  533. begin
  534. Result := TRttiUtils.IsDynamicArrayOf(ARttiType, TClass(T), AAllowInherithance);
  535. end;
  536. class function TRttiUtils.IsObjectOfType(ARttiType: TRttiType;
  537. const AClass: TClass; const AAllowInherithance: Boolean): Boolean;
  538. begin
  539. Result := False;
  540. if ARttiType is TRttiInstanceType then
  541. begin
  542. if AAllowInherithance then
  543. Result := TRttiInstanceType(ARttiType).MetaclassType.InheritsFrom(AClass)
  544. else
  545. Result := TRttiInstanceType(ARttiType).MetaclassType = AClass;
  546. end;
  547. end;
  548. class function TRttiUtils.IsObjectOfType<T>(ARttiType: TRttiType;
  549. const AAllowInherithance: Boolean): Boolean;
  550. begin
  551. Result := TRttiUtils.IsObjectOfType(ARttiType, TClass(T), AAllowInherithance);
  552. end;
  553. class function TRttiUtils.FindAttribute<T>(AType: TRttiObject): T;
  554. var
  555. LAttribute: TCustomAttribute;
  556. begin
  557. Result := nil;
  558. for LAttribute in AType.GetAttributes do
  559. begin
  560. if LAttribute.InheritsFrom(TClass(T)) then
  561. begin
  562. Result := LAttribute as T;
  563. Break;
  564. end;
  565. end;
  566. end;
  567. class function TRttiUtils.CreateInstance(AClass: TClass;
  568. const Args: array of TValue): TObject;
  569. var
  570. LType: TRttiType;
  571. begin
  572. LType := FContext.GetType(AClass);
  573. Result := CreateInstance(LType, Args);
  574. end;
  575. class function TRttiUtils.CreateInstance(AType: TRttiType; const Args: array of TValue): TObject;
  576. var
  577. LMethod: TRttiMethod;
  578. LMetaClass: TClass;
  579. begin
  580. Result := nil;
  581. if Assigned(AType) then
  582. begin
  583. for LMethod in AType.GetMethods do
  584. begin
  585. if LMethod.HasExtendedInfo and LMethod.IsConstructor then
  586. begin
  587. if Length(LMethod.GetParameters) = Length(Args) then
  588. begin
  589. LMetaClass := AType.AsInstance.MetaclassType;
  590. Exit(LMethod.Invoke(LMetaClass, Args).AsObject);
  591. end;
  592. end;
  593. end;
  594. end;
  595. if not Assigned(Result) then
  596. raise Exception.CreateFmt('TRttiUtils.CreateInstance: can''t create object [%s]', [AType.Name]);
  597. end;
  598. class function TRttiUtils.CreateInstance(const ATypeName: string; const Args: array of TValue): TObject;
  599. var
  600. LType: TRttiType;
  601. begin
  602. LType := Context.FindType(ATypeName);
  603. Result := CreateInstance(LType, Args);
  604. end;
  605. class function TJSONUtils.BooleanToTJSON(AValue: Boolean): TJSONValue;
  606. begin
  607. if AValue then
  608. Result := TJSONTrue.Create
  609. else
  610. Result := TJSONFalse.Create;
  611. end;
  612. class function TJSONUtils.DateToJSON(ADate: TDateTime; AInputIsUTC: Boolean = True): string;
  613. begin
  614. Result := '';
  615. if ADate <> 0 then
  616. Result := FormatDateTime('yyyy-mm-dd hh:nn:ss.zzz', ADate);
  617. // Result := DateToISO8601(ADate, AInputIsUTC);
  618. end;
  619. class procedure TJSONUtils.Decode(const ASource: string; ADest: TStream);
  620. {$IFDEF HAS_NET_ENCODING}
  621. var
  622. LBase64Stream: TStringStream;
  623. {$ENDIF}
  624. begin
  625. {$IFDEF HAS_NET_ENCODING}
  626. LBase64Stream := TStringStream.Create(ASource);
  627. LBase64Stream.Position := soFromBeginning;
  628. try
  629. TNetEncoding.Base64.Decode(LBase64Stream, ADest);
  630. finally
  631. LBase64Stream.Free;
  632. end;
  633. {$ELSE}
  634. TIdDecoderMIME.DecodeStream(ASource, ADest);
  635. {$ENDIF}
  636. end;
  637. class function TJSONUtils.DoubleArrayToJsonArray(const AValues: TArray<Double>): string;
  638. var
  639. LArray: TJSONArray;
  640. LIndex: Integer;
  641. begin
  642. LArray := TJSONArray.Create;
  643. try
  644. for LIndex := 0 to High(AValues) do
  645. LArray.Add(AValues[LIndex]);
  646. Result := ToJSON(LArray);
  647. finally
  648. LArray.Free;
  649. end;
  650. end;
  651. class function TJSONUtils.Encode(const ASource: TStream): string;
  652. {$IFDEF HAS_NET_ENCODING}
  653. var
  654. LBase64Stream: TStringStream;
  655. {$ENDIF}
  656. begin
  657. {$IFDEF HAS_NET_ENCODING}
  658. LBase64Stream := TStringStream.Create;
  659. try
  660. TNetEncoding.Base64.Encode(ASource, LBase64Stream);
  661. Result := LBase64Stream.DataString;
  662. finally
  663. LBase64Stream.Free;
  664. end;
  665. {$ELSE}
  666. Result := TIdEncoderMIME.EncodeStream(ASource);
  667. {$ENDIF}
  668. end;
  669. class function TJSONUtils.IntegerArrayToJsonArray(const AValues: TArray<Integer>): string;
  670. var
  671. LArray: TJSONArray;
  672. LIndex: Integer;
  673. begin
  674. LArray := TJSONArray.Create;
  675. try
  676. for LIndex := 0 to High(AValues) do
  677. LArray.Add(AValues[LIndex]);
  678. Result := ToJSON(LArray);
  679. finally
  680. LArray.Free;
  681. end;
  682. end;
  683. class function TJSONUtils.JSONToDate(const ADate: string; AReturnUTC: Boolean = True): TDateTime;
  684. var
  685. AFormat: TFormatSettings;
  686. begin
  687. Result := 0.0;
  688. if ADate<>'' then
  689. begin
  690. AFormat := TFormatSettings.Create();
  691. AFormat.ShortDateFormat := 'yyyy-mm-dd';
  692. AFormat.ShortTimeFormat := 'hh:nn:ss';
  693. AFormat.DateSeparator := '-';
  694. AFormat.TimeSeparator := ':';
  695. Result := StrToDateTime(ADate, AFormat);
  696. end;
  697. // Result := ISO8601ToDate(ADate, AReturnUTC);
  698. end;
  699. class function TJSONUtils.ToJSON(AJSONValue: TJSONValue): string;
  700. var
  701. LBytes: TBytes;
  702. begin
  703. SetLength(LBytes, AJSONValue.ToString.Length * 6);
  704. SetLength(LBytes, AJSONValue.ToBytes(LBytes, 0));
  705. Result := TEncoding.Default.GetString(LBytes);
  706. end;
  707. class function TJSONUtils.StringArrayToJsonArray(const AValues: TArray<string>): string;
  708. var
  709. LArray: TJSONArray;
  710. LIndex: Integer;
  711. begin
  712. LArray := TJSONArray.Create;
  713. try
  714. for LIndex := 0 to High(AValues) do
  715. LArray.Add(AValues[LIndex]);
  716. Result := ToJSON(LArray);
  717. finally
  718. LArray.Free;
  719. end;
  720. end;
  721. class procedure TJSONUtils.JSONCopyFrom(ASource, ADestination: TJSONObject);
  722. var
  723. LPair: TJSONPair;
  724. begin
  725. for LPair in ASource do
  726. ADestination.AddPair(TJSONPair(LPair.Clone));
  727. end;
  728. class function TBase64.Encode(const ASource: TBytes): string;
  729. begin
  730. {$IFDEF HAS_NET_ENCODING}
  731. Result := TNetEncoding.Base64.EncodeBytesToString(ASource);
  732. {$ELSE}
  733. Result := TIdEncoderMIME.EncodeBytes(TIdBytes(ASource));
  734. {$ENDIF}
  735. end;
  736. class function TBase64.Encode(const ASource: TStream): string;
  737. {$IFDEF HAS_NET_ENCODING}
  738. var
  739. LBase64Stream: TStringStream;
  740. {$ENDIF}
  741. begin
  742. {$IFDEF HAS_NET_ENCODING}
  743. LBase64Stream := TStringStream.Create;
  744. try
  745. TNetEncoding.Base64.Encode(ASource, LBase64Stream);
  746. Result := LBase64Stream.DataString;
  747. finally
  748. LBase64Stream.Free;
  749. end;
  750. {$ELSE}
  751. Result := TIdEncoderMIME.EncodeStream(ASource);
  752. {$ENDIF}
  753. end;
  754. class function TBase64.Decode(const ASource: string): TBytes;
  755. begin
  756. {$IFDEF HAS_NET_ENCODING}
  757. Result := TNetEncoding.Base64.DecodeStringToBytes(ASource);
  758. {$ELSE}
  759. Result := TIdDecoderMIME.DecodeBytes(ASource) as TBytes;
  760. {$ENDIF}
  761. end;
  762. class procedure TBase64.Decode(const ASource: string; ADest: TStream);
  763. {$IFDEF HAS_NET_ENCODING}
  764. var
  765. LBase64Stream: TStringStream;
  766. {$ENDIF}
  767. begin
  768. {$IFDEF HAS_NET_ENCODING}
  769. LBase64Stream := TStringStream.Create(ASource);
  770. LBase64Stream.Position := soFromBeginning;
  771. try
  772. TNetEncoding.Base64.Decode(LBase64Stream, ADest);
  773. finally
  774. LBase64Stream.Free;
  775. end;
  776. {$ELSE}
  777. TIdDecoderMIME.DecodeStream(ASource, ADest);
  778. {$ENDIF}
  779. end;
  780. class function TDataSetUtils.RecordToCSV(const ADataSet: TDataSet; AUseUTCDate: Boolean): string;
  781. var
  782. LField: TField;
  783. begin
  784. if not Assigned(ADataSet) then
  785. raise Exception.Create('DataSet not assigned');
  786. if not ADataSet.Active then
  787. raise Exception.Create('DataSet is not active');
  788. if ADataSet.IsEmpty then
  789. raise Exception.Create('DataSet is empty');
  790. Result := '';
  791. for LField in ADataSet.Fields do
  792. begin
  793. Result := Result + LField.AsString + ',';
  794. end;
  795. Result := Result.TrimRight([',']);
  796. end;
  797. class function TDataSetUtils.RecordToJSONObject(const ADataSet: TDataSet; AUseUTCDate: Boolean): TJSONObject;
  798. var
  799. LField: TField;
  800. LPairName: string;
  801. begin
  802. Result := TJSONObject.Create;
  803. for LField in ADataSet.Fields do
  804. begin
  805. LPairName := LField.FieldName;
  806. if ContainsStr(LPairName, '.') then
  807. Continue;
  808. case LField.DataType of
  809. TFieldType.ftString: Result.AddPair(LPairName, LField.AsString);
  810. TFieldType.ftSmallint: Result.AddPair(LPairName, TJSONNumber.Create(LField.AsInteger));
  811. TFieldType.ftInteger: Result.AddPair(LPairName, TJSONNumber.Create(LField.AsInteger));
  812. TFieldType.ftWord: Result.AddPair(LPairName, TJSONNumber.Create(LField.AsInteger));
  813. TFieldType.ftBoolean: Result.AddPair(LPairName, TJSONUtils.BooleanToTJSON(LField.AsBoolean));
  814. TFieldType.ftFloat: Result.AddPair(LPairName, TJSONNumber.Create(LField.AsFloat));
  815. TFieldType.ftCurrency: Result.AddPair(LPairName, TJSONNumber.Create(LField.AsCurrency));
  816. TFieldType.ftBCD: Result.AddPair(LPairName, TJSONNumber.Create(LField.AsFloat));
  817. TFieldType.ftDate: Result.AddPair(LPairName, TJSONUtils.DateToJSON(LField.AsDateTime, AUseUTCDate));
  818. TFieldType.ftTime: Result.AddPair(LPairName, TJSONUtils.DateToJSON(LField.AsDateTime, AUseUTCDate));
  819. TFieldType.ftDateTime: Result.AddPair(LPairName, TJSONUtils.DateToJSON(LField.AsDateTime, AUseUTCDate));
  820. TFieldType.ftBytes: Result.AddPair(LPairName, TBase64.Encode(LField.AsBytes));
  821. TFieldType.ftVarBytes: Result.AddPair(LPairName, TBase64.Encode(LField.AsBytes));
  822. TFieldType.ftAutoInc: Result.AddPair(LPairName, TJSONNumber.Create(LField.AsInteger));
  823. TFieldType.ftBlob: Result.AddPair(LPairName, BlobFieldToBase64(LField as TBlobField));
  824. TFieldType.ftMemo: Result.AddPair(LPairName, LField.AsString);
  825. TFieldType.ftGraphic: Result.AddPair(LPairName, TBase64.Encode(LField.AsBytes));
  826. // TFieldType.ftFmtMemo: ;
  827. // TFieldType.ftParadoxOle: ;
  828. // TFieldType.ftDBaseOle: ;
  829. TFieldType.ftTypedBinary: Result.AddPair(LPairName, TBase64.Encode(LField.AsBytes));
  830. // TFieldType.ftCursor: ;
  831. TFieldType.ftFixedChar: Result.AddPair(LPairName, LField.AsString);
  832. TFieldType.ftWideString: Result.AddPair(LPairName, LField.AsWideString);
  833. TFieldType.ftLargeint: Result.AddPair(LPairName, TJSONNumber.Create(LField.AsLargeInt));
  834. TFieldType.ftADT: Result.AddPair(LPairName, TBase64.Encode(LField.AsBytes));
  835. TFieldType.ftArray: Result.AddPair(LPairName, TBase64.Encode(LField.AsBytes));
  836. // TFieldType.ftReference: ;
  837. TFieldType.ftDataSet: Result.AddPair(LPairName, DataSetToJSONArray((LField as TDataSetField).NestedDataSet, AUseUTCDate));
  838. TFieldType.ftOraBlob: Result.AddPair(LPairName, TBase64.Encode(LField.AsBytes));
  839. TFieldType.ftOraClob: Result.AddPair(LPairName, TBase64.Encode(LField.AsBytes));
  840. TFieldType.ftVariant: Result.AddPair(LPairName, LField.AsString);
  841. // TFieldType.ftInterface: ;
  842. // TFieldType.ftIDispatch: ;
  843. TFieldType.ftGuid: Result.AddPair(LPairName, LField.AsString);
  844. TFieldType.ftTimeStamp: Result.AddPair(LPairName, TJSONUtils.DateToJSON(LField.AsDateTime, AUseUTCDate));
  845. TFieldType.ftFMTBcd: Result.AddPair(LPairName, TJSONNumber.Create(LField.AsFloat));
  846. TFieldType.ftFixedWideChar: Result.AddPair(LPairName, LField.AsString);
  847. TFieldType.ftWideMemo: Result.AddPair(LPairName, LField.AsString);
  848. TFieldType.ftOraTimeStamp: Result.AddPair(LPairName, TJSONUtils.DateToJSON(LField.AsDateTime, AUseUTCDate));
  849. TFieldType.ftOraInterval: Result.AddPair(LPairName, LField.AsString);
  850. TFieldType.ftLongWord: Result.AddPair(LPairName, TJSONNumber.Create(LField.AsInteger));
  851. TFieldType.ftShortint: Result.AddPair(LPairName, TJSONNumber.Create(LField.AsInteger));
  852. TFieldType.ftByte: Result.AddPair(LPairName, TJSONNumber.Create(LField.AsInteger));
  853. TFieldType.ftExtended: Result.AddPair(LPairName, TJSONNumber.Create(LField.AsFloat));
  854. // TFieldType.ftConnection: ;
  855. // TFieldType.ftParams: ;
  856. // TFieldType.ftStream: ;
  857. TFieldType.ftTimeStampOffset: Result.AddPair(LPairName, LField.AsString);
  858. // TFieldType.ftObject: ;
  859. TFieldType.ftSingle: Result.AddPair(LPairName, TJSONNumber.Create(LField.AsFloat));
  860. end;
  861. end;
  862. end;
  863. class function TDataSetUtils.RecordToJSONSchema(const ADataSet: TDataSet; AUseUTCDate: Boolean): TJSONObject;
  864. var
  865. LField: TField;
  866. LPairName: string;
  867. LJSONField: TJSONObject;
  868. begin
  869. Result := TJSONObject.Create;
  870. if not Assigned(ADataSet) then
  871. Exit;
  872. if not ADataSet.Active then
  873. ADataSet.Open;
  874. for LField in ADataSet.Fields do
  875. begin
  876. LPairName := LField.FieldName;
  877. if LPairName.Contains('.') then
  878. Continue;
  879. LJSONField := TJSONObject.Create;
  880. Result.AddPair(LPairName, LJSONField);
  881. case LField.DataType of
  882. TFieldType.ftString:
  883. begin
  884. LJSONField.AddPair('type', 'string');
  885. end;
  886. TFieldType.ftSmallint,
  887. TFieldType.ftInteger,
  888. TFieldType.ftWord,
  889. TFieldType.ftLongWord,
  890. TFieldType.ftShortint,
  891. TFieldType.ftByte:
  892. begin
  893. LJSONField.AddPair('type', 'integer').AddPair('format', 'int32');
  894. end;
  895. TFieldType.ftBoolean:
  896. begin
  897. LJSONField.AddPair('type', 'boolean');
  898. end;
  899. TFieldType.ftFloat,
  900. TFieldType.ftSingle:
  901. begin
  902. LJSONField.AddPair('type', 'number').AddPair('format', 'float');
  903. end;
  904. TFieldType.ftCurrency,
  905. TFieldType.ftExtended:
  906. begin
  907. LJSONField.AddPair('type', 'number').AddPair('format', 'double');
  908. end;
  909. TFieldType.ftBCD:
  910. begin
  911. LJSONField.AddPair('type', 'number').AddPair('format', 'double');
  912. end;
  913. TFieldType.ftDate:
  914. begin
  915. LJSONField.AddPair('type', 'string').AddPair('format', 'date');
  916. end;
  917. TFieldType.ftTime:
  918. begin
  919. LJSONField.AddPair('type', 'string').AddPair('format', 'date-time');
  920. end;
  921. TFieldType.ftDateTime:
  922. begin
  923. LJSONField.AddPair('type', 'string').AddPair('format', 'date-time');
  924. end;
  925. // ftBytes: ;
  926. // ftVarBytes: ;
  927. TFieldType.ftAutoInc:
  928. begin
  929. LJSONField.AddPair('type', 'integer').AddPair('format', 'int32');
  930. end;
  931. // ftBlob: ;
  932. TFieldType.ftMemo,
  933. TFieldType.ftWideMemo:
  934. begin
  935. LJSONField.AddPair('type', 'string');
  936. end;
  937. // ftGraphic: ;
  938. // ftFmtMemo: ;
  939. // ftParadoxOle: ;
  940. // ftDBaseOle: ;
  941. // ftTypedBinary: ;
  942. // ftCursor: ;
  943. TFieldType.ftFixedChar,
  944. TFieldType.ftFixedWideChar,
  945. TFieldType.ftWideString:
  946. begin
  947. LJSONField.AddPair('type', 'string');
  948. end;
  949. TFieldType.ftLargeint:
  950. begin
  951. LJSONField.AddPair('type', 'integer').AddPair('format', 'int64');
  952. end;
  953. // ftADT: ;
  954. // ftArray: ;
  955. // ftReference: ;
  956. // ftDataSet: ;
  957. // ftOraBlob: ;
  958. // ftOraClob: ;
  959. TFieldType.ftVariant:
  960. begin
  961. LJSONField.AddPair('type', 'string');
  962. end;
  963. // ftInterface: ;
  964. // ftIDispatch: ;
  965. TFieldType.ftGuid:
  966. begin
  967. LJSONField.AddPair('type', 'string');
  968. end;
  969. TFieldType.ftTimeStamp:
  970. begin
  971. LJSONField.AddPair('type', 'string').AddPair('format', 'date-time');
  972. end;
  973. TFieldType.ftFMTBcd:
  974. begin
  975. LJSONField.AddPair('type', 'number').AddPair('format', 'double');
  976. end;
  977. // ftOraTimeStamp: ;
  978. // ftOraInterval: ;
  979. // ftConnection: ;
  980. // ftParams: ;
  981. // ftStream: ;
  982. // ftTimeStampOffset: ;
  983. // ftObject: ;
  984. end;
  985. end;
  986. end;
  987. class function TDataSetUtils.RecordToXML(const ADataSet: TDataSet; const ARootPath: string; AUseUTCDate: Boolean): string;
  988. var
  989. LField: TField;
  990. begin
  991. Result := '';
  992. for LField in ADataSet.Fields do
  993. begin
  994. Result := Result
  995. + Format('<%s>%s</%s>', [LField.FieldName, LField.AsString, LField.FieldName]);
  996. end;
  997. end;
  998. class function TDataSetUtils.DataSetToJSONArray(const ADataSet: TDataSet; AUseUTCDate: Boolean): TJSONArray;
  999. begin
  1000. Result := DataSetToJSONArray(ADataSet, nil, AUseUTCDate);
  1001. end;
  1002. class function TDataSetUtils.DataSetToCSV(const ADataSet: TDataSet; AUseUTCDate: Boolean): string;
  1003. var
  1004. LBookmark: TBookmark;
  1005. begin
  1006. Result := '';
  1007. if not Assigned(ADataSet) then
  1008. Exit;
  1009. if not ADataSet.Active then
  1010. ADataSet.Open;
  1011. ADataSet.DisableControls;
  1012. try
  1013. LBookmark := ADataSet.Bookmark;
  1014. try
  1015. ADataSet.First;
  1016. while not ADataSet.Eof do
  1017. try
  1018. Result := Result + TDataSetUtils.RecordToCSV(ADataSet, AUseUTCDate) + sLineBreak;
  1019. finally
  1020. ADataSet.Next;
  1021. end;
  1022. finally
  1023. ADataSet.GotoBookmark(LBookmark);
  1024. end;
  1025. finally
  1026. ADataSet.EnableControls;
  1027. end;
  1028. end;
  1029. class function TDataSetUtils.DataSetToJSONArray(const ADataSet: TDataSet; const AAcceptFunc: TFunc<Boolean>; AUseUTCDate: Boolean): TJSONArray;
  1030. var
  1031. LBookmark: TBookmark;
  1032. begin
  1033. Result := TJSONArray.Create;
  1034. if not Assigned(ADataSet) then
  1035. Exit;
  1036. if not ADataSet.Active then
  1037. ADataSet.Open;
  1038. ADataSet.DisableControls;
  1039. try
  1040. LBookmark := ADataSet.Bookmark;
  1041. try
  1042. ADataSet.First;
  1043. while not ADataSet.Eof do
  1044. try
  1045. if (not Assigned(AAcceptFunc)) or (AAcceptFunc()) then
  1046. Result.AddElement(RecordToJSONObject(ADataSet, AUseUTCDate));
  1047. finally
  1048. ADataSet.Next;
  1049. end;
  1050. finally
  1051. ADataSet.GotoBookmark(LBookmark);
  1052. end;
  1053. finally
  1054. ADataSet.EnableControls;
  1055. end;
  1056. end;
  1057. class function TDataSetUtils.DataSetToXML(const ADataSet: TDataSet; AUseUTCDate: Boolean): string;
  1058. begin
  1059. Result := DataSetToXML(ADataSet, nil, AUseUTCDate);
  1060. end;
  1061. class function TDataSetUtils.DataSetToXML(const ADataSet: TDataSet; const AAcceptFunc: TFunc<Boolean>; AUseUTCDate: Boolean): string;
  1062. var
  1063. LBookmark: TBookmark;
  1064. begin
  1065. Result := '';
  1066. if not Assigned(ADataSet) then
  1067. Exit;
  1068. if not ADataSet.Active then
  1069. ADataSet.Open;
  1070. ADataSet.DisableControls;
  1071. try
  1072. LBookmark := ADataSet.Bookmark;
  1073. try
  1074. ADataSet.First;
  1075. while not ADataSet.Eof do
  1076. try
  1077. if (not Assigned(AAcceptFunc)) or (AAcceptFunc()) then
  1078. Result := Result + '<row>' + RecordToXML(ADataSet, '', AUseUTCDate) + '</row>';
  1079. finally
  1080. ADataSet.Next;
  1081. end;
  1082. finally
  1083. ADataSet.GotoBookmark(LBookmark);
  1084. end;
  1085. finally
  1086. ADataSet.EnableControls;
  1087. end;
  1088. end;
  1089. class procedure TDataSetUtils.JSONToDataSet(AJSONValue: TJSONValue; ADataSet: TDataSet; AUseUTCDate: Boolean);
  1090. var
  1091. LJSONArray: TJSONArray;
  1092. LJSONItem: TJSONObject;
  1093. LIndex: Integer;
  1094. begin
  1095. LJSONArray := AJSONValue as TJSONArray;
  1096. for LIndex := 0 to LJSONArray.Count - 1 do
  1097. begin
  1098. LJSONItem := LJSONArray.Items[LIndex] as TJSONObject;
  1099. JSONToRecord(LJSONItem, ADataSet, AUseUTCDate);
  1100. end;
  1101. end;
  1102. class procedure TDataSetUtils.JSONToRecord(AJSONObject: TJSONObject; ADataSet: TDataSet; AUseUTCDate: Boolean);
  1103. var
  1104. LJSONField: TJSONValue;
  1105. LIndex: Integer;
  1106. LField: TField;
  1107. begin
  1108. ADataSet.Append;
  1109. for LIndex := 0 to ADataSet.Fields.Count - 1 do
  1110. begin
  1111. LField := ADataSet.Fields[LIndex];
  1112. LJSONField := AJSONObject.GetValue(LField.FieldName);
  1113. if not Assigned(LJSONField) then
  1114. Continue;
  1115. case LField.DataType of
  1116. //TFieldType.ftUnknown: ;
  1117. TFieldType.ftString: LField.AsString := LJSONField.Value;
  1118. TFieldType.ftSmallint: LField.AsString := LJSONField.Value;
  1119. TFieldType.ftInteger: LField.AsString := LJSONField.Value;
  1120. TFieldType.ftWord: LField.AsString := LJSONField.Value;
  1121. TFieldType.ftBoolean: LField.AsString := LJSONField.Value;
  1122. TFieldType.ftFloat: LField.AsString := LJSONField.Value;
  1123. TFieldType.ftCurrency: LField.AsString := LJSONField.Value;
  1124. TFieldType.ftBCD: LField.AsString := LJSONField.Value;
  1125. TFieldType.ftDate: LField.AsDateTime := TJSONUtils.JSONToDate(LJSONField.Value, AUseUTCDate);
  1126. TFieldType.ftTime: LField.AsDateTime := TJSONUtils.JSONToDate(LJSONField.Value, AUseUTCDate);
  1127. TFieldType.ftDateTime: LField.AsDateTime := TJSONUtils.JSONToDate(LJSONField.Value, AUseUTCDate);
  1128. TFieldType.ftBytes: ADataSet.Fields[LIndex].AsBytes := TBase64.Decode(LJSONField.Value);
  1129. TFieldType.ftVarBytes: ADataSet.Fields[LIndex].AsBytes := TBase64.Decode(LJSONField.Value);
  1130. TFieldType.ftAutoInc: LField.AsString := LJSONField.Value;
  1131. TFieldType.ftBlob: TDataSetUtils.Base64ToBlobField(LJSONField.Value, ADataSet.Fields[LIndex] as TBlobField);
  1132. TFieldType.ftMemo: LField.AsString := LJSONField.Value;
  1133. TFieldType.ftGraphic: (ADataSet.Fields[LIndex] as TGraphicField).Value := TBase64.Decode(LJSONField.Value);
  1134. //TFieldType.ftFmtMemo: ;
  1135. //TFieldType.ftParadoxOle: ;
  1136. //TFieldType.ftDBaseOle: ;
  1137. TFieldType.ftTypedBinary: ADataSet.Fields[LIndex].AsBytes := TBase64.Decode(LJSONField.Value);
  1138. //TFieldType.ftCursor: ;
  1139. TFieldType.ftFixedChar: LField.AsString := LJSONField.Value;
  1140. TFieldType.ftWideString: LField.AsString := LJSONField.Value;
  1141. TFieldType.ftLargeint: LField.AsString := LJSONField.Value;
  1142. TFieldType.ftADT: ADataSet.Fields[LIndex].AsBytes := TBase64.Decode(LJSONField.Value);
  1143. TFieldType.ftArray: ADataSet.Fields[LIndex].AsBytes := TBase64.Decode(LJSONField.Value);
  1144. //TFieldType.ftReference: ;
  1145. TFieldType.ftDataSet: JSONToDataSet(LJSONField, (ADataSet.Fields[LIndex] as TDataSetField).NestedDataSet, AUseUTCDate);
  1146. TFieldType.ftOraBlob: TDataSetUtils.Base64ToBlobField(LJSONField.Value, ADataSet.Fields[LIndex] as TBlobField);
  1147. TFieldType.ftOraClob: TDataSetUtils.Base64ToBlobField(LJSONField.Value, ADataSet.Fields[LIndex] as TBlobField);
  1148. TFieldType.ftVariant: TDataSetUtils.Base64ToBlobField(LJSONField.Value, ADataSet.Fields[LIndex] as TBlobField);
  1149. //TFieldType.ftInterface: ;
  1150. //TFieldType.ftIDispatch: ;
  1151. TFieldType.ftGuid: LField.AsString := LJSONField.Value;
  1152. TFieldType.ftTimeStamp: LField.AsDateTime := TJSONUtils.JSONToDate(LJSONField.Value, AUseUTCDate);
  1153. TFieldType.ftFMTBcd: ADataSet.Fields[LIndex].AsBytes := TBase64.Decode(LJSONField.Value);
  1154. TFieldType.ftFixedWideChar: LField.AsString := LJSONField.Value;
  1155. TFieldType.ftWideMemo: LField.AsString := LJSONField.Value;
  1156. TFieldType.ftOraTimeStamp: LField.AsDateTime := TJSONUtils.JSONToDate(LJSONField.Value, AUseUTCDate);
  1157. TFieldType.ftOraInterval: LField.AsString := LJSONField.Value;
  1158. TFieldType.ftLongWord: LField.AsString := LJSONField.Value;
  1159. TFieldType.ftShortint: LField.AsString := LJSONField.Value;
  1160. TFieldType.ftByte: LField.AsString := LJSONField.Value;
  1161. TFieldType.ftExtended: LField.AsString := LJSONField.Value;
  1162. //TFieldType.ftConnection: ;
  1163. //TFieldType.ftParams: ;
  1164. TFieldType.ftStream: ADataSet.Fields[LIndex].AsBytes := TBase64.Decode(LJSONField.Value);
  1165. //TFieldType.ftTimeStampOffset: ;
  1166. //TFieldType.ftObject: ;
  1167. TFieldType.ftSingle: LField.AsString := LJSONField.Value;
  1168. end;
  1169. end;
  1170. try
  1171. ADataSet.Post;
  1172. except
  1173. ADataSet.Cancel;
  1174. raise;
  1175. end;
  1176. end;
  1177. class procedure TDataSetUtils.Base64ToBlobField(const ABase64: string; ABlobField: TBlobField);
  1178. var
  1179. LBinaryStream: TMemoryStream;
  1180. begin
  1181. LBinaryStream := TMemoryStream.Create;
  1182. try
  1183. TBase64.Decode(ABase64, LBinaryStream);
  1184. ABlobField.LoadFromStream(LBinaryStream);
  1185. finally
  1186. LBinaryStream.Free;
  1187. end;
  1188. end;
  1189. class function TDataSetUtils.BlobFieldToBase64(ABlobField: TBlobField): string;
  1190. var
  1191. LBlobStream: TMemoryStream;
  1192. begin
  1193. LBlobStream := TMemoryStream.Create;
  1194. try
  1195. ABlobField.SaveToStream(LBlobStream);
  1196. LBlobStream.Position := soFromBeginning;
  1197. Result := TBase64.Encode(LBlobStream);
  1198. finally
  1199. LBlobStream.Free;
  1200. end;
  1201. end;
  1202. class function TDataSetUtils.DatasetMetadataToJSONObject(const ADataSet: TDataSet; AUseUTCDate: Boolean): TJSONObject;
  1203. procedure AddPropertyValue(APropertyName: string);
  1204. begin
  1205. TValueToJSONObject(Result, APropertyName, ReadPropertyValue(ADataSet, APropertyName));
  1206. end;
  1207. begin
  1208. Result := TJSONObject.Create;
  1209. AddPropertyValue('Eof');
  1210. AddPropertyValue('Bof');
  1211. AddPropertyValue('RecNo');
  1212. AddPropertyValue('Name');
  1213. end;
  1214. end.