fpddpopcode.pp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589
  1. unit FPDDPopCode;
  2. {$mode objfpc}{$H+}
  3. interface
  4. uses
  5. Classes, SysUtils, typinfo, fpdatadict, db;
  6. Type
  7. TDDCodeGenOption = (dcoFields,dcoIndexes,dcoProcedurePerTable,dcoUseWith,
  8. dcoClassDecl,dcoGenerators,dcoDomains,dcoMergeDomains);
  9. TDDCodeGenOptions = Set of TDDCodeGenoption;
  10. { TFPDDPopulateCodeGenerator }
  11. TFPDDPopulateCodeGenerator = Class(TComponent)
  12. private
  13. FClassName: String;
  14. FDD: TFPDataDictionary;
  15. FDDV: String;
  16. FIndent: Integer;
  17. FCurrentIndent: Integer;
  18. FOptions: TDDCodeGenOptions;
  19. FTables: TStrings;
  20. FProcedures : TStrings;
  21. procedure SetOptions(const AValue: TDDCodeGenOptions);
  22. procedure SetTables(const AValue: TStrings);
  23. Protected
  24. // General code generating routines
  25. procedure AddProperty(const ObjName, PropName, PropValue: String; Lines: TStrings);
  26. procedure AddProperty(const ObjName, PropName: String; PropValue: Boolean; Lines: TStrings);
  27. procedure AddStringProperty(const ObjName, PropName, PropValue: String; Lines: TStrings);
  28. procedure AddProcedure(AProcedureName: String; Lines: TStrings); virtual;
  29. procedure EndProcedure(Lines: TStrings);
  30. Procedure Indent;
  31. Procedure Undent;
  32. procedure AddLine(ALine: String; Lines: TStrings); virtual;
  33. Function EscapeString(Const S : String) : string;
  34. procedure CreateClassDecl(Lines: TStrings); virtual;
  35. // Data dictionare specific
  36. procedure CheckDatadict;
  37. procedure CreateFooter(Lines: TStrings);
  38. procedure CreateHeader(Lines: TStrings);
  39. // Table code
  40. Function DoTable (Const ATable : TDDtableDef) : Boolean; virtual;
  41. procedure CreateTableCode(T: TDDTableDef; Lines: TStrings);
  42. procedure AddTableVars(Lines: TStrings);
  43. procedure AddDomainVars(Lines: TStrings);
  44. procedure AddSequenceVars(Lines: TStrings);
  45. procedure DoTableHeader(ATable: TDDTableDef; Lines: TStrings);
  46. procedure DoTableFooter(ATable: TDDTableDef; Lines: TStrings);
  47. // Field code
  48. Function DoField (Const ATable : TDDtableDef; Const AField : TDDFieldDef) : Boolean; virtual;
  49. procedure CreateFieldCode(ATable: TDDTableDef; AField: TDDFieldDef; Lines: TStrings);
  50. // Index code
  51. Function DoIndex (Const ATable : TDDtableDef; Const AIndex : TDDIndexDef) : Boolean; virtual;
  52. procedure CreateIndexCode(ATable: TDDTableDef; AIndex: TDDIndexDef; Lines: TStrings);
  53. // Sequence code
  54. Procedure WriteSequences(Const ASequences : TDDSequenceDefs; Lines :TStrings);
  55. Function DoSequence (Const ASequence : TDDSequenceDef) : Boolean; virtual;
  56. procedure CreateSequenceCode(ASequence: TDDSequenceDef; Lines: TStrings);
  57. // Domain code
  58. Procedure WriteDomains(Const ADomains : TDDDomainDefs; Lines :TStrings);
  59. Function DoDomain (Const ADomain : TDDDomainDef) : Boolean; virtual;
  60. procedure CreateDomainCode(ADomain: TDDDomainDef; Lines: TStrings);
  61. Public
  62. Constructor Create(AOwner : TComponent); override;
  63. Destructor Destroy; override;
  64. Procedure CreateCode(Lines : TStrings);
  65. Property DataDictionary : TFPDataDictionary Read FDD Write FDD;
  66. Published
  67. Property Options : TDDCodeGenOptions Read FOptions Write SetOptions;
  68. Property Tables : TStrings Read FTables Write SetTables;
  69. Property IndentSize : Integer Read FIndent Write FIndent;
  70. Property DDVarName : String Read FDDV Write FDDV;
  71. Property ClassName : String Read FClassName Write FClassName;
  72. end;
  73. implementation
  74. Resourcestring
  75. SErrNoDataDictionary = 'Cannot perform this operation without datadictionary';
  76. SErrNoDataDictionaryName = 'Cannot perform this operation without datadictionary name';
  77. { TFPDDPopulateCodeGenerator }
  78. procedure TFPDDPopulateCodeGenerator.SetOptions(const AValue: TDDCodeGenOptions);
  79. begin
  80. if FOptions=AValue then exit;
  81. FOptions:=AValue;
  82. end;
  83. procedure TFPDDPopulateCodeGenerator.SetTables(const AValue: TStrings);
  84. begin
  85. if FTables=AValue then exit;
  86. FTables.Assign(AValue);
  87. end;
  88. function TFPDDPopulateCodeGenerator.DoTable(Const ATable: TDDtableDef): Boolean;
  89. begin
  90. Result:=Assigned(ATable) and ((FTables.Count=0) or (FTables.IndexOf(ATable.TableName)<>-1));
  91. end;
  92. function TFPDDPopulateCodeGenerator.DoField(const ATable: TDDtableDef;
  93. const AField: TDDFieldDef): Boolean;
  94. begin
  95. Result:=Assigned(ATable) and Assigned(AField);
  96. end;
  97. constructor TFPDDPopulateCodeGenerator.Create(AOwner: TComponent);
  98. Var
  99. T : TStringList;
  100. begin
  101. inherited Create(AOwner);
  102. T:=TStringList.Create;
  103. T.Sorted:=true;
  104. T.Duplicates:=dupIgnore;
  105. FTables:=T;
  106. IndentSize:=2;
  107. end;
  108. destructor TFPDDPopulateCodeGenerator.Destroy;
  109. begin
  110. FreeAndNil(FTables);
  111. inherited Destroy;
  112. end;
  113. procedure TFPDDPopulateCodeGenerator.CheckDatadict;
  114. begin
  115. If (FDD=Nil) then
  116. Raise EDataDict.Create(SErrNoDataDictionary);
  117. If (FDDV='') then
  118. Raise EDataDict.Create(SErrNoDataDictionaryName);
  119. end;
  120. function TFPDDPopulateCodeGenerator.EscapeString(const S: String): string;
  121. begin
  122. Result:=StringReplace(S,'''','''''',[rfReplaceAll]);
  123. end;
  124. procedure TFPDDPopulateCodeGenerator.AddProcedure(AProcedureName : String; Lines: TStrings);
  125. Var
  126. S : String;
  127. begin
  128. S:=AProcedureName;
  129. FProcedures.Add(S);
  130. If (FClassName<>'') then
  131. S:=FClassName+'.'+S;
  132. AddLine('Procedure '+S+';',Lines);
  133. end;
  134. procedure TFPDDPopulateCodeGenerator.EndProcedure(Lines: TStrings);
  135. begin
  136. Undent;
  137. AddLine('end;',lines);
  138. AddLine('',Lines)
  139. end;
  140. procedure TFPDDPopulateCodeGenerator.AddLine(ALine: String; Lines: TStrings);
  141. begin
  142. If (ALine<>'') and (FCurrentIndent<>0) then
  143. Aline:=StringOfChar(' ',FCurrentIndent)+ALine;
  144. Lines.Add(ALine);
  145. end;
  146. procedure TFPDDPopulateCodeGenerator.Indent;
  147. begin
  148. Inc(FCurrentIndent,FIndent);
  149. end;
  150. procedure TFPDDPopulateCodeGenerator.Undent;
  151. begin
  152. Dec(FCurrentIndent,FIndent);
  153. If (FCurrentIndent<0) then
  154. FCurrentIndent:=0;
  155. end;
  156. procedure TFPDDPopulateCodeGenerator.AddTableVars(Lines: TStrings);
  157. begin
  158. AddLine('',Lines);
  159. AddLine('Var',Lines);
  160. Indent;
  161. AddLine('T : TDDTableDef;',lines);
  162. If dcoFields in Options then
  163. AddLine('F : TDDFieldDef;',lines);
  164. If dcoIndexes in Options then
  165. AddLine('ID : TDDIndexDef;',lines);
  166. Undent;
  167. end;
  168. procedure TFPDDPopulateCodeGenerator.AddDomainVars(Lines: TStrings);
  169. begin
  170. AddLine('Var',Lines);
  171. Indent;
  172. AddLine('D : TDDDomainDef;',lines);
  173. Undent;
  174. end;
  175. procedure TFPDDPopulateCodeGenerator.AddSequenceVars(Lines: TStrings);
  176. begin
  177. AddLine('Var',Lines);
  178. Indent;
  179. AddLine('D : TDDSequenceDef;',lines);
  180. Undent;
  181. end;
  182. procedure TFPDDPopulateCodeGenerator.DoTableHeader(ATable : TDDTableDef; Lines: TStrings);
  183. begin
  184. If dcoProcedurePerTable in Options then
  185. begin
  186. AddProcedure('PopulateTable'+ATable.TableName,Lines);
  187. AddTableVars(Lines);
  188. AddLine('',Lines);
  189. AddLine('begin',Lines);
  190. Indent;
  191. end;
  192. AddLine(Format('T:=%s.Tables.AddTable(''%s'');',[FDDV,ATable.TableName]),Lines);
  193. end;
  194. procedure TFPDDPopulateCodeGenerator.DoTableFooter(ATable : TDDTableDef; Lines: TStrings);
  195. begin
  196. If dcoProcedurePerTable in Options then
  197. EndProcedure(Lines);
  198. end;
  199. procedure TFPDDPopulateCodeGenerator.AddProperty(Const ObjName,PropName : String; PropValue : Boolean; Lines: TStrings);
  200. begin
  201. If PropValue then
  202. AddProperty(ObjName,PropName,'True',Lines)
  203. else
  204. AddProperty(ObjName,PropName,'False',Lines);
  205. end;
  206. procedure TFPDDPopulateCodeGenerator.AddProperty(Const ObjName,PropName,PropValue : String; Lines: TStrings);
  207. begin
  208. If Not (dcoUseWith in Options) then
  209. AddLine(Format('%s.%s:=%s;',[Objname,Propname,PropValue]),lines)
  210. else
  211. AddLine(Format('%s:=%s;',[Propname,PropValue]),lines);
  212. end;
  213. procedure TFPDDPopulateCodeGenerator.AddStringProperty(Const ObjName,PropName,PropValue : String; Lines: TStrings);
  214. begin
  215. If (PropValue<>'') then
  216. If Not (dcoUseWith in Options) then
  217. AddLine(Format('%s.%s:=''%s'';',[Objname,Propname,EscapeString(PropValue)]),lines)
  218. else
  219. AddLine(Format('%s:=''%s'';',[Propname,EscapeString(PropValue)]),lines);
  220. end;
  221. procedure TFPDDPopulateCodeGenerator.CreateFieldCode(ATable : TDDTableDef; AField : TDDFieldDef; Lines: TStrings);
  222. Var
  223. I : Integer;
  224. S : String;
  225. begin
  226. AddLine(Format('F:=T.Fields.AddField(''%s'');',[AField.FieldName]),Lines);
  227. If (dcoUseWith in Options) then
  228. begin
  229. AddLine('With F do',Lines);
  230. Indent;
  231. AddLine('begin',Lines);
  232. end;
  233. if (AField.FieldType<>ftUnknown) then
  234. AddProperty('F','FieldType',GetEnumName(TypeInfo(TFieldType),Ord(AField.FieldType)),Lines);
  235. If (AField.AlignMent<>taLeftJustify) then
  236. AddProperty('F','AlignMent',GetEnumName(TypeInfo(TAlignMent),Ord(AField.AlignMent)),Lines);
  237. AddStringProperty('F','CustomConstraint',AField.CustomConstraint,Lines);
  238. AddStringProperty('F','ConstraintErrorMessage',AField.ConstraintErrorMessage,Lines);
  239. AddStringProperty('F','DBDefault',AField.DBDefault,Lines);
  240. AddStringProperty('F','DefaultExpression',AField.DefaultExpression,Lines);
  241. AddStringProperty('F','DisplayLabel',AField.DisplayLabel,Lines);
  242. AddStringProperty('F','DomainName',AField.DomainName,Lines);
  243. If (AField.DisplayWidth<>0) then
  244. AddProperty('F','DisplayWidth1',IntToStr(AField.DisplayWidth),Lines);
  245. AddStringProperty('F','Constraint',AField.Constraint,Lines);
  246. AddProperty('F','ReadOnly',AField.ReadOnly,Lines);
  247. If (dcoMergeDomains in Options) then
  248. AddProperty('F','Required',AField.FieldIsRequired,Lines)
  249. else
  250. AddProperty('F','Required',AField.Required,Lines);
  251. AddProperty('F','Visible',AField.Visible,Lines);
  252. If (AField.Size<>0) then
  253. AddProperty('F','Size',IntToStr(AField.Size),Lines);
  254. If (AField.Precision<>0) then
  255. AddProperty('F','Precision',IntToStr(AField.Precision),Lines);
  256. AddStringProperty('F','Hint',AField.Hint,Lines);
  257. I:=Integer(AField.ProviderFlags);
  258. S:=SetToString(PTypeInfo(TypeInfo(TProviderFlags)),I,True);
  259. AddProperty('F','ProviderFlags',S,Lines);
  260. If (dcoUseWith in Options) then
  261. begin
  262. AddLine('end;',Lines);
  263. Undent;
  264. end;
  265. end;
  266. function TFPDDPopulateCodeGenerator.DoIndex(const ATable: TDDtableDef;
  267. const AIndex: TDDIndexDef): Boolean;
  268. begin
  269. Result:=Assigned(ATable) and Assigned(AIndex);
  270. end;
  271. procedure TFPDDPopulateCodeGenerator.CreateIndexCode(ATable: TDDTableDef;
  272. AIndex: TDDIndexDef; Lines: TStrings);
  273. Var
  274. S : string;
  275. I : Integer;
  276. begin
  277. AddLine(Format('ID:=T.Indexes.AddIndex(''%s'');',[AIndex.IndexName]),Lines);
  278. If (dcoUseWith in Options) then
  279. begin
  280. AddLine('With ID do',Lines);
  281. Indent;
  282. AddLine('begin',Lines);
  283. end;
  284. AddStringProperty('ID','Expression',AIndex.Expression,Lines);
  285. AddStringProperty('ID','Fields',AIndex.Fields,Lines);
  286. AddStringProperty('ID','CaseInsFields',AIndex.CaseInsFields,Lines);
  287. AddStringProperty('ID','DescFields',AIndex.DescFields,Lines);
  288. AddStringProperty('ID','Source',AIndex.Source,Lines);
  289. I:=Integer(AIndex.Options);
  290. S:=SetToString(PTypeInfo(TypeInfo(TIndexOptions)),I,True);
  291. AddProperty('ID','Options',S,Lines);
  292. If (dcoUseWith in Options) then
  293. begin
  294. AddLine('end;',Lines);
  295. Undent;
  296. end;
  297. end;
  298. procedure TFPDDPopulateCodeGenerator.WriteSequences(
  299. const ASequences: TDDSequenceDefs; Lines: TStrings);
  300. Var
  301. I : Integer;
  302. S : TDDSequenceDef;
  303. begin
  304. If (dcoProcedurePerTable in Options) then
  305. begin
  306. AddProcedure('PopulateSequences',Lines);
  307. AddSequenceVars(Lines);
  308. AddLine('',Lines);
  309. AddLine('begin',Lines);
  310. Indent;
  311. end;
  312. For I:=0 to ASequences.Count-1 do
  313. begin
  314. S:=ASequences[i];
  315. If DoSequence(S) then
  316. CreateSequenceCode(S,Lines);
  317. end;
  318. If (dcoProcedurePerTable in Options) then
  319. EndProcedure(Lines);
  320. end;
  321. function TFPDDPopulateCodeGenerator.DoSequence(const ASequence: TDDSequenceDef): Boolean;
  322. begin
  323. Result:=Assigned(ASequence);
  324. end;
  325. procedure TFPDDPopulateCodeGenerator.CreateSequenceCode(ASequence: TDDSequenceDef; Lines: TStrings);
  326. begin
  327. AddLine(Format('S:=%s.Sequences.AddSequence(''%s'');',[FDDV,ASequence.SequenceName]),Lines);
  328. If (dcoUseWith in Options) then
  329. begin
  330. AddLine('With S do',Lines);
  331. Indent;
  332. AddLine('begin',Lines);
  333. end;
  334. If (ASequence.StartValue<>0) then
  335. AddProperty('S','StartValue',IntToStr(ASequence.StartValue),Lines);
  336. If (ASequence.Increment<>0) then
  337. AddProperty('S','Increment',IntToStr(ASequence.Increment),Lines);
  338. If (dcoUseWith in Options) then
  339. begin
  340. AddLine('end;',Lines);
  341. Undent;
  342. end;
  343. end;
  344. procedure TFPDDPopulateCodeGenerator.WriteDomains(const ADomains: TDDDomainDefs; Lines :TStrings);
  345. Var
  346. I : Integer;
  347. D : TDDDomainDef;
  348. begin
  349. If (dcoProcedurePerTable in Options) then
  350. begin
  351. AddProcedure('PopulateDomains',Lines);
  352. AddDomainVars(Lines);
  353. AddLine('',Lines);
  354. AddLine('begin',Lines);
  355. Indent;
  356. end;
  357. For I:=0 to FDD.Domains.Count-1 do
  358. begin
  359. D:=FDD.Domains[i];
  360. If DoDomain(D) then
  361. CreateDomainCode(D,Lines);
  362. end;
  363. If (dcoProcedurePerTable in Options) then
  364. EndProcedure(Lines);
  365. end;
  366. function TFPDDPopulateCodeGenerator.DoDomain(const ADomain: TDDDomainDef
  367. ): Boolean;
  368. begin
  369. Result:=Assigned(ADomain);
  370. end;
  371. procedure TFPDDPopulateCodeGenerator.CreateDomainCode(ADomain: TDDDomainDef;
  372. Lines: TStrings);
  373. begin
  374. AddLine(Format('D:=%s.Domains.AddDomain(''%s'');',[FDDV,ADomain.DomainName]),Lines);
  375. If (dcoUseWith in Options) then
  376. begin
  377. AddLine('With D do',Lines);
  378. Indent;
  379. AddLine('begin',Lines);
  380. end;
  381. if (ADomain.FieldType<>ftUnknown) then
  382. AddProperty('D','FieldType',GetEnumName(TypeInfo(TFieldType),Ord(ADomain.FieldType)),Lines);
  383. AddProperty('D','Required',ADomain.Required,Lines);
  384. If (ADomain.Size<>0) then
  385. AddProperty('D','Size',IntToStr(ADomain.Size),Lines);
  386. If (ADomain.Precision<>0) then
  387. AddProperty('D','Precision',IntToStr(ADomain.Precision),Lines);
  388. If (dcoUseWith in Options) then
  389. begin
  390. AddLine('end;',Lines);
  391. Indent;
  392. end;
  393. end;
  394. procedure TFPDDPopulateCodeGenerator.CreateHeader(Lines: TStrings);
  395. begin
  396. If Not (dcoProcedurePerTable in Options) then
  397. begin
  398. AddProcedure('PopulateDataDictionary',Lines);
  399. AddTableVars(Lines);
  400. AddLine('',Lines);
  401. AddLine('begin',Lines);
  402. Indent;
  403. end
  404. end;
  405. procedure TFPDDPopulateCodeGenerator.CreateFooter(Lines: TStrings);
  406. Var
  407. i : integer;
  408. L : TStrings;
  409. begin
  410. If (dcoProcedurePerTable in Options) then
  411. begin
  412. L:=TStringList.Create;
  413. try
  414. L.Assign(FProcedures);
  415. AddProcedure('PopulateDataDictionary',Lines);
  416. AddLine('',Lines);
  417. AddLine('begin',Lines);
  418. Indent;
  419. For I:=0 to L.Count-1 do
  420. begin
  421. AddLine(L[i]+';',Lines);
  422. end;
  423. finally
  424. L.Free;
  425. end;
  426. end;
  427. Undent;
  428. EndProcedure(Lines);
  429. end;
  430. procedure TFPDDPopulateCodeGenerator.CreateTableCode(T : TDDTableDef; Lines: TStrings);
  431. Var
  432. I : Integer;
  433. F : TDDFieldDef;
  434. Id : TDDindexDef;
  435. begin
  436. DoTableHeader(T,Lines);
  437. try
  438. If dcoFields in Options then
  439. For I:=0 to T.Fields.Count-1 Do
  440. begin
  441. F:=T.Fields[I];
  442. If DoField(T,F) then
  443. CreateFieldcode(T,F,Lines);
  444. end;
  445. If dcoIndexes in Options then
  446. For I:=0 to T.Indexes.Count-1 Do
  447. begin
  448. ID:=T.Indexes[I];
  449. If DoIndex(T,ID) then
  450. CreateIndexCode(T,ID,Lines);
  451. end;
  452. Finally
  453. DoTableFooter(T,Lines);
  454. end;
  455. end;
  456. procedure TFPDDPopulateCodeGenerator.CreateClassDecl(Lines: TStrings);
  457. Var
  458. I : integer;
  459. begin
  460. AddLine('(*',Lines);
  461. Indent;
  462. AddLine(Format('%s = Class(TObject)',[ClassName]),Lines);
  463. AddLine('Private',lines);
  464. Indent;
  465. AddLine(Format('F%s : TFPDataDictionary;',[FDDV]),Lines);
  466. Undent;
  467. AddLine('Public',Lines);
  468. Indent;
  469. For I:=0 to FProcedures.Count-1 do
  470. AddLine(Format('Procedure %s;',[FProcedures[i]]),Lines);
  471. AddLine(Format('Property %s : TFPDataDictionary Read F%:0s Write F%:0s;',[FDDV]),Lines);
  472. Undent;
  473. AddLine('end;',lines);
  474. Undent;
  475. AddLine('*)',Lines);
  476. end;
  477. procedure TFPDDPopulateCodeGenerator.CreateCode(Lines: TStrings);
  478. Var
  479. I : Integer;
  480. T : TDDTableDef;
  481. F : TDDFieldDef;
  482. begin
  483. FCurrentIndent:=0;
  484. CheckDataDict;
  485. FProcedures:=TStringList.Create;
  486. try
  487. CreateHeader(Lines);
  488. Try
  489. If (FDD.Domains.Count>0) then
  490. WriteDomains(FDD.Domains,Lines);
  491. If (FDD.Sequences.Count>0) then
  492. WriteSequences(FDD.Sequences,Lines);
  493. For I:=0 to FDD.Tables.Count-1 do
  494. begin
  495. T:=FDD.Tables[i];
  496. If DoTable(T) then
  497. CreateTableCode(T,Lines);
  498. end;
  499. Finally
  500. CreateFooter(Lines);
  501. end;
  502. If (dcoClassDecl in Options) and (FClassName<>'') then
  503. CreateClassDecl(Lines);
  504. finally
  505. FreeAndNil(FProcedures);
  506. end;
  507. end;
  508. end.