odatacodegen.pp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545
  1. unit odatacodegen;
  2. {$mode objfpc}{$H+}
  3. interface
  4. uses
  5. Classes, SysUtils, pastree, restcodegen, inifiles;
  6. Type
  7. EEDMX2PasConverter = Class(Exception);
  8. // Extra set of keywords to take into account when cleaning a property name.
  9. TExtraKeyWords = (ekwNone,ekwObject,ekwEntity,ekwEntitySet,ekwEntityContainer,ekwservice);
  10. TODataVersion = (ODataV2,ODataV4);
  11. TEnumerationMode = (emScoped,emPrefixTypeName,emPlain);
  12. { TPropertySetter }
  13. TPropertyFlag = (pfRequired,pfNavigation, pfIndexed, pfReadOnly, pfNeedSetter, pfNeedGetter, pfInkey);
  14. TPropertyFlags = Set of TPropertyFlag;
  15. TResultType = (rtNone,rtSimple,rtObject,rtArraySimple,rtArrayObject);
  16. // Specialized TPasElement classes.
  17. // Using these tells the code generator what kind of code it must generate for an identifier.
  18. TPropertySetter = Class(TPasProcedure)
  19. private
  20. FProp: TPasElement;
  21. Public
  22. Property TheProperty : TPasElement Read FProp Write FProp;
  23. end;
  24. TPropertyGetter = Class(TPasFunction)
  25. private
  26. FProp: TPasElement;
  27. Public
  28. Property TheProperty : TPasElement Read FProp Write FProp;
  29. end;
  30. TGetRestKind = Class(TPasProcedure);
  31. TObjectRestKind = Class(TPasClassFunction);
  32. TExportPropertyName = class(TPasClassFunction);
  33. TCreateContainer = Class(TPasFunction);
  34. TCreateEntitySet = Class(TPasFunction);
  35. TEntityClassFunction = Class(TPasClassFunction);
  36. TGetNavigationProperty = Class(TPasFunction);
  37. TGetSingleton = Class(TPasFunction);
  38. TGetContainedSingleton = Class(TPasFunction);
  39. TKeyAsURLPart = Class(TPasFunction);
  40. TEntityMethod = Class(TPasFunction);
  41. TSetArrayLength = Class(TPasProcedure);
  42. TGetStream = Class(TPasProcedure);
  43. TSetStream = Class(TPasProcedure);
  44. TBoundFunction = Class(TPasFunction);
  45. TBoundActionProc = Class(TPasProcedure);
  46. TBoundActionFunc = Class(TPasFunction);
  47. TUnBoundFunction = Class(TPasFunction)
  48. private
  49. FPath: STring;
  50. Public
  51. Property ExportPath : STring Read FPath Write FPath;
  52. end;
  53. TUnBoundActionFunc = Class(TPasFunction)
  54. private
  55. FPath: STring;
  56. Public
  57. Property ExportPath : STring Read FPath Write FPath;
  58. end;
  59. TUnBoundActionProc = Class(TPasProcedure)
  60. private
  61. FPath: STring;
  62. Public
  63. Property ExportPath : STring Read FPath Write FPath;
  64. end;
  65. TEntityGet = Class(TEntityMethod);
  66. TEntityList = Class(TEntityMethod);
  67. TEntityListAll = Class(TEntityList);
  68. TEntityPut = Class(TEntityMethod);
  69. TEntityPatch = Class(TEntityMethod);
  70. TEntityPost = Class(TEntityMethod);
  71. TEntityDelete = Class(TEntityMethod);
  72. TServiceClass = Class(TPasClassType);
  73. TComplexClass = Class(TPasClassType);
  74. TEntityClass = Class(TPasClassType);
  75. TEntityContainerClass = Class(TPasClassType);
  76. TEntitySetClass = Class(TPasClassType);
  77. { TODataCodeGenerator }
  78. TODataCodeGenerator = class(TRestCodeGenerator)
  79. private
  80. FAliases: TStrings;
  81. FBaseComplexType: String;
  82. FBaseEntityContainerType: String;
  83. FBaseEntitySetType: String;
  84. FBaseEntityType: String;
  85. FBaseServiceType: String;
  86. FEnumerationMode: TEnumerationMode;
  87. FFieldPrefix: String;
  88. FSchemaAncestor: String;
  89. FServiceSuffix: String;
  90. FReservedWords : TStringList;
  91. FIdentifierMap : TStrings;
  92. procedure SetAliases(AValue: TStrings);
  93. function GetReservedWords: TStrings;
  94. procedure SetReservedWords(AValue: TStrings);
  95. Protected
  96. procedure EmitOptions; virtual;
  97. function ConvertTypeToStringExpr(const ExprName, ExprType: String): String;
  98. Function GetResultType(Const aType: String; Out AElementType : String): TResultType;
  99. function GetBaseClassName(El: TPasClassType): String;
  100. Procedure RegisterBaseTypes; virtual;
  101. function IsSimpleType(const aType: String): Boolean;
  102. function FlattenName(const AName: String): String;
  103. procedure WriteProcedureDecl(P: TPasProcedure);
  104. function CleanPropertyName(const AName: String; UseExtra: TExtraKeyWords): string;
  105. function CleanPropertyName(const AName: UnicodeString; UseExtra: TExtraKeyWords): string;
  106. Function CountProperties(C: TPasClassType): Integer;
  107. Property IdentifierMap : TStrings Read FIdentifierMap;
  108. Public
  109. Constructor Create(AOwner : TComponent); override;
  110. Destructor destroy; override;
  111. Class Function WTOA(Const S : UnicodeString) : String;
  112. Function is26Only(P: TPasProcedure): Boolean;
  113. Function BaseUnits : String; override;
  114. Class function IndentStrings(S: TStrings; aindent: Integer): string;
  115. Class Function ODataVersion : TODataVersion; virtual; abstract;
  116. Published
  117. Property BaseComplexType : String Read FBaseComplexType Write FBaseComplexType;
  118. Property BaseEntityType : String Read FBaseEntityType Write FBaseEntityType;
  119. Property BaseEntityContainerType : String Read FBaseEntityContainerType Write FBaseEntityContainerType;
  120. Property BaseServiceType : String Read FBaseServiceType Write FBaseServiceType;
  121. Property BaseEntitySetType : String Read FBaseEntitySetType Write FBaseEntitySetType;
  122. Property Aliases : TStrings Read FAliases Write SetAliases;
  123. Property SchemaAncestor : String Read FSchemaAncestor Write FSchemaAncestor;
  124. Property FieldPrefix: String Read FFieldPrefix Write FFieldPrefix;
  125. Property ServiceSuffix : String Read FServiceSuffix Write FServiceSuffix;
  126. property EnumerationMode : TEnumerationMode Read FEnumerationMode Write FEnumerationMode;
  127. Property ReservedWords : TStrings Read GetReservedWords Write SetReservedWords;
  128. end;
  129. implementation
  130. { TODataCodeGenerator }
  131. procedure TODataCodeGenerator.SetAliases(AValue: TStrings);
  132. begin
  133. if FAliases=AValue then Exit;
  134. FAliases.Assign(AValue);
  135. end;
  136. constructor TODataCodeGenerator.Create(AOwner: TComponent);
  137. begin
  138. inherited Create(AOwner);
  139. BaseClassName:='TODataObject';
  140. BaseComplexType:='TODataObject';
  141. BaseEntityType:='TODataEntity';
  142. BaseEntityContainerType:='TODataEntityContainer';
  143. BaseServiceType:='TODataService';
  144. BaseEntitySetType:='TODataEntitySet';
  145. SchemaAncestor:='TObject';
  146. FieldPrefix:='F';
  147. ServiceSuffix:='_';
  148. FAliases:=TStringlist.Create;
  149. FIdentifierMap:=THashedStringList.Create;
  150. end;
  151. destructor TODataCodeGenerator.destroy;
  152. begin
  153. FreeAndNil(FAliases);
  154. FreeAndNil(FReservedWords);
  155. FreeAndNil(FIdentifierMap);
  156. Inherited;
  157. end;
  158. function TODataCodeGenerator.BaseUnits: String;
  159. begin
  160. Result:='fpjson, restbase, odatabase, odataservice';
  161. end;
  162. function TODataCodeGenerator.GetReservedWords: TStrings;
  163. begin
  164. if (FReservedWords=Nil) then
  165. begin
  166. FReservedWords:=TStringList.Create;
  167. FReservedWords.Sorted:=True;
  168. end;
  169. Result:=FReservedWords;
  170. end;
  171. procedure TODataCodeGenerator.SetReservedWords(AValue: TStrings);
  172. begin
  173. if AValue=FReservedwords then exit;
  174. if AValue.Count=0 then
  175. FreeAndNil(FReservedWords)
  176. else
  177. ReservedWords.Assign(AValue);
  178. end;
  179. class function TODataCodeGenerator.WTOA(const S: UnicodeString): String;
  180. begin
  181. Result:=AnsiString(S);
  182. end;
  183. function TODataCodeGenerator.is26Only(P: TPasProcedure): Boolean;
  184. begin
  185. Result:=P is TSetArrayLength;
  186. end;
  187. class function TODataCodeGenerator.IndentStrings(S: TStrings; aindent: Integer
  188. ): string;
  189. Var
  190. I,CurrLen,CurrPos : Integer;
  191. begin
  192. Result:='';
  193. CurrLen:=0;
  194. CurrPos:=0;
  195. For I:=0 to S.Count-1 do
  196. begin
  197. CurrLen:=Length(S[i]);
  198. If (CurrLen+CurrPos)>72 then
  199. begin
  200. Result:=Result+LineEnding+StringOfChar(' ',aIndent);
  201. CurrPos:=aIndent;
  202. end;
  203. Result:=Result+S[i];
  204. CurrPos:=CurrPos+CurrLen;
  205. end;
  206. end;
  207. procedure TODataCodeGenerator.WriteProcedureDecl(P : TPasProcedure);
  208. Var
  209. S : TStrings;
  210. R: TPasResultElement;
  211. T : String;
  212. B : Boolean;
  213. begin
  214. S:=TStringList.Create;
  215. try
  216. S.Add(P.TypeName+' '+P.Name);
  217. P.ProcType.GetArguments(S);
  218. if P.ProcType.InheritsFrom(TPasFunctionType) then
  219. If Assigned(TPasFunctionType(P.ProcType).ResultEl) then
  220. begin
  221. R:=TPasFunctionType(P.ProcType).ResultEl;
  222. T:=' : ';
  223. If (R.ResultType.Name<>'') then
  224. T:=T+R.ResultType.Name
  225. else
  226. T:=T+R.ResultType.GetDeclaration(False);
  227. S.Add(T);
  228. end;
  229. P.GetModifiers(S);
  230. B:=Is26Only(P);
  231. if B then
  232. AddLn('{$IFDEF VER2_6}');
  233. AddLn(IndentStrings(S,Length(S[0]))+';');
  234. if B then
  235. AddLn('{$ENDIF VER2_6}');
  236. finally
  237. S.Free;
  238. end;
  239. end;
  240. function TODataCodeGenerator.CleanPropertyName(const AName: String;
  241. UseExtra: TExtraKeyWords): string;
  242. Const
  243. // Pascal keywords
  244. KW=';absolute;and;array;asm;begin;case;const;constructor;destructor;div;do;'+
  245. 'downto;else;end;file;for;function;goto;if;implementation;in;inherited;'+
  246. 'inline;interface;label;mod;nil;not;object;of;on;operator;or;packed;'+
  247. 'procedure;program;record;reintroduce;repeat;self;set;shl;shr;string;then;'+
  248. 'to;type;unit;until;uses;var;while;with;xor;dispose;exit;false;new;true;'+
  249. 'as;class;dispinterface;except;exports;finalization;finally;initialization;'+
  250. 'inline;is;library;on;out;packed;property;raise;resourcestring;threadvar;try;'+
  251. 'private;published;length;setlength;result;';
  252. // Reserved words (methods)
  253. RWComponent = ';post;component;name;notification;componentcount;';
  254. RWOdataObject = 'destroy;loadPropertyfromjson;makekeystring;allowadditionalproperties;odataannotations;odataannotationvalues;odataannotationcount;';
  255. RWEntity = 'baseurl;keyasurlpart;delete;basepath;post;put;patch;';
  256. RWEntitySet = RWComponent+'getbaseurl;checkservice;checkcontainer;notification;getsingle;getmulti;containerurl;containedpath;service;objectrestkind;entityclass;getservice;container;';
  257. RWEntityContainer = RWComponent+'checkservice;objectrestkind;entitycontainername;defaultservice;createentityset;service;';
  258. RWService = RWComponent+'dolog;composeurl;service;jsontoodataerror;resptoerror;objectrestkind;servicename;registerservice;registerentitycontainers;addtoquery;'+
  259. 'queryparamstostring;servicecall;getstream;setstream;arrayservicecall;getmulti;createentitycontainer;getentityclass;onlog;webclient;serviceurl;apineedsauth;'+
  260. 'odatarequestheaders;lastresponseheaders;odatametadata;';
  261. Var
  262. I : Integer;
  263. RW : String;
  264. begin
  265. Result:=Aname;
  266. For I:=Length(Result) downto 1 do
  267. If Not ((Upcase(Result[i]) in ['_','A'..'Z'])
  268. or ((I>1) and (Result[i] in (['0'..'9'])))) then
  269. Delete(Result,i,1);
  270. if Pos(';'+lowercase(Result)+';',KW)<>0 then
  271. Result:='_'+Result;
  272. if UseExtra<>ekwNone then
  273. begin
  274. Case useExtra of
  275. ekwObject : RW:=RWOdataObject;
  276. ekwEntity : RW:=RWEntity;
  277. ekwEntitySet : RW:=RWEntitySet;
  278. ekwEntityContainer : RW:=RWEntityContainer;
  279. ekwservice : RW:=RWService;
  280. end;
  281. if Pos(';'+lowercase(Result)+';',RW)<>0 then
  282. Result:='_'+Result;
  283. if Assigned(FReservedWords) then
  284. if FReservedWords.IndexOf(Result)<>-1 then
  285. Result:='_'+Result;
  286. end;
  287. end;
  288. function TODataCodeGenerator.CleanPropertyName(const AName: UnicodeString;
  289. UseExtra: TExtraKeyWords): string;
  290. begin
  291. Result:=CleanpropertyName(WTOA(AName),UseExtra);
  292. end;
  293. function TODataCodeGenerator.FlattenName(const AName: String): String;
  294. begin
  295. Result:=StringReplace(AName,'.','_',[rfReplaceAll]);
  296. end;
  297. function TODataCodeGenerator.IsSimpleType(const aType: String): Boolean;
  298. begin
  299. Case LowerCase(aType) of
  300. 'boolean': Result:=True;
  301. 'byte' : Result:=True;
  302. 'tsbyte': Result:=True;
  303. 'shortint': Result:=True;
  304. 'int16': Result:=True;
  305. 'smallint': Result:=True;
  306. 'word': Result:=True;
  307. 'int32': Result:=True;
  308. 'integer': Result:=True;
  309. 'cardinal': Result:=True;
  310. 'dword': Result:=True;
  311. 'int64': Result:=True;
  312. 'qwordl': Result:=True;
  313. 'tint16': Result:=True;
  314. 'tint32': Result:=True;
  315. 'tint64': Result:=True;
  316. 'string': Result:=True;
  317. 'guidstring': Result:=True;
  318. 'tguidstring': Result:=True;
  319. 'double': Result:=True;
  320. 'single': Result:=True;
  321. else
  322. Result:=False;
  323. end;
  324. end;
  325. procedure TODataCodeGenerator.RegisterBaseTypes;
  326. Const
  327. TypeCount = 68;
  328. BaseTypes : Array[1..TypeCount,1..2] of String =
  329. (('Edm.Byte','Byte'), ('Collection(Edm.Byte)','TByteArray'),
  330. ('Edm.SByte','TSByte'), ('Collection(Edm.SByte)','TShortintArray'),
  331. ('Edm.int16','TInt16'), ('Collection(Edm.int16)','TInt16Array'),
  332. ('Edm.int32','TInt32'), ('Collection(Edm.int32)','TInt32Array'),
  333. ('Edm.int64','int64'), ('Collection(Edm.int64)','TInt64Array'),
  334. ('Edm.string','string'), ('Collection(Edm.string)','TStringArray'),
  335. ('Edm.Guid','TGUIDString'), ('Collection(Edm.guid)','TGuidStringArray'),
  336. ('Edm.Duration','TDuration'), ('Collection(Edm.Duration)','TStringArray'),
  337. ('Edm.Boolean','boolean'), ('Collection(Edm.boolean)','TBooleanArray'),
  338. ('Edm.Date','TDate'), ('Collection(Edm.Date)','TDateArray'),
  339. ('Edm.DateTime','TDateTime'), ('Collection(Edm.DateTime)','TDateTimeArray'),
  340. ('Edm.Time','TTime'), ('Collection(Edm.Time)','TTimeArray'),
  341. ('Edm.TimeOfDay','TTimeOfDay'), ('Collection(Edm.TimeOfDay)','TTimeOfDayArray'),
  342. ('Edm.DateTimeOffset','TDateTime'), ('Collection(Edm.DateTimeOffcset)','TDateTimeArray'),
  343. ('Edm.Decimal','double'), ('Collection(Edm.Decimal)','TDoubleArray'),
  344. ('Edm.Double','Double'), ('Collection(Edm.Double)','TDoubleArray'),
  345. ('Edm.Single','Single'), ('Collection(Edm.Single)','TSingleArray'),
  346. ('Edm.Binary','TBinary'), ('Collection(Edm.Binary)','TBinaryArray'),
  347. ('Edm.Stream','TStream'), ('Collection(Edm.Stream)','TByteArrayArray'),
  348. ('Edm.Geography','TGeography'), ('Collection(Edm.Geography)','TGeographyArray'),
  349. ('Edm.GeographyPoint','TGeographyPoint'), ('Collection(Edm.GeographyPoint)','TGeographyPointArray'),
  350. ('Edm.GeographyPolygon','TGeographyPolygon'), ('Collection(Edm.GeographyPolygon)','TGeographyPolygonArray'),
  351. ('Edm.GeographyLineString','TGeographyLineString'), ('Collection(Edm.GeographyLineString)','TGeographyLineStringArray'),
  352. ('Edm.GeographyMultiPoint','TGeographyMultiPoint'), ('Collection(Edm.GeographyMultiPoint)','TGeographyMultiPointArray'),
  353. ('Edm.GeographyMultiString','TGeographyMultiLineString'), ('Collection(Edm.GeographyMultiLineString)','TGeographyMultiLineStringArray'),
  354. ('Edm.GeographyMultiPolygon','TGeographyMultiPolygon'), ('Collection(Edm.GeographyMultiPolygon)','TGeographyMultiPolygonArray'),
  355. ('Edm.Geometry','TGeometry'), ('Collection(Edm.Geometry)','TGeometryArray'),
  356. ('Edm.GeometryPoint','TGeometryPoint'), ('Collection(Edm.GeometryPoint)','TGeometryPointArray'),
  357. ('Edm.GeometryPolygon','TGeometryPolygon'), ('Collection(Edm.GeometryPolygon)','TGeometryPolygonArray'),
  358. ('Edm.GeometryLineString','TGeometryLineString'), ('Collection(Edm.GeometryLineString)','TGeometryLineStringArray'),
  359. ('Edm.GeometryMultiPoint','TGeometryMultiPoint'), ('Collection(Edm.GeometryMultiPoint)','TGeometryMultiPointArray'),
  360. ('Edm.GeometryMultiString','TGeometryMultiLineString'), ('Collection(Edm.GeometryMultiLineString)','TGeometryMultiLineStringArray'),
  361. ('Edm.GeometryMultiPolygon','TGeometryMultiPolygon'), ('Collection(Edm.GeometryMultiPolygon)','TGeometryMultiPolygonArray'),
  362. ('Edm.GeographyCollection','TGeographyArray'), ('Edm.GeometryCollection','TGeometryArray')
  363. );
  364. Var
  365. I : integer;
  366. begin
  367. For I:=1 to TypeCount do
  368. FIdentifierMap.Add(LowerCase(BaseTypes[I,1])+'='+BaseTypes[I,2]);
  369. end;
  370. function TODataCodeGenerator.GetBaseClassName(El: TPasClassType): String;
  371. begin
  372. Result:='';
  373. if Assigned(EL.AncestorType) then
  374. Result:=EL.AncestorType.Name;
  375. if (Result='') then
  376. begin
  377. if EL.InheritsFrom(TServiceClass) then
  378. Result:=BaseServiceType
  379. else if EL.InheritsFrom(TEntityContainerClass) then
  380. Result:=BaseEntityContainerType
  381. else if EL.InheritsFrom(TEntitySetClass) then
  382. Result:=BaseEntitySetType
  383. else if EL.InheritsFrom(TEntityClass) then
  384. Result:=BaseEntityType
  385. else if EL.InheritsFrom(TComplexClass) then
  386. Result:=BaseComplexType
  387. else
  388. Result:=BaseClassName;
  389. end;
  390. end;
  391. function TODataCodeGenerator.CountProperties(C: TPasClassType): Integer;
  392. Var
  393. I : Integer;
  394. begin
  395. Result:=0;
  396. While (C<>Nil) do
  397. begin
  398. For I:=0 to C.Members.Count-1 do
  399. If TObject(C.Members[i]) is TPasProperty then
  400. Inc(Result);
  401. if C.AncestorType is TPasClassType then
  402. C:=C.AncestorType as TPasClassType
  403. else
  404. C:=Nil;
  405. end;
  406. end;
  407. function TODataCodeGenerator.GetResultType(const aType: String; out
  408. AElementType: String): TResultType;
  409. Var
  410. P : Integer;
  411. EN : String;
  412. begin
  413. P:=Pos('array',lowercase(aType));
  414. if (aType='') then
  415. Result:=rtNone
  416. else if IsSimpleType(AType) then
  417. Result:=rtSimple
  418. else if P>0 then
  419. begin
  420. AElementType:=Copy(atype,1,P-1);
  421. EN:=AElementType;
  422. if (EN<>'') and (EN[1]='T') then
  423. Delete(EN,1,1);
  424. if IsSimpleType(EN) then
  425. begin
  426. Result:=rtArraySimple;
  427. AElementType:=EN;
  428. end
  429. else
  430. Result:=rtArrayObject;
  431. end
  432. else
  433. Result:=rtObject;
  434. end;
  435. function TODataCodeGenerator.ConvertTypeToStringExpr(const ExprName,
  436. ExprType: String): String;
  437. begin
  438. Case LowerCase(ExprType) of
  439. 'boolean' : Result:='BoolToStr('+ExprName+',''true'',''false'')';
  440. 'byte' : Result:='IntToStr('+ExprName+')';
  441. 'tsbyte': Result:='IntToStr('+ExprName+')';
  442. 'int16': Result:='IntToStr('+ExprName+')';
  443. 'int32': Result:='IntToStr('+ExprName+')';
  444. 'int64': Result:='IntToStr('+ExprName+')';
  445. 'tint16': Result:='IntToStr('+ExprName+')';
  446. 'tint32': Result:='IntToStr('+ExprName+')';
  447. 'tint64': Result:='IntToStr('+ExprName+')';
  448. 'string': Result:='TODataObject.MakeKeyString('+ExprName+')';
  449. 'tguidstring': Result:='TODataObject.MakeKeyString('+ExprName+')';
  450. 'tdatetime': Result:='FormatDateTime(''yyyy-mm-dd"T"hhmmss'','+ExprName+')';
  451. 'double': Result:='FloatToStr('+ExprName+')';
  452. 'single': Result:='FloatToStr('+ExprName+')';
  453. 'tbinary' : Result:='BinaryToString('+ExprName+')';
  454. else
  455. Raise EEDMX2PasConverter.CreateFmt('GET : Unsupported key type "%s" for %s',[ExprType,ExprName]);
  456. end;
  457. end;
  458. procedure TODataCodeGenerator.EmitOptions;
  459. Var
  460. I : Integer;
  461. S : String;
  462. begin
  463. Addln('(*');
  464. IncIndent;
  465. Addln('Options used to generate: ');
  466. Str(ODataVersion,S);
  467. Addln('OData version : '+S);
  468. Addln('BasecomplexType : '+BaseComplexType);
  469. Addln('BaseEntityType : '+BaseEntityType);
  470. Addln('BaseEntityContainerType : '+BaseEntityContainerType);
  471. Addln('BaseServiceType : '+BaseServiceType);
  472. Addln('BaseEntitySetType : '+BaseEntitySetType);
  473. For I:=0 to Aliases.Count-1 do
  474. Addln('Aliases[%d] : %s',[i,Aliases[i]]);
  475. Addln('SchemaAncestor : '+SchemaAncestor);
  476. Addln('FieldPrefix : '+FieldPrefix);
  477. Addln('ServiceSuffix : '+ServiceSuffix);
  478. Str(EnumerationMode,S);
  479. Addln('EnumerationMode : '+S);
  480. decIndent;
  481. Addln('*)');
  482. end;
  483. end.