github.com/cosmos/cosmos-sdk@v0.50.10/types/query/collections_pagination_test.go (about)

     1  package query
     2  
     3  import (
     4  	"context"
     5  	"testing"
     6  
     7  	db "github.com/cosmos/cosmos-db"
     8  	"github.com/stretchr/testify/require"
     9  
    10  	"cosmossdk.io/collections"
    11  	"cosmossdk.io/core/store"
    12  )
    13  
    14  func TestCollectionPagination(t *testing.T) {
    15  	sk, ctx := deps()
    16  	sb := collections.NewSchemaBuilder(sk)
    17  	m := collections.NewMap(sb, collections.NewPrefix(0), "_", collections.Uint64Key, collections.Uint64Value)
    18  
    19  	for i := uint64(0); i < 300; i++ {
    20  		require.NoError(t, m.Set(ctx, i, i))
    21  	}
    22  
    23  	createResults := func(from, to uint64) []collections.KeyValue[uint64, uint64] {
    24  		var res []collections.KeyValue[uint64, uint64]
    25  		if from <= to {
    26  			for i := from; i <= to; i++ {
    27  				res = append(res, collections.KeyValue[uint64, uint64]{
    28  					Key:   i,
    29  					Value: i,
    30  				})
    31  			}
    32  		} else {
    33  			for i := from; i >= to; i-- {
    34  				res = append(res, collections.KeyValue[uint64, uint64]{
    35  					Key:   i,
    36  					Value: i,
    37  				})
    38  			}
    39  		}
    40  		return res
    41  	}
    42  
    43  	encodeKey := func(key uint64) []byte {
    44  		b, err := encodeCollKey[uint64, uint64](m, key)
    45  		require.NoError(t, err)
    46  		return b
    47  	}
    48  
    49  	type test struct {
    50  		req        *PageRequest
    51  		expResp    *PageResponse
    52  		filter     func(key, value uint64) (bool, error)
    53  		expResults []collections.KeyValue[uint64, uint64]
    54  		wantErr    error
    55  	}
    56  
    57  	tcs := map[string]test{
    58  		"nil pagination": {
    59  			req: nil,
    60  			expResp: &PageResponse{
    61  				NextKey: encodeKey(100),
    62  				Total:   300,
    63  			},
    64  			expResults: createResults(0, 99),
    65  		},
    66  		"with key and limit": {
    67  			req: &PageRequest{
    68  				Key:   encodeKey(100),
    69  				Limit: 149,
    70  			},
    71  			expResp: &PageResponse{
    72  				NextKey: encodeKey(249),
    73  			},
    74  			expResults: createResults(100, 248),
    75  		},
    76  		"with reverse": {
    77  			req: &PageRequest{
    78  				Reverse: true,
    79  			},
    80  			expResp: &PageResponse{
    81  				NextKey: encodeKey(199),
    82  				Total:   300,
    83  			},
    84  			expResults: createResults(299, 200),
    85  		},
    86  		"with key and reverse": {
    87  			req: &PageRequest{
    88  				Key:     encodeKey(199),
    89  				Reverse: true,
    90  			},
    91  			expResp: &PageResponse{
    92  				NextKey: encodeKey(99),
    93  			},
    94  			expResults: createResults(199, 100),
    95  		},
    96  		"with offset and count total": {
    97  			req: &PageRequest{
    98  				Offset:     50,
    99  				Limit:      100,
   100  				CountTotal: true,
   101  			},
   102  			expResp: &PageResponse{
   103  				NextKey: encodeKey(150),
   104  				Total:   300,
   105  			},
   106  			expResults: createResults(50, 149),
   107  		},
   108  		"filtered no key": {
   109  			req: &PageRequest{
   110  				Limit: 3,
   111  			},
   112  			expResp: &PageResponse{
   113  				NextKey: encodeKey(5),
   114  			},
   115  			filter: func(key, value uint64) (bool, error) {
   116  				return key%2 == 0, nil
   117  			},
   118  			expResults: []collections.KeyValue[uint64, uint64]{
   119  				{Key: 0, Value: 0},
   120  				{Key: 2, Value: 2},
   121  				{Key: 4, Value: 4},
   122  			},
   123  		},
   124  		"filtered with key": {
   125  			req: &PageRequest{
   126  				Key:   encodeKey(2),
   127  				Limit: 3,
   128  			},
   129  			expResp: &PageResponse{
   130  				NextKey: encodeKey(5),
   131  			},
   132  			filter: func(key, value uint64) (bool, error) {
   133  				return key%2 == 0, nil
   134  			},
   135  			expResults: []collections.KeyValue[uint64, uint64]{
   136  				{Key: 2, Value: 2},
   137  				{Key: 4, Value: 4},
   138  			},
   139  		},
   140  	}
   141  
   142  	for name, tc := range tcs {
   143  		tc := tc
   144  		t.Run(name, func(t *testing.T) {
   145  			gotResults, gotResponse, err := CollectionFilteredPaginate(
   146  				ctx,
   147  				m,
   148  				tc.req,
   149  				tc.filter,
   150  				func(key, value uint64) (collections.KeyValue[uint64, uint64], error) {
   151  					return collections.KeyValue[uint64, uint64]{Key: key, Value: value}, nil
   152  				},
   153  			)
   154  			if tc.wantErr != nil {
   155  				require.ErrorIs(t, err, tc.wantErr)
   156  				return
   157  			}
   158  			require.NoError(t, err)
   159  			require.Equal(t, tc.expResults, gotResults)
   160  			require.Equal(t, tc.expResp, gotResponse)
   161  		})
   162  	}
   163  }
   164  
   165  type testStore struct {
   166  	db db.DB
   167  }
   168  
   169  func (t testStore) OpenKVStore(ctx context.Context) store.KVStore {
   170  	return t
   171  }
   172  
   173  func (t testStore) Get(key []byte) ([]byte, error) {
   174  	return t.db.Get(key)
   175  }
   176  
   177  func (t testStore) Has(key []byte) (bool, error) {
   178  	return t.db.Has(key)
   179  }
   180  
   181  func (t testStore) Set(key, value []byte) error {
   182  	return t.db.Set(key, value)
   183  }
   184  
   185  func (t testStore) Delete(key []byte) error {
   186  	return t.db.Delete(key)
   187  }
   188  
   189  func (t testStore) Iterator(start, end []byte) (store.Iterator, error) {
   190  	return t.db.Iterator(start, end)
   191  }
   192  
   193  func (t testStore) ReverseIterator(start, end []byte) (store.Iterator, error) {
   194  	return t.db.ReverseIterator(start, end)
   195  }
   196  
   197  var _ store.KVStore = testStore{}
   198  
   199  func deps() (store.KVStoreService, context.Context) {
   200  	kv := db.NewMemDB()
   201  	return &testStore{kv}, context.Background()
   202  }