odatabase.pp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  1. {$IFNDEF FPC_DOTTEDUNITS}
  2. unit odatabase;
  3. {$ENDIF FPC_DOTTEDUNITS}
  4. {$mode objfpc}{$H+}
  5. interface
  6. {$IFDEF FPC_DOTTEDUNITS}
  7. uses
  8. System.TypInfo,System.Classes, System.SysUtils, FpJson.Data, FpWeb.Rest.Base;
  9. {$ELSE FPC_DOTTEDUNITS}
  10. uses
  11. TypInfo,Classes, SysUtils, fpjson, restbase;
  12. {$ENDIF FPC_DOTTEDUNITS}
  13. Type
  14. TInt16 = Type Smallint;
  15. TInt32 = Type Integer;
  16. SByte = Type Shortint;
  17. TTimeOfDay = Type TDateTime;
  18. TDateTimeOffset = Type TDateTime;
  19. TGUIDString = Type string;
  20. TBinary = Array of Byte;
  21. TDuration = type string;
  22. { TGeography }
  23. TGeography = Class(TBaseObject)
  24. private
  25. FType: String;
  26. Public
  27. Class function AllowAdditionalProperties: Boolean; override;
  28. Published
  29. Property _type : String Read FType Write FType;
  30. end;
  31. { TGeographyPoint }
  32. TGeographyPoint = Class(TGeography)
  33. private
  34. FCoordinates: TDoubleArray;
  35. Procedure SetCoordinates(AIndex : integer; AValue : TDoubleArray);
  36. Published
  37. Property coordinates : TDoubleArray Index 8 Read FCoordinates Write SetCoordinates;
  38. end;
  39. TDoubleArrayArray = Array of TDoubleArray;
  40. { TGeographyLineString }
  41. TGeographyLineString = Class(TGeography)
  42. private
  43. FCoordinates: TDoubleArrayArray;
  44. Published
  45. Property coordinates : TDoubleArrayArray Read FCoordinates Write FCoordinates;
  46. end;
  47. TGeographyPolygon = Class(TGeography)
  48. end;
  49. TGeographyMultiPoint = Class(TGeography)
  50. end;
  51. TGeographyMultiLineString = Class(TGeography)
  52. end;
  53. TSByteArray = Array of SByte;
  54. TByteArray = Array of Byte;
  55. TInt32Array = Array of TInt32;
  56. TInt16Array = Array of TInt16;
  57. TDurationArray = Array of TDuration;
  58. TDateArray = Array of TDate;
  59. TTimeArray = Array of TTime;
  60. TTimeOfDayArray = Array of TTimeOfDay;
  61. TDateTimeOffsetArray = Array of TDateTimeOffset;
  62. TGUIDStringArray = Array of TGUIDString;
  63. TBinaryArray = Array of TBinary;
  64. TGeographyArray = Array of TGeography;
  65. TGeographyPointArray = Array of TGeographyPoint;
  66. TGeographyLineStringArray = Array of TGeographyLineString;
  67. TGeographyPolygonArray = Array of TGeographyPolygon;
  68. TGeographyMultiPointArray = Array of TGeographyMultiPoint;
  69. TGeographyMultiLineStringArray = Array of TGeographyMultiLineString;
  70. TAnnotation = TJSONEnum;
  71. { TODataObject }
  72. TODataObject = Class(TBaseObject)
  73. Private
  74. FAns : TJSONObject;
  75. function GetAnnotation(Index : Integer): TAnnotation;
  76. function GetAnnotationValue(AName : String): TJSONData;
  77. function GetDataAnnotationCount: Integer;
  78. Protected
  79. Procedure AddAnnotation(Const AName : String; AValue : TJSONData);
  80. Class Function DynArrayToJSONArray(A : Pointer; AType : string; AClassType : TBaseObjectClass = Nil) : TJSONArray;
  81. Class Function JSONArrayToDynArray(A : TJSONArray; AType : string; AClassType : TBaseObjectClass = Nil) : Pointer;
  82. Public
  83. Destructor Destroy; override;
  84. Procedure LoadPropertyFromJSON(Const AName : String; JSON : TJSONData); override;
  85. Class Function MakeKeyString(Const AKey : String) : String;
  86. Class Function AllowAdditionalProperties : Boolean; override;
  87. Property ODataAnnotations[Index : Integer] : TAnnotation Read GetAnnotation;
  88. Property ODataAnnotationValues[AName : String] : TJSONData Read GetAnnotationValue;
  89. Property ODataAnnotationCount : Integer Read GetDataAnnotationCount;
  90. end;
  91. TODataObjectClass = Class of TODataObject;
  92. TODataObjectArray = Array of TODataObject;
  93. TODataComplexType = Class(TODataObject);
  94. TODataComplexTypeClass = Class of TODataComplexType;
  95. { TODataError }
  96. TODataErrorDetail = Record
  97. Code : String;
  98. Message : String;
  99. Target : String;
  100. end;
  101. TODataErrorDetails = Array of TODataErrorDetail;
  102. TODataError = Class(TObject)
  103. private
  104. FCode: String;
  105. FDetails: TODataErrorDetails;
  106. FInnerError: String;
  107. FMessage: String;
  108. FTargetCode: String;
  109. Public
  110. Property Code : String Read FCode Write FCode;
  111. Property Message : String Read FMessage Write FMessage;
  112. Property Target : String Read FTargetCode Write FTargetCode;
  113. Property Details : TODataErrorDetails Read FDetails Write FDetails;
  114. // JSON
  115. Property InnerError : String Read FInnerError Write FInnerError;
  116. end;
  117. { EOData }
  118. EOData =Class(Exception)
  119. private
  120. FError: TODataError;
  121. FStatusCode: Integer;
  122. FStatusText: String;
  123. Public
  124. Destructor Destroy; override;
  125. Property StatusCode : Integer Read FStatusCode Write FStatusCode;
  126. Property StatusText : String Read FStatusText Write FStatusText;
  127. Property Error : TODataError Read FError Write FError;
  128. end;
  129. Function BinaryToString(B : TBinary) : String;
  130. implementation
  131. Function BinaryToString(B : TBinary) : String;
  132. Var
  133. E : Byte;
  134. begin
  135. Result:='';
  136. For E in B do
  137. Result:=Result+HexStr(E,2);
  138. end;
  139. { TGeographyPoint }
  140. Procedure TGeographyPoint.SetCoordinates(AIndex: integer; AValue: TDoubleArray);
  141. Var
  142. D : Double;
  143. begin
  144. { Writeln('Setting coordinates');
  145. For d in AValue do
  146. writeln('Got ',D);}
  147. FCoordinates:=AValue;
  148. end;
  149. { TGeography }
  150. Class function TGeography.AllowAdditionalProperties: Boolean;
  151. begin
  152. Result:=True;
  153. end;
  154. { EOData }
  155. Destructor EOData.Destroy;
  156. begin
  157. FreeAndNil(FError);
  158. inherited Destroy;
  159. end;
  160. { TODataObject }
  161. function TODataObject.GetAnnotation(Index : Integer): TAnnotation;
  162. begin
  163. If Not Assigned(FAns) or (Index<0) or (Index>=FAns.Count) then
  164. begin
  165. Result.Key:='';
  166. Result.KeyNum:=-1;
  167. Result.Value:=Nil;
  168. end
  169. else
  170. begin
  171. Result.Key:=FAns.Names[Index];
  172. Result.KeyNum:=Index;
  173. Result.Value:=FAns.Items[Index];
  174. end;
  175. end;
  176. function TODataObject.GetAnnotationValue(AName : String): TJSONData;
  177. Var
  178. I : Integer;
  179. begin
  180. Result:=Nil;
  181. if Assigned(FAns) then
  182. begin
  183. I:=FAns.IndexOfName(AName);
  184. if I<>-1 then
  185. Result:=FAns.Items[i];
  186. end;
  187. end;
  188. function TODataObject.GetDataAnnotationCount: Integer;
  189. begin
  190. if Assigned(FAns) then
  191. Result:=FAns.Count
  192. else
  193. Result:=0;
  194. end;
  195. Procedure TODataObject.AddAnnotation(Const AName: String; AValue: TJSONData);
  196. begin
  197. If Not Assigned(FAns) then
  198. FAns:=TJSONObject.Create();
  199. FAns.Add(AName,AValue.Clone);
  200. end;
  201. Type
  202. TShortIntArray = Array of ShortInt;
  203. TSmallIntArray = Array of SmallInt;
  204. TWordArray = Array of Word;
  205. TCardinalArray = Array of Cardinal;
  206. TQWordArray= Array of QWord;
  207. TSingleArray = Array of Single;
  208. Class Function TODataObject.DynArrayToJSONArray(A: Pointer; AType: string; AClassType : TBaseObjectClass = Nil): TJSONArray;
  209. Var
  210. I,L : Integer;
  211. begin
  212. Result:=TJSONArray.Create;
  213. L:=Length(TByteArray(A));
  214. Case LowerCase(aType) of
  215. 'boolean':
  216. For I:=0 to L-1 do
  217. Result.Add(TBooleanArray(A)[i]);
  218. 'byte',
  219. 'tsbyte':
  220. For I:=0 to L-1 do
  221. Result.Add(TByteArray(A)[i]);
  222. 'shortint':
  223. For I:=0 to L-1 do
  224. Result.Add(TShortIntArray(A)[i]);
  225. 'int16',
  226. 'tint16',
  227. 'smallint':
  228. For I:=0 to L-1 do
  229. Result.Add(TSmallIntArray(A)[i]);
  230. 'word':
  231. For I:=0 to L-1 do
  232. Result.Add(TWordArray(A)[i]);
  233. 'tint32',
  234. 'int32',
  235. 'integer':
  236. For I:=0 to L-1 do
  237. Result.Add(TIntegerArray(A)[i]);
  238. 'cardinal',
  239. 'dword':
  240. For I:=0 to L-1 do
  241. Result.Add(TCardinalArray(A)[i]);
  242. 'tint64',
  243. 'int64':
  244. For I:=0 to L-1 do
  245. Result.Add(TInt64Array(A)[i]);
  246. 'qword':
  247. For I:=0 to L-1 do
  248. {$IFNDEF VER2_6}
  249. Result.Add(TQWordArray(A)[i]);
  250. {$else}
  251. Result.Add(TInt64Array(A)[i]);
  252. {$ENDIF}
  253. 'string':
  254. For I:=0 to L-1 do
  255. Result.Add(TStringArray(A)[i]);
  256. 'tguidstring':
  257. For I:=0 to L-1 do
  258. Result.Add(TStringArray(A)[i]);
  259. 'double':
  260. For I:=0 to L-1 do
  261. Result.Add(TDoubleArray(A)[i]);
  262. 'single':
  263. For I:=0 to L-1 do
  264. Result.Add(TSingleArray(A)[i]);
  265. else
  266. if Pos('array',lowerCase(atype))<>0 then
  267. Raise EOData.Create('Cannot convert array of array: '+atype);
  268. if (AClassType=Nil) then
  269. Raise EOData.Create('Cannot convert array of object without class type');
  270. For I:=0 to L-1 do
  271. if (TObjectArray(A)[i].InheritsFrom(AClassType)) then
  272. Result.Add(TObjectArray(A)[i].SaveToJSON);
  273. end;
  274. end;
  275. Class Function TODataObject.JSONArrayToDynArray(A: TJSONArray; AType: string; AClassType : TBaseObjectClass = Nil ): Pointer;
  276. Var
  277. I,L : Integer;
  278. begin
  279. Result:=TJSONArray.Create;
  280. L:=A.Count;
  281. Case LowerCase(aType) of
  282. 'boolean':
  283. begin
  284. SetLength(TBooleanArray(Result),L);
  285. For I:=0 to L-1 do
  286. TBooleanArray(Result)[i]:=A.Booleans[i];
  287. end;
  288. 'byte',
  289. 'tsbyte':
  290. begin
  291. SetLength(TByteArray(Result),L);
  292. For I:=0 to L-1 do
  293. TByteArray(Result)[i]:=A.Integers[i];
  294. end;
  295. 'shortint':
  296. begin
  297. SetLength(TShortIntArray(Result),L);
  298. For I:=0 to L-1 do
  299. TShortIntArray(Result)[i]:=A.Integers[i];
  300. end;
  301. 'int16',
  302. 'tint16',
  303. 'smallint':
  304. begin
  305. SetLength(TSmallIntArray(Result),L);
  306. For I:=0 to L-1 do
  307. TSmallIntArray(Result)[i]:=A.Integers[i];
  308. end;
  309. 'word':
  310. begin
  311. SetLength(TWordArray(Result),L);
  312. For I:=0 to L-1 do
  313. TWordArray(Result)[i]:=A.Integers[i];
  314. end;
  315. 'tint32',
  316. 'int32',
  317. 'integer':
  318. begin
  319. SetLength(TIntegerArray(Result),L);
  320. For I:=0 to L-1 do
  321. TIntegerArray(Result)[i]:=A.Integers[i];
  322. end;
  323. 'cardinal',
  324. 'dword':
  325. begin
  326. SetLength(TCardinalArray(Result),L);
  327. For I:=0 to L-1 do
  328. TCardinalArray(Result)[i]:=A.Integers[i];
  329. end;
  330. 'tint64',
  331. 'int64':
  332. begin
  333. SetLength(TInt64Array(Result),L);
  334. For I:=0 to L-1 do
  335. TInt64Array(Result)[i]:=A.Int64s[i];
  336. end;
  337. 'qword':
  338. begin
  339. SetLength(TQWordArray(Result),L);
  340. For I:=0 to L-1 do
  341. {$IFDEF VER2_6}
  342. TInt64Array(Result)[i]:=A.Int64s[i];
  343. {$ELSE}
  344. TQWordArray(Result)[i]:=A.QWords[i];
  345. {$ENDIF}
  346. end;
  347. 'tstring',
  348. 'string':
  349. begin
  350. SetLength(TStringArray(Result),L);
  351. For I:=0 to L-1 do
  352. TStringArray(Result)[i]:=A.Strings[i];
  353. end;
  354. 'guidstring',
  355. 'tguidstring':
  356. begin
  357. SetLength(TStringArray(Result),L);
  358. For I:=0 to L-1 do
  359. TStringArray(Result)[i]:=A.Strings[i];
  360. end;
  361. 'double':
  362. begin
  363. SetLength(TDoubleArray(Result),L);
  364. For I:=0 to L-1 do
  365. TDoubleArray(Result)[i]:=A.Floats[i];
  366. end;
  367. 'single':
  368. begin
  369. SetLength(TSingleArray(Result),L);
  370. For I:=0 to L-1 do
  371. TSingleArray(Result)[i]:=A.Floats[i];
  372. end;
  373. else
  374. if (Pos('array',lowercase(atype))<>0) then
  375. Raise EOData.Create('Cannot convert array of array: '+atype);
  376. if (AClassType=Nil) then
  377. Raise EOData.Create('Cannot convert array of object without class type');
  378. SetLength(TObjectArray(Result),L);
  379. For I:=0 to L-1 do
  380. begin
  381. if A.Types[i]<>jtObject then
  382. Raise EOData.CreateFmt('Element %d of array is not an object: %s',[I,A.Items[i].AsJSON]);
  383. TObjectArray(Result)[i]:=AClassType.Create;
  384. TObjectArray(Result)[i].LoadFromJSON(A.Objects[i]);
  385. end;
  386. end;
  387. end;
  388. Destructor TODataObject.Destroy;
  389. begin
  390. FreeAndNil(FAns);
  391. Inherited;
  392. end;
  393. Procedure TODataObject.LoadPropertyFromJSON(Const AName: String; JSON: TJSONData
  394. );
  395. begin
  396. if (AName<>'') and (AName[1]='@') then
  397. AddAnnotation(AName,JSON)
  398. else
  399. inherited LoadPropertyFromJSON(AName, JSON);
  400. end;
  401. Class Function TODataObject.MakeKeyString(Const AKey: String): String;
  402. begin
  403. Result:=''''+AKey+'''';
  404. end;
  405. Class Function TODataObject.AllowAdditionalProperties: Boolean;
  406. begin
  407. Result:=True; // So we catch annnotations
  408. end;
  409. end.