-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpagination.ts
More file actions
166 lines (157 loc) · 4.29 KB
/
Copy pathpagination.ts
File metadata and controls
166 lines (157 loc) · 4.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
/**
* Demonstrates pagination using Deno KV.
*
* The key thing here is to use `iterator.done` to determine that you have reached the last item
* of a list (@see processIterator).
*/
import { deleteAllRecords } from "./util.ts";
// get rid of previous records
await deleteAllRecords();
interface User {
id: number;
name: string;
age: number;
}
const users = [
{
"id": 1,
"name": "John Doe",
"age": 25,
},
{
"id": 2,
"name": "Emma Smith",
"age": 32,
},
{
"id": 3,
"name": "Michael Brown",
"age": 40,
},
{
"id": 4,
"name": "Sophia Jackson",
"age": 19,
},
{
"id": 5,
"name": "William Davis",
"age": 37,
},
{
"id": 6,
"name": "Olivia Miller",
"age": 22,
},
{
"id": 7,
"name": "Barbara Jones",
"age": 17,
},
{
"id": 8,
"name": "Craig Sampson",
"age": 33,
},
];
const kv = await Deno.openKv();
// Insert users in two KV indexes; one by id, the other by age
for (const user of users) {
const result = await kv.atomic()
// check() not called since this is an insert
.set(["user", user.id], user)
.set(["user_by_age", user.age, user.id], user)
.commit();
if (!result.ok) {
throw new Error(`Problem persisting user ${user.name}`);
}
}
/**
* Obtains an iterator within a iteration series done by calling `Deno.Kv.list()` multiple times during
* pagination. The start of an iteration series is signalled when the cursor value is an empty string.
*
* @param {string} cursor - signals where is a group of results you currently are located. The start of
* iteration is signalled when `cursor` is an empty string.
* @param {number} limit - the number of items per iteration
* @param {Deno.KvKeyPart} - the prefix `list()` argument per iteration
* @param {T} - the generic parameter indicating the type of the item being iterated
* @returns {Deno.KvListIterator<T>} - an iterator over items of T type
*/
function getIterator<T>(
cursor: string,
limit: number,
prefix: Deno.KvKeyPart[],
): Deno.KvListIterator<T> {
const optionsArg = cursor !== "" ? { limit, cursor } : { limit };
const iterator = kv.list<T>({ prefix }, optionsArg);
return iterator;
}
/**
* Pulls out the data (items) contained in an iterator from a call to `getIterator()`
* and returns them with the latest cursor string.
*
* @param {T} - the type being iterated
* @param {Deno.KvListIterator<T>} iterator - the item iterator
* @returns {{ cursor: string; items: T[] }}
*/
async function processIterator<T>(
iterator: Deno.KvListIterator<T>,
): Promise<{ cursor: string; items: T[] }> {
let cursor = "";
let result = await iter.next();
const items: T[] = [];
while (!result.done) {
cursor = iterator.cursor;
// result.value returns full KvEntry object
const item = result.value.value as T;
items.push(item as T);
result = await iter.next();
}
return { cursor, items };
}
/**
* Prints `User` objects (name and age) with the page number to the console.
*
* @param users - the users to be printed
* @param {number} pageNum - the page number to be printed
*/
function printUsers(users: User[], pageNum: number) {
console.log(`Page ${pageNum}`);
for (const u of users) {
console.log(`${u.name} ${u.age}`);
}
}
// print out users in batches of USERS_PER_PAGE
const USERS_PER_PAGE = 3; // a.k.a. page size
const keyPart = ["user_by_age"]; // index key to sort users by age
let pageNum = 1; // in a webapp, this will be a query param
let cursor = ""; // in a webapp, this will be a query param
let iter = getIterator<User>(cursor, USERS_PER_PAGE, keyPart);
const processedItems = await processIterator<User>(iter);
printUsers(processedItems.items as User[], pageNum);
pageNum++; // in a webapp. increment this in the handler as a query param
cursor = processedItems.cursor; // in a webapp, set this in the handler as a query param
while (cursor !== "") {
iter = getIterator<User>(cursor, USERS_PER_PAGE, keyPart);
const iterRet = await processIterator<User>(iter);
cursor = iterRet.cursor;
const items: User[] = iterRet.items as User[];
if (items.length > 0) {
printUsers(items, pageNum);
}
pageNum++;
}
/*
EXPECTED RESULTS:
Page 1
Barbara Jones 17
Sophia Jackson 19
Olivia Miller 22
Page 2
John Doe 25
Emma Smith 32
Craig Sampson 33
Page 3
William Davis 37
Michael Brown 40
*/