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 }