fpcgfieldmap.pp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. unit fpcgfieldmap;
  2. {$mode objfpc}{$H+}
  3. interface
  4. uses
  5. Classes, SysUtils, fpddcodegen;
  6. Type
  7. { TGenFieldMapOptions }
  8. TFieldMapOption = (fmoPublicFields,fmoRequireFields,fmoLoadObject);
  9. TFieldMapOptions = Set of TFieldMapOption;
  10. TGenFieldMapOptions = Class(TClassCodeGeneratorOptions)
  11. Private
  12. FOptions: TFieldMapOptions;
  13. FMapClassName : String;
  14. FMapAncestorClassName : String;
  15. Protected
  16. function GetMapAncestorName: String; virtual;
  17. function GetMapName: String; virtual;
  18. procedure SetMapAncestorName(const AValue: String); virtual;
  19. procedure SetMapClassName(const AValue: String); virtual;
  20. Public
  21. Constructor Create; override;
  22. Procedure Assign(ASource: TPersistent); override;
  23. Property MapAncestorName : String Read GetMapAncestorName Write SetMapAncestorName;
  24. Property MapClassName : String Read GetMapName Write SetMapClassName;
  25. Property AncestorClass;
  26. Published
  27. Property FieldMapOptions : TFieldMapOptions Read FOptions Write FOptions;
  28. end;
  29. { TDDDBFieldMapCodeGenerator }
  30. { TDDBaseFieldMapCodeGenerator }
  31. TDDBaseFieldMapCodeGenerator = Class(TDDClassCodeGenerator)
  32. private
  33. function GetOpt: TGenFieldMapOptions;
  34. Protected
  35. // Overrides;
  36. Function GetInterfaceUsesClause : string; override;
  37. Function CreateOptions : TCodeGeneratorOptions; override;
  38. // New methods
  39. procedure WriteFillMethod(Strings: TStrings; const ObjectClassName, MapClassName: String); virtual;
  40. procedure DoCreateFieldMapDeclaration(Strings: TStrings; const ObjectClassName,MapClassName, MapAncestorName: String); virtual;
  41. procedure WriteMapInitFields(Strings: TStrings; const ObjectClassName, MapClassName: String); virtual;
  42. procedure CreateFieldMapImplementation(Strings: TStrings; const ObjectClassName, MapClassName: String);
  43. Property FieldMapOpts : TGenFieldMapOptions Read Getopt;
  44. Public
  45. Class function NeedsFieldDefs: Boolean; override;
  46. procedure CreateFieldMapDeclaration(Strings: TStrings; const ObjectClassName,MapClassName, MapAncestorName: String);
  47. end;
  48. { TGenFieldMapCodeGenOptions }
  49. TGenFieldMapCodeGenOptions = class(TGenFieldMapOptions)
  50. Public
  51. constructor create; override;
  52. Published
  53. Property AncestorClass;
  54. Property MapClassName;
  55. Property MapAncestorName;
  56. end;
  57. TDDDBFieldMapCodeGenerator = Class(TDDBaseFieldMapCodeGenerator)
  58. Protected
  59. Function CreateOptions : TCodeGeneratorOptions; override;
  60. Procedure DoGenerateInterface(Strings: TStrings); override;
  61. Procedure DoGenerateImplementation(Strings: TStrings); override;
  62. Public
  63. Property FieldMapOpts;
  64. end;
  65. implementation
  66. uses typinfo;
  67. { TGenFieldMapCodeGenOptions }
  68. constructor TGenFieldMapCodeGenOptions.create;
  69. begin
  70. inherited create;
  71. FieldMapOptions:=[fmoLoadObject]
  72. end;
  73. { TDDDBFieldMapCodeGenerator }
  74. function TDDBaseFieldMapCodeGenerator.GetOpt: TGenFieldMapOptions;
  75. begin
  76. Result:=CodeOptions as TGenFieldMapOptions;
  77. end;
  78. function TDDBaseFieldMapCodeGenerator.GetInterfaceUsesClause: string;
  79. begin
  80. Result:=inherited GetInterfaceUsesClause;
  81. If (Result<>'') then
  82. Result:=Result+', db, fieldmap';
  83. end;
  84. procedure TDDDBFieldMapCodeGenerator.DoGenerateInterface(Strings: TStrings);
  85. begin
  86. inherited DoGenerateInterface(Strings);
  87. AddLn(Strings,'Type');
  88. CreatefieldMapDeclaration(Strings,GetOpt.ObjectClassName,GetOpt.MapClassName,GetOpt.MapAncestorName);
  89. end;
  90. procedure TDDDBFieldMapCodeGenerator.DoGenerateImplementation(Strings: TStrings
  91. );
  92. begin
  93. inherited DoGenerateImplementation(Strings);
  94. With FieldMapOpts do
  95. CreateFieldMapImplementation(Strings,ObjectClassName,MapClassName);
  96. end;
  97. Function TDDDBFieldMapCodeGenerator.CreateOptions : TCodeGeneratorOptions;
  98. begin
  99. Result:=TGenFieldMapCodeGenOptions.Create
  100. end;
  101. function TDDBaseFieldMapCodeGenerator.CreateOptions: TCodeGeneratorOptions;
  102. begin
  103. Result:=TGenFieldMapOptions.Create;
  104. end;
  105. procedure TDDBaseFieldMapCodeGenerator.DoCreateFieldMapDeclaration(
  106. Strings: TStrings; const ObjectClassName, MapClassName,
  107. MapAncestorName: String);
  108. Var
  109. I : Integer;
  110. F : TFieldPropDef;
  111. begin
  112. AddLn(Strings,'Private');
  113. IncIndent;
  114. Try
  115. For I:=0 to Fields.Count-1 do
  116. begin
  117. F:=Fields[I];
  118. If F.Enabled then
  119. AddLn(Strings,'F%s : TField;',[F.PropertyName]);
  120. end;
  121. Finally
  122. DecIndent;
  123. end;
  124. AddLn(Strings,'Public');
  125. IncIndent;
  126. Try
  127. AddLn(Strings,'Procedure InitFields; Override;');
  128. if fmoLoadObject in FieldMapOpts.FieldMapOptions then
  129. begin
  130. AddLn(Strings,'Procedure Fill(aObject: %s); virtual;',[ObjectClassName]);
  131. AddLn(Strings,'Procedure LoadObject(aObject: TObject); override;');
  132. end;
  133. if fmoPublicFields in FieldMapOpts.FieldMapOptions then
  134. For I:=0 to Fields.Count-1 do
  135. begin
  136. F:=Fields[I];
  137. If F.Enabled then
  138. AddLn(Strings,'Property %s : TField read F%s;',[F.PropertyName,F.FieldName]);
  139. end;
  140. Finally
  141. DecIndent;
  142. end;
  143. end;
  144. procedure TDDBaseFieldMapCodeGenerator.CreateFieldMapDeclaration(Strings: TStrings; const ObjectClassName, MapClassName, MapAncestorName: String);
  145. begin
  146. Addln(Strings);
  147. IncIndent;
  148. try
  149. Addln(Strings,'{ %s }',[MapClassName]);
  150. Addln(Strings);
  151. Addln(Strings,'%s = Class(%s)',[MapClassName,MapAncestorName]);
  152. DoCreateFieldMapDeclaration(Strings,ObjectClassName,MapClassName,MapAncestorName);
  153. AddLn(Strings,'end;');
  154. Finally
  155. DecIndent;
  156. end;
  157. end;
  158. procedure TDDBaseFieldMapCodeGenerator.CreateFieldMapImplementation(
  159. Strings: TStrings; const ObjectClassName, MapClassName: String);
  160. Var
  161. S : String;
  162. begin
  163. AddLn(Strings,' { %s }',[MapClassName]);
  164. AddLn(Strings);
  165. S:=Format('Procedure %s.InitFields;',[MapClassName]);
  166. BeginMethod(Strings,S);
  167. Try
  168. WriteMapInitFields(Strings,ObjectClassName,MapClassName);
  169. Finally
  170. EndMethod(Strings,S);
  171. end;
  172. if fmoLoadObject in FieldMapOpts.FieldMapOptions then
  173. begin
  174. WriteFillMethod(Strings, ObjectClassName, MapClassName);
  175. S:=Format('Procedure %s.LoadObject(aObject: TObject);',[MapClassName]);
  176. BeginMethod(Strings,S);
  177. Try
  178. Addln(Strings,'begin');
  179. IncIndent;
  180. AddLn(Strings,'Fill(aObject as %s);',[ObjectClassName]);
  181. DecIndent;
  182. finally
  183. EndMethod(Strings,S);
  184. end;
  185. end;
  186. end;
  187. class function TDDBaseFieldMapCodeGenerator.NeedsFieldDefs: Boolean;
  188. begin
  189. Result:=True;
  190. end;
  191. procedure TDDBaseFieldMapCodeGenerator.WriteFillMethod(Strings: TStrings; const ObjectClassName, MapClassName: String);
  192. Const
  193. SAddLoadCode = '// Add code to load property %s (of type %s) from field %s';
  194. SupportedPropTypes = [ptBoolean, // Boolean
  195. ptShortString, ptAnsiString, ptUtf8String, // Ansistring
  196. ptWord,ptByte,ptLongint,ptCardinal,ptSmallInt,ptShortInt, // Integer
  197. ptCurrency, // Currency
  198. ptDateTime // DateTime
  199. ];
  200. Var
  201. S,Fmt : String;
  202. F : TFieldPropDef;
  203. I : Integer;
  204. begin
  205. S:=Format('Procedure %s.Fill(aObject: %s);',[MapClassName,ObjectClassName]);
  206. BeginMethod(Strings,S);
  207. Try
  208. Addln(Strings,'begin');
  209. IncIndent;
  210. Fmt:='%s:=GetFromField(Self.F%s,%s);';
  211. Addln(Strings,'With aObject do');
  212. IncIndent;
  213. Addln(Strings,'begin');
  214. For I:=0 to Fields.Count-1 Do
  215. begin
  216. F:=Fields[i];
  217. If F.PropertyType in SupportedPropTypes then
  218. AddLn(Strings,Fmt,[F.PropertyName,F.PropertyName,F.PropertyName])
  219. else if F.PropertyType in [ptWideString, ptUnicodeString] then
  220. begin
  221. AddLn(Strings,'If Assigned(Self.F%s) then',[F.PropertyName]);
  222. incIndent;
  223. AddLn(Strings,'%s:=F%s.AsUnicodeString;',[F.PropertyName,F.PropertyName]);
  224. DecIndent;
  225. end
  226. else if F.PropertyType in [ptSingle,ptDouble,ptExtended,ptComp] then
  227. begin
  228. AddLn(Strings,'If Assigned(Self.F%s) then',[F.PropertyName]);
  229. incIndent;
  230. AddLn(Strings,'%s:=Self.F%s.AsFloat;',[F.PropertyName,F.PropertyName]);
  231. DecIndent;
  232. end
  233. else if F.PropertyType in [ptInt64,ptQWord] then
  234. begin
  235. AddLn(Strings,'If Assigned(Self.F%s) then',[F.PropertyName]);
  236. incIndent;
  237. AddLn(Strings,'%s:=Self.F%s.AsLargeInt;',[F.PropertyName,F.PropertyName]);
  238. DecIndent;
  239. end
  240. else
  241. AddLn(Strings,SAddLoadCode,[F.PropertyName,GetEnumName(TypeInfo(TPropType),Ord(F.PropertyType)), F.FieldName]);
  242. end;
  243. Addln(Strings,'end;');
  244. DecIndent;
  245. Finally
  246. DecIndent;
  247. EndMethod(Strings,S);
  248. end;
  249. end;
  250. procedure TDDBaseFieldMapCodeGenerator.WriteMapInitFields(Strings: TStrings;
  251. const ObjectClassName, MapClassName: String);
  252. Const
  253. Finders : Array[Boolean] of string = ('FindField','FieldByName');
  254. Var
  255. I: Integer;
  256. F : TFieldPropDef;
  257. Fmt : String;
  258. begin
  259. AddLn(Strings,'begin');
  260. IncIndent;
  261. try
  262. Fmt:='F%s:='+Finders[fmoRequireFields in FieldMapOpts.FieldMapOptions]+'(%s);';
  263. For I:=0 to Fields.Count-1 Do
  264. begin
  265. F:=Fields[i];
  266. If F.Enabled then
  267. AddLn(Strings,Fmt,[F.PropertyName,CreateString(F.FieldName)]);
  268. end;
  269. Finally
  270. DecIndent;
  271. end;
  272. end;
  273. { TGenFieldMapOptions }
  274. function TGenFieldMapOptions.GetMapAncestorName: String;
  275. begin
  276. Result:=FMapAncestorClassName;
  277. if Result='' then
  278. Result:='TFieldMap';
  279. end;
  280. function TGenFieldMapOptions.GetMapName: String;
  281. begin
  282. Result:=FMapClassName;
  283. if Result='' then
  284. Result:=ObjectClassName+'Map';
  285. end;
  286. procedure TGenFieldMapOptions.SetMapAncestorName(const AValue: String);
  287. begin
  288. FMapAncestorClassName:=AValue;
  289. end;
  290. procedure TGenFieldMapOptions.SetMapClassName(const AValue: String);
  291. begin
  292. FMapClassName:=AValue;
  293. end;
  294. constructor TGenFieldMapOptions.Create;
  295. begin
  296. inherited Create;
  297. AncestorClass:='TObject';
  298. ObjectClassName:='TMyObject';
  299. MapClassName:='TMyObjectMap';
  300. MapAncestorName:='TFieldMap';
  301. end;
  302. procedure TGenFieldMapOptions.Assign(ASource: TPersistent);
  303. Var
  304. O : TGenFieldMapOptions;
  305. begin
  306. if ASource is TGenFieldMapOptions then
  307. begin
  308. O:=ASource as TGenFieldMapOptions;
  309. MapClassName:=O.MapClassName;
  310. MapAncestorName:=O.MapAncestorName;
  311. FieldMapOptions:=O.FieldMapOptions;
  312. end;
  313. inherited Assign(ASource);
  314. end;
  315. Initialization
  316. RegisterCodeGenerator('FieldMap','Object and TFieldMap descendent.',TDDDBFieldMapCodeGenerator);
  317. Finalization
  318. UnRegisterCodeGenerator(TDDDBFieldMapCodeGenerator);
  319. end.