unit uDASchemaUnitsGenerator; interface uses Classes, uDAInterfaces, uDAClasses; type { TDASchemaCodeGenerator } TDASchemaCodeGenerator = class(TStringList) private fSchema : TDASchema; fFileName : string; protected procedure DoWriteCode; virtual; abstract; property FileName : string read fFileName; property Schema : TDASchema read fSchema; public constructor Create(aSchema : TDASchema); procedure Write(const someText: string; Indentation: integer = 0); overload; procedure WriteLines(const someText: string); procedure WriteEmptyLine; procedure WriteCode(const aFileName : string); end; { TClientUnitSchemaGenerator } TClientUnitSchemaGenerator = class(TDASchemaCodeGenerator) protected procedure DoWriteCode; override; end; { TServerUnitSchemaGenerator } TServerUnitSchemaGenerator = class(TDASchemaCodeGenerator) private fClientUnitName: string; protected procedure DoWriteCode; override; public property ClientUnitName : string read fClientUnitName write fClientUnitName; end; procedure GenerateSchemaUnits(aSchema : TDASchema); function GetDAType(ad: TDADataType): string; implementation uses uROIDETools, uRODLToPascal, SysUtils, Dialogs, uROTypes, uROClasses; function GetDATypeMethod(ad: TDADataType): string; begin case ad of datAutoInc: Result := 'Integer'; datLargeAutoInc: Result := 'LargeInt'; datWideMemo: Result := 'WideString'; datSingleFloat: Result := 'Single'; else Result := DADataTypeNames[ad]; end; end; { TDASchemaCodeGenerator } procedure TDASchemaCodeGenerator.Write(const someText: string; Indentation: integer = 0); var i: integer; s: string; begin s := ''; for i := 1 to Indentation do s := s + ' '; s := s + someText; Add(s) end; procedure TDASchemaCodeGenerator.WriteLines(const someText: string); begin Text := Text+someText; end; procedure TDASchemaCodeGenerator.WriteEmptyLine; begin Add(''); end; constructor TDASchemaCodeGenerator.Create(aSchema: TDASchema); begin inherited Create; fSchema := aSchema; end; procedure TDASchemaCodeGenerator.WriteCode(const aFileName: string); begin fFileName := aFileName; Clear; DoWriteCode; SaveToFile(aFileName); end; { Misc } procedure GenerateSchemaUnits(aSchema : TDASchema); var clienttargetfilename, servertargetfilename : string; begin clienttargetfilename := IncludeTrailingPathDelimiter(ModuleDir(CurrentProject))+aSchema.Name+'Client_Intf.pas'; if PromptForFileName(clienttargetfilename, 'Delphi unit (*.pas)|*.pas', '*.pas', 'Save '+aSchema.Name+' client access unit', '', TRUE) then begin with TClientUnitSchemaGenerator.Create(aSchema) do try WriteCode(clienttargetfilename); CurrentProject.AddFile(clienttargetfilename, TRUE); finally Free; end; end; servertargetfilename := IncludeTrailingPathDelimiter(ModuleDir(CurrentProject))+aSchema.Name+'Server_Intf.pas'; if PromptForFileName(servertargetfilename, 'Delphi unit (*.pas)|*.pas', '*.pas', 'Save '+aSchema.Name+' server access unit', '', TRUE) then begin with TServerUnitSchemaGenerator.Create(aSchema) do try ClientUnitName := ChangeFileExt(ExtractFileName(clienttargetfilename), ''); WriteCode(servertargetfilename); CurrentProject.AddFile(servertargetfilename, TRUE); finally Free; end; end; end; function GenFindParams(aDataset : TDADataset; AddType, UsePrefix, UseComma : boolean) : string; var x : integer; begin result := ''; with aDataset do begin for x := 0 to (Fields.Count-1) do if Fields[x].InPrimaryKey then begin if UsePrefix then result := result+'a'+Fields[x].Name else result := result+Fields[x].Name; if AddType then result := result+': '+GetDAType(Fields[x].DataType); if UseComma then result := result+',' else result := result+'; '; end; if UseComma then result := Copy(result, 1, Length(result)-1) else result := Copy(result, 1, Length(result)-2); end; end; function GetDAType(ad: TDADataType): string; begin case ad of datMemo: Result := 'IROStrings'; datBlob: Result := 'IROStream'; datAutoInc: Result := 'Integer'; datWideMemo: Result := 'WideString'; datLargeAutoInc: Result := 'Int64'; datGuid: result := 'TGuid'; datXml: result := 'IXmlNode'; datLargeUint, datLargeInt: Result := 'Int64'; datDecimal: Result := 'TBcd'; datSingleFloat: Result := 'Single'; else Result := DADataTypeNames[ad]; end; end; { TClientUnitSchemaGenerator } procedure TClientUnitSchemaGenerator.DoWriteCode; var i, x : integer; guid : TGUID; guids : TStringList; //s, s2 : string; bVar: boolean; begin guids := TStringList.Create; with Schema do try for i := 0 to (Datasets.Count-1) do begin CreateGUID(guid); guids.Add(GUIDToString(guid)); end; Write(Format('unit %s;', [ChangeFileExt(ExtractFileName(FileName), '')])); WriteEmptyLine; Write('interface'); WriteEmptyLine; Write('uses'); Write(' Classes, DB, SysUtils, uROClasses, uDADataTable, FmtBCD, uROXMLIntf;'); // Data table GUIDs WriteEmptyLine; Write('const'); Write('{ Data table rules ids', PASCAL_INDENTATION_LEVEL_1); Write(' Feel free to change them to something more human readable', PASCAL_INDENTATION_LEVEL_1); Write(' but make sure they are unique in the context of your application }', PASCAL_INDENTATION_LEVEL_1); for i := 0 to (Datasets.Count-1) do begin Write(Format('RID_%s = ''%s'';', [MakeValidIdentifier(Datasets[i].Name), guids[i]]), PASCAL_INDENTATION_LEVEL_1); end; // Data table names WriteEmptyLine; Write('{ Data table names }', PASCAL_INDENTATION_LEVEL_1); for i := 0 to (Datasets.Count-1) do begin Write(Format('nme_%s = ''%s'';', [MakeValidIdentifier(Datasets[i].Name), Datasets[i].Name]), PASCAL_INDENTATION_LEVEL_1); end; WriteEmptyLine; // Data table fields for i := 0 to (Datasets.Count-1) do begin Write(Format('{ %s fields }', [Datasets[i].Name]), PASCAL_INDENTATION_LEVEL_1); for x := 0 to (Datasets[i].Fields.Count-1) do Write(Format('fld_%s%s = ''%s'';', [MakeValidIdentifier(Datasets[i].Name), Datasets[i].Fields[x].Name, Datasets[i].Fields[x].Name]), PASCAL_INDENTATION_LEVEL_1); WriteEmptyLine; Write(Format('{ %s field indexes }', [Datasets[i].Name]), PASCAL_INDENTATION_LEVEL_1); for x := 0 to (Datasets[i].Fields.Count-1) do Write(Format('idx_%s%s = %d;', [MakeValidIdentifier(Datasets[i].Name), MakeValidIdentifier(Datasets[i].Fields[x].Name), x]), PASCAL_INDENTATION_LEVEL_1); WriteEmptyLine; end; Write('type'); for i := 0 to (Datasets.Count-1) do begin if (Trim(Datasets[i].Description)<>'') then begin Write('{', PASCAL_INDENTATION_LEVEL_1); Write(Datasets[i].Description, PASCAL_INDENTATION_LEVEL_1); Write('}', PASCAL_INDENTATION_LEVEL_1); end; // Base interface CreateGUID(guid); // This interface is just for reference. People will use the others Write(Format('{ I%s }', [MakeValidIdentifier(Datasets[i].Name)]), PASCAL_INDENTATION_LEVEL_1); Write(Format('I%s = interface(IDAStronglyTypedDataTable)', [MakeValidIdentifier(Datasets[i].Name)]), PASCAL_INDENTATION_LEVEL_1); Write(Format('[''%s'']', [GuidToString(guid)]), PASCAL_INDENTATION_LEVEL_1); with Datasets[i] do begin Write('{ Property getters and setters }', PASCAL_INDENTATION_LEVEL_2); for x := 0 to (Fields.Count-1) do begin Write(Format('function Get%sValue: %s;', [MakeValidIdentifier(Fields[x].Name), GetDAType(Fields[x].DataType)]), PASCAL_INDENTATION_LEVEL_2); if not (Fields[x].DataType in [datMemo, datblob]) then Write(Format('procedure Set%sValue(const aValue: %s);', [MakeValidIdentifier(Fields[x].Name), GetDAType(Fields[x].DataType)]), PASCAL_INDENTATION_LEVEL_2); Write(Format('function Get%sIsNull: Boolean;', [MakeValidIdentifier(Fields[x].Name)]), PASCAL_INDENTATION_LEVEL_2); Write(Format('procedure Set%sIsNull(const aValue: Boolean);', [MakeValidIdentifier(Fields[x].Name)]), PASCAL_INDENTATION_LEVEL_2); end; WriteEmptyLine; {Write('// Methods', PASCAL_INDENTATION_LEVEL_2); // Generates the Find method s := GenFindParams(Datasets[i], TRUE, TRUE, FALSE); if (s<>'') then Write(Format('function Find(%s; LocateOptions : TLocateOptions) : boolean;', [s]), PASCAL_INDENTATION_LEVEL_2);} // Properties WriteEmptyLine; Write('{ Properties }', PASCAL_INDENTATION_LEVEL_2); for x := 0 to (Fields.Count-1) do begin if Fields[x].DataType in [datMemo, datBlob] then Write(Format('property %s: %s read Get%sValue;', [MakeValidIdentifier(Fields[x].Name), GetDAType(Fields[x].DataType), MakeValidIdentifier(Fields[x].Name)]), PASCAL_INDENTATION_LEVEL_2) else Write(Format('property %s: %s read Get%sValue write Set%sValue;', [MakeValidIdentifier(Fields[x].Name), GetDAType(Fields[x].DataType), MakeValidIdentifier(Fields[x].Name), MakeValidIdentifier(Fields[x].Name)]), PASCAL_INDENTATION_LEVEL_2); Write(Format('property %sIsNull: Boolean read Get%sIsNull write Set%sIsNull;', [MakeValidIdentifier(Fields[x].Name), MakeValidIdentifier(Fields[x].Name), MakeValidIdentifier(Fields[x].Name)]), PASCAL_INDENTATION_LEVEL_2); end; end; Write(Format('end;', []), PASCAL_INDENTATION_LEVEL_1); WriteEmptyLine; // Implementor class Write(Format('{ T%sDataTableRules }', [MakeValidIdentifier(Datasets[i].Name)]), PASCAL_INDENTATION_LEVEL_1); Write(Format('T%sDataTableRules = class(TDADataTableRules, I%s)', [MakeValidIdentifier(Datasets[i].Name), MakeValidIdentifier(Datasets[i].Name)]), PASCAL_INDENTATION_LEVEL_1); with Datasets[i] do begin Write('private', PASCAL_INDENTATION_LEVEL_1); for x := 0 to (Fields.Count-1) do begin if Fields[x].DataType in [datMemo, datBlob] then Write(Format('f_%s: %s;',[MakeValidIdentifier(Fields[x].Name), GetDAType(Fields[x].DataType)]),PASCAL_INDENTATION_LEVEL_2); end; for x := 0 to (Fields.Count-1) do begin if Fields[x].DataType = datMemo then Write(Format('procedure %s_OnChange(Sender: TObject);',[MakeValidIdentifier(Fields[x].Name)]),PASCAL_INDENTATION_LEVEL_2) else if Fields[x].DataType = datBlob then Write(Format('procedure %s_OnChange(Sender: TObject);',[MakeValidIdentifier(Fields[x].Name)]),PASCAL_INDENTATION_LEVEL_2); end; Write('protected', PASCAL_INDENTATION_LEVEL_1); Write('{ Property getters and setters }', PASCAL_INDENTATION_LEVEL_2); for x := 0 to (Fields.Count-1) do begin Write(Format('function Get%sValue: %s; virtual;', [MakeValidIdentifier(Fields[x].Name), GetDAType(Fields[x].DataType)]), PASCAL_INDENTATION_LEVEL_2); if not (Fields[x].DataType in [datMemo, datBlob]) then Write(Format('procedure Set%sValue(const aValue: %s); virtual;', [MakeValidIdentifier(Fields[x].Name), GetDAType(Fields[x].DataType)]), PASCAL_INDENTATION_LEVEL_2); Write(Format('function Get%sIsNull: Boolean; virtual;', [MakeValidIdentifier(Fields[x].Name)]), PASCAL_INDENTATION_LEVEL_2); Write(Format('procedure Set%sIsNull(const aValue: Boolean); virtual;', [MakeValidIdentifier(Fields[x].Name)]), PASCAL_INDENTATION_LEVEL_2); end; WriteEmptyLine; Write('{ Properties }', PASCAL_INDENTATION_LEVEL_2); for x := 0 to (Fields.Count-1) do begin if Fields[x].DataType in [datMemo, datBlob] then Write(Format('property %s: %s read Get%sValue;', [MakeValidIdentifier(Fields[x].Name), GetDAType(Fields[x].DataType), MakeValidIdentifier(Fields[x].Name)]), PASCAL_INDENTATION_LEVEL_2) else Write(Format('property %s: %s read Get%sValue write Set%sValue;', [MakeValidIdentifier(Fields[x].Name), GetDAType(Fields[x].DataType), MakeValidIdentifier(Fields[x].Name), MakeValidIdentifier(Fields[x].Name)]), PASCAL_INDENTATION_LEVEL_2); Write(Format('property %sIsNull: Boolean read Get%sIsNull write Set%sIsNull;', [MakeValidIdentifier(Fields[x].Name), MakeValidIdentifier(Fields[x].Name), MakeValidIdentifier(Fields[x].Name)]), PASCAL_INDENTATION_LEVEL_2); end; WriteEmptyLine; {Write('procedure Validate; override;', PASCAL_INDENTATION_LEVEL_3); WriteEmptyLine;} Write('public', PASCAL_INDENTATION_LEVEL_1); Write('constructor Create(aDataTable: TDADataTable); override;', PASCAL_INDENTATION_LEVEL_2); Write('destructor Destroy; override;', PASCAL_INDENTATION_LEVEL_2); WriteEmptyLine; // Generates the Find method {s := GenFindParams(Datasets[i], TRUE, TRUE, FALSE); if (s<>'') then Write(Format('function Find(%s; LocateOptions : TLocateOptions) : boolean;', [s]), PASCAL_INDENTATION_LEVEL_2);} end; Write(Format('end;', []), PASCAL_INDENTATION_LEVEL_1); WriteEmptyLine; end; Write('implementation'); WriteEmptyLine; Write('uses Variants, uROBinaryHelpers;'); WriteEmptyLine; for i := 0 to (Datasets.Count-1) do begin // Implementor class Write(Format('{ T%sDataTableRules }', [MakeValidIdentifier(Datasets[i].Name)])); with Datasets[i] do begin Write(Format('constructor T%sDataTableRules.Create(aDataTable: TDADataTable);', [MakeValidIdentifier(Name)])); bVar:=False; // create StrList for x := 0 to (Fields.Count-1) do begin if Fields[x].DataType = datMemo then begin if not bVar then begin Write('var'); bVar:=True; end; Write(' StrList: TStringList;'); Break; end; end; // create ROStream for x := 0 to (Fields.Count-1) do begin if Fields[x].DataType = datBlob then begin if not bVar then begin Write('var'); end; Write(' ROStream: TROStream;'); Break; end; end; Write('begin'); Write(' inherited;'); for x := 0 to (Fields.Count-1) do begin if Fields[x].DataType = datMemo then begin WriteEmptyLine; Write(' StrList := TStringList.Create;'); Write(Format(' StrList.OnChange := %s_OnChange;', [MakeValidIdentifier(Fields[x].Name)])); Write(Format(' f_%s := NewROStrings(StrList,True);', [MakeValidIdentifier(Fields[x].Name)])); end else if Fields[x].DataType = datBlob then begin WriteEmptyLine; Write(' ROStream := TROStream.Create;'); Write(Format(' ROStream.OnChange := %s_OnChange;', [MakeValidIdentifier(Fields[x].Name)])); Write(Format(' f_%s := ROStream;', [MakeValidIdentifier(Fields[x].Name)])); end; end; Write('end;'); WriteEmptyLine; Write(Format('destructor T%sDataTableRules.Destroy;', [MakeValidIdentifier(Name)])); Write('begin'); Write(' inherited;'); Write('end;'); WriteEmptyLine; // Generates the Find method body {s := GenFindParams(Datasets[i], TRUE, TRUE, FALSE); if (s<>'') then begin Write(Format('function T%s.Find(%s; LocateOptions : TLocateOptions) : boolean;', [Name, s])); Write('begin'); s := GenFindParams(Datasets[i], FALSE, FALSE, TRUE); s2 := GenFindParams(Datasets[i], FALSE, TRUE, TRUE); if (Pos(',', s2)=0) then Write(Format('result := DataTable.Locate(''%s'', %s, LocateOptions);', [s, s2]), PASCAL_INDENTATION_LEVEL_1) else Write(Format('result := DataTable.Locate(''%s'', VarArrayOf([%s]), LocateOptions);', [s, s2]), PASCAL_INDENTATION_LEVEL_1); Write('end;'); WriteEmptyLine; end;} {Write(Format('procedure T%s.Validate;', [Name])); Write('begin'); Write('end;'); WriteEmptyLine;} {ToDo: -cDA3 improve handling of Memos (and possibly Blobs, too), so that assignments to the returned IROStream (ie MyField.Text := 'Hello') get carried back to the field data properly. currently, the onmly way to chage the field is to actually assign a new IROStream to the property via "MyField := ...", which is NOT GOOD.} for x := 0 to (Fields.Count-1) do begin if Fields[x].DataType = datMemo then begin Write(Format('procedure T%sDataTableRules.%s_OnChange(Sender: TObject);', [MakeValidIdentifier(Name), MakeValidIdentifier(Fields[x].Name)])); Write('begin'); Write(Format(' if DataTable.Editing then DataTable.Fields[idx_%s%s].AsVariant := TStringList(Sender).Text;', [MakeValidIdentifier(Datasets[i].Name), MakeValidIdentifier(Datasets[i].Fields[x].Name), GetDAType(Fields[x].DataType)])); Write('end;'); WriteEmptyLine; end else if Fields[x].DataType = datBlob then begin Write(Format('procedure T%sDataTableRules.%s_OnChange(Sender: TObject);', [MakeValidIdentifier(Name), MakeValidIdentifier(Fields[x].Name)])); Write('begin'); Write(Format(' if DataTable.Editing then DataTable.Fields[idx_%s%s].LoadFromStream(TROStream(Sender));', [MakeValidIdentifier(Datasets[i].Name), MakeValidIdentifier(Datasets[i].Fields[x].Name), GetDAType(Fields[x].DataType)])); Write('end;'); WriteEmptyLine; end; end; for x := 0 to (Fields.Count-1) do begin Write(Format('function T%sDataTableRules.Get%sValue: %s;', [MakeValidIdentifier(Name), MakeValidIdentifier(Fields[x].Name), GetDAType(Fields[x].DataType)])); Write('begin'); case Fields[x].DataType of { } datMemo:begin Write(Format(' result := f_%s;',[MakeValidIdentifier(Fields[x].Name)])); Write(Format(' result.Text := DataTable.Fields[idx_%s%s].AsString;', [MakeValidIdentifier(Datasets[i].Name), MakeValidIdentifier(Datasets[i].Fields[x].Name)])); end; datBlob:begin Write(Format(' result := f_%s;',[MakeValidIdentifier(Fields[x].Name)])); Write(' result.Position := 0;'); Write(' if not Result.InUpdateMode then begin'); Write(Format(' DataTable.Fields[idx_%s%s].SaveToStream(result);', [MakeValidIdentifier(Datasets[i].Name), MakeValidIdentifier(Datasets[i].Fields[x].Name)])); Write(' result.Position := 0;'); Write(' end;'); end; else Write(Format(' result := DataTable.Fields[idx_%s%s].As%s;', [MakeValidIdentifier(Datasets[i].Name), MakeValidIdentifier(Datasets[i].Fields[x].Name), GetDATypeMethod(Fields[x].DataType)])); end; { case } Write('end;'); WriteEmptyLine; if not (Fields[x].DataType in [datMemo, datBlob]) then begin Write(Format('procedure T%sDataTableRules.Set%sValue(const aValue: %s);', [MakeValidIdentifier(Name), MakeValidIdentifier(Fields[x].Name), GetDAType(Fields[x].DataType)])); Write('begin'); Write(Format(' DataTable.Fields[idx_%s%s].As%s := aValue;', [MakeValidIdentifier(Datasets[i].Name), MakeValidIdentifier(Datasets[i].Fields[x].Name), GetDATypeMethod(Fields[x].DataType)])); Write('end;'); WriteEmptyLine; end; Write(Format('function T%sDataTableRules.Get%sIsNull: boolean;', [MakeValidIdentifier(Name), MakeValidIdentifier(Fields[x].Name)])); Write('begin'); Write(Format(' result := DataTable.Fields[idx_%s%s].IsNull;', [MakeValidIdentifier(Datasets[i].Name), MakeValidIdentifier(Datasets[i].Fields[x].Name)])); Write('end;'); WriteEmptyLine; Write(Format('procedure T%sDataTableRules.Set%sIsNull(const aValue: Boolean);', [MakeValidIdentifier(Name), MakeValidIdentifier(Fields[x].Name)])); Write('begin'); Write(' if aValue then'); Write(Format(' DataTable.Fields[idx_%s%s].AsVariant := Null;', [MakeValidIdentifier(Datasets[i].Name), MakeValidIdentifier(Datasets[i].Fields[x].Name)])); Write('end;'); WriteEmptyLine; end; end; WriteEmptyLine; end; Write('initialization'); for i := 0 to (Datasets.Count-1) do Write(Format('RegisterDataTableRules(RID_%s, T%sDataTableRules);', [MakeValidIdentifier(Datasets[i].Name), MakeValidIdentifier(Datasets[i].Name)]), PASCAL_INDENTATION_LEVEL_1); WriteEmptyLine; Write('end.'); finally guids.Free; end; end; { TServerUnitSchemaGenerator } procedure TServerUnitSchemaGenerator.DoWriteCode; var i, x : integer; guid : TGUID; guids : TStringList; //s, s2 : string; bVar: Boolean; begin guids := TStringList.Create; with Schema do try for i := 0 to (Datasets.Count-1) do begin CreateGUID(guid); guids.Add(GUIDToString(guid)); end; Write(Format('unit %s;', [ChangeFileExt(ExtractFileName(FileName), '')])); WriteEmptyLine; Write('interface'); WriteEmptyLine; Write('uses'); Write(Format(' Classes, DB, SysUtils, uROClasses, uDADataTable, uDABusinessProcessor, FmtBCD, uROXMLIntf, %s;', [ClientUnitName])); // Data table GUIDs WriteEmptyLine; Write('const'); Write('{ Delta rules ids ', PASCAL_INDENTATION_LEVEL_1); Write(' Feel free to change them to something more human readable', PASCAL_INDENTATION_LEVEL_1); Write(' but make sure they are unique in the context of your application }', PASCAL_INDENTATION_LEVEL_1); for i := 0 to (Datasets.Count-1) do begin Write(Format('RID_%sDelta = ''%s'';', [MakeValidIdentifier(Datasets[i].Name), guids[i]]), PASCAL_INDENTATION_LEVEL_1); end; WriteEmptyLine; Write('type'); for i := 0 to (Datasets.Count-1) do begin // Business delta change Write(Format('{ I%sDelta }', [MakeValidIdentifier(Datasets[i].Name)]), PASCAL_INDENTATION_LEVEL_1); Write(Format('I%sDelta = interface(I%s)', [MakeValidIdentifier(Datasets[i].Name), MakeValidIdentifier(Datasets[i].Name)]), PASCAL_INDENTATION_LEVEL_1); Write(Format('[''%s'']', [guids[i]]), PASCAL_INDENTATION_LEVEL_1); with Datasets[i] do begin Write('{ Property getters and setters }', PASCAL_INDENTATION_LEVEL_2); for x := 0 to (Fields.Count-1) do begin Write(Format('function GetOld%sValue : %s;', [MakeValidIdentifier(Fields[x].Name), GetDAType(Fields[x].DataType)]), PASCAL_INDENTATION_LEVEL_2); end; WriteEmptyLine; // Properties Write('{ Properties }', PASCAL_INDENTATION_LEVEL_2); for x := 0 to (Fields.Count-1) do Write(Format('property Old%s : %s read GetOld%sValue;', [MakeValidIdentifier(Fields[x].Name), GetDAType(Fields[x].DataType), MakeValidIdentifier(Fields[x].Name), MakeValidIdentifier(Fields[x].Name)]), PASCAL_INDENTATION_LEVEL_2); Write(Format('end;', []), PASCAL_INDENTATION_LEVEL_1); end; WriteEmptyLine; // Implementor class Write(Format('{ T%sBusinessProcessorRules }', [MakeValidIdentifier(Datasets[i].Name)]), PASCAL_INDENTATION_LEVEL_1); Write(Format('T%sBusinessProcessorRules = class(TDABusinessProcessorRules, I%s, I%sDelta)', [MakeValidIdentifier(Datasets[i].Name), MakeValidIdentifier(Datasets[i].Name), MakeValidIdentifier(Datasets[i].Name)]), PASCAL_INDENTATION_LEVEL_1); with Datasets[i] do begin Write('private', PASCAL_INDENTATION_LEVEL_1); for x := 0 to (Fields.Count-1) do begin if Fields[x].DataType in [datMemo, datBlob] then Write(Format('f_%s: %s;',[MakeValidIdentifier(Fields[x].Name), GetDAType(Fields[x].DataType)]),PASCAL_INDENTATION_LEVEL_2); end; for x := 0 to (Fields.Count-1) do begin if Fields[x].DataType = datMemo then Write(Format('procedure %s_OnChange(Sender: TObject);',[MakeValidIdentifier(Fields[x].Name)]),PASCAL_INDENTATION_LEVEL_2) else if Fields[x].DataType = datBlob then Write(Format('procedure %s_OnChange(Sender: Tobject);',[MakeValidIdentifier(Fields[x].Name)]),PASCAL_INDENTATION_LEVEL_2); end; Write('protected', PASCAL_INDENTATION_LEVEL_1); Write('{ Property getters and setters }', PASCAL_INDENTATION_LEVEL_2); for x := 0 to (Fields.Count-1) do begin Write(Format('function Get%sValue: %s; virtual;', [MakeValidIdentifier(Fields[x].Name), GetDAType(Fields[x].DataType)]), PASCAL_INDENTATION_LEVEL_2); Write(Format('function Get%sIsNull: Boolean; virtual;', [MakeValidIdentifier(Fields[x].Name)]), PASCAL_INDENTATION_LEVEL_2); Write(Format('function GetOld%sValue: %s; virtual;', [MakeValidIdentifier(Fields[x].Name), GetDAType(Fields[x].DataType)]), PASCAL_INDENTATION_LEVEL_2); Write(Format('function GetOld%sIsNull: Boolean; virtual;', [MakeValidIdentifier(Fields[x].Name)]), PASCAL_INDENTATION_LEVEL_2); if not(Fields[x].DataType in [datMemo, datBlob]) then Write(Format('procedure Set%sValue(const aValue: %s); virtual;', [MakeValidIdentifier(Fields[x].Name), GetDAType(Fields[x].DataType)]), PASCAL_INDENTATION_LEVEL_2); Write(Format('procedure Set%sIsNull(const aValue: Boolean); virtual;', [MakeValidIdentifier(Fields[x].Name)]), PASCAL_INDENTATION_LEVEL_2); end; WriteEmptyLine; Write('{ Properties }', PASCAL_INDENTATION_LEVEL_2); for x := 0 to (Fields.Count-1) do begin if (Fields[x].DataType in [datMemo, datBlob]) then Write(Format('property %s : %s read Get%sValue;', [MakeValidIdentifier(Fields[x].Name), GetDAType(Fields[x].DataType), MakeValidIdentifier(Fields[x].Name)]), PASCAL_INDENTATION_LEVEL_2) else Write(Format('property %s : %s read Get%sValue write Set%sValue;', [MakeValidIdentifier(Fields[x].Name), GetDAType(Fields[x].DataType), MakeValidIdentifier(Fields[x].Name), MakeValidIdentifier(Fields[x].Name)]), PASCAL_INDENTATION_LEVEL_2); Write(Format('property %sIsNull : Boolean read Get%sIsNull write Set%sIsNull;', [MakeValidIdentifier(Fields[x].Name), MakeValidIdentifier(Fields[x].Name), MakeValidIdentifier(Fields[x].Name)]), PASCAL_INDENTATION_LEVEL_2); Write(Format('property Old%s : %s read GetOld%sValue;', [MakeValidIdentifier(Fields[x].Name), GetDAType(Fields[x].DataType), MakeValidIdentifier(Fields[x].Name), MakeValidIdentifier(Fields[x].Name)]), PASCAL_INDENTATION_LEVEL_2); Write(Format('property Old%sIsNull : Boolean read GetOld%sIsNull;', [MakeValidIdentifier(Fields[x].Name), MakeValidIdentifier(Fields[x].Name), MakeValidIdentifier(Fields[x].Name)]), PASCAL_INDENTATION_LEVEL_2); end; WriteEmptyLine; Write('public', PASCAL_INDENTATION_LEVEL_1); Write('constructor Create(aBusinessProcessor: TDABusinessProcessor); override;', PASCAL_INDENTATION_LEVEL_2); Write('destructor Destroy; override;', PASCAL_INDENTATION_LEVEL_2); WriteEmptyLine; // Generates the Find method {s := GenFindParams(Datasets[i], TRUE, TRUE, FALSE); if (s<>'') then Write(Format('function Find(%s; LocateOptions : TLocateOptions) : boolean;', [s]), PASCAL_INDENTATION_LEVEL_2);} end; Write(Format('end;', []), PASCAL_INDENTATION_LEVEL_1); WriteEmptyLine; end; Write('implementation'); WriteEmptyLine; Write('uses'); Write(' Variants, uROBinaryHelpers, uDAInterfaces;'); WriteEmptyLine; for i := 0 to (Datasets.Count-1) do begin // Implementor class Write(Format('{ T%sBusinessProcessorRules }', [MakeValidIdentifier(Datasets[i].Name)])); with Datasets[i] do begin Write(Format('constructor T%sBusinessProcessorRules.Create(aBusinessProcessor: TDABusinessProcessor);', [MakeValidIdentifier(Name)])); bVar:=False; // create StrList for x := 0 to (Fields.Count-1) do begin if Fields[x].DataType = datMemo then begin if not bVar then begin Write('var'); bVar:=True; end; Write(' StrList: TStringList;'); Break; end; end; // create ROStream for x := 0 to (Fields.Count-1) do begin if Fields[x].DataType = datBlob then begin if not bVar then begin Write('var'); end; Write(' ROStream: TROStream;'); Break; end; end; Write('begin'); Write(' inherited;'); for x := 0 to (Fields.Count-1) do begin if Fields[x].DataType = datMemo then begin WriteEmptyLine; Write(' StrList := TStringList.Create;'); Write(Format(' StrList.OnChange := %s_OnChange;', [MakeValidIdentifier(Fields[x].Name)])); Write(Format(' f_%s := NewROStrings(StrList,True);', [MakeValidIdentifier(Fields[x].Name)])); end else if Fields[x].DataType = datBlob then begin WriteEmptyLine; Write(' ROStream := TROStream.Create;'); Write(Format(' ROStream.OnChange := %s_OnChange;', [MakeValidIdentifier(Fields[x].Name)])); Write(Format(' f_%s := ROStream;', [MakeValidIdentifier(Fields[x].Name)])); end; end; Write('end;'); WriteEmptyLine; Write(Format('destructor T%sBusinessProcessorRules.Destroy;', [MakeValidIdentifier(Name)])); Write('begin'); Write(' inherited;'); Write('end;'); WriteEmptyLine; for x := 0 to (Fields.Count-1) do begin if Fields[x].DataType = datMemo then begin Write(Format('procedure T%sBusinessProcessorRules.%s_OnChange(Sender: TObject);', [MakeValidIdentifier(Name), MakeValidIdentifier(Fields[x].Name)])); Write('begin'); Write(Format(' BusinessProcessor.CurrentChange.NewValueByName[fld_%s%s] := TStringList(Sender).Text;', [MakeValidIdentifier(Datasets[i].Name), MakeValidIdentifier(Datasets[i].Fields[x].Name)])); Write('end;'); WriteEmptyLine; end else if Fields[x].DataType = datBlob then begin Write(Format('procedure T%sBusinessProcessorRules.%s_OnChange(Sender: TObject);', [MakeValidIdentifier(Name), MakeValidIdentifier(Fields[x].Name)])); Write('begin'); Write(Format(' BusinessProcessor.CurrentChange.NewValueByName[fld_%s%s] := VariantBinaryFromBinary((TROStream(Sender) as IROStream).Stream);', [MakeValidIdentifier(Datasets[i].Name), MakeValidIdentifier(Datasets[i].Fields[x].Name)])); Write('end;'); WriteEmptyLine; end; end; for x := 0 to (Fields.Count-1) do begin Write(Format('function T%sBusinessProcessorRules.Get%sValue: %s;', [MakeValidIdentifier(Name), MakeValidIdentifier(Fields[x].Name), GetDAType(Fields[x].DataType)])); Write('begin'); case Fields[x].DataType of datMemo:begin Write(Format(' result := f_%s;',[MakeValidIdentifier(Fields[x].Name)])); Write(Format(' result.Text := BusinessProcessor.CurrentChange.NewValueByName[fld_%s%s];', [MakeValidIdentifier(Datasets[i].Name), MakeValidIdentifier(Datasets[i].Fields[x].Name)])); end; datBlob:begin Write(Format(' result := f_%s;',[MakeValidIdentifier(Fields[x].Name)])); Write(' result.Position := 0;'); Write(' if not Result.InUpdateMode then begin'); Write(Format(' WriteVariantBinaryToBinary(BusinessProcessor.CurrentChange.NewValueByName[fld_%s%s], result.Stream);', [MakeValidIdentifier(Datasets[i].Name), MakeValidIdentifier(Datasets[i].Fields[x].Name)])); Write(' result.Position := 0;'); Write(' end;'); end; datDecimal: begin Write(Format(' result := GetVarDecimal(BusinessProcessor.CurrentChange.NewValueByName[fld_%s%s]);', [MakeValidIdentifier(Datasets[i].Name), MakeValidIdentifier(Datasets[i].Fields[x].Name), GetDAType(Fields[x].DataType)])); end; datXml: begin Write(Format(' result := GetVarXml(BusinessProcessor.CurrentChange.NewValueByName[fld_%s%s]);', [MakeValidIdentifier(Datasets[i].Name), MakeValidIdentifier(Datasets[i].Fields[x].Name), GetDAType(Fields[x].DataType)])); end; datGuid: begin Write(Format(' result := GetVarGuid(BusinessProcessor.CurrentChange.NewValueByName[fld_%s%s]);', [MakeValidIdentifier(Datasets[i].Name), MakeValidIdentifier(Datasets[i].Fields[x].Name), GetDAType(Fields[x].DataType)])); end; else begin Write(Format(' result := BusinessProcessor.CurrentChange.NewValueByName[fld_%s%s];', [MakeValidIdentifier(Datasets[i].Name), MakeValidIdentifier(Datasets[i].Fields[x].Name), GetDAType(Fields[x].DataType)])); end; end; Write('end;'); WriteEmptyLine; Write(Format('function T%sBusinessProcessorRules.Get%sIsNull: Boolean;', [MakeValidIdentifier(Name), MakeValidIdentifier(Fields[x].Name)])); Write('begin'); Write(Format(' result := VarIsNull(BusinessProcessor.CurrentChange.NewValueByName[fld_%s%s]);', [MakeValidIdentifier(Datasets[i].Name), MakeValidIdentifier(Datasets[i].Fields[x].Name)])); Write('end;'); WriteEmptyLine; Write(Format('function T%sBusinessProcessorRules.GetOld%sValue: %s;', [MakeValidIdentifier(Name), MakeValidIdentifier(Fields[x].Name), GetDAType(Fields[x].DataType)])); Write('begin'); case Fields[x].DataType of datMemo:begin Write(' result := NewROStrings();'); Write(Format(' result.Text := BusinessProcessor.CurrentChange.OldValueByName[fld_%s%s];', [MakeValidIdentifier(Datasets[i].Name), MakeValidIdentifier(Datasets[i].Fields[x].Name)])); end; datBlob:begin Write(' result := NewROStream();'); Write(Format(' WriteVariantBinaryToBinary(BusinessProcessor.CurrentChange.OldValueByName[fld_%s%s], result.Stream);', [MakeValidIdentifier(Datasets[i].Name), MakeValidIdentifier(Datasets[i].Fields[x].Name)])); end; datDecimal: begin Write(Format(' result := GetVarDecimal(BusinessProcessor.CurrentChange.OldValueByName[fld_%s%s]);', [MakeValidIdentifier(Datasets[i].Name), MakeValidIdentifier(Datasets[i].Fields[x].Name), GetDAType(Fields[x].DataType)])); end; datXml: begin Write(Format(' result := GetVarXml(BusinessProcessor.CurrentChange.OldValueByName[fld_%s%s]);', [MakeValidIdentifier(Datasets[i].Name), MakeValidIdentifier(Datasets[i].Fields[x].Name), GetDAType(Fields[x].DataType)])); end; datGuid: begin Write(Format(' result := GetVarGuid(BusinessProcessor.CurrentChange.OldValueByName[fld_%s%s]);', [MakeValidIdentifier(Datasets[i].Name), MakeValidIdentifier(Datasets[i].Fields[x].Name), GetDAType(Fields[x].DataType)])); end; else begin Write(Format(' result := BusinessProcessor.CurrentChange.OldValueByName[fld_%s%s];', [MakeValidIdentifier(Datasets[i].Name), MakeValidIdentifier(Datasets[i].Fields[x].Name), GetDAType(Fields[x].DataType)])); end; end; Write('end;'); WriteEmptyLine; Write(Format('function T%sBusinessProcessorRules.GetOld%sIsNull: Boolean;', [MakeValidIdentifier(Name), MakeValidIdentifier(Fields[x].Name)])); Write('begin'); Write(Format(' result := VarIsNull(BusinessProcessor.CurrentChange.OldValueByName[fld_%s%s]);', [MakeValidIdentifier(Datasets[i].Name), MakeValidIdentifier(Datasets[i].Fields[x].Name)])); Write('end;'); WriteEmptyLine; if not(Fields[x].DataType in [datMemo, datBlob]) then begin Write(Format('procedure T%sBusinessProcessorRules.Set%sValue(const aValue: %s);', [MakeValidIdentifier(Name), MakeValidIdentifier(Fields[x].Name), GetDAType(Fields[x].DataType)])); Write('begin'); case Fields[x].DataType of datDecimal: begin Write(Format(' BusinessProcessor.CurrentChange.NewValueByName[fld_%s%s] := BCDToVariant(aValue);', [MakeValidIdentifier(Datasets[i].Name), MakeValidIdentifier(Datasets[i].Fields[x].Name), GetDAType(Fields[x].DataType)])); end; datXml: begin Write( ' if aValue = nil then'); Write(Format(' BusinessProcessor.CurrentChange.NewValueByName[fld_%s%s] := ''''', [MakeValidIdentifier(Datasets[i].Name), MakeValidIdentifier(Datasets[i].Fields[x].Name), GetDAType(Fields[x].DataType)])); Write( ' else'); Write(Format(' BusinessProcessor.CurrentChange.NewValueByName[fld_%s%s] := aValue.XML;', [MakeValidIdentifier(Datasets[i].Name), MakeValidIdentifier(Datasets[i].Fields[x].Name), GetDAType(Fields[x].DataType)])); end; datGuid: begin Write(Format(' BusinessProcessor.CurrentChange.NewValueByName[fld_%s%s] := GUIDToString(aValue);', [MakeValidIdentifier(Datasets[i].Name), MakeValidIdentifier(Datasets[i].Fields[x].Name), GetDAType(Fields[x].DataType)])); end; else Write(Format(' BusinessProcessor.CurrentChange.NewValueByName[fld_%s%s] := aValue;', [MakeValidIdentifier(Datasets[i].Name), MakeValidIdentifier(Datasets[i].Fields[x].Name), GetDAType(Fields[x].DataType)])); end; Write('end;'); WriteEmptyLine; end; Write(Format('procedure T%sBusinessProcessorRules.Set%sIsNull(const aValue: Boolean);', [MakeValidIdentifier(Name), MakeValidIdentifier(Fields[x].Name)])); Write('begin'); write(' if aValue then'); Write(Format(' BusinessProcessor.CurrentChange.NewValueByName[fld_%s%s] := Null;', [MakeValidIdentifier(Datasets[i].Name), MakeValidIdentifier(Datasets[i].Fields[x].Name)])); Write('end;'); WriteEmptyLine; end; end; WriteEmptyLine; end; Write('initialization'); for i := 0 to (Datasets.Count-1) do Write(Format('RegisterBusinessProcessorRules(RID_%sDelta, T%sBusinessProcessorRules);', [MakeValidIdentifier(Datasets[i].Name), MakeValidIdentifier(Datasets[i].Name)]), PASCAL_INDENTATION_LEVEL_1); WriteEmptyLine; Write('end.'); finally guids.Free; end; end; end.