@@ -16,6 +16,7 @@ import { ScanOptions, ScanCommonOptions } from '../commands/SCAN';
16
16
import { RedisLegacyClient , RedisLegacyClientType } from './legacy-mode' ;
17
17
import { RedisPoolOptions , RedisClientPool } from './pool' ;
18
18
import { RedisVariadicArgument , parseArgs , pushVariadicArguments } from '../commands/generic-transformers' ;
19
+ import { BasicClientSideCache , ClientSideCacheConfig , ClientSideCacheProvider } from './cache' ;
19
20
import { BasicCommandParser , CommandParser } from './parser' ;
20
21
21
22
export interface RedisClientOptions <
@@ -80,6 +81,10 @@ export interface RedisClientOptions<
80
81
* TODO
81
82
*/
82
83
commandOptions ?: CommandOptions < TYPE_MAPPING > ;
84
+ /**
85
+ * TODO
86
+ */
87
+ clientSideCache ?: ClientSideCacheProvider | ClientSideCacheConfig ;
83
88
}
84
89
85
90
type WithCommands <
@@ -300,9 +305,8 @@ export default class RedisClient<
300
305
private _self = this ;
301
306
private _commandOptions ?: CommandOptions < TYPE_MAPPING > ;
302
307
#dirtyWatch?: string ;
303
- #epoch: number ;
304
308
#watchEpoch?: number ;
305
-
309
+ #clientSideCache?: ClientSideCacheProvider ;
306
310
#credentialsSubscription: Disposable | null = null ;
307
311
308
312
get options ( ) : RedisClientOptions < M , F , S , RESP > | undefined {
@@ -321,6 +325,11 @@ export default class RedisClient<
321
325
return this . _self . #queue. isPubSubActive ;
322
326
}
323
327
328
+ get socketEpoch ( ) {
329
+ return this . _self . #socket. socketEpoch ;
330
+ }
331
+
332
+
324
333
get isWatching ( ) {
325
334
return this . _self . #watchEpoch !== undefined ;
326
335
}
@@ -331,10 +340,20 @@ export default class RedisClient<
331
340
332
341
constructor ( options ?: RedisClientOptions < M , F , S , RESP , TYPE_MAPPING > ) {
333
342
super ( ) ;
343
+
334
344
this . #options = this . #initiateOptions( options ) ;
335
345
this . #queue = this . #initiateQueue( ) ;
336
346
this . #socket = this . #initiateSocket( ) ;
337
- this . #epoch = 0 ;
347
+
348
+ if ( options ?. clientSideCache ) {
349
+ if ( options . clientSideCache instanceof ClientSideCacheProvider ) {
350
+ this . #clientSideCache = options . clientSideCache ;
351
+ } else {
352
+ const cscConfig = options . clientSideCache ;
353
+ this . #clientSideCache = new BasicClientSideCache ( cscConfig ) ;
354
+ }
355
+ this . #queue. setInvalidateCallback ( this . #clientSideCache. invalidate . bind ( this . #clientSideCache) ) ;
356
+ }
338
357
}
339
358
340
359
#initiateOptions( options ?: RedisClientOptions < M , F , S , RESP , TYPE_MAPPING > ) : RedisClientOptions < M , F , S , RESP , TYPE_MAPPING > | undefined {
@@ -495,6 +514,13 @@ export default class RedisClient<
495
514
) ;
496
515
}
497
516
517
+ if ( this . #clientSideCache) {
518
+ const tracking = this . #clientSideCache. trackingOn ( ) ;
519
+ if ( tracking ) {
520
+ commands . push ( tracking ) ;
521
+ }
522
+ }
523
+
498
524
return commands ;
499
525
}
500
526
@@ -548,6 +574,7 @@ export default class RedisClient<
548
574
} )
549
575
. on ( 'error' , err => {
550
576
this . emit ( 'error' , err ) ;
577
+ this . #clientSideCache?. onError ( ) ;
551
578
if ( this . #socket. isOpen && ! this . #options?. disableOfflineQueue ) {
552
579
this . #queue. flushWaitingForReply ( err ) ;
553
580
} else {
@@ -556,7 +583,6 @@ export default class RedisClient<
556
583
} )
557
584
. on ( 'connect' , ( ) => this . emit ( 'connect' ) )
558
585
. on ( 'ready' , ( ) => {
559
- this . #epoch++ ;
560
586
this . emit ( 'ready' ) ;
561
587
this . #setPingTimer( ) ;
562
588
this . #maybeScheduleWrite( ) ;
@@ -684,13 +710,21 @@ export default class RedisClient<
684
710
commandOptions : CommandOptions < TYPE_MAPPING > | undefined ,
685
711
transformReply : TransformReply | undefined ,
686
712
) {
687
- const reply = await this . sendCommand ( parser . redisArgs , commandOptions ) ;
713
+ const csc = this . _self . #clientSideCache;
714
+ const defaultTypeMapping = this . _self . #options?. commandOptions === commandOptions ;
688
715
689
- if ( transformReply ) {
690
- return transformReply ( reply , parser . preserve , commandOptions ?. typeMapping ) ;
691
- }
716
+ const fn = ( ) => { return this . sendCommand ( parser . redisArgs , commandOptions ) } ;
692
717
693
- return reply ;
718
+ if ( csc && command . CACHEABLE && defaultTypeMapping ) {
719
+ return await csc . handleCache ( this . _self , parser as BasicCommandParser , fn , transformReply , commandOptions ?. typeMapping ) ;
720
+ } else {
721
+ const reply = await fn ( ) ;
722
+
723
+ if ( transformReply ) {
724
+ return transformReply ( reply , parser . preserve , commandOptions ?. typeMapping ) ;
725
+ }
726
+ return reply ;
727
+ }
694
728
}
695
729
696
730
/**
@@ -855,7 +889,7 @@ export default class RedisClient<
855
889
const reply = await this . _self . sendCommand (
856
890
pushVariadicArguments ( [ 'WATCH' ] , key )
857
891
) ;
858
- this . _self . #watchEpoch ??= this . _self . #epoch ;
892
+ this . _self . #watchEpoch ??= this . _self . socketEpoch ;
859
893
return reply as unknown as ReplyWithTypeMapping < SimpleStringReply < 'OK' > , TYPE_MAPPING > ;
860
894
}
861
895
@@ -922,7 +956,7 @@ export default class RedisClient<
922
956
}
923
957
924
958
const chainId = Symbol ( 'Pipeline Chain' ) ,
925
- promise = Promise . all (
959
+ promise = Promise . allSettled (
926
960
commands . map ( ( { args } ) => this . _self . #queue. addCommand ( args , {
927
961
chainId,
928
962
typeMapping : this . _commandOptions ?. typeMapping
@@ -958,7 +992,7 @@ export default class RedisClient<
958
992
throw new WatchError ( dirtyWatch ) ;
959
993
}
960
994
961
- if ( watchEpoch && watchEpoch !== this . _self . #epoch ) {
995
+ if ( watchEpoch && watchEpoch !== this . _self . socketEpoch ) {
962
996
throw new WatchError ( 'Client reconnected after WATCH' ) ;
963
997
}
964
998
@@ -1182,6 +1216,7 @@ export default class RedisClient<
1182
1216
return new Promise < void > ( resolve => {
1183
1217
clearTimeout ( this . _self . #pingTimer) ;
1184
1218
this . _self . #socket. close ( ) ;
1219
+ this . _self . #clientSideCache?. onClose ( ) ;
1185
1220
1186
1221
if ( this . _self . #queue. isEmpty ( ) ) {
1187
1222
this . _self . #socket. destroySocket ( ) ;
@@ -1208,6 +1243,7 @@ export default class RedisClient<
1208
1243
clearTimeout ( this . _self . #pingTimer) ;
1209
1244
this . _self . #queue. flushAll ( new DisconnectsClientError ( ) ) ;
1210
1245
this . _self . #socket. destroy ( ) ;
1246
+ this . _self . #clientSideCache?. onClose ( ) ;
1211
1247
this . _self . #credentialsSubscription?. dispose ( ) ;
1212
1248
this . _self . #credentialsSubscription = null ;
1213
1249
}
0 commit comments