Componentes.Terceros.RemObj.../internal/5.0.23.613/1/Data Abstract for Delphi/Source/uDADataStreamer.pas
david 2824855ea7 - Modificación del paquete RemObjects_Core_D10 para que sea un paquete de runtime/designtime (antes era designtime sólo)
- Recompilación en Delphi10 de todos los paquetes de RO para generar las DCU's en Lib\D10
- Recompilación en Delphi10 de todos los paquetes de DA para generar las DCU's en Lib\D10

git-svn-id: https://192.168.0.254/svn/Componentes.Terceros.RemObjects@9 b6239004-a887-0f4b-9937-50029ccdca16
2007-09-10 14:06:19 +00:00

651 lines
21 KiB
ObjectPascal

unit uDADataStreamer;
{----------------------------------------------------------------------------}
{ Data Abstract Library - Core Library }
{ }
{ compiler: Delphi 6 and up, Kylix 3 and up }
{ platform: Win32, Linux }
{ }
{ (c)opyright RemObjects Software. all rights reserved. }
{ }
{ Using this code requires a valid license of the Data Abstract }
{ which can be obtained at http://www.remobjects.com. }
{----------------------------------------------------------------------------}
{$I DataAbstract.inc}
interface
uses
Classes, SysUtils,
uRODL, uROTypes, uROClientIntf,
uDAInterfaces, uDAEngine, uDADelta,
DataAbstract3_Intf, DataAbstract4_Intf;
const
AllRows = -1;
DEFAULT_BUFFER_SIZE = 262144; //256kb
type
TDADataForAppend = class
public
TableSchema: TDADataset;
EndDataPosition: Integer;
CountOfRecordsPosition: Integer;
RecordCount: Integer;
MaxRowCount: Integer;
RealFields: array of integer;
end;
type
TDAAdapterInitialization = (aiUnknown, aiRead, aiReadFromBeginning, aiWrite);
TDAWriteOption = (woRows, woSchema);
TDAWriteOptions = set of TDAWriteOption;
const
AdapterReadModes = [aiRead, aiReadFromBeginning];
AdapterWriteModes = [aiWrite];
type
TDADataStreamer = class;
TDADatasetOperation = procedure(DataStreamer: TDADataStreamer; const Datasetname: string; const Dataset: IDADataset) of object;
TDADeltaOperation = procedure(DataStreamer: TDADataStreamer; const DeltaName: string; const Delta: IDADelta) of object;
TDAReadWriteFieldValue = procedure(const aField: TDAField; var Value: Variant) of object;
{ TDADataStreamer }
TDADataStreamer = class(TComponent)
private
fDeltaNames,
fDatasetNames: TStringList;
fOnInitialized,
fOnFinalized: TNotifyEvent;
fOnWriteDataset,
fOnReadDataset: TDADatasetOperation;
fOnWriteDelta,
fOnReadDelta: TDADeltaOperation;
fOnWriteFieldValue,
fOnReadFieldValue,
fOnBeforeFieldValueSerialization: TDAReadWriteFieldValue;
fBusy: boolean;
fAdapterInitialization: TDAAdapterInitialization;
fData: TStream;
FBufferSize: cardinal;
FSendReducedDelta: boolean;
function GetDatasetCount: integer;
function GetDatasetNames(Index: integer): string;
function GetDeltaCount: integer;
function GetDeltaNames(Index: integer): string;
procedure ClearReferences;
procedure CheckCanRead;
procedure CheckCanWrite;
function GetDatasetInfoObjects(Index: integer): TObject;
function GetDeltaInfoObjects(Index: integer): TObject;
procedure SetAdapterInitialization(const Value: TDAAdapterInitialization);
protected
// To override
function DoCreateStream: TStream; virtual; abstract;
procedure DoInitialize(Mode: TDAAdapterInitialization); virtual; abstract;
procedure DoFinalize; virtual; abstract;
function DoWriteDataset(const Source: IDADataset;
Options: TDAWriteOptions;
MaxRows: integer): integer;overload;
function DoWriteDataset(const Source: IDADataset;
Options: TDAWriteOptions;
MaxRows: integer;
ADynFieldNames: array of string): integer; overload; virtual; abstract;
procedure DoWriteDelta(const Source: IDADelta); virtual; abstract;
procedure DoReadDataset(const DatasetName: string;
const Destination: IDADataset;
ApplySchema: boolean); virtual;
procedure DoReadDelta(const DeltaName: string;
const Destination: IDADelta); virtual; abstract;
function DoBeginWriteDataset( const Source: IDADataset; const Schema: TDADataset;
Options: TDAWriteOptions; MaxRows: integer;
ADynFieldNames: array of string): TDADataForAppend; virtual; abstract;
function DoWriteDatasetData(const Source: IDADataset; var aDataForAppend: TDADataForAppend; aUnionSourceIndex: Integer = -1): Integer; virtual; abstract;
function DoEndWriteDataset(aDataForAppend: TDADataForAppend): Integer;virtual; abstract;
// Internal
procedure AddingDataset(const aDatasetName: string; InfoObject: TObject = nil);
procedure AddingDelta(const aDeltaName: string; InfoObject: TObject = nil);
property AdapterInitialization: TDAAdapterInitialization read fAdapterInitialization write SetAdapterInitialization;
property Data: TStream read fData;
property DatasetInfoObjects[Index: integer]: TObject read GetDatasetInfoObjects;
property DeltaInfoObjects[Index: integer]: TObject read GetDeltaInfoObjects;
procedure SetBufferSize(const Value: cardinal); virtual;
public
constructor Create(aOwner: TComponent); override;
destructor Destroy; override;
// Initialization methods
procedure Initialize({var }Stream: TStream; Mode: TDAAdapterInitialization);
procedure Finalize;
// Writing methods
function WriteDataset(const Source: IDADataset;
Options: TDAWriteOptions;
MaxRows: integer;
ADynFieldNames: array of string): integer; overload;
function WriteDataset(const Source: IDADataset;
Options: TDAWriteOptions;
MaxRows: integer = AllRows): integer; overload;
function WriteDataset(Stream: TStream;
const Source: IDADataset;
Options: TDAWriteOptions;
MaxRows: integer = AllRows): integer; overload;
function WriteDataset(Stream: TStream;
const Schema: IDASchema;
const Connection: IDAConnection;
const DatasetName: string;
const ParamNames: array of string;
const ParamValues: array of Variant;
InitializeStream: boolean = TRUE;
FinalizeStream: boolean = TRUE;
MaxRows: integer = AllRows): integer; overload;
function WriteDataset(Stream: TStream;
const Schema: IDASchema;
const Connection: IDAConnection;
const DatasetName: string;
InitializeStream: boolean = TRUE;
FinalizeStream: boolean = TRUE;
MaxRows: integer = AllRows): integer; overload;
procedure WriteDelta(const Source: IDADataset); overload;
procedure WriteDelta(const Source: IDADelta); overload;
procedure WriteDelta(Stream: TStream; const Source: IDADataset); overload;
// Reading methods
procedure ReadDelta(const DeltaName: string; const Destination: IDADelta); overload;
function ReadDelta(const DeltaName: string): IDADelta; overload;
procedure ReadDelta(const Destination: IDADataset); overload;
procedure ReadDelta(Stream: TStream;
const Destination: IDADelta;
DeltaName: string = '';
ReadFromBeginning: boolean = TRUE); overload;
procedure ReadDataset(const DatasetName: string;
const Destination: IDADataset;
ApplySchema: boolean = FALSE;
LoadRecords: boolean = TRUE); overload;
procedure ReadDataset(Stream: TStream;
const Destination: IDADataset;
ApplySchema: boolean = FALSE;
DatasetName: string = '';
LoadRecords: boolean = TRUE;
ReadFromBeginning: boolean = TRUE); overload;
function BeginWriteDataset(const Source: IDADataset; const Schema: TDADataset;
Options: TDAWriteOptions; MaxRows: integer;
ADynFieldNames: array of string): TDADataForAppend;
function WriteDatasetData(const Source: IDADataset; var aDataForAppend: TDADataForAppend; aUnionSourceIndex: Integer = -1): Integer;
function EndWriteDataset(aDataForAppend: TDADataForAppend): Integer;
// Misc
function FindDatasetIndex(const aName: string): integer;
function FindDeltaIndex(const aName: string): integer;
function GetDatasetIndex(const aName: string): integer;
function GetDeltaIndex(const aName: string): integer;
function GetTargetDataType: TRODataType; virtual; abstract;
function HasReducedDelta: Boolean; virtual;
property DatasetCount: integer read GetDatasetCount;
property DatasetNames[Index: integer]: string read GetDatasetNames;
property DeltaCount: integer read GetDeltaCount;
property DeltaNames[Index: integer]: string read GetDeltaNames;
property TargetDataType: TRODataType read GetTargetDataType;
property BufferSize: Cardinal read FBufferSize write SetBufferSize default DEFAULT_BUFFER_SIZE;
property SendReducedDelta: boolean read FSendReducedDelta write FSendReducedDelta default False;
published
property OnInitialized: TNotifyEvent read fOnInitialized write fOnInitialized;
property OnFinalized: TNotifyEvent read fOnFinalized write fOnFinalized;
property OnReadDataset: TDADatasetOperation read fOnReadDataset write fOnReadDataset;
property OnWriteDataset: TDADatasetOperation read fOnWriteDataset write fOnWriteDataset;
property OnReadDelta: TDADeltaOperation read fOnReadDelta write fOnReadDelta;
property OnWriteDelta: TDADeltaOperation read fOnWriteDelta write fOnWriteDelta;
property OnReadFieldValue: TDAReadWriteFieldValue read fOnReadFieldValue write fOnReadFieldValue;
property OnWriteFieldValue: TDAReadWriteFieldValue read fOnWriteFieldValue write fOnWriteFieldValue;
property OnBeforeFieldValueSerialization: TDAReadWriteFieldValue read fOnBeforeFieldValueSerialization write fOnBeforeFieldValueSerialization;
end;
TDADataAdapter = TDADataStreamer;
implementation
{ TDADataStreamer }
constructor TDADataStreamer.Create(aOwner: TComponent);
begin
inherited;
FBufferSize := DEFAULT_BUFFER_SIZE;
fDeltaNames := TStringList.Create;
{ Doesn't work correctly because it messes up the order in which the server processes the deltas!!!!
Fixed the methods that add elements to this down.
fDeltaNames.Sorted := TRUE;
fDeltaNames.Duplicates := dupError;}
fDatasetNames := TStringList.Create;
{ Fixed for consistency with the above
fDatasetNames.Sorted := TRUE;
fDatasetNames.Duplicates := dupError;}
end;
destructor TDADataStreamer.Destroy;
begin
ClearReferences;
FreeAndNIL(fDeltaNames);
FreeAndNIL(fDatasetNames);
inherited;
end;
function TDADataStreamer.GetDatasetCount: integer;
begin
result := fDatasetNames.Count;
end;
function TDADataStreamer.GetDatasetNames(Index: integer): string;
begin
result := fDatasetNames[Index];
end;
function TDADataStreamer.GetDeltaCount: integer;
begin
result := fDeltaNames.Count;
end;
function TDADataStreamer.GetDeltaNames(Index: integer): string;
begin
result := fDeltaNames[Index];
end;
procedure TDADataStreamer.ClearReferences;
var
i: integer;
begin
for i := 0 to (fDatasetNames.Count - 1) do
if (fDatasetNames.Objects[i] <> nil) then fDatasetNames.Objects[i].Free;
fDatasetNames.Clear;
for i := 0 to (fDeltaNames.Count - 1) do
if (fDeltaNames.Objects[i] <> nil) then fDeltaNames.Objects[i].Free;
fDeltaNames.Clear;
end;
procedure TDADataStreamer.Initialize({var }Stream: TStream; Mode: TDAAdapterInitialization);
begin
if fBusy then
raise EDAException.Create('Cannot Initialize Streamer that is already in use.');
ClearReferences;
fAdapterInitialization := aiUnknown;
fData := nil;
if Mode = aiUnknown then raise Exception.Create('Invalid DataStreamer initialization parameter.');
if (Stream = nil) then raise Exception.Create('Stream parameter must assigned.');
if (Mode in AdapterReadModes) and (Stream.Size = 0) then raise Exception.Create('Stream may not me empty for Read mode.');
try
if (Mode = aiReadFromBeginning) then Stream.Position := 0;
// Sets internal references
fData := Stream;
AdapterInitialization := Mode;
fDatasetNames.Clear;
DoInitialize(Mode); // Calls descendant's implementation
if Assigned(fOnInitialized) then fOnInitialized(Self);
fBusy := true;
except
ClearReferences;
raise;
end;
end;
procedure TDADataStreamer.Finalize;
begin
DoFinalize; // Calls descendant's implementation
if Assigned(fOnFinalized) then fOnFinalized(Self);
fBusy := false;
end;
procedure TDADataStreamer.CheckCanRead;
begin
if not (AdapterInitialization in AdapterReadModes) then raise Exception.Create('Adapter was not initialized for this operation');
end;
procedure TDADataStreamer.CheckCanWrite;
begin
if not (AdapterInitialization in AdapterWriteModes) then raise Exception.Create('Adapter was not initialized for this operation');
end;
procedure TDADataStreamer.ReadDelta(const DeltaName: string;
const Destination: IDADelta);
begin
CheckCanRead;
if Assigned(fOnReadDelta) then fOnReadDelta(Self, DeltaName, Destination);
DoReadDelta(DeltaName, Destination); // Calls descendant's implementation
end;
function TDADataStreamer.WriteDataset(const Source: IDADataset; Options: TDAWriteOptions;
MaxRows: integer = AllRows): integer;
begin
Result := WriteDataset(Source, Options, MaxRows, []);
end;
procedure TDADataStreamer.WriteDelta(const Source: IDADataset);
var
deltaowner: IDADeltaOwner;
delta: IDADelta;
begin
if not Supports(Source, IDADeltaOwner, deltaowner)
then raise Exception.Create('Source does not have a delta')
else delta := deltaowner.GetDelta;
CheckCanWrite;
if Assigned(fOnWriteDelta) then fOnWriteDelta(Self, delta.LogicalName, delta);
DoWriteDelta(delta); // Calls descendant's implementation
end;
procedure TDADataStreamer.AddingDataset(const aDatasetName: string; InfoObject: TObject = nil);
var i : integer;
begin
i := fDatasetNames.IndexOf(aDatasetName);
if (i>=0)
then raise Exception.Create('A dataset called "'+aDatasetName+'" is already present')
else fDatasetNames.AddObject(aDatasetName, InfoObject)
end;
procedure TDADataStreamer.AddingDelta(const aDeltaName: string; InfoObject: TObject = nil);
var i : integer;
begin
i := fDeltaNames.IndexOf(aDeltaName);
if (i>=0)
then raise Exception.Create('A delta called "'+aDeltaName+'" is already present')
else fDeltaNames.AddObject(aDeltaName, InfoObject)
end;
function TDADataStreamer.GetDatasetInfoObjects(Index: integer): TObject;
begin
result := fDatasetNames.Objects[Index]
end;
function TDADataStreamer.GetDeltaInfoObjects(Index: integer): TObject;
begin
result := fDeltaNames.Objects[Index]
end;
function TDADataStreamer.GetDatasetIndex(const aName: string): integer;
begin
result := FindDatasetIndex(aName);
if (result = -1) then raise Exception.Create('Unknown dataset ' + aName);
end;
function TDADataStreamer.GetDeltaIndex(const aName: string): integer;
begin
result := FindDeltaIndex(aName);
if (result = -1) then raise Exception.Create('Unknown delta ' + aName);
end;
procedure TDADataStreamer.ReadDataset(const DatasetName: string;
const Destination: IDADataset; ApplySchema: boolean = FALSE; LoadRecords: boolean = TRUE);
var editable: IDAEditableDataset;
begin
CheckCanRead;
if Assigned(fOnReadDataset) then fOnReadDataset(Self, DatasetName, Destination);
editable := Destination as IDAEditableDataset;
Destination.DisableControls;
try
editable.DisableEventHandlers;
try
if ApplySchema then begin
if Destination.Active then Destination.Close;
DoReadDataset(DatasetName, Destination, TRUE);
end;
if LoadRecords then
DoReadDataset(DatasetName, Destination, FALSE);
finally
editable.EnableEventHandlers;
end;
if LoadRecords then editable.Dataset.Resync([]);
finally
Destination.EnableControls;
end;
end;
procedure TDADataStreamer.ReadDataset(Stream: TStream;
const Destination: IDADataset;
ApplySchema: boolean = FALSE;
DatasetName: string = '';
LoadRecords: boolean = TRUE;
ReadFromBeginning: boolean = TRUE);
var
nme: string;
begin
if ReadFromBeginning then
Initialize(Stream, aiReadFromBeginning)
else
Initialize(Stream, aiRead);
if (DatasetName = '') then
nme := DatasetNames[0]
else
nme := DatasetName;
try
ReadDataset(nme, Destination, ApplySchema, LoadRecords);
finally
Finalize;
end;
end;
procedure TDADataStreamer.ReadDelta(Stream: TStream;
const Destination: IDADelta;
DeltaName: string = '';
ReadFromBeginning: boolean = TRUE);
var
nme: string;
begin
if ReadFromBeginning then
Initialize(Stream, aiReadFromBeginning)
else
Initialize(Stream, aiRead);
try
if (DeltaName <> '') then
nme := DeltaName
else
nme := DeltaNames[0];
ReadDelta(nme, Destination);
finally
Finalize;
end;
end;
function TDADataStreamer.WriteDataset(Stream: TStream;
const Source: IDADataset; Options: TDAWriteOptions;
MaxRows: integer): integer;
begin
Initialize(Stream, aiWrite);
try
result := WriteDataset(Source, Options, MaxRows);
finally
Finalize;
end;
end;
procedure TDADataStreamer.WriteDelta(Stream: TStream;
const Source: IDADataset);
begin
Initialize(Stream, aiWrite);
try
WriteDelta(Source);
finally
Finalize;
end;
end;
procedure TDADataStreamer.WriteDelta(const Source: IDADelta);
begin
DoWriteDelta(Source);
end;
procedure TDADataStreamer.ReadDelta(const Destination: IDADataset);
var
deltaowner: IDADeltaOwner;
delta: IDADelta;
begin
if not Supports(Destination, IDADeltaOwner, deltaowner)
then raise Exception.Create('Destination does not have a delta')
else delta := deltaowner.GetDelta;
ReadDelta(delta.LogicalName, delta);
end;
function TDADataStreamer.WriteDataset(Stream: TStream;
const Schema: IDASchema; const Connection: IDAConnection;
const DatasetName: string; const ParamNames: array of string;
const ParamValues: array of Variant; InitializeStream: boolean = TRUE;
FinalizeStream: boolean = TRUE; MaxRows: integer = AllRows): integer;
var
ds: IDADataset;
begin
if InitializeStream then Initialize(Stream, aiWrite);
ds := Schema.NewDataset(Connection, DatasetName, ParamNames, ParamValues, TRUE);
result := WriteDataset(ds, [woRows], MaxRows);
if FinalizeStream then Finalize;
end;
function TDADataStreamer.WriteDataset(Stream: TStream;
const Schema: IDASchema; const Connection: IDAConnection;
const DatasetName: string; InitializeStream, FinalizeStream: boolean;
MaxRows: integer): integer;
begin
result := WriteDataset(Stream, Schema, Connection, DatasetName, [], [],
InitializeStream, FinalizeStream, MaxRows);
end;
procedure TDADataStreamer.SetAdapterInitialization(
const Value: TDAAdapterInitialization);
begin
fAdapterInitialization := Value;
end;
function TDADataStreamer.ReadDelta(const DeltaName: string): IDADelta;
begin
result := NewDelta(DeltaName);
ReadDelta(DeltaName, Result);
end;
function TDADataStreamer.FindDatasetIndex(const aName: string): integer;
begin
result := fDatasetNames.IndexOf(aName);
end;
function TDADataStreamer.FindDeltaIndex(const aName: string): integer;
begin
result := fDeltaNames.IndexOf(aName);
end;
procedure TDADataStreamer.DoReadDataset(const DatasetName: string;
const Destination: IDADataset; ApplySchema: boolean);
begin
if Destination.Active and ApplySchema then raise Exception.Create('Cannot apply a schema if the destination is active');
end;
procedure TDADataStreamer.SetBufferSize(const Value: cardinal);
begin
FBufferSize := Value;
end;
function TDADataStreamer.HasReducedDelta: Boolean;
begin
Result:=False;
end;
function TDADataStreamer.DoWriteDataset(const Source: IDADataset;
Options: TDAWriteOptions; MaxRows: integer): integer;
begin
Result:= DoWriteDataset(Source, Options, MaxRows, []);
end;
function TDADataStreamer.WriteDataset(const Source: IDADataset;
Options: TDAWriteOptions; MaxRows: integer;
ADynFieldNames: array of string): integer;
begin
CheckCanWrite;
if Assigned(fOnWriteDataset) then fOnWriteDataset(Self, Source.LogicalName, Source);
result := DoWriteDataset(Source, Options, MaxRows, ADynFieldNames); // Calls descendant's implementation
end;
function TDADataStreamer.BeginWriteDataset(const Source: IDADataset; const Schema: TDADataset;
Options: TDAWriteOptions; MaxRows: integer;
ADynFieldNames: array of string): TDADataForAppend;
begin
result := DoBeginWriteDataset(Source, Schema, Options, MaxRows, ADynFieldNames); // Calls descendant's implementation
end;
function TDADataStreamer.WriteDatasetData(const Source: IDADataset; var aDataForAppend: TDADataForAppend; aUnionSourceIndex: Integer = -1): Integer;
begin
CheckCanWrite;
if Assigned(fOnWriteDataset) then fOnWriteDataset(Self, Source.LogicalName, Source);
result := DoWriteDatasetData(Source, aDataForAppend, aUnionSourceIndex); // Calls descendant's implementation
end;
function TDADataStreamer.EndWriteDataset(aDataForAppend: TDADataForAppend): Integer;
begin
result := DoEndWriteDataset(aDataForAppend); // Calls descendant's implementation
end;
end.