Extra Systems Database
unit table;

interface

uses
     common, database, windows, classes, sysutils;

type

     TEditMode = (emNone, emEdit, emAppend);

     TESDBTable = class(TObject)
     private
          FActive             : Boolean;
          FHandle             : HTABLE;
          FParent             : TESDBDatabase;
          FRecordSize         : Integer;
          FRecordBuffer       : Pointer;
          FCurrentRecord      : Integer;
          FTotalRecordsCount  : Integer;
          FRealRecordsCount   : Integer;
          FLastGetRecord      : Integer;
          FEditMode           : TEditMode;
          function ReadCurrentRecord:Boolean;
     public
          FieldsList: TESDBFieldsList;
          constructor Create(const Parent:TESDBDatabase);
          destructor Destroy; override;
          function Open(const TableName:String):Boolean;
          procedure Close;
          procedure Append;
          procedure Edit;
          function Pack:Boolean;
          procedure Delete;
          procedure Cancel;
          function SetIntegerField(const FieldName:String; const Value:Integer):Boolean;
          function SetStringField(const FieldName:String; const Value:String):Boolean;
          function SetDateTimeField(const FieldName:String; const Value:TDateTime):Boolean;
          function GetIntegerField(const FieldName:String):Integer;
          function GetStringField(const FieldName:String):String;
          function GetDateTimeField(const FieldName:String):TDateTime;
          function Post:Boolean;
          function TotalRecordsCount:Integer;
          function RealRecordsCount:Integer;
          procedure First;
          procedure Last;
          procedure Next;
          procedure Prior;
          function EOF:Boolean;
          function BOF:Boolean;
          property Active:Boolean read FActive;
     end;

implementation

constructor TESDBTable.Create(const Parent:TESDBDatabase);
begin
     inherited Create;
     FParent:=Parent;
     FActive:=False;
     FieldsList:=TESDBFieldsList.Create;
     FRecordBuffer:=nil;
     FEditMode:=emNone;
end;

destructor TESDBTable.Destroy;
begin
     Close;
     FieldsList.Free;
     inherited Destroy;
end;

function TESDBTable.Open(const TableName:String):Boolean;
var
     i,j:Integer;
     Field:TESDBField;
begin
     Result:=False;
     if FActive then Exit;
     FHandle:=FParent.OpenTable(TableName);
     FActive:=(FHandle > 0);
     Result:=FActive;
     if not Result then Exit;
     FParent.GetTableStructure(FHandle, FieldsList);
     FRecordSize:=0;
     j:=0;
     for i:=0 to FieldsList.Count - 1 do begin
          FieldsList.GetItem(i, Field);
          FRecordSize:=FRecordSize + Field.FieldLength;
          Field.FieldPosition:=j;
          j:=j + Field.FieldLength;
          FieldsList.SetItem(i, Field);
     end;
     FTotalRecordsCount:=FParent.GetTotalRecordsCount(FHandle);
     FRealRecordsCount:=FParent.GetRealRecordsCount(FHandle);
     FLastGetRecord:=-1;
     if (FRecordBuffer = nil) then begin
          GetMem(FRecordBuffer, FRecordSize);
          FillChar(FRecordBuffer^, FRecordSize, 0);
     end;
     First;
     FEditMode:=emNone;
end;

procedure TESDBTable.Close;
begin
     if not FActive then Exit;
     FParent.CloseTable(FHandle);
     if (FRecordBuffer <> nil) then begin
          FreeMem(FRecordBuffer);
          FRecordBuffer:=nil;
     end;
     FActive:=False;
end;

procedure TESDBTable.Append;
begin
     if not FActive then Exit;
     if (FEditMode <> emNone) then Exit;
     FCurrentRecord:=0;
     FillChar(FRecordBuffer^, FRecordSize, 0);
     FEditMode:=emAppend;
end;

procedure TESDBTable.Edit;
begin
     if not FActive then Exit;
     if (FEditMode <> emNone) then Exit;
     if (EOF or BOF) then Exit;
     if (FLastGetRecord <> FCurrentRecord) then Exit;
     FEditMode:=emEdit;
end;

procedure TESDBTable.Delete;
begin
     if not FActive then Exit;
     if (FEditMode <> emNone) then Exit;
     if (EOF or BOF) then Exit;
     if (FLastGetRecord <> FCurrentRecord) then Exit;
     if FParent.DeleteTableRecord(FHandle, FCurrentRecord) then begin
          Next;
     end;
end;

procedure TESDBTable.Cancel;
begin
     FEditMode:=emNone;
end;

