encore.dev 1.54.2 → 1.56.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/config/secrets.ts +7 -1
- package/dist/config/secrets.js +4 -0
- package/dist/config/secrets.js.map +1 -1
- package/dist/internal/runtime/napi/napi.cjs +3 -1
- package/dist/internal/runtime/napi/napi.d.cts +114 -1
- package/dist/storage/cache/basic.d.ts +268 -0
- package/dist/storage/cache/basic.js +383 -0
- package/dist/storage/cache/basic.js.map +1 -0
- package/dist/storage/cache/cluster.d.ts +48 -0
- package/dist/storage/cache/cluster.js +40 -0
- package/dist/storage/cache/cluster.js.map +1 -0
- package/dist/storage/cache/errors.d.ts +19 -0
- package/dist/storage/cache/errors.js +59 -0
- package/dist/storage/cache/errors.js.map +1 -0
- package/dist/storage/cache/expiry.d.ts +55 -0
- package/dist/storage/cache/expiry.js +74 -0
- package/dist/storage/cache/expiry.js.map +1 -0
- package/dist/storage/cache/keyspace.d.ts +77 -0
- package/dist/storage/cache/keyspace.js +100 -0
- package/dist/storage/cache/keyspace.js.map +1 -0
- package/dist/storage/cache/list.d.ts +249 -0
- package/dist/storage/cache/list.js +376 -0
- package/dist/storage/cache/list.js.map +1 -0
- package/dist/storage/cache/mod.d.ts +10 -0
- package/dist/storage/cache/mod.js +13 -0
- package/dist/storage/cache/mod.js.map +1 -0
- package/dist/storage/cache/set.d.ts +258 -0
- package/dist/storage/cache/set.js +411 -0
- package/dist/storage/cache/set.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/internal/runtime/napi/napi.cjs +3 -1
- package/internal/runtime/napi/napi.d.cts +114 -1
- package/package.json +6 -1
- package/storage/cache/basic.ts +511 -0
- package/storage/cache/cluster.ts +67 -0
- package/storage/cache/errors.ts +66 -0
- package/storage/cache/expiry.ts +98 -0
- package/storage/cache/keyspace.ts +142 -0
- package/storage/cache/list.ts +496 -0
- package/storage/cache/mod.ts +36 -0
- package/storage/cache/set.ts +491 -0
|
@@ -0,0 +1,496 @@
|
|
|
1
|
+
import { getCurrentRequest } from "../../internal/reqtrack/mod";
|
|
2
|
+
import { CacheCluster } from "./cluster";
|
|
3
|
+
import { Keyspace, KeyspaceConfig, WriteOptions } from "./keyspace";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Position in a list (left/head or right/tail).
|
|
7
|
+
*/
|
|
8
|
+
export type ListPosition = "left" | "right";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Base class for list keyspaces with all list operations.
|
|
12
|
+
* Subclasses provide typed serialization/deserialization.
|
|
13
|
+
* @internal
|
|
14
|
+
*/
|
|
15
|
+
abstract class ListKeyspace<K, V> extends Keyspace<K> {
|
|
16
|
+
constructor(cluster: CacheCluster, config: KeyspaceConfig<K>) {
|
|
17
|
+
super(cluster, config);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
protected abstract serializeItem(value: V): Buffer;
|
|
21
|
+
protected abstract deserializeItem(data: Buffer): V;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Pushes one or more values at the head of the list stored at key.
|
|
25
|
+
* If the key does not already exist, it is first created as an empty list.
|
|
26
|
+
*
|
|
27
|
+
* If multiple values are given, they are inserted one after another,
|
|
28
|
+
* starting with the leftmost value. For instance,
|
|
29
|
+
* `pushLeft(key, "a", "b", "c")` will result in a list containing
|
|
30
|
+
* "c" as its first element, "b" as its second, and "a" as its third.
|
|
31
|
+
*
|
|
32
|
+
* @returns The length of the list after the operation.
|
|
33
|
+
* @see https://redis.io/commands/lpush/
|
|
34
|
+
*/
|
|
35
|
+
async pushLeft(key: K, ...values: V[]): Promise<number> {
|
|
36
|
+
const source = getCurrentRequest();
|
|
37
|
+
const mappedKey = this.mapKey(key);
|
|
38
|
+
const serialized = values.map((v) => this.serializeItem(v));
|
|
39
|
+
const ttlMs = this.resolveTtl();
|
|
40
|
+
const result = await this.cluster.impl.lpush(
|
|
41
|
+
mappedKey,
|
|
42
|
+
serialized,
|
|
43
|
+
ttlMs,
|
|
44
|
+
source
|
|
45
|
+
);
|
|
46
|
+
return Number(result);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Pushes one or more values at the tail of the list stored at key.
|
|
51
|
+
* If the key does not already exist, it is first created as an empty list.
|
|
52
|
+
*
|
|
53
|
+
* If multiple values are given, they are inserted one after another,
|
|
54
|
+
* starting with the leftmost value. For instance,
|
|
55
|
+
* `pushRight(key, "a", "b", "c")` will result in a list containing
|
|
56
|
+
* "a" as its first element, "b" as its second, and "c" as its third.
|
|
57
|
+
*
|
|
58
|
+
* @returns The length of the list after the operation.
|
|
59
|
+
* @see https://redis.io/commands/rpush/
|
|
60
|
+
*/
|
|
61
|
+
async pushRight(key: K, ...values: V[]): Promise<number> {
|
|
62
|
+
const source = getCurrentRequest();
|
|
63
|
+
const mappedKey = this.mapKey(key);
|
|
64
|
+
const serialized = values.map((v) => this.serializeItem(v));
|
|
65
|
+
const ttlMs = this.resolveTtl();
|
|
66
|
+
const result = await this.cluster.impl.rpush(
|
|
67
|
+
mappedKey,
|
|
68
|
+
serialized,
|
|
69
|
+
ttlMs,
|
|
70
|
+
source
|
|
71
|
+
);
|
|
72
|
+
return Number(result);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Pops a single element off the head of the list stored at key.
|
|
77
|
+
*
|
|
78
|
+
* @returns The popped value, or `undefined` if the key does not exist.
|
|
79
|
+
* @see https://redis.io/commands/lpop/
|
|
80
|
+
*/
|
|
81
|
+
async popLeft(key: K, options?: WriteOptions): Promise<V | undefined> {
|
|
82
|
+
const source = getCurrentRequest();
|
|
83
|
+
const mappedKey = this.mapKey(key);
|
|
84
|
+
const ttlMs = this.resolveTtl(options);
|
|
85
|
+
const result = await this.cluster.impl.lpop(mappedKey, ttlMs, source);
|
|
86
|
+
if (result === null) {
|
|
87
|
+
return undefined;
|
|
88
|
+
}
|
|
89
|
+
return this.deserializeItem(result);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Pops a single element off the tail of the list stored at key.
|
|
94
|
+
*
|
|
95
|
+
* @returns The popped value, or `undefined` if the key does not exist.
|
|
96
|
+
* @see https://redis.io/commands/rpop/
|
|
97
|
+
*/
|
|
98
|
+
async popRight(key: K, options?: WriteOptions): Promise<V | undefined> {
|
|
99
|
+
const source = getCurrentRequest();
|
|
100
|
+
const mappedKey = this.mapKey(key);
|
|
101
|
+
const ttlMs = this.resolveTtl(options);
|
|
102
|
+
const result = await this.cluster.impl.rpop(mappedKey, ttlMs, source);
|
|
103
|
+
if (result === null) {
|
|
104
|
+
return undefined;
|
|
105
|
+
}
|
|
106
|
+
return this.deserializeItem(result);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Returns the length of the list stored at key.
|
|
111
|
+
*
|
|
112
|
+
* Non-existing keys are considered as empty lists.
|
|
113
|
+
*
|
|
114
|
+
* @returns The list length.
|
|
115
|
+
* @see https://redis.io/commands/llen/
|
|
116
|
+
*/
|
|
117
|
+
async len(key: K): Promise<number> {
|
|
118
|
+
const source = getCurrentRequest();
|
|
119
|
+
const mappedKey = this.mapKey(key);
|
|
120
|
+
const result = await this.cluster.impl.llen(mappedKey, source);
|
|
121
|
+
return Number(result);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Trims the list stored at key to only contain the elements between the indices
|
|
126
|
+
* `start` and `stop` (inclusive). Both are zero-based indices.
|
|
127
|
+
*
|
|
128
|
+
* Negative indices can be used to indicate offsets from the end of the list,
|
|
129
|
+
* where -1 is the last element of the list, -2 the penultimate element, and so on.
|
|
130
|
+
*
|
|
131
|
+
* Out of range indices are valid and are treated as if they specify the start or end of the list,
|
|
132
|
+
* respectively. If `start` > `stop` the end result is an empty list.
|
|
133
|
+
*
|
|
134
|
+
* @param key - The cache key.
|
|
135
|
+
* @param start - Start index (inclusive).
|
|
136
|
+
* @param stop - Stop index (inclusive).
|
|
137
|
+
* @see https://redis.io/commands/ltrim/
|
|
138
|
+
*/
|
|
139
|
+
async trim(
|
|
140
|
+
key: K,
|
|
141
|
+
start: number,
|
|
142
|
+
stop: number,
|
|
143
|
+
options?: WriteOptions
|
|
144
|
+
): Promise<void> {
|
|
145
|
+
const source = getCurrentRequest();
|
|
146
|
+
const mappedKey = this.mapKey(key);
|
|
147
|
+
const ttlMs = this.resolveTtl(options);
|
|
148
|
+
await this.cluster.impl.ltrim(mappedKey, start, stop, ttlMs, source);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Updates the list element at the given index.
|
|
153
|
+
*
|
|
154
|
+
* Negative indices can be used to indicate offsets from the end of the list,
|
|
155
|
+
* where -1 is the last element of the list, -2 the penultimate element, and so on.
|
|
156
|
+
*
|
|
157
|
+
* @param key - The cache key.
|
|
158
|
+
* @param index - Zero-based index of the element to update.
|
|
159
|
+
* @param value - The new value.
|
|
160
|
+
* @throws {Error} If the index is out of range.
|
|
161
|
+
* @see https://redis.io/commands/lset/
|
|
162
|
+
*/
|
|
163
|
+
async set(
|
|
164
|
+
key: K,
|
|
165
|
+
index: number,
|
|
166
|
+
value: V,
|
|
167
|
+
options?: WriteOptions
|
|
168
|
+
): Promise<void> {
|
|
169
|
+
const source = getCurrentRequest();
|
|
170
|
+
const mappedKey = this.mapKey(key);
|
|
171
|
+
const serialized = this.serializeItem(value);
|
|
172
|
+
const ttlMs = this.resolveTtl(options);
|
|
173
|
+
await this.cluster.impl.lset(mappedKey, index, serialized, ttlMs, source);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Returns the value of the list element at the given index.
|
|
178
|
+
*
|
|
179
|
+
* Negative indices can be used to indicate offsets from the end of the list,
|
|
180
|
+
* where -1 is the last element of the list, -2 the penultimate element, and so on.
|
|
181
|
+
*
|
|
182
|
+
* @param key - The cache key.
|
|
183
|
+
* @param index - Zero-based index of the element to retrieve.
|
|
184
|
+
* @returns The value at the index, or `undefined` if out of range or the key does not exist.
|
|
185
|
+
* @see https://redis.io/commands/lindex/
|
|
186
|
+
*/
|
|
187
|
+
async get(key: K, index: number): Promise<V | undefined> {
|
|
188
|
+
const source = getCurrentRequest();
|
|
189
|
+
const mappedKey = this.mapKey(key);
|
|
190
|
+
const result = await this.cluster.impl.lindex(mappedKey, index, source);
|
|
191
|
+
|
|
192
|
+
if (result === null) {
|
|
193
|
+
return undefined;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return this.deserializeItem(result);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Returns all the elements in the list stored at key.
|
|
201
|
+
*
|
|
202
|
+
* If the key does not exist it returns an empty array.
|
|
203
|
+
*
|
|
204
|
+
* @returns All elements in the list.
|
|
205
|
+
* @see https://redis.io/commands/lrange/
|
|
206
|
+
*/
|
|
207
|
+
async items(key: K): Promise<V[]> {
|
|
208
|
+
const source = getCurrentRequest();
|
|
209
|
+
const mappedKey = this.mapKey(key);
|
|
210
|
+
const results = await this.cluster.impl.lrangeAll(mappedKey, source);
|
|
211
|
+
return results.map((r) => this.deserializeItem(r));
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Returns the elements in the list stored at key between `start` and `stop` (inclusive).
|
|
216
|
+
* Both are zero-based indices.
|
|
217
|
+
*
|
|
218
|
+
* Negative indices can be used to indicate offsets from the end of the list,
|
|
219
|
+
* where -1 is the last element of the list, -2 the penultimate element, and so on.
|
|
220
|
+
*
|
|
221
|
+
* If the key does not exist it returns an empty array.
|
|
222
|
+
*
|
|
223
|
+
* @param key - The cache key.
|
|
224
|
+
* @param start - Start index (inclusive).
|
|
225
|
+
* @param stop - Stop index (inclusive).
|
|
226
|
+
* @returns The elements in the specified range.
|
|
227
|
+
* @see https://redis.io/commands/lrange/
|
|
228
|
+
*/
|
|
229
|
+
async getRange(key: K, start: number, stop: number): Promise<V[]> {
|
|
230
|
+
const source = getCurrentRequest();
|
|
231
|
+
const mappedKey = this.mapKey(key);
|
|
232
|
+
const results = await this.cluster.impl.lrange(
|
|
233
|
+
mappedKey,
|
|
234
|
+
start,
|
|
235
|
+
stop,
|
|
236
|
+
source
|
|
237
|
+
);
|
|
238
|
+
return results.map((r) => this.deserializeItem(r));
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Inserts `value` into the list stored at key, at the position just before `pivot`.
|
|
243
|
+
*
|
|
244
|
+
* If the list does not contain `pivot`, the value is not inserted and -1 is returned.
|
|
245
|
+
*
|
|
246
|
+
* @param key - The cache key.
|
|
247
|
+
* @param pivot - The existing element to insert before.
|
|
248
|
+
* @param value - The value to insert.
|
|
249
|
+
* @returns The new list length, or -1 if `pivot` was not found.
|
|
250
|
+
* @see https://redis.io/commands/linsert/
|
|
251
|
+
*/
|
|
252
|
+
async insertBefore(
|
|
253
|
+
key: K,
|
|
254
|
+
pivot: V,
|
|
255
|
+
value: V,
|
|
256
|
+
options?: WriteOptions
|
|
257
|
+
): Promise<number> {
|
|
258
|
+
const source = getCurrentRequest();
|
|
259
|
+
const mappedKey = this.mapKey(key);
|
|
260
|
+
const pivotSerialized = this.serializeItem(pivot);
|
|
261
|
+
const valueSerialized = this.serializeItem(value);
|
|
262
|
+
const ttlMs = this.resolveTtl(options);
|
|
263
|
+
const result = await this.cluster.impl.linsertBefore(
|
|
264
|
+
mappedKey,
|
|
265
|
+
pivotSerialized,
|
|
266
|
+
valueSerialized,
|
|
267
|
+
ttlMs,
|
|
268
|
+
source
|
|
269
|
+
);
|
|
270
|
+
return Number(result);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Inserts `value` into the list stored at key, at the position just after `pivot`.
|
|
275
|
+
*
|
|
276
|
+
* If the list does not contain `pivot`, the value is not inserted and -1 is returned.
|
|
277
|
+
*
|
|
278
|
+
* @param key - The cache key.
|
|
279
|
+
* @param pivot - The existing element to insert after.
|
|
280
|
+
* @param value - The value to insert.
|
|
281
|
+
* @returns The new list length, or -1 if `pivot` was not found.
|
|
282
|
+
* @see https://redis.io/commands/linsert/
|
|
283
|
+
*/
|
|
284
|
+
async insertAfter(
|
|
285
|
+
key: K,
|
|
286
|
+
pivot: V,
|
|
287
|
+
value: V,
|
|
288
|
+
options?: WriteOptions
|
|
289
|
+
): Promise<number> {
|
|
290
|
+
const source = getCurrentRequest();
|
|
291
|
+
const mappedKey = this.mapKey(key);
|
|
292
|
+
const pivotSerialized = this.serializeItem(pivot);
|
|
293
|
+
const valueSerialized = this.serializeItem(value);
|
|
294
|
+
const ttlMs = this.resolveTtl(options);
|
|
295
|
+
const result = await this.cluster.impl.linsertAfter(
|
|
296
|
+
mappedKey,
|
|
297
|
+
pivotSerialized,
|
|
298
|
+
valueSerialized,
|
|
299
|
+
ttlMs,
|
|
300
|
+
source
|
|
301
|
+
);
|
|
302
|
+
return Number(result);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Removes all occurrences of `value` in the list stored at key.
|
|
307
|
+
*
|
|
308
|
+
* If the list does not contain `value`, or the list does not exist, returns 0.
|
|
309
|
+
*
|
|
310
|
+
* @param key - The cache key.
|
|
311
|
+
* @param value - The value to remove.
|
|
312
|
+
* @returns The number of elements removed.
|
|
313
|
+
* @see https://redis.io/commands/lrem/
|
|
314
|
+
*/
|
|
315
|
+
async removeAll(key: K, value: V, options?: WriteOptions): Promise<number> {
|
|
316
|
+
const source = getCurrentRequest();
|
|
317
|
+
const mappedKey = this.mapKey(key);
|
|
318
|
+
const valueSerialized = this.serializeItem(value);
|
|
319
|
+
const ttlMs = this.resolveTtl(options);
|
|
320
|
+
const result = await this.cluster.impl.lremAll(
|
|
321
|
+
mappedKey,
|
|
322
|
+
valueSerialized,
|
|
323
|
+
ttlMs,
|
|
324
|
+
source
|
|
325
|
+
);
|
|
326
|
+
return Number(result);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Removes the first `count` occurrences of `value` in the list stored at key,
|
|
331
|
+
* scanning from head to tail.
|
|
332
|
+
*
|
|
333
|
+
* If the list does not contain `value`, or the list does not exist, returns 0.
|
|
334
|
+
*
|
|
335
|
+
* @param key - The cache key.
|
|
336
|
+
* @param count - Maximum number of occurrences to remove.
|
|
337
|
+
* @param value - The value to remove.
|
|
338
|
+
* @returns The number of elements removed.
|
|
339
|
+
* @see https://redis.io/commands/lrem/
|
|
340
|
+
*/
|
|
341
|
+
async removeFirst(
|
|
342
|
+
key: K,
|
|
343
|
+
count: number,
|
|
344
|
+
value: V,
|
|
345
|
+
options?: WriteOptions
|
|
346
|
+
): Promise<number> {
|
|
347
|
+
if (count < 0) {
|
|
348
|
+
throw new Error("count must be non-negative");
|
|
349
|
+
}
|
|
350
|
+
const source = getCurrentRequest();
|
|
351
|
+
const mappedKey = this.mapKey(key);
|
|
352
|
+
const valueSerialized = this.serializeItem(value);
|
|
353
|
+
const ttlMs = this.resolveTtl(options);
|
|
354
|
+
const result = await this.cluster.impl.lremFirst(
|
|
355
|
+
mappedKey,
|
|
356
|
+
count,
|
|
357
|
+
valueSerialized,
|
|
358
|
+
ttlMs,
|
|
359
|
+
source
|
|
360
|
+
);
|
|
361
|
+
return Number(result);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Removes the last `count` occurrences of `value` in the list stored at key,
|
|
366
|
+
* scanning from tail to head.
|
|
367
|
+
*
|
|
368
|
+
* If the list does not contain `value`, or the list does not exist, returns 0.
|
|
369
|
+
*
|
|
370
|
+
* @param key - The cache key.
|
|
371
|
+
* @param count - Maximum number of occurrences to remove.
|
|
372
|
+
* @param value - The value to remove.
|
|
373
|
+
* @returns The number of elements removed.
|
|
374
|
+
* @see https://redis.io/commands/lrem/
|
|
375
|
+
*/
|
|
376
|
+
async removeLast(
|
|
377
|
+
key: K,
|
|
378
|
+
count: number,
|
|
379
|
+
value: V,
|
|
380
|
+
options?: WriteOptions
|
|
381
|
+
): Promise<number> {
|
|
382
|
+
if (count < 0) {
|
|
383
|
+
throw new Error("count must be non-negative");
|
|
384
|
+
}
|
|
385
|
+
const source = getCurrentRequest();
|
|
386
|
+
const mappedKey = this.mapKey(key);
|
|
387
|
+
const valueSerialized = this.serializeItem(value);
|
|
388
|
+
const ttlMs = this.resolveTtl(options);
|
|
389
|
+
// Negative count means remove from tail to head
|
|
390
|
+
const result = await this.cluster.impl.lremLast(
|
|
391
|
+
mappedKey,
|
|
392
|
+
count,
|
|
393
|
+
valueSerialized,
|
|
394
|
+
ttlMs,
|
|
395
|
+
source
|
|
396
|
+
);
|
|
397
|
+
return Number(result);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* Atomically moves an element from the list stored at `src` to the list stored at `dst`.
|
|
402
|
+
*
|
|
403
|
+
* The value moved can be either the head (`srcPos === "left"`) or tail (`srcPos === "right"`)
|
|
404
|
+
* of the list at `src`. Similarly, the value can be placed either at the head (`dstPos === "left"`)
|
|
405
|
+
* or tail (`dstPos === "right"`) of the list at `dst`.
|
|
406
|
+
*
|
|
407
|
+
* If `src` and `dst` are the same list, the value is atomically rotated from one end to the other
|
|
408
|
+
* when `srcPos !== dstPos`, or if `srcPos === dstPos` nothing happens.
|
|
409
|
+
*
|
|
410
|
+
* @param src - Source list key.
|
|
411
|
+
* @param dst - Destination list key.
|
|
412
|
+
* @param srcPos - Position to pop from in the source list.
|
|
413
|
+
* @param dstPos - Position to push to in the destination list.
|
|
414
|
+
* @returns The moved element, or `undefined` if the source list does not exist.
|
|
415
|
+
* @see https://redis.io/commands/lmove/
|
|
416
|
+
*/
|
|
417
|
+
async move(
|
|
418
|
+
src: K,
|
|
419
|
+
dst: K,
|
|
420
|
+
srcPos: ListPosition,
|
|
421
|
+
dstPos: ListPosition,
|
|
422
|
+
options?: WriteOptions
|
|
423
|
+
): Promise<V | undefined> {
|
|
424
|
+
const source = getCurrentRequest();
|
|
425
|
+
const srcKey = this.mapKey(src);
|
|
426
|
+
const dstKey = this.mapKey(dst);
|
|
427
|
+
const ttlMs = this.resolveTtl(options);
|
|
428
|
+
const result = await this.cluster.impl.lmove(
|
|
429
|
+
srcKey,
|
|
430
|
+
dstKey,
|
|
431
|
+
srcPos,
|
|
432
|
+
dstPos,
|
|
433
|
+
ttlMs,
|
|
434
|
+
source
|
|
435
|
+
);
|
|
436
|
+
if (result === null || result === undefined) {
|
|
437
|
+
return undefined;
|
|
438
|
+
}
|
|
439
|
+
return this.deserializeItem(result);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* StringListKeyspace stores lists of string values.
|
|
445
|
+
*
|
|
446
|
+
* @example
|
|
447
|
+
* ```ts
|
|
448
|
+
* const recentViews = new StringListKeyspace<string>(cluster, {
|
|
449
|
+
* keyPattern: "recent-views/:userId",
|
|
450
|
+
* defaultExpiry: ExpireIn(86400000), // 24 hours
|
|
451
|
+
* });
|
|
452
|
+
*
|
|
453
|
+
* await recentViews.pushLeft("user1", "product-123", "product-456");
|
|
454
|
+
* const views = await recentViews.items("user1");
|
|
455
|
+
* ```
|
|
456
|
+
*/
|
|
457
|
+
export class StringListKeyspace<K> extends ListKeyspace<K, string> {
|
|
458
|
+
constructor(cluster: CacheCluster, config: KeyspaceConfig<K>) {
|
|
459
|
+
super(cluster, config);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
protected serializeItem(value: string): Buffer {
|
|
463
|
+
return Buffer.from(value, "utf-8");
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
protected deserializeItem(data: Buffer): string {
|
|
467
|
+
return data.toString("utf-8");
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/**
|
|
472
|
+
* NumberListKeyspace stores lists of numeric values.
|
|
473
|
+
*
|
|
474
|
+
* @example
|
|
475
|
+
* ```ts
|
|
476
|
+
* const scores = new NumberListKeyspace<string>(cluster, {
|
|
477
|
+
* keyPattern: "scores/:gameId",
|
|
478
|
+
* });
|
|
479
|
+
*
|
|
480
|
+
* await scores.pushRight("game1", 100, 200, 300);
|
|
481
|
+
* const allScores = await scores.items("game1");
|
|
482
|
+
* ```
|
|
483
|
+
*/
|
|
484
|
+
export class NumberListKeyspace<K> extends ListKeyspace<K, number> {
|
|
485
|
+
constructor(cluster: CacheCluster, config: KeyspaceConfig<K>) {
|
|
486
|
+
super(cluster, config);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
protected serializeItem(value: number): Buffer {
|
|
490
|
+
return Buffer.from(String(value), "utf-8");
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
protected deserializeItem(data: Buffer): number {
|
|
494
|
+
return Number(data.toString("utf-8"));
|
|
495
|
+
}
|
|
496
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// Cache cluster
|
|
2
|
+
export { CacheCluster } from "./cluster";
|
|
3
|
+
export type { CacheClusterConfig, EvictionPolicy } from "./cluster";
|
|
4
|
+
|
|
5
|
+
// Keyspace configuration
|
|
6
|
+
export type { KeyspaceConfig, WriteOptions } from "./keyspace";
|
|
7
|
+
|
|
8
|
+
// Basic keyspaces
|
|
9
|
+
export {
|
|
10
|
+
StringKeyspace,
|
|
11
|
+
IntKeyspace,
|
|
12
|
+
FloatKeyspace,
|
|
13
|
+
StructKeyspace
|
|
14
|
+
} from "./basic";
|
|
15
|
+
|
|
16
|
+
// List keyspaces
|
|
17
|
+
export { StringListKeyspace, NumberListKeyspace } from "./list";
|
|
18
|
+
export type { ListPosition } from "./list";
|
|
19
|
+
|
|
20
|
+
// Set keyspaces
|
|
21
|
+
export { StringSetKeyspace, NumberSetKeyspace } from "./set";
|
|
22
|
+
|
|
23
|
+
// Expiry utilities
|
|
24
|
+
export {
|
|
25
|
+
expireIn,
|
|
26
|
+
expireInSeconds,
|
|
27
|
+
expireInMinutes,
|
|
28
|
+
expireInHours,
|
|
29
|
+
expireDailyAt,
|
|
30
|
+
neverExpire,
|
|
31
|
+
keepTTL
|
|
32
|
+
} from "./expiry";
|
|
33
|
+
export type { Expiry } from "./expiry";
|
|
34
|
+
|
|
35
|
+
// Error types
|
|
36
|
+
export { CacheError, CacheMiss, CacheKeyExists } from "./errors";
|