diff --git a/go.mod b/go.mod index 3636ed1..fdbb203 100644 --- a/go.mod +++ b/go.mod @@ -128,6 +128,7 @@ require ( google.golang.org/grpc v1.64.1 // indirect google.golang.org/protobuf v1.34.2 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + gorm.io/driver/sqlite v1.4.3 ) replace gorm.io/gorm => github.com/itering/gorm v1.22.1 diff --git a/plugins/evm/dao/api.go b/plugins/evm/dao/api.go index 00b53ac..1ef91f5 100644 --- a/plugins/evm/dao/api.go +++ b/plugins/evm/dao/api.go @@ -6,6 +6,7 @@ import ( "github.com/itering/subscan/model" balanceModel "github.com/itering/subscan/plugins/balance/model" "github.com/itering/subscan/util" + chainAddress "github.com/itering/subscan/util/address" "github.com/shopspring/decimal" "strings" ) @@ -475,16 +476,24 @@ func (a AccountsJson) Cursor() string { func (a *ApiSrv) AccountsCursor(ctx context.Context, address string, limit int, before, after *string) ([]AccountsJson, map[string]interface{}) { var list []AccountsJson fetch := limit + 1 - q := sg.db.WithContext(ctx).Select("evm_account,balance").Model(&Account{}).Joins("join balance_accounts on evm_accounts.address=balance_accounts.address") + const balanceExpr = "COALESCE(balance_accounts.balance, 0)" + q := sg.db.WithContext(ctx). + Select("evm_accounts.evm_account, " + balanceExpr + " AS balance"). + Model(&Account{}). + Joins("left join balance_accounts on evm_accounts.address=balance_accounts.address") if address != "" { - q.Where("evm_account = ?", address) + q = q.Where("evm_accounts.evm_account = ?", chainAddress.Format(address)) } if cursor := cursorDecode(after); len(cursor) == 2 { - q = q.Where("(balance,evm_account) < (?,?)", cursor[0], cursor[1]).Order("balance desc").Order("balance_accounts.address desc") - } else if cursor = cursorDecode(after); len(cursor) == 2 { - q = q.Where("(balance,evm_account) < (?,?)", cursor[0], cursor[1]).Order("balance asc").Order("balance_accounts.address asc") + q = q.Where("("+balanceExpr+", evm_accounts.evm_account) < (?,?)", cursor[0], cursor[1]). + Order(balanceExpr + " desc"). + Order("evm_accounts.evm_account desc") + } else if cursor = cursorDecode(before); len(cursor) == 2 { + q = q.Where("("+balanceExpr+", evm_accounts.evm_account) > (?,?)", cursor[0], cursor[1]). + Order(balanceExpr + " asc"). + Order("evm_accounts.evm_account asc") } else { - q = q.Order("balance desc").Order("balance_accounts.address desc") + q = q.Order(balanceExpr + " desc").Order("evm_accounts.evm_account desc") } q.Limit(fetch).Scan(&list) var hasPrev, hasNext bool diff --git a/plugins/evm/dao/api_accounts_test.go b/plugins/evm/dao/api_accounts_test.go new file mode 100644 index 0000000..c9f7e5a --- /dev/null +++ b/plugins/evm/dao/api_accounts_test.go @@ -0,0 +1,40 @@ +package dao + +import ( + "context" + "testing" + + balanceModel "github.com/itering/subscan/plugins/balance/model" + "github.com/shopspring/decimal" + "github.com/stretchr/testify/require" + "gorm.io/driver/sqlite" + "gorm.io/gorm" +) + +func TestAccountsCursorIncludesAccountWithoutBalance(t *testing.T) { + db, err := gorm.Open(sqlite.Open("file::memory:?cache=shared"), &gorm.Config{}) + require.NoError(t, err) + require.NoError(t, db.AutoMigrate(&Account{}, &balanceModel.Account{})) + + previousStorage := sg + sg = &Storage{db: db} + t.Cleanup(func() { sg = previousStorage }) + + const evmAccount = "0x63c4545ac01c77cc74044f25b8edea3880224577" + require.NoError(t, db.Create(&Account{ + Address: "4c4a0baf647e07cc63c83684b35c7974421fda41e99d31741d1c8826c5abfc39", + EvmAccount: evmAccount, + }).Error) + require.NoError(t, db.Create(&Account{ + Address: "4c4a0baf647e07cc63c83684b35c7974421fda41e99d31741d1c8826c5abfc40", + EvmAccount: "0xffffffffffffffffffffffffffffffffffffffff", + }).Error) + + list, page := (&ApiSrv{}).AccountsCursor(context.Background(), "0x63C4545AC01C77CC74044F25B8EDEA3880224577", 10, nil, nil) + + require.Len(t, list, 1) + require.Equal(t, evmAccount, list[0].EvmAccount) + require.True(t, decimal.Zero.Equal(list[0].Balance)) + require.Equal(t, false, page["has_previous_page"]) + require.Equal(t, false, page["has_next_page"]) +}