Browse Source

Refactor: improve datasource pattern

Herman Schoenfeld 7 years ago
parent
commit
e9b50760a7

+ 13 - 2
src/core.utils/UCoreUtils.pas

@@ -16,7 +16,7 @@ unit UCoreUtils;
 interface
 
 uses
-  Classes, SysUtils, UCrypto, UAccounts, UBlockChain,
+  Classes, SysUtils, UCrypto, UAccounts, UBlockChain, UCommon,
   Generics.Collections, Generics.Defaults;
 
 type
@@ -44,10 +44,14 @@ TOperationResumeHelper = record helper for TOperationResume
   function GetInfoText(const ABank : TPCBank) : utf8string;
 end;
 
+TTimeSpanHelper = record helper for TTimeSpan
+  function TotalBlockCount : Integer;
+end;
+
 implementation
 
 uses
-  UCommon, UMemory;
+  UMemory, UConst;
 
 { TAccountKeyComparer }
 
@@ -167,5 +171,12 @@ begin
   Result := builder.Text;
 end;
 
+{ TTimeSpanHelper }
+
+function TTimeSpanHelper.TotalBlockCount : Integer;
+begin
+  Result := Round( Self.TotalSeconds / CT_NewLineSecondsAvg );
+end;
+
 end.
 

+ 2 - 2
src/core.utils/UDataSources.pas

@@ -107,8 +107,8 @@ end;
 function TAccountsDataSourceBase.GetColumns : TDataColumns;
 begin
   Result := TDataColumns.Create(
+    TDataColumn.From('AccountNumber', true),
     TDataColumn.From('Account'),
-    TDataColumn.From('AccountNumber'),
     TDataColumn.From('Name'),
     TDataColumn.From('Balance'),
     TDataColumn.From('BalanceDecimal'),
@@ -266,6 +266,7 @@ end;
 function TOperationsDataSourceBase.GetColumns : TDataColumns;
 begin
   Result := TDataColumns.Create(
+    TDataColumn.From('OPHASH', true),
     TDataColumn.From('UnixTime'),
     TDataColumn.From('Time'),
     TDataColumn.From('Block'),
@@ -283,7 +284,6 @@ begin
     TDataColumn.From('Balance'),
     TDataColumn.From('BalanceDecimal'),
     TDataColumn.From('Payload'),
-    TDataColumn.From('OPHASH'),
     TDataColumn.From('Description')
   );
 end;

+ 29 - 59
src/core/UDataSources.pas

@@ -14,10 +14,8 @@ type
 
   TAccountsDataSourceBase = class(TCustomDataSource<TAccount>)
     protected
-      function GetItemDisposePolicy : TDisposePolicy; override;
       function GetColumns : TDataColumns; override;
     public
-      function GetEntityKey(constref AItem: TAccount) : Variant; override;
       function GetItemField(constref AItem: TAccount; const ABindingName : AnsiString) : Variant; override;
   end;
 
@@ -53,14 +51,12 @@ type
       function GetTimeSpan : TTimeSpan;
       procedure SetTimeSpan(const ASpan : TTimeSpan);
     protected
-      function GetItemDisposePolicy : TDisposePolicy; override;
       function GetColumns : TDataColumns;  override;
     public
       constructor Create(AOwner: TComponent); override;
       property TimeSpan : TTimeSpan read GetTimeSpan write SetTimeSpan;
       property StartBlock : Cardinal read FStart write FStart;
       property EndBlock : Cardinal read FEnd write FEnd;
-      function GetEntityKey(constref AItem: TOperationResume) : Variant; override;
       function GetItemField(constref AItem: TOperationResume; const ABindingName : AnsiString) : Variant; override;
   end;
 
@@ -99,16 +95,11 @@ uses
 
 { TAccountsDataSourceBase }
 
-function TAccountsDataSourceBase.GetItemDisposePolicy : TDisposePolicy;
-begin
-  Result := idpNone;
-end;
-
 function TAccountsDataSourceBase.GetColumns : TDataColumns;
 begin
   Result := TDataColumns.Create(
+    TDataColumn.From('AccountNumber', true),
     TDataColumn.From('Account'),
-    TDataColumn.From('AccountNumber'),
     TDataColumn.From('Name'),
     TDataColumn.From('Balance'),
     TDataColumn.From('BalanceDecimal'),
@@ -121,41 +112,35 @@ begin
   );
 end;
 
-function TAccountsDataSourceBase.GetEntityKey(constref AItem: TAccount) : Variant;
-begin
-  Result := AItem.account;
-end;
-
 function TAccountsDataSourceBase.GetItemField(constref AItem: TAccount; const ABindingName : AnsiString) : Variant;
 var
   index : Integer;
 begin
-   if ABindingName = 'Account' then
-     Result := TAccountComp.AccountNumberToAccountTxtNumber(AItem.account)
-   else if ABindingName = 'AccountNumber' then
-     Result := AItem.account
-   else if ABindingName = 'Name' then
-     Result := AItem.name
-   else if ABindingName = 'Balance' then
-     Result := AItem.Balance
-   else if ABindingName = 'BalanceDecimal' then
-     Result := TAccountComp.FormatMoneyDecimal(AItem.Balance)
-   else if ABindingName = 'Key' then
-     Result := TAccountComp.AccountPublicKeyExport(AItem.accountInfo.accountKey)
-   else if ABindingName = 'Type' then
-     Result := AItem.account_type
-   else if ABindingName = 'State' then
-     Result := AItem.accountInfo.state
-   else if ABindingName = 'Price' then
-     Result := AItem.accountInfo.price
-   else if ABindingName = 'PriceDecimal' then
-     Result := TAccountComp.FormatMoneyDecimal(AItem.accountInfo.price)
-   else if ABindingName = 'LockedUntil' then
-     Result := AItem.accountInfo.locked_until_block
-   else raise Exception.Create(Format('Field not found "%s"', [ABindingName]));
+  if ABindingName = 'AccountNumber' then
+    Result := AItem.account
+  else if ABindingName = 'Account' then
+    Result := TAccountComp.AccountNumberToAccountTxtNumber(AItem.account)
+  else if ABindingName = 'Name' then
+    Result := AItem.name
+  else if ABindingName = 'Balance' then
+    Result := AItem.Balance
+  else if ABindingName = 'BalanceDecimal' then
+    Result := TAccountComp.FormatMoneyDecimal(AItem.Balance)
+  else if ABindingName = 'Key' then
+    Result := TAccountComp.AccountPublicKeyExport(AItem.accountInfo.accountKey)
+  else if ABindingName = 'Type' then
+    Result := AItem.account_type
+  else if ABindingName = 'State' then
+    Result := AItem.accountInfo.state
+  else if ABindingName = 'Price' then
+    Result := AItem.accountInfo.price
+  else if ABindingName = 'PriceDecimal' then
+    Result := TAccountComp.FormatMoneyDecimal(AItem.accountInfo.price)
+  else if ABindingName = 'LockedUntil' then
+    Result := AItem.accountInfo.locked_until_block
+  else raise Exception.Create(Format('Field not found "%s"', [ABindingName]));
 end;
 
-
 { TAccountsDataSource }
 
 constructor TAccountsDataSource.Create(AOwner: TComponent);
@@ -244,7 +229,6 @@ end;
 function TOperationsDataSourceBase.GetTimeSpan : TTimeSpan;
 begin
   Result := TTimeSpan.FromSeconds( CT_NewLineSecondsAvg * (FEnd - FStart + 1) );
-  //XXXXXXXXXX TTimeSpan use not available at TPCOperationsComp  Result := TPCOperationsComp.ConvertBlockCountToTimeSpan(FEnd - FStart + 1);
 end;
 
 procedure TOperationsDataSourceBase.SetTimeSpan(const ASpan : TTimeSpan);
@@ -254,18 +238,13 @@ begin
  node := TNode.Node;
  if Not Assigned(Node) then exit;
  FEnd := node.Bank.BlocksCount - 1;
- FStart := ClipValue(FEnd - (Round( ASpan.TotalSeconds / CT_NewLineSecondsAvg ) + 1), 0, FEnd);
- //XXXXXXXXXX TTimeSpan use not available at TPCOperationsComp  FStart := ClipValue(FEnd - (TPCOperationsComp.ConvertTimeSpanToBlockCount(ASpan) + 1), 0, FEnd);
-end;
-
-function TOperationsDataSourceBase.GetItemDisposePolicy : TDisposePolicy;
-begin
-  Result := idpNone;
+ FStart := ClipValue(FEnd - (ASpan.TotalBlockCount + 1), 0, FEnd);
 end;
 
 function TOperationsDataSourceBase.GetColumns : TDataColumns;
 begin
   Result := TDataColumns.Create(
+    TDataColumn.From('OPHASH', true),
     TDataColumn.From('UnixTime'),
     TDataColumn.From('Time'),
     TDataColumn.From('Block'),
@@ -283,24 +262,17 @@ begin
     TDataColumn.From('Balance'),
     TDataColumn.From('BalanceDecimal'),
     TDataColumn.From('Payload'),
-    TDataColumn.From('OPHASH'),
     TDataColumn.From('Description')
   );
 end;
 
-function TOperationsDataSourceBase.GetEntityKey(constref AItem: TOperationResume) : Variant;
-begin
-  if AItem.valid then
-    Result := TPCOperation.OperationHashAsHexa(AItem.OperationHash)
-  else
-    Result := nil;
-end;
-
 function TOperationsDataSourceBase.GetItemField(constref AItem: TOperationResume; const ABindingName : AnsiString) : Variant;
 var
   index : Integer;
 begin
-  if ABindingName = 'UnixTime' then
+  if ABindingName = 'OPHASH' then
+    Result := TPCOperation.OperationHashAsHexa(AItem.OperationHash)
+  else if ABindingName = 'UnixTime' then
     Result := AItem.Time
   else if ABindingName = 'Time' then
     Result := UnixTimeToLocalStr(AItem.time)
@@ -334,8 +306,6 @@ begin
     Result := TAccountComp.FormatMoneyDecimal(AItem.Balance)
   else if ABindingName = 'Payload' then
     Result := AItem.PrintablePayload
-  else if ABindingName = 'OPHASH' then
-    Result := TPCOperation.OperationHashAsHexa(AItem.OperationHash)
   else if ABindingName = 'Description' then
     Result := AItem.OperationTxt
   else raise Exception.Create(Format('Field not found [%s]', [ABindingName]));

+ 25 - 17
src/libraries/sphere10/UCommon.Data.pas

@@ -48,9 +48,13 @@ const
   { TDataColumn }
 
   TDataColumn = record
-    Name : AnsiString;
-    // FType: typecode??
-    class function From(AName: AnsiString) : TDataColumn; overload; static;
+    private
+      FName : AnsiString;
+      FKey : boolean;
+    public
+      property Name : AnsiString read FName;
+      property IsKey : boolean read FKey;
+      class function From(const AName: AnsiString; IsKey : boolean = False) : TDataColumn; overload; static;
   end;
 
   TDataColumns = TArray<TDataColumn>;
@@ -118,12 +122,12 @@ const
 
   { TDataTable }
 
-  PDataTable = ^TDataTable;
   TDataTable = record
-  public
     Columns: TDataColumns;
     Rows : TArray<Variant>;
   end;
+  PDataTable = ^TDataTable;
+  EDataTable = class(Exception);
 
   { TColumnFilterPredicate -- should be implementation only }
 
@@ -181,14 +185,13 @@ const
       FClassID : PtrInt;
     protected
       function GetNullPolicy(const AFilter : TColumnFilter) : TSortNullPolicy; virtual;
-      function GetItemDisposePolicy : TDisposePolicy; virtual; abstract;
+      function GetItemDisposePolicy : TDisposePolicy; virtual;
       function GetColumns : TDataColumns; virtual; abstract;
       function ApplyColumnSort(constref Left, Right : T; constref AFilter: TColumnFilter) : Integer; virtual;
       function ApplyColumnFilter(constref AItem: T; constref AFilter: TColumnFilter) : boolean; virtual;
       function GetItemField(constref AItem: T; const ABindingName : AnsiString) : Variant; virtual; abstract;
       procedure DehydrateItem(constref AItem: T; var ADataRow: Variant);
       function FetchPage(constref AParams: TPageFetchParams; var ADataTable: TDataTable): TPageFetchResult;
-      function GetEntityKey(constref AItem: T) : Variant; virtual;
       procedure OnBeforeFetchAll(constref AParams: TPageFetchParams); virtual;
       procedure FetchAll(const AContainer : TList<T>); virtual; abstract;
       procedure OnAfterFetchAll(constref AParams: TPageFetchParams); virtual;
@@ -265,9 +268,10 @@ var
 
 { TDataColumn }
 
-class function TDataColumn.From(AName: AnsiString) : TDataColumn;
+class function TDataColumn.From(const AName: AnsiString; IsKey : boolean = False) : TDataColumn;
 begin
-  Result.Name := AName;
+  Result.FName := AName;
+  Result.FKey:= IsKey;
 end;
 
 { TDataRow }
@@ -422,6 +426,11 @@ begin
   end;
 end;
 
+function TCustomDataSource<T>.GetItemDisposePolicy : TDisposePolicy;
+begin
+  Result := idpNone;
+end;
+
 function TCustomDataSource<T>.ApplyColumnSort(constref Left, Right : T; constref AFilter: TColumnFilter) : Integer;
 var
   leftField, rightField : Variant;
@@ -490,11 +499,6 @@ begin
   end else Result := false;
 end;
 
-function TCustomDataSource<T>.GetEntityKey(constref AItem: T) : Variant;
-begin
-  Result := nil;
-end;
-
 function TCustomDataSource<T>.FetchPage(constref AParams: TPageFetchParams; var ADataTable: TDataTable): TPageFetchResult;
 var
   i, j : SizeInt;
@@ -553,7 +557,6 @@ begin
        for i := pageStart to pageEnd do begin
          ADataTable.Rows[j] := TDataRow.New(FClassID, ADataTable.Columns);
          DehydrateItem( data[i], ADataTable.Rows[j]);
-         ADataTable.Rows[j].__KEY := GetEntityKey(data[i]);
          inc(j)
        end;
      end;
@@ -568,11 +571,16 @@ var
   i : integer;
   LCols : TArray<TDataColumn>;
   LData : TDataRowData;
+  LField : Variant;
 begin
   LCols := GetColumns;
   LData := TDataRowData(ADataRow);
-  for i := Low(LCols) to High(LCols) do
-    LData[LCols[i].Name] := GetItemField(AItem, LCols[i].Name);
+  for i := Low(LCols) to High(LCols) do begin
+    LField := GetItemField(AItem, LCols[i].Name);
+    LData[LCols[i].Name] := LField;
+    if LCols[i].IsKey then
+      LData['__KEY'] := LField;
+  end;
 end;
 
 procedure TCustomDataSource<T>.OnBeforeFetchAll(constref AParams: TPageFetchParams);