function TESDBTable.SetIntegerField(const FieldName:String; const Value:Integer):Boolean;
begin
     Result:=False;
     if not FActive then Exit;
     if (FEditMode = emNone) then Exit;
     Result:=FParent.SetIntegerField(FieldName, Value, FieldsList, FRecordBuffer);
end;

function TESDBTable.GetStringField(const FieldName:String):String;
begin
     Result:='';
     if not FActive then Exit;
     Result:=FParent.GetStringField(FieldName, FieldsList, FRecordBuffer);
end;

function TESDBTable.GetIntegerField(const FieldName:String):Integer;
begin
     Result:=0;
     if not FActive then Exit;
     Result:=FParent.GetIntegerField(FieldName, FieldsList, FRecordBuffer);
end;

function TESDBTable.GetDateTimeField(const FieldName:String):TDateTime;
begin
     Result:=0;
     if not FActive then Exit;
     Result:=FParent.GetDateTimeField(FieldName, FieldsList, FRecordBuffer);
end;

function TESDBTable.SetDateTimeField(const FieldName:String; const Value:TDateTime):Boolean;
begin
     Result:=False;
     if not FActive then Exit;
     if (FEditMode = emNone) then Exit;
     Result:=FParent.SetDateTimeField(FieldName, Value, FieldsList, FRecordBuffer);
end;

function TESDBTable.SetStringField(const FieldName:String; const Value:String):Boolean;
begin
     Result:=False;
     if not FActive then Exit;
     if (FEditMode = emNone) then Exit;
     Result:=FParent.SetStringField(FieldName, Value, FieldsList, FRecordBuffer);
end;

function TESDBTable.Post:Boolean;
begin
     Result:=False;
     if not FActive then Exit;
     if (FEditMode = emNone) then Exit;
     Result:=FParent.PostTableRecord(FHandle, FCurrentRecord, FRecordBuffer, FRecordSize);
     if (Result and (FEditMode = emAppend)) then begin
          FTotalRecordsCount:=FTotalRecordsCount + 1;
          FRealRecordsCount:=FRealRecordsCount + 1;
          FCurrentRecord:=FTotalRecordsCount;
     end;
     FEditMode:=emNone;
end;

function TESDBTable.TotalRecordsCount:Integer;
begin
     if FActive then Result:=FTotalRecordsCount else Result:=0;
end;

function TESDBTable.RealRecordsCount:Integer;
begin
     if FActive then Result:=FRealRecordsCount else Result:=0;
end;

procedure TESDBTable.First;
begin
     if not FActive then Exit;
     FCurrentRecord:=1;
     while not EOF do begin
          if ReadCurrentRecord then Break;
          FCurrentRecord:=FCurrentRecord + 1;
     end;
end;

procedure TESDBTable.Last;
begin
     if not FActive then Exit;
     FCurrentRecord:=FTotalRecordsCount;
     while not BOF do begin
          if ReadCurrentRecord then Break;
          FCurrentRecord:=FCurrentRecord - 1;
     end;
end;

procedure TESDBTable.Next;
begin
     if not FActive then Exit;
     while not EOF do begin
          FCurrentRecord:=FCurrentRecord + 1;
          if EOF then Break;
          if ReadCurrentRecord then Break;
     end;
end;

procedure TESDBTable.Prior;
begin
     if not FActive then Exit;
     while not BOF do begin
          FCurrentRecord:=FCurrentRecord - 1;
          if BOF then Break;
          if ReadCurrentRecord then Break;
     end;
end;

function TESDBTable.ReadCurrentRecord:Boolean;
begin
     if (FRecordBuffer = nil) then begin
          GetMem(FRecordBuffer, FRecordSize);
          FillChar(FRecordBuffer^, FRecordSize, 0);
     end;
     Result:=(FParent.GetTableRecord(FHandle, FCurrentRecord, FRecordBuffer, FRecordSize) = grrOK);
     if Result then FLastGetRecord:=FCurrentRecord;
end;

function TESDBTable.EOF:Boolean;
begin
     if not FActive then begin
          Result:=True;
     end else begin
          Result:=(FCurrentRecord > FTotalRecordsCount);
     end;
end;

function TESDBTable.BOF:Boolean;
begin
     if not FActive then begin
          Result:=True;
     end else begin
          Result:=(FCurrentRecord < 1);
     end;
end;

function TESDBTable.Pack:Boolean;
begin
     if not FActive then begin
          Result:=False;
     end else begin
          Result:=FParent.PackTable(FHandle);
          if Result then begin
               FTotalRecordsCount:=FParent.GetTotalRecordsCount(FHandle);
               FRealRecordsCount:=FParent.GetRealRecordsCount(FHandle);
               FLastGetRecord:=-1;
               First;
               FEditMode:=emNone;
          end;
     end;
end;

end.