github.com/RevenueMonster/sqlike@v1.0.6/examples/pagination.go (about)

     1  package examples
     2  
     3  import (
     4  	"context"
     5  	"sort"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/RevenueMonster/sqlike/sql/expr"
    10  	"github.com/RevenueMonster/sqlike/sqlike"
    11  	"github.com/RevenueMonster/sqlike/sqlike/actions"
    12  	"github.com/RevenueMonster/sqlike/sqlike/options"
    13  	"github.com/stretchr/testify/require"
    14  )
    15  
    16  type status string
    17  
    18  const (
    19  	statusActive  status = "ACTIVE"
    20  	statusSuspend status = "SUSPEND"
    21  )
    22  
    23  // User :
    24  type User struct {
    25  	ID        int64
    26  	Name      string
    27  	Age       int
    28  	Status    status `sqlike:",enum=ACTIVE|SUSPEND"`
    29  	CreatedAt time.Time
    30  }
    31  
    32  // Users :
    33  type Users []User
    34  
    35  // Len is part of sort.Interface.
    36  func (usrs Users) Len() int {
    37  	return len(usrs)
    38  }
    39  
    40  // Swap is part of sort.Interface.
    41  func (usrs Users) Swap(i, j int) {
    42  	usrs[i], usrs[j] = usrs[j], usrs[i]
    43  }
    44  
    45  // PaginationExamples :
    46  func PaginationExamples(ctx context.Context, t *testing.T, c *sqlike.Client) {
    47  	var (
    48  		// result *sqlike.Result
    49  		err error
    50  	)
    51  
    52  	db := c.SetPrimaryKey("ID").Database("sqlike")
    53  	table := db.Table("User")
    54  
    55  	{
    56  		err = table.DropIfExists(ctx)
    57  		require.NoError(t, err)
    58  	}
    59  
    60  	{
    61  		err = table.Migrate(ctx, User{})
    62  		require.NoError(t, err)
    63  	}
    64  
    65  	data := []User{
    66  		{10, "User A", 18, statusActive, time.Now().UTC()},
    67  		{88, "User B", 12, statusActive, time.Now().UTC()},
    68  		{8, "User F", 20, statusActive, time.Now().UTC()},
    69  		{27, "User C", 16, statusSuspend, time.Now().UTC()},
    70  		{20, "User C", 16, statusActive, time.Now().UTC()},
    71  		{100, "User G", 10, statusSuspend, time.Now().UTC()},
    72  		{21, "User C", 16, statusActive, time.Now().UTC()},
    73  		{50, "User D", 23, statusActive, time.Now().UTC()},
    74  		{5, "User E", 30, statusSuspend, time.Now().UTC()},
    75  	}
    76  
    77  	{
    78  		_, err = table.Insert(
    79  			ctx,
    80  			data, options.Insert().SetDebug(true),
    81  		)
    82  		require.NoError(t, err)
    83  	}
    84  
    85  	var (
    86  		users  []User
    87  		cursor interface{}
    88  	)
    89  
    90  	sort.SliceStable(data, func(i, j int) bool {
    91  		if data[i].Age > data[j].Age {
    92  			return true
    93  		}
    94  		if data[i].Age < data[j].Age {
    95  			return false
    96  		}
    97  		return data[i].ID > data[j].ID
    98  	})
    99  
   100  	// Paginate with simple query
   101  	{
   102  		pg, err := table.Paginate(
   103  			ctx,
   104  			actions.Paginate().
   105  				Where(
   106  					expr.GreaterOrEqual("Age", 0),
   107  				).
   108  				OrderBy(
   109  					expr.Desc("Age"),
   110  				).Limit(2),
   111  			options.Paginate().
   112  				SetDebug(true))
   113  		require.NoError(t, err)
   114  
   115  		for i := 0; i < len(data); i++ {
   116  			users = []User{}
   117  			err = pg.All(&users)
   118  			require.NoError(t, err)
   119  			if len(users) == 0 {
   120  				break
   121  			}
   122  			require.Equal(t, data[i].ID, users[0].ID)
   123  			cursor = users[len(users)-1].ID
   124  			if pg.NextCursor(ctx, cursor) != nil {
   125  				break
   126  			}
   127  		}
   128  	}
   129  
   130  	// Paginate with complex query
   131  	{
   132  		users = []User{} // reset
   133  		var result *sqlike.Result
   134  		result, err := table.Find(
   135  			ctx,
   136  			actions.Find().
   137  				Where(
   138  					expr.GreaterOrEqual("Age", 16),
   139  				).
   140  				OrderBy(
   141  					expr.Desc("Age"),
   142  					expr.Desc("ID"),
   143  				).Limit(100),
   144  			options.Find().
   145  				SetDebug(true))
   146  		require.NoError(t, err)
   147  		err = result.All(&users)
   148  		require.NoError(t, err)
   149  
   150  		results := []User{}
   151  		limit := 2
   152  		pg, err := table.Paginate(
   153  			ctx,
   154  			actions.Paginate().
   155  				Where(
   156  					expr.GreaterOrEqual("Age", 16),
   157  				).
   158  				OrderBy(
   159  					expr.Desc("Age"),
   160  				).
   161  				Limit(uint(limit)),
   162  			options.Paginate().SetDebug(true),
   163  		)
   164  		require.NoError(t, err)
   165  
   166  		var (
   167  			cursor int64
   168  			i      int
   169  		)
   170  
   171  		for {
   172  			err = pg.All(&results)
   173  			if err != nil {
   174  				require.NoError(t, err)
   175  			}
   176  
   177  			if len(results) == 0 || len(results) < limit {
   178  				break
   179  			}
   180  
   181  			cursor = results[len(results)-1].ID
   182  			require.True(t, len(users) > i)
   183  
   184  			require.Equal(t, results[0], users[i])
   185  			if err := pg.NextCursor(ctx, cursor); err != nil {
   186  				require.NoError(t, err)
   187  			}
   188  
   189  			i++
   190  		}
   191  	}
   192  
   193  	length := 4
   194  	actuals := [][]User{
   195  		data[:length],
   196  		data[length:(length * 2)],
   197  		data[length*2:],
   198  	}
   199  
   200  	pg, err := table.Paginate(
   201  		ctx,
   202  		actions.Paginate().
   203  			OrderBy(
   204  				expr.Desc("Age"),
   205  			).
   206  			Limit(uint(length)),
   207  		options.Paginate().
   208  			SetDebug(true))
   209  	require.NoError(t, err)
   210  
   211  	// Expected paginate with error
   212  	{
   213  		err = pg.NextCursor(ctx, nil)
   214  		require.Error(t, err)
   215  		err = pg.NextCursor(ctx, []string{})
   216  		require.Error(t, err)
   217  		var nilslice []string
   218  		err = pg.NextCursor(ctx, nilslice)
   219  		require.Error(t, err)
   220  		var nilmap map[string]interface{}
   221  		err = pg.NextCursor(ctx, nilmap)
   222  		require.Error(t, err)
   223  		err = pg.NextCursor(ctx, "")
   224  		require.Error(t, err)
   225  		err = pg.NextCursor(ctx, 0)
   226  		require.Error(t, err)
   227  		err = pg.NextCursor(ctx, false)
   228  		require.Error(t, err)
   229  		err = pg.NextCursor(ctx, float64(0))
   230  		require.Error(t, err)
   231  		err = pg.NextCursor(ctx, []byte(nil))
   232  		require.Error(t, err)
   233  	}
   234  
   235  	// pagination required more than 1 record
   236  	{
   237  		pg, err := table.Paginate(
   238  			ctx,
   239  			actions.Paginate().
   240  				OrderBy(
   241  					expr.Desc("Age"),
   242  				).
   243  				Limit(1),
   244  			options.Paginate().
   245  				SetDebug(true))
   246  		require.Error(t, err)
   247  		require.Nil(t, pg)
   248  	}
   249  
   250  	// Loop and get result set
   251  	{
   252  		users = []User{} // reset
   253  		for i := 0; i < len(actuals); i++ {
   254  			users = []User{}
   255  			err = pg.All(&users)
   256  			require.NoError(t, err)
   257  			if len(users) == 0 {
   258  				break
   259  			}
   260  			// require.ElementsMatch(t, actuals[i], users)
   261  			cursor = users[len(users)-1].ID
   262  			if pg.NextCursor(ctx, cursor) != nil {
   263  				break
   264  			}
   265  		}
   266  	}
   267  }