odatabase.pp 11 KB

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