@@ -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 <
@@ -303,9 +308,8 @@ export default class RedisClient<
303
308
// was in a watch transaction when
304
309
// a topology change occured
305
310
#dirtyWatch?: string ;
306
- #epoch: number ;
307
311
#watchEpoch?: number ;
308
-
312
+ #clientSideCache?: ClientSideCacheProvider ;
309
313
#credentialsSubscription: Disposable | null = null ;
310
314
311
315
get options ( ) : RedisClientOptions < M , F , S , RESP > | undefined {
@@ -324,6 +328,11 @@ export default class RedisClient<
324
328
return this . _self . #queue. isPubSubActive ;
325
329
}
326
330
331
+ get socketEpoch ( ) {
332
+ return this . _self . #socket. socketEpoch ;
333
+ }
334
+
335
+
327
336
get isWatching ( ) {
328
337
return this . _self . #watchEpoch !== undefined ;
329
338
}
@@ -348,10 +357,20 @@ export default class RedisClient<
348
357
349
358
constructor ( options ?: RedisClientOptions < M , F , S , RESP , TYPE_MAPPING > ) {
350
359
super ( ) ;
360
+
351
361
this . #options = this . #initiateOptions( options ) ;
352
362
this . #queue = this . #initiateQueue( ) ;
353
363
this . #socket = this . #initiateSocket( ) ;
354
- this . #epoch = 0 ;
364
+
365
+ if ( options ?. clientSideCache ) {
366
+ if ( options . clientSideCache instanceof ClientSideCacheProvider ) {
367
+ this . #clientSideCache = options . clientSideCache ;
368
+ } else {
369
+ const cscConfig = options . clientSideCache ;
370
+ this . #clientSideCache = new BasicClientSideCache ( cscConfig ) ;
371
+ }
372
+ this . #queue. setInvalidateCallback ( this . #clientSideCache. invalidate . bind ( this . #clientSideCache) ) ;
373
+ }
355
374
}
356
375
357
376
#initiateOptions( options ?: RedisClientOptions < M , F , S , RESP , TYPE_MAPPING > ) : RedisClientOptions < M , F , S , RESP , TYPE_MAPPING > | undefined {
@@ -512,6 +531,13 @@ export default class RedisClient<
512
531
) ;
513
532
}
514
533
534
+ if ( this . #clientSideCache) {
535
+ const tracking = this . #clientSideCache. trackingOn ( ) ;
536
+ if ( tracking ) {
537
+ commands . push ( tracking ) ;
538
+ }
539
+ }
540
+
515
541
return commands ;
516
542
}
517
543
@@ -565,6 +591,7 @@ export default class RedisClient<
565
591
} )
566
592
. on ( 'error' , err => {
567
593
this . emit ( 'error' , err ) ;
594
+ this . #clientSideCache?. onError ( ) ;
568
595
if ( this . #socket. isOpen && ! this . #options?. disableOfflineQueue ) {
569
596
this . #queue. flushWaitingForReply ( err ) ;
570
597
} else {
@@ -573,7 +600,6 @@ export default class RedisClient<
573
600
} )
574
601
. on ( 'connect' , ( ) => this . emit ( 'connect' ) )
575
602
. on ( 'ready' , ( ) => {
576
- this . #epoch++ ;
577
603
this . emit ( 'ready' ) ;
578
604
this . #setPingTimer( ) ;
579
605
this . #maybeScheduleWrite( ) ;
@@ -701,13 +727,21 @@ export default class RedisClient<
701
727
commandOptions : CommandOptions < TYPE_MAPPING > | undefined ,
702
728
transformReply : TransformReply | undefined ,
703
729
) {
704
- const reply = await this . sendCommand ( parser . redisArgs , commandOptions ) ;
730
+ const csc = this . _self . #clientSideCache;
731
+ const defaultTypeMapping = this . _self . #options?. commandOptions === commandOptions ;
705
732
706
- if ( transformReply ) {
707
- return transformReply ( reply , parser . preserve , commandOptions ?. typeMapping ) ;
708
- }
733
+ const fn = ( ) => { return this . sendCommand ( parser . redisArgs , commandOptions ) } ;
709
734
710
- return reply ;
735
+ if ( csc && command . CACHEABLE && defaultTypeMapping ) {
736
+ return await csc . handleCache ( this . _self , parser as BasicCommandParser , fn , transformReply , commandOptions ?. typeMapping ) ;
737
+ } else {
738
+ const reply = await fn ( ) ;
739
+
740
+ if ( transformReply ) {
741
+ return transformReply ( reply , parser . preserve , commandOptions ?. typeMapping ) ;
742
+ }
743
+ return reply ;
744
+ }
711
745
}
712
746
713
747
/**
@@ -872,7 +906,7 @@ export default class RedisClient<
872
906
const reply = await this . _self . sendCommand (
873
907
pushVariadicArguments ( [ 'WATCH' ] , key )
874
908
) ;
875
- this . _self . #watchEpoch ??= this . _self . #epoch ;
909
+ this . _self . #watchEpoch ??= this . _self . socketEpoch ;
876
910
return reply as unknown as ReplyWithTypeMapping < SimpleStringReply < 'OK' > , TYPE_MAPPING > ;
877
911
}
878
912
@@ -939,7 +973,7 @@ export default class RedisClient<
939
973
}
940
974
941
975
const chainId = Symbol ( 'Pipeline Chain' ) ,
942
- promise = Promise . all (
976
+ promise = Promise . allSettled (
943
977
commands . map ( ( { args } ) => this . _self . #queue. addCommand ( args , {
944
978
chainId,
945
979
typeMapping : this . _commandOptions ?. typeMapping
@@ -975,7 +1009,7 @@ export default class RedisClient<
975
1009
throw new WatchError ( dirtyWatch ) ;
976
1010
}
977
1011
978
- if ( watchEpoch && watchEpoch !== this . _self . #epoch ) {
1012
+ if ( watchEpoch && watchEpoch !== this . _self . socketEpoch ) {
979
1013
throw new WatchError ( 'Client reconnected after WATCH' ) ;
980
1014
}
981
1015
@@ -1199,6 +1233,7 @@ export default class RedisClient<
1199
1233
return new Promise < void > ( resolve => {
1200
1234
clearTimeout ( this . _self . #pingTimer) ;
1201
1235
this . _self . #socket. close ( ) ;
1236
+ this . _self . #clientSideCache?. onClose ( ) ;
1202
1237
1203
1238
if ( this . _self . #queue. isEmpty ( ) ) {
1204
1239
this . _self . #socket. destroySocket ( ) ;
@@ -1225,6 +1260,7 @@ export default class RedisClient<
1225
1260
clearTimeout ( this . _self . #pingTimer) ;
1226
1261
this . _self . #queue. flushAll ( new DisconnectsClientError ( ) ) ;
1227
1262
this . _self . #socket. destroy ( ) ;
1263
+ this . _self . #clientSideCache?. onClose ( ) ;
1228
1264
this . _self . #credentialsSubscription?. dispose ( ) ;
1229
1265
this . _self . #credentialsSubscription = null ;
1230
1266
}
0 commit comments