Browse Source

Add search accounts starting by name indexed feature

PascalCoin 5 years ago
parent
commit
844ecbc166
3 changed files with 64 additions and 15 deletions
  1. 26 0
      src/core/UAccounts.pas
  2. 10 6
      src/core/UBaseTypes.pas
  3. 28 9
      src/core/UPCRPCFindAccounts.pas

+ 26 - 0
src/core/UAccounts.pas

@@ -348,6 +348,7 @@ Type
     Function GetActualCompactTargetHash(protocolVersion : Word): Cardinal;
     Function FindAccountByName(const aName : String) : Integer; overload;
     Function FindAccountByName(const aName : TRawBytes) : Integer; overload;
+    Function FindAccountsStartingByName(const AStartName : TRawBytes; const ARawList : TOrderedRawList; const AMax : Integer = 0) : Integer;
 
     Procedure Clear;
     Function Account(account_number : Cardinal) : TAccount;
@@ -4197,6 +4198,31 @@ begin
   end;
 end;
 
+function TPCSafeBox.FindAccountsStartingByName(const AStartName: TRawBytes;
+  const ARawList: TOrderedRawList; const AMax: Integer = 0): Integer;
+var LIndex : Integer;
+begin
+  ARawList.Clear;
+  StartThreadSafe;
+  try
+
+    if FOrderedByName.Find(AStartName,LIndex) then begin
+      ARawList.Add( FOrderedByName.Get(LIndex), FOrderedByName.GetTag(LIndex) );
+      inc(LIndex);
+    end;
+    while (LIndex<FOrderedByName.Count) and (TBaseType.StartsWith(AStartName,FOrderedByName.Get(LIndex)))
+      and ((AMax<=0) or (AMax>ARawList.Count)) // AMax <=0 inifinte results
+      do begin
+      ARawList.Add( FOrderedByName.Get(LIndex), FOrderedByName.GetTag(LIndex) );
+      inc(LIndex);
+    end;
+
+    Result := ARawList.Count;
+  finally
+    EndThreadSave;
+  end;
+end;
+
 procedure TPCSafeBox.SearchBlockWhenOnSeparatedChain(blockNumber: Cardinal; out blockAccount: TBlockAccount);
   Function WasUpdatedBeforeOrigin : Boolean;
   var j, maxUB : Integer;

+ 10 - 6
src/core/UBaseTypes.pas

@@ -457,20 +457,24 @@ begin
    Str2Len := Length(Str2);
    if ((Str1Len=0) and (Str2Len=0)) or (@Str1[Low(Str1)] = @Str2[Low(Str2)]) then
      Result := 0
-   else if (Str1Len < Str2Len) then
-     Result := -1
-   else if (Str1Len > Str2Len) then
-     Result := 1
    else begin
      Result := 0;
-     for i:= Low(Str1) to High(Str1) do begin
+     i := 0;
+     while (i<Length(Str1)) and (i<Length(Str2)) do begin
        if Str1[i] < Str2[i] then begin
          Result := -1;
          Break;
        end else if Str1[i] > Str2[i] then begin
          Result := 1;
          Break;
-       end
+       end;
+       inc(i);
+     end;
+     if (Result=0) then begin
+       if (Str1Len < Str2Len) then
+         Result := -1
+       else if (Str1Len > Str2Len) then
+         Result := 1;
      end;
    end;
 End;

+ 28 - 9
src/core/UPCRPCFindAccounts.pas

@@ -27,7 +27,7 @@ interface
 Uses classes, SysUtils,
   UJSONFunctions, UAccounts, UBaseTypes, UOpTransaction, UConst,
   {$IFNDEF FPC}System.Generics.Collections{$ELSE}Generics.Collections{$ENDIF},
-  URPC, UCrypto, UWallet, UBlockChain, ULog;
+  URPC, UCrypto, UWallet, UBlockChain, ULog, UPCOrderedLists;
 
 
 Type
@@ -149,7 +149,7 @@ var
   LErrors : String;
   LAccPubKey : TAccountKey;
   LOutput : TPCJSONArray;
-
+  LStartsWith : TOrderedRawList;
 begin
   // Get Parameters
   Result := False;
@@ -240,13 +240,32 @@ begin
     end;
   end else LSearchByPubkey := False;
   // Search by name
-  if ((Length(LAccountName)>0) AND (LSearchByNameType in [st_exact] )) then begin
-    LAccountNumber := ASender.Node.Bank.SafeBox.FindAccountByName(LAccountName);
-    if LAccountNumber >= 0 then begin
-      LAccount := ASender.Node.GetMempoolAccount(LAccountNumber);
-      if (_IsValidAccount(LAccount)) and
-        ((Not LSearchByPubkey) OR (TAccountComp.EqualAccountKeys(LAccPubKey,LAccount.accountInfo.accountKey))) then begin
-         TPascalCoinJSONComp.FillAccountObject(LAccount,LOutput.GetAsObject(LOutput.Count));
+  if ((Length(LAccountName)>0) AND (LSearchByNameType in [st_exact,st_startswith] )) then begin
+    if (LSearchByNameType in [st_exact]) then begin
+      LAccountNumber := ASender.Node.Bank.SafeBox.FindAccountByName(LAccountName);
+      if LAccountNumber >= 0 then begin
+        LAccount := ASender.Node.GetMempoolAccount(LAccountNumber);
+        if (_IsValidAccount(LAccount)) and
+          ((Not LSearchByPubkey) OR (TAccountComp.EqualAccountKeys(LAccPubKey,LAccount.accountInfo.accountKey))) then begin
+           TPascalCoinJSONComp.FillAccountObject(LAccount,LOutput.GetAsObject(LOutput.Count));
+        end;
+      end;
+    end else begin
+      // Starts-with indexed
+      LStartsWith := TOrderedRawList.Create;
+      try
+        LRaw.FromString(LAccountName);
+        ASender.Node.Bank.SafeBox.FindAccountsStartingByName(LRaw,LStartsWith,LMax);
+        for i := 0 to LStartsWith.Count-1 do begin
+          LAccountNumber := LStartsWith.GetTag(i);
+          LAccount := ASender.Node.GetMempoolAccount(LAccountNumber);
+          if (_IsValidAccount(LAccount)) and
+            ((Not LSearchByPubkey) OR (TAccountComp.EqualAccountKeys(LAccPubKey,LAccount.accountInfo.accountKey))) then begin
+             TPascalCoinJSONComp.FillAccountObject(LAccount,LOutput.GetAsObject(LOutput.Count));
+          end;
+        end;
+      finally
+        LStartsWith.Free;
       end;
     end;
   end else begin