@@ -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
import SingleEntryCache from '../single-entry-cache' ;
21
22
@@ -81,6 +82,10 @@ export interface RedisClientOptions<
81
82
* TODO
82
83
*/
83
84
commandOptions ?: CommandOptions < TYPE_MAPPING > ;
85
+ /**
86
+ * TODO
87
+ */
88
+ clientSideCache ?: ClientSideCacheProvider | ClientSideCacheConfig ;
84
89
}
85
90
86
91
type WithCommands <
@@ -313,9 +318,8 @@ export default class RedisClient<
313
318
// was in a watch transaction when
314
319
// a topology change occured
315
320
#dirtyWatch?: string ;
316
- #epoch: number ;
317
321
#watchEpoch?: number ;
318
-
322
+ #clientSideCache?: ClientSideCacheProvider ;
319
323
#credentialsSubscription: Disposable | null = null ;
320
324
321
325
get options ( ) : RedisClientOptions < M , F , S , RESP > | undefined {
@@ -334,6 +338,11 @@ export default class RedisClient<
334
338
return this . _self . #queue. isPubSubActive ;
335
339
}
336
340
341
+ get socketEpoch ( ) {
342
+ return this . _self . #socket. socketEpoch ;
343
+ }
344
+
345
+
337
346
get isWatching ( ) {
338
347
return this . _self . #watchEpoch !== undefined ;
339
348
}
@@ -358,10 +367,20 @@ export default class RedisClient<
358
367
359
368
constructor ( options ?: RedisClientOptions < M , F , S , RESP , TYPE_MAPPING > ) {
360
369
super ( ) ;
370
+
361
371
this . #options = this . #initiateOptions( options ) ;
362
372
this . #queue = this . #initiateQueue( ) ;
363
373
this . #socket = this . #initiateSocket( ) ;
364
- this . #epoch = 0 ;
374
+
375
+ if ( options ?. clientSideCache ) {
376
+ if ( options . clientSideCache instanceof ClientSideCacheProvider ) {
377
+ this . #clientSideCache = options . clientSideCache ;
378
+ } else {
379
+ const cscConfig = options . clientSideCache ;
380
+ this . #clientSideCache = new BasicClientSideCache ( cscConfig ) ;
381
+ }
382
+ this . #queue. setInvalidateCallback ( this . #clientSideCache. invalidate . bind ( this . #clientSideCache) ) ;
383
+ }
365
384
}
366
385
367
386
#initiateOptions( options ?: RedisClientOptions < M , F , S , RESP , TYPE_MAPPING > ) : RedisClientOptions < M , F , S , RESP , TYPE_MAPPING > | undefined {
@@ -522,6 +541,13 @@ export default class RedisClient<
522
541
) ;
523
542
}
524
543
544
+ if ( this . #clientSideCache) {
545
+ const tracking = this . #clientSideCache. trackingOn ( ) ;
546
+ if ( tracking ) {
547
+ commands . push ( tracking ) ;
548
+ }
549
+ }
550
+
525
551
return commands ;
526
552
}
527
553
@@ -575,6 +601,7 @@ export default class RedisClient<
575
601
} )
576
602
. on ( 'error' , err => {
577
603
this . emit ( 'error' , err ) ;
604
+ this . #clientSideCache?. onError ( ) ;
578
605
if ( this . #socket. isOpen && ! this . #options?. disableOfflineQueue ) {
579
606
this . #queue. flushWaitingForReply ( err ) ;
580
607
} else {
@@ -583,7 +610,6 @@ export default class RedisClient<
583
610
} )
584
611
. on ( 'connect' , ( ) => this . emit ( 'connect' ) )
585
612
. on ( 'ready' , ( ) => {
586
- this . #epoch++ ;
587
613
this . emit ( 'ready' ) ;
588
614
this . #setPingTimer( ) ;
589
615
this . #maybeScheduleWrite( ) ;
@@ -711,14 +737,21 @@ export default class RedisClient<
711
737
commandOptions : CommandOptions < TYPE_MAPPING > | undefined ,
712
738
transformReply : TransformReply | undefined ,
713
739
) {
714
- const reply = await this . sendCommand ( parser . redisArgs , commandOptions ) ;
740
+ const csc = this . _self . #clientSideCache;
741
+ const defaultTypeMapping = this . _self . #options?. commandOptions === commandOptions ;
715
742
716
- if ( transformReply ) {
717
- const res = transformReply ( reply , parser . preserve , commandOptions ?. typeMapping ) ;
718
- return res
719
- }
743
+ const fn = ( ) => { return this . sendCommand ( parser . redisArgs , commandOptions ) } ;
720
744
721
- return reply ;
745
+ if ( csc && command . CACHEABLE && defaultTypeMapping ) {
746
+ return await csc . handleCache ( this . _self , parser as BasicCommandParser , fn , transformReply , commandOptions ?. typeMapping ) ;
747
+ } else {
748
+ const reply = await fn ( ) ;
749
+
750
+ if ( transformReply ) {
751
+ return transformReply ( reply , parser . preserve , commandOptions ?. typeMapping ) ;
752
+ }
753
+ return reply ;
754
+ }
722
755
}
723
756
724
757
/**
@@ -883,7 +916,7 @@ export default class RedisClient<
883
916
const reply = await this . _self . sendCommand (
884
917
pushVariadicArguments ( [ 'WATCH' ] , key )
885
918
) ;
886
- this . _self . #watchEpoch ??= this . _self . #epoch ;
919
+ this . _self . #watchEpoch ??= this . _self . socketEpoch ;
887
920
return reply as unknown as ReplyWithTypeMapping < SimpleStringReply < 'OK' > , TYPE_MAPPING > ;
888
921
}
889
922
@@ -950,7 +983,7 @@ export default class RedisClient<
950
983
}
951
984
952
985
const chainId = Symbol ( 'Pipeline Chain' ) ,
953
- promise = Promise . all (
986
+ promise = Promise . allSettled (
954
987
commands . map ( ( { args } ) => this . _self . #queue. addCommand ( args , {
955
988
chainId,
956
989
typeMapping : this . _commandOptions ?. typeMapping
@@ -986,7 +1019,7 @@ export default class RedisClient<
986
1019
throw new WatchError ( dirtyWatch ) ;
987
1020
}
988
1021
989
- if ( watchEpoch && watchEpoch !== this . _self . #epoch ) {
1022
+ if ( watchEpoch && watchEpoch !== this . _self . socketEpoch ) {
990
1023
throw new WatchError ( 'Client reconnected after WATCH' ) ;
991
1024
}
992
1025
@@ -1210,6 +1243,7 @@ export default class RedisClient<
1210
1243
return new Promise < void > ( resolve => {
1211
1244
clearTimeout ( this . _self . #pingTimer) ;
1212
1245
this . _self . #socket. close ( ) ;
1246
+ this . _self . #clientSideCache?. onClose ( ) ;
1213
1247
1214
1248
if ( this . _self . #queue. isEmpty ( ) ) {
1215
1249
this . _self . #socket. destroySocket ( ) ;
@@ -1236,6 +1270,7 @@ export default class RedisClient<
1236
1270
clearTimeout ( this . _self . #pingTimer) ;
1237
1271
this . _self . #queue. flushAll ( new DisconnectsClientError ( ) ) ;
1238
1272
this . _self . #socket. destroy ( ) ;
1273
+ this . _self . #clientSideCache?. onClose ( ) ;
1239
1274
this . _self . #credentialsSubscription?. dispose ( ) ;
1240
1275
this . _self . #credentialsSubscription = null ;
1241
1276
}
0 commit comments