├── .deepsource.toml ├── .github ├── ISSUE_TEMPLATE │ ├── BUG-REPORT.yml │ ├── DOCUMENTATION.yml │ └── FEATURE-REQUEST.yml ├── PULL_REQUEST_TEMPLATE.md ├── release-drafter-base.yml ├── release-drafter │ ├── bloom-config.yml │ ├── entraid-config.yml │ ├── json-config.yml │ ├── search-config.yml │ └── time-series-config.yml └── workflows │ ├── codeql.yml │ ├── documentation.yml │ ├── release-drafter-bloom.yml │ ├── release-drafter-entraid.yml │ ├── release-drafter-json.yml │ ├── release-drafter-search.yml │ ├── release-drafter-time-series.yml │ ├── release.yml │ ├── stale-issues.yml │ └── tests.yml ├── .gitignore ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── SECURITY.md ├── benchmark ├── .gitignore ├── lib │ ├── defaults.yml │ ├── index.js │ ├── ping │ │ ├── ioredis-auto-pipeline.js │ │ ├── ioredis.js │ │ ├── local-resp2.js │ │ ├── local-resp3-buffer-proxy.js │ │ ├── local-resp3-buffer.js │ │ ├── local-resp3-module-with-flags.js │ │ ├── local-resp3-module.js │ │ ├── local-resp3.js │ │ ├── ping.yml │ │ ├── v3.js │ │ └── v4.js │ ├── runner.js │ └── set-get-delete-string │ │ ├── 1KB.yml │ │ ├── 1MB.yml │ │ ├── 8B.yml │ │ ├── index.js │ │ ├── ioredis.js │ │ ├── v3.js │ │ └── v4.js ├── package-lock.json ├── package.json └── requirements.txt ├── docs ├── FAQ.md ├── RESP.md ├── client-configuration.md ├── clustering.md ├── command-options.md ├── pool.md ├── programmability.md ├── pub-sub.md ├── scan-iterators.md ├── sentinel.md ├── todo.md ├── transactions.md ├── v3-to-v4.md ├── v4-to-v5.md └── v5.md ├── examples ├── .gitignore ├── README.md ├── blocking-list-pop.js ├── bloom-filter.js ├── check-connection-status.js ├── command-with-modifiers.js ├── connect-as-acl-user.js ├── connect-to-cluster.js ├── count-min-sketch.js ├── cuckoo-filter.js ├── dump-and-restore.js ├── get-server-time.js ├── hyperloglog.js ├── lua-multi-incr.js ├── managing-json.js ├── package.json ├── pubsub-publisher.js ├── pubsub-subscriber.js ├── search-hashes.js ├── search-json.js ├── search-knn.js ├── set-scan.js ├── sorted-set.js ├── stream-consumer-group.js ├── stream-consumer.js ├── stream-producer.js ├── time-series.js ├── topk.js ├── transaction-with-arbitrary-commands.js └── transaction-with-watch.js ├── package-lock.json ├── package.json ├── packages ├── bloom │ ├── .nycrc.json │ ├── .release-it.json │ ├── README.md │ ├── lib │ │ ├── commands │ │ │ ├── bloom │ │ │ │ ├── ADD.spec.ts │ │ │ │ ├── ADD.ts │ │ │ │ ├── CARD.spec.ts │ │ │ │ ├── CARD.ts │ │ │ │ ├── EXISTS.spec.ts │ │ │ │ ├── EXISTS.ts │ │ │ │ ├── INFO.spec.ts │ │ │ │ ├── INFO.ts │ │ │ │ ├── INSERT.spec.ts │ │ │ │ ├── INSERT.ts │ │ │ │ ├── LOADCHUNK.spec.ts │ │ │ │ ├── LOADCHUNK.ts │ │ │ │ ├── MADD.spec.ts │ │ │ │ ├── MADD.ts │ │ │ │ ├── MEXISTS.spec.ts │ │ │ │ ├── MEXISTS.ts │ │ │ │ ├── RESERVE.spec.ts │ │ │ │ ├── RESERVE.ts │ │ │ │ ├── SCANDUMP.spec.ts │ │ │ │ ├── SCANDUMP.ts │ │ │ │ ├── helpers.ts │ │ │ │ └── index.ts │ │ │ ├── count-min-sketch │ │ │ │ ├── INCRBY.spec.ts │ │ │ │ ├── INCRBY.ts │ │ │ │ ├── INFO.spec.ts │ │ │ │ ├── INFO.ts │ │ │ │ ├── INITBYDIM.spec.ts │ │ │ │ ├── INITBYDIM.ts │ │ │ │ ├── INITBYPROB.spec.ts │ │ │ │ ├── INITBYPROB.ts │ │ │ │ ├── MERGE.spec.ts │ │ │ │ ├── MERGE.ts │ │ │ │ ├── QUERY.spec.ts │ │ │ │ ├── QUERY.ts │ │ │ │ └── index.ts │ │ │ ├── cuckoo │ │ │ │ ├── ADD.spec.ts │ │ │ │ ├── ADD.ts │ │ │ │ ├── ADDNX.spec.ts │ │ │ │ ├── ADDNX.ts │ │ │ │ ├── COUNT.spec.ts │ │ │ │ ├── COUNT.ts │ │ │ │ ├── DEL.spec.ts │ │ │ │ ├── DEL.ts │ │ │ │ ├── EXISTS.spec.ts │ │ │ │ ├── EXISTS.ts │ │ │ │ ├── INFO.spec.ts │ │ │ │ ├── INFO.ts │ │ │ │ ├── INSERT.spec.ts │ │ │ │ ├── INSERT.ts │ │ │ │ ├── INSERTNX.spec.ts │ │ │ │ ├── INSERTNX.ts │ │ │ │ ├── LOADCHUNK.spec.ts │ │ │ │ ├── LOADCHUNK.ts │ │ │ │ ├── RESERVE.spec.ts │ │ │ │ ├── RESERVE.ts │ │ │ │ ├── SCANDUMP.spec.ts │ │ │ │ ├── SCANDUMP.ts │ │ │ │ └── index.ts │ │ │ ├── index.ts │ │ │ ├── t-digest │ │ │ │ ├── ADD.spec.ts │ │ │ │ ├── ADD.ts │ │ │ │ ├── BYRANK.spec.ts │ │ │ │ ├── BYRANK.ts │ │ │ │ ├── BYREVRANK.spec.ts │ │ │ │ ├── BYREVRANK.ts │ │ │ │ ├── CDF.spec.ts │ │ │ │ ├── CDF.ts │ │ │ │ ├── CREATE.spec.ts │ │ │ │ ├── CREATE.ts │ │ │ │ ├── INFO.spec.ts │ │ │ │ ├── INFO.ts │ │ │ │ ├── MAX.spec.ts │ │ │ │ ├── MAX.ts │ │ │ │ ├── MERGE.spec.ts │ │ │ │ ├── MERGE.ts │ │ │ │ ├── MIN.spec.ts │ │ │ │ ├── MIN.ts │ │ │ │ ├── QUANTILE.spec.ts │ │ │ │ ├── QUANTILE.ts │ │ │ │ ├── RANK.spec.ts │ │ │ │ ├── RANK.ts │ │ │ │ ├── RESET.spec.ts │ │ │ │ ├── RESET.ts │ │ │ │ ├── REVRANK.spec.ts │ │ │ │ ├── REVRANK.ts │ │ │ │ ├── TRIMMED_MEAN.spec.ts │ │ │ │ ├── TRIMMED_MEAN.ts │ │ │ │ └── index.ts │ │ │ └── top-k │ │ │ │ ├── ADD.spec.ts │ │ │ │ ├── ADD.ts │ │ │ │ ├── COUNT.spec.ts │ │ │ │ ├── COUNT.ts │ │ │ │ ├── INCRBY.spec.ts │ │ │ │ ├── INCRBY.ts │ │ │ │ ├── INFO.spec.ts │ │ │ │ ├── INFO.ts │ │ │ │ ├── LIST.spec.ts │ │ │ │ ├── LIST.ts │ │ │ │ ├── LIST_WITHCOUNT.spec.ts │ │ │ │ ├── LIST_WITHCOUNT.ts │ │ │ │ ├── QUERY.spec.ts │ │ │ │ ├── QUERY.ts │ │ │ │ ├── RESERVE.spec.ts │ │ │ │ ├── RESERVE.ts │ │ │ │ └── index.ts │ │ ├── index.ts │ │ └── test-utils.ts │ ├── package.json │ └── tsconfig.json ├── client │ ├── .nycrc.json │ ├── .release-it.json │ ├── README.md │ ├── index.ts │ ├── lib │ │ ├── RESP │ │ │ ├── decoder.spec.ts │ │ │ ├── decoder.ts │ │ │ ├── encoder.spec.ts │ │ │ ├── encoder.ts │ │ │ ├── types.ts │ │ │ └── verbatim-string.ts │ │ ├── authx │ │ │ ├── credentials-provider.ts │ │ │ ├── disposable.ts │ │ │ ├── identity-provider.ts │ │ │ ├── index.ts │ │ │ ├── token-manager.spec.ts │ │ │ ├── token-manager.ts │ │ │ └── token.ts │ │ ├── client │ │ │ ├── cache.spec.ts │ │ │ ├── cache.ts │ │ │ ├── commands-queue.ts │ │ │ ├── index.spec.ts │ │ │ ├── index.ts │ │ │ ├── legacy-mode.spec.ts │ │ │ ├── legacy-mode.ts │ │ │ ├── linked-list.spec.ts │ │ │ ├── linked-list.ts │ │ │ ├── multi-command.ts │ │ │ ├── parser.ts │ │ │ ├── pool.spec.ts │ │ │ ├── pool.ts │ │ │ ├── pub-sub.spec.ts │ │ │ ├── pub-sub.ts │ │ │ ├── socket.spec.ts │ │ │ └── socket.ts │ │ ├── cluster │ │ │ ├── cluster-slots.spec.ts │ │ │ ├── cluster-slots.ts │ │ │ ├── index.spec.ts │ │ │ ├── index.ts │ │ │ └── multi-command.ts │ │ ├── commander.ts │ │ ├── commands │ │ │ ├── ACL_CAT.spec.ts │ │ │ ├── ACL_CAT.ts │ │ │ ├── ACL_DELUSER.spec.ts │ │ │ ├── ACL_DELUSER.ts │ │ │ ├── ACL_DRYRUN.spec.ts │ │ │ ├── ACL_DRYRUN.ts │ │ │ ├── ACL_GENPASS.spec.ts │ │ │ ├── ACL_GENPASS.ts │ │ │ ├── ACL_GETUSER.spec.ts │ │ │ ├── ACL_GETUSER.ts │ │ │ ├── ACL_LIST.spec.ts │ │ │ ├── ACL_LIST.ts │ │ │ ├── ACL_LOAD.spec.ts │ │ │ ├── ACL_LOAD.ts │ │ │ ├── ACL_LOG.spec.ts │ │ │ ├── ACL_LOG.ts │ │ │ ├── ACL_LOG_RESET.spec.ts │ │ │ ├── ACL_LOG_RESET.ts │ │ │ ├── ACL_SAVE.spec.ts │ │ │ ├── ACL_SAVE.ts │ │ │ ├── ACL_SETUSER.spec.ts │ │ │ ├── ACL_SETUSER.ts │ │ │ ├── ACL_USERS.spec.ts │ │ │ ├── ACL_USERS.ts │ │ │ ├── ACL_WHOAMI.spec.ts │ │ │ ├── ACL_WHOAMI.ts │ │ │ ├── APPEND.spec.ts │ │ │ ├── APPEND.ts │ │ │ ├── ASKING.spec.ts │ │ │ ├── ASKING.ts │ │ │ ├── AUTH.spec.ts │ │ │ ├── AUTH.ts │ │ │ ├── BGREWRITEAOF.spec.ts │ │ │ ├── BGREWRITEAOF.ts │ │ │ ├── BGSAVE.spec.ts │ │ │ ├── BGSAVE.ts │ │ │ ├── BITCOUNT.spec.ts │ │ │ ├── BITCOUNT.ts │ │ │ ├── BITFIELD.spec.ts │ │ │ ├── BITFIELD.ts │ │ │ ├── BITFIELD_RO.spec.ts │ │ │ ├── BITFIELD_RO.ts │ │ │ ├── BITOP.spec.ts │ │ │ ├── BITOP.ts │ │ │ ├── BITPOS.spec.ts │ │ │ ├── BITPOS.ts │ │ │ ├── BLMOVE.spec.ts │ │ │ ├── BLMOVE.ts │ │ │ ├── BLMPOP.spec.ts │ │ │ ├── BLMPOP.ts │ │ │ ├── BLPOP.spec.ts │ │ │ ├── BLPOP.ts │ │ │ ├── BRPOP.spec.ts │ │ │ ├── BRPOP.ts │ │ │ ├── BRPOPLPUSH.spec.ts │ │ │ ├── BRPOPLPUSH.ts │ │ │ ├── BZMPOP.spec.ts │ │ │ ├── BZMPOP.ts │ │ │ ├── BZPOPMAX.spec.ts │ │ │ ├── BZPOPMAX.ts │ │ │ ├── BZPOPMIN.spec.ts │ │ │ ├── BZPOPMIN.ts │ │ │ ├── CLIENT_CACHING.spec.ts │ │ │ ├── CLIENT_CACHING.ts │ │ │ ├── CLIENT_GETNAME.spec.ts │ │ │ ├── CLIENT_GETNAME.ts │ │ │ ├── CLIENT_GETREDIR.spec.ts │ │ │ ├── CLIENT_GETREDIR.ts │ │ │ ├── CLIENT_ID.spec.ts │ │ │ ├── CLIENT_ID.ts │ │ │ ├── CLIENT_INFO.spec.ts │ │ │ ├── CLIENT_INFO.ts │ │ │ ├── CLIENT_KILL.spec.ts │ │ │ ├── CLIENT_KILL.ts │ │ │ ├── CLIENT_LIST.spec.ts │ │ │ ├── CLIENT_LIST.ts │ │ │ ├── CLIENT_NO-EVICT.spec.ts │ │ │ ├── CLIENT_NO-EVICT.ts │ │ │ ├── CLIENT_NO-TOUCH.spec.ts │ │ │ ├── CLIENT_NO-TOUCH.ts │ │ │ ├── CLIENT_PAUSE.spec.ts │ │ │ ├── CLIENT_PAUSE.ts │ │ │ ├── CLIENT_SETNAME.spec.ts │ │ │ ├── CLIENT_SETNAME.ts │ │ │ ├── CLIENT_TRACKING.spec.ts │ │ │ ├── CLIENT_TRACKING.ts │ │ │ ├── CLIENT_TRACKINGINFO.spec.ts │ │ │ ├── CLIENT_TRACKINGINFO.ts │ │ │ ├── CLIENT_UNPAUSE.spec.ts │ │ │ ├── CLIENT_UNPAUSE.ts │ │ │ ├── CLUSTER_ADDSLOTS.spec.ts │ │ │ ├── CLUSTER_ADDSLOTS.ts │ │ │ ├── CLUSTER_ADDSLOTSRANGE.spec.ts │ │ │ ├── CLUSTER_ADDSLOTSRANGE.ts │ │ │ ├── CLUSTER_BUMPEPOCH.spec.ts │ │ │ ├── CLUSTER_BUMPEPOCH.ts │ │ │ ├── CLUSTER_COUNT-FAILURE-REPORTS.spec.ts │ │ │ ├── CLUSTER_COUNT-FAILURE-REPORTS.ts │ │ │ ├── CLUSTER_COUNTKEYSINSLOT.spec.ts │ │ │ ├── CLUSTER_COUNTKEYSINSLOT.ts │ │ │ ├── CLUSTER_DELSLOTS.spec.ts │ │ │ ├── CLUSTER_DELSLOTS.ts │ │ │ ├── CLUSTER_DELSLOTSRANGE.spec.ts │ │ │ ├── CLUSTER_DELSLOTSRANGE.ts │ │ │ ├── CLUSTER_FAILOVER.spec.ts │ │ │ ├── CLUSTER_FAILOVER.ts │ │ │ ├── CLUSTER_FLUSHSLOTS.spec.ts │ │ │ ├── CLUSTER_FLUSHSLOTS.ts │ │ │ ├── CLUSTER_FORGET.spec.ts │ │ │ ├── CLUSTER_FORGET.ts │ │ │ ├── CLUSTER_GETKEYSINSLOT.spec.ts │ │ │ ├── CLUSTER_GETKEYSINSLOT.ts │ │ │ ├── CLUSTER_INFO.spec.ts │ │ │ ├── CLUSTER_INFO.ts │ │ │ ├── CLUSTER_KEYSLOT.spec.ts │ │ │ ├── CLUSTER_KEYSLOT.ts │ │ │ ├── CLUSTER_LINKS.spec.ts │ │ │ ├── CLUSTER_LINKS.ts │ │ │ ├── CLUSTER_MEET.spec.ts │ │ │ ├── CLUSTER_MEET.ts │ │ │ ├── CLUSTER_MYID.spec.ts │ │ │ ├── CLUSTER_MYID.ts │ │ │ ├── CLUSTER_MYSHARDID.spec.ts │ │ │ ├── CLUSTER_MYSHARDID.ts │ │ │ ├── CLUSTER_NODES.spec.ts │ │ │ ├── CLUSTER_NODES.ts │ │ │ ├── CLUSTER_REPLICAS.spec.ts │ │ │ ├── CLUSTER_REPLICAS.ts │ │ │ ├── CLUSTER_REPLICATE.spec.ts │ │ │ ├── CLUSTER_REPLICATE.ts │ │ │ ├── CLUSTER_RESET.spec.ts │ │ │ ├── CLUSTER_RESET.ts │ │ │ ├── CLUSTER_SAVECONFIG.spec.ts │ │ │ ├── CLUSTER_SAVECONFIG.ts │ │ │ ├── CLUSTER_SET-CONFIG-EPOCH.spec.ts │ │ │ ├── CLUSTER_SET-CONFIG-EPOCH.ts │ │ │ ├── CLUSTER_SETSLOT.spec.ts │ │ │ ├── CLUSTER_SETSLOT.ts │ │ │ ├── CLUSTER_SLOTS.spec.ts │ │ │ ├── CLUSTER_SLOTS.ts │ │ │ ├── COMMAND.spec.ts │ │ │ ├── COMMAND.ts │ │ │ ├── COMMAND_COUNT.spec.ts │ │ │ ├── COMMAND_COUNT.ts │ │ │ ├── COMMAND_GETKEYS.spec.ts │ │ │ ├── COMMAND_GETKEYS.ts │ │ │ ├── COMMAND_GETKEYSANDFLAGS.spec.ts │ │ │ ├── COMMAND_GETKEYSANDFLAGS.ts │ │ │ ├── COMMAND_INFO.spec.ts │ │ │ ├── COMMAND_INFO.ts │ │ │ ├── COMMAND_LIST.spec.ts │ │ │ ├── COMMAND_LIST.ts │ │ │ ├── CONFIG_GET.spec.ts │ │ │ ├── CONFIG_GET.ts │ │ │ ├── CONFIG_RESETSTAT.spec.ts │ │ │ ├── CONFIG_RESETSTAT.ts │ │ │ ├── CONFIG_REWRITE.spec.ts │ │ │ ├── CONFIG_REWRITE.ts │ │ │ ├── CONFIG_SET.spec.ts │ │ │ ├── CONFIG_SET.ts │ │ │ ├── COPY.spec.ts │ │ │ ├── COPY.ts │ │ │ ├── DBSIZE.spec.ts │ │ │ ├── DBSIZE.ts │ │ │ ├── DECR.spec.ts │ │ │ ├── DECR.ts │ │ │ ├── DECRBY.spec.ts │ │ │ ├── DECRBY.ts │ │ │ ├── DEL.spec.ts │ │ │ ├── DEL.ts │ │ │ ├── DISCARD.spec.ts │ │ │ ├── DISCARD.ts │ │ │ ├── DUMP.spec.ts │ │ │ ├── DUMP.ts │ │ │ ├── ECHO.spec.ts │ │ │ ├── ECHO.ts │ │ │ ├── EVAL.spec.ts │ │ │ ├── EVAL.ts │ │ │ ├── EVALSHA.spec.ts │ │ │ ├── EVALSHA.ts │ │ │ ├── EVALSHA_RO.spec.ts │ │ │ ├── EVALSHA_RO.ts │ │ │ ├── EVAL_RO.spec.ts │ │ │ ├── EVAL_RO.ts │ │ │ ├── EXISTS.spec.ts │ │ │ ├── EXISTS.ts │ │ │ ├── EXPIRE.spec.ts │ │ │ ├── EXPIRE.ts │ │ │ ├── EXPIREAT.spec.ts │ │ │ ├── EXPIREAT.ts │ │ │ ├── EXPIRETIME.spec.ts │ │ │ ├── EXPIRETIME.ts │ │ │ ├── FAILOVER.spec.ts │ │ │ ├── FAILOVER.ts │ │ │ ├── FCALL.spec.ts │ │ │ ├── FCALL.ts │ │ │ ├── FCALL_RO.spec.ts │ │ │ ├── FCALL_RO.ts │ │ │ ├── FLUSHALL.spec.ts │ │ │ ├── FLUSHALL.ts │ │ │ ├── FLUSHDB.spec.ts │ │ │ ├── FLUSHDB.ts │ │ │ ├── FUNCTION_DELETE.spec.ts │ │ │ ├── FUNCTION_DELETE.ts │ │ │ ├── FUNCTION_DUMP.spec.ts │ │ │ ├── FUNCTION_DUMP.ts │ │ │ ├── FUNCTION_FLUSH.spec.ts │ │ │ ├── FUNCTION_FLUSH.ts │ │ │ ├── FUNCTION_KILL.spec.ts │ │ │ ├── FUNCTION_KILL.ts │ │ │ ├── FUNCTION_LIST.spec.ts │ │ │ ├── FUNCTION_LIST.ts │ │ │ ├── FUNCTION_LIST_WITHCODE.spec.ts │ │ │ ├── FUNCTION_LIST_WITHCODE.ts │ │ │ ├── FUNCTION_LOAD.spec.ts │ │ │ ├── FUNCTION_LOAD.ts │ │ │ ├── FUNCTION_RESTORE.spec.ts │ │ │ ├── FUNCTION_RESTORE.ts │ │ │ ├── FUNCTION_STATS.spec.ts │ │ │ ├── FUNCTION_STATS.ts │ │ │ ├── GEOADD.spec.ts │ │ │ ├── GEOADD.ts │ │ │ ├── GEODIST.spec.ts │ │ │ ├── GEODIST.ts │ │ │ ├── GEOHASH.spec.ts │ │ │ ├── GEOHASH.ts │ │ │ ├── GEOPOS.spec.ts │ │ │ ├── GEOPOS.ts │ │ │ ├── GEORADIUS.spec.ts │ │ │ ├── GEORADIUS.ts │ │ │ ├── GEORADIUSBYMEMBER.spec.ts │ │ │ ├── GEORADIUSBYMEMBER.ts │ │ │ ├── GEORADIUSBYMEMBER_RO.spec.ts │ │ │ ├── GEORADIUSBYMEMBER_RO.ts │ │ │ ├── GEORADIUSBYMEMBER_RO_WITH.spec.ts │ │ │ ├── GEORADIUSBYMEMBER_RO_WITH.ts │ │ │ ├── GEORADIUSBYMEMBER_STORE.spec.ts │ │ │ ├── GEORADIUSBYMEMBER_STORE.ts │ │ │ ├── GEORADIUSBYMEMBER_WITH.spec.ts │ │ │ ├── GEORADIUSBYMEMBER_WITH.ts │ │ │ ├── GEORADIUS_RO.spec.ts │ │ │ ├── GEORADIUS_RO.ts │ │ │ ├── GEORADIUS_RO_WITH.spec.ts │ │ │ ├── GEORADIUS_RO_WITH.ts │ │ │ ├── GEORADIUS_STORE.spec.ts │ │ │ ├── GEORADIUS_STORE.ts │ │ │ ├── GEORADIUS_WITH.spec.ts │ │ │ ├── GEORADIUS_WITH.ts │ │ │ ├── GEOSEARCH.spec.ts │ │ │ ├── GEOSEARCH.ts │ │ │ ├── GEOSEARCHSTORE.spec.ts │ │ │ ├── GEOSEARCHSTORE.ts │ │ │ ├── GEOSEARCH_WITH.spec.ts │ │ │ ├── GEOSEARCH_WITH.ts │ │ │ ├── GET.spec.ts │ │ │ ├── GET.ts │ │ │ ├── GETBIT.spec.ts │ │ │ ├── GETBIT.ts │ │ │ ├── GETDEL.spec.ts │ │ │ ├── GETDEL.ts │ │ │ ├── GETEX.spec.ts │ │ │ ├── GETEX.ts │ │ │ ├── GETRANGE.spec.ts │ │ │ ├── GETRANGE.ts │ │ │ ├── GETSET.spec.ts │ │ │ ├── GETSET.ts │ │ │ ├── HDEL.spec.ts │ │ │ ├── HDEL.ts │ │ │ ├── HELLO.spec.ts │ │ │ ├── HELLO.ts │ │ │ ├── HEXISTS.spec.ts │ │ │ ├── HEXISTS.ts │ │ │ ├── HEXPIRE.spec.ts │ │ │ ├── HEXPIRE.ts │ │ │ ├── HEXPIREAT.spec.ts │ │ │ ├── HEXPIREAT.ts │ │ │ ├── HEXPIRETIME.spec.ts │ │ │ ├── HEXPIRETIME.ts │ │ │ ├── HGET.spec.ts │ │ │ ├── HGET.ts │ │ │ ├── HGETALL.spec.ts │ │ │ ├── HGETALL.ts │ │ │ ├── HGETDEL.spec.ts │ │ │ ├── HGETDEL.ts │ │ │ ├── HGETEX.spec.ts │ │ │ ├── HGETEX.ts │ │ │ ├── HINCRBY.spec.ts │ │ │ ├── HINCRBY.ts │ │ │ ├── HINCRBYFLOAT.spec.ts │ │ │ ├── HINCRBYFLOAT.ts │ │ │ ├── HKEYS.spec.ts │ │ │ ├── HKEYS.ts │ │ │ ├── HLEN.spec.ts │ │ │ ├── HLEN.ts │ │ │ ├── HMGET.spec.ts │ │ │ ├── HMGET.ts │ │ │ ├── HPERSIST.spec.ts │ │ │ ├── HPERSIST.ts │ │ │ ├── HPEXPIRE.spec.ts │ │ │ ├── HPEXPIRE.ts │ │ │ ├── HPEXPIREAT.spec.ts │ │ │ ├── HPEXPIREAT.ts │ │ │ ├── HPEXPIRETIME.spec.ts │ │ │ ├── HPEXPIRETIME.ts │ │ │ ├── HPTTL.spec.ts │ │ │ ├── HPTTL.ts │ │ │ ├── HRANDFIELD.spec.ts │ │ │ ├── HRANDFIELD.ts │ │ │ ├── HRANDFIELD_COUNT.spec.ts │ │ │ ├── HRANDFIELD_COUNT.ts │ │ │ ├── HRANDFIELD_COUNT_WITHVALUES.spec.ts │ │ │ ├── HRANDFIELD_COUNT_WITHVALUES.ts │ │ │ ├── HSCAN.spec.ts │ │ │ ├── HSCAN.ts │ │ │ ├── HSCAN_NOVALUES.spec.ts │ │ │ ├── HSCAN_NOVALUES.ts │ │ │ ├── HSET.spec.ts │ │ │ ├── HSET.ts │ │ │ ├── HSETEX.spec.ts │ │ │ ├── HSETEX.ts │ │ │ ├── HSETNX.spec.ts │ │ │ ├── HSETNX.ts │ │ │ ├── HSTRLEN.spec.ts │ │ │ ├── HSTRLEN.ts │ │ │ ├── HTTL.spec.ts │ │ │ ├── HTTL.ts │ │ │ ├── HVALS.spec.ts │ │ │ ├── HVALS.ts │ │ │ ├── INCR.spec.ts │ │ │ ├── INCR.ts │ │ │ ├── INCRBY.spec.ts │ │ │ ├── INCRBY.ts │ │ │ ├── INCRBYFLOAT.spec.ts │ │ │ ├── INCRBYFLOAT.ts │ │ │ ├── INFO.spec.ts │ │ │ ├── INFO.ts │ │ │ ├── KEYS.spec.ts │ │ │ ├── KEYS.ts │ │ │ ├── LASTSAVE.spec.ts │ │ │ ├── LASTSAVE.ts │ │ │ ├── LATENCY_DOCTOR.spec.ts │ │ │ ├── LATENCY_DOCTOR.ts │ │ │ ├── LATENCY_GRAPH.spec.ts │ │ │ ├── LATENCY_GRAPH.ts │ │ │ ├── LATENCY_HISTORY.spec.ts │ │ │ ├── LATENCY_HISTORY.ts │ │ │ ├── LATENCY_LATEST.spec.ts │ │ │ ├── LATENCY_LATEST.ts │ │ │ ├── LCS.spec.ts │ │ │ ├── LCS.ts │ │ │ ├── LCS_IDX.spec.ts │ │ │ ├── LCS_IDX.ts │ │ │ ├── LCS_IDX_WITHMATCHLEN.spec.ts │ │ │ ├── LCS_IDX_WITHMATCHLEN.ts │ │ │ ├── LCS_LEN.spec.ts │ │ │ ├── LCS_LEN.ts │ │ │ ├── LINDEX.spec.ts │ │ │ ├── LINDEX.ts │ │ │ ├── LINSERT.spec.ts │ │ │ ├── LINSERT.ts │ │ │ ├── LLEN.spec.ts │ │ │ ├── LLEN.ts │ │ │ ├── LMOVE.spec.ts │ │ │ ├── LMOVE.ts │ │ │ ├── LMPOP.spec.ts │ │ │ ├── LMPOP.ts │ │ │ ├── LOLWUT.spec.ts │ │ │ ├── LOLWUT.ts │ │ │ ├── LPOP.spec.ts │ │ │ ├── LPOP.ts │ │ │ ├── LPOP_COUNT.spec.ts │ │ │ ├── LPOP_COUNT.ts │ │ │ ├── LPOS.spec.ts │ │ │ ├── LPOS.ts │ │ │ ├── LPOS_COUNT.spec.ts │ │ │ ├── LPOS_COUNT.ts │ │ │ ├── LPUSH.spec.ts │ │ │ ├── LPUSH.ts │ │ │ ├── LPUSHX.spec.ts │ │ │ ├── LPUSHX.ts │ │ │ ├── LRANGE.spec.ts │ │ │ ├── LRANGE.ts │ │ │ ├── LREM.spec.ts │ │ │ ├── LREM.ts │ │ │ ├── LSET.spec.ts │ │ │ ├── LSET.ts │ │ │ ├── LTRIM.spec.ts │ │ │ ├── LTRIM.ts │ │ │ ├── MEMORY_DOCTOR.spec.ts │ │ │ ├── MEMORY_DOCTOR.ts │ │ │ ├── MEMORY_MALLOC-STATS.spec.ts │ │ │ ├── MEMORY_MALLOC-STATS.ts │ │ │ ├── MEMORY_PURGE.spec.ts │ │ │ ├── MEMORY_PURGE.ts │ │ │ ├── MEMORY_STATS.spec.ts │ │ │ ├── MEMORY_STATS.ts │ │ │ ├── MEMORY_USAGE.spec.ts │ │ │ ├── MEMORY_USAGE.ts │ │ │ ├── MGET.spec.ts │ │ │ ├── MGET.ts │ │ │ ├── MIGRATE.spec.ts │ │ │ ├── MIGRATE.ts │ │ │ ├── MODULE_LIST.spec.ts │ │ │ ├── MODULE_LIST.ts │ │ │ ├── MODULE_LOAD.spec.ts │ │ │ ├── MODULE_LOAD.ts │ │ │ ├── MODULE_UNLOAD.spec.ts │ │ │ ├── MODULE_UNLOAD.ts │ │ │ ├── MOVE.spec.ts │ │ │ ├── MOVE.ts │ │ │ ├── MSET.spec.ts │ │ │ ├── MSET.ts │ │ │ ├── MSETNX.spec.ts │ │ │ ├── MSETNX.ts │ │ │ ├── OBJECT_ENCODING.spec.ts │ │ │ ├── OBJECT_ENCODING.ts │ │ │ ├── OBJECT_FREQ.spec.ts │ │ │ ├── OBJECT_FREQ.ts │ │ │ ├── OBJECT_IDLETIME.spec.ts │ │ │ ├── OBJECT_IDLETIME.ts │ │ │ ├── OBJECT_REFCOUNT.spec.ts │ │ │ ├── OBJECT_REFCOUNT.ts │ │ │ ├── PERSIST.spec.ts │ │ │ ├── PERSIST.ts │ │ │ ├── PEXPIRE.spec.ts │ │ │ ├── PEXPIRE.ts │ │ │ ├── PEXPIREAT.spec.ts │ │ │ ├── PEXPIREAT.ts │ │ │ ├── PEXPIRETIME.spec.ts │ │ │ ├── PEXPIRETIME.ts │ │ │ ├── PFADD.spec.ts │ │ │ ├── PFADD.ts │ │ │ ├── PFCOUNT.spec.ts │ │ │ ├── PFCOUNT.ts │ │ │ ├── PFMERGE.spec.ts │ │ │ ├── PFMERGE.ts │ │ │ ├── PING.spec.ts │ │ │ ├── PING.ts │ │ │ ├── PSETEX.spec.ts │ │ │ ├── PSETEX.ts │ │ │ ├── PTTL.spec.ts │ │ │ ├── PTTL.ts │ │ │ ├── PUBLISH.spec.ts │ │ │ ├── PUBLISH.ts │ │ │ ├── PUBSUB_CHANNELS.spec.ts │ │ │ ├── PUBSUB_CHANNELS.ts │ │ │ ├── PUBSUB_NUMPAT.spec.ts │ │ │ ├── PUBSUB_NUMPAT.ts │ │ │ ├── PUBSUB_NUMSUB.spec.ts │ │ │ ├── PUBSUB_NUMSUB.ts │ │ │ ├── PUBSUB_SHARDCHANNELS.spec.ts │ │ │ ├── PUBSUB_SHARDCHANNELS.ts │ │ │ ├── PUBSUB_SHARDNUMSUB.spec.ts │ │ │ ├── PUBSUB_SHARDNUMSUB.ts │ │ │ ├── RANDOMKEY.spec.ts │ │ │ ├── RANDOMKEY.ts │ │ │ ├── READONLY.spec.ts │ │ │ ├── READONLY.ts │ │ │ ├── READWRITE.spec.ts │ │ │ ├── READWRITE.ts │ │ │ ├── RENAME.spec.ts │ │ │ ├── RENAME.ts │ │ │ ├── RENAMENX.spec.ts │ │ │ ├── RENAMENX.ts │ │ │ ├── REPLICAOF.spec.ts │ │ │ ├── REPLICAOF.ts │ │ │ ├── RESTORE-ASKING.spec.ts │ │ │ ├── RESTORE-ASKING.ts │ │ │ ├── RESTORE.spec.ts │ │ │ ├── RESTORE.ts │ │ │ ├── ROLE.spec.ts │ │ │ ├── ROLE.ts │ │ │ ├── RPOP.spec.ts │ │ │ ├── RPOP.ts │ │ │ ├── RPOPLPUSH.spec.ts │ │ │ ├── RPOPLPUSH.ts │ │ │ ├── RPOP_COUNT.spec.ts │ │ │ ├── RPOP_COUNT.ts │ │ │ ├── RPUSH.spec.ts │ │ │ ├── RPUSH.ts │ │ │ ├── RPUSHX.spec.ts │ │ │ ├── RPUSHX.ts │ │ │ ├── SADD.spec.ts │ │ │ ├── SADD.ts │ │ │ ├── SAVE.spec.ts │ │ │ ├── SAVE.ts │ │ │ ├── SCAN.spec.ts │ │ │ ├── SCAN.ts │ │ │ ├── SCARD.spec.ts │ │ │ ├── SCARD.ts │ │ │ ├── SCRIPT_DEBUG.spec.ts │ │ │ ├── SCRIPT_DEBUG.ts │ │ │ ├── SCRIPT_EXISTS.spec.ts │ │ │ ├── SCRIPT_EXISTS.ts │ │ │ ├── SCRIPT_FLUSH.spec.ts │ │ │ ├── SCRIPT_FLUSH.ts │ │ │ ├── SCRIPT_KILL.spec.ts │ │ │ ├── SCRIPT_KILL.ts │ │ │ ├── SCRIPT_LOAD.spec.ts │ │ │ ├── SCRIPT_LOAD.ts │ │ │ ├── SDIFF.spec.ts │ │ │ ├── SDIFF.ts │ │ │ ├── SDIFFSTORE.spec.ts │ │ │ ├── SDIFFSTORE.ts │ │ │ ├── SET.spec.ts │ │ │ ├── SET.ts │ │ │ ├── SETBIT.spec.ts │ │ │ ├── SETBIT.ts │ │ │ ├── SETEX.spec.ts │ │ │ ├── SETEX.ts │ │ │ ├── SETNX .spec.ts │ │ │ ├── SETNX.ts │ │ │ ├── SETRANGE.spec.ts │ │ │ ├── SETRANGE.ts │ │ │ ├── SHUTDOWN.spec.ts │ │ │ ├── SHUTDOWN.ts │ │ │ ├── SINTER.spec.ts │ │ │ ├── SINTER.ts │ │ │ ├── SINTERCARD.spec.ts │ │ │ ├── SINTERCARD.ts │ │ │ ├── SINTERSTORE.spec.ts │ │ │ ├── SINTERSTORE.ts │ │ │ ├── SISMEMBER.spec.ts │ │ │ ├── SISMEMBER.ts │ │ │ ├── SMEMBERS.spec.ts │ │ │ ├── SMEMBERS.ts │ │ │ ├── SMISMEMBER.spec.ts │ │ │ ├── SMISMEMBER.ts │ │ │ ├── SMOVE.spec.ts │ │ │ ├── SMOVE.ts │ │ │ ├── SORT.spec.ts │ │ │ ├── SORT.ts │ │ │ ├── SORT_RO.spec.ts │ │ │ ├── SORT_RO.ts │ │ │ ├── SORT_STORE.spec.ts │ │ │ ├── SORT_STORE.ts │ │ │ ├── SPOP.spec.ts │ │ │ ├── SPOP.ts │ │ │ ├── SPOP_COUNT.spec.ts │ │ │ ├── SPOP_COUNT.ts │ │ │ ├── SPUBLISH.spec.ts │ │ │ ├── SPUBLISH.ts │ │ │ ├── SRANDMEMBER.spec.ts │ │ │ ├── SRANDMEMBER.ts │ │ │ ├── SRANDMEMBER_COUNT.spec.ts │ │ │ ├── SRANDMEMBER_COUNT.ts │ │ │ ├── SREM.spec.ts │ │ │ ├── SREM.ts │ │ │ ├── SSCAN.spec.ts │ │ │ ├── SSCAN.ts │ │ │ ├── STRLEN.spec.ts │ │ │ ├── STRLEN.ts │ │ │ ├── SUNION.spec.ts │ │ │ ├── SUNION.ts │ │ │ ├── SUNIONSTORE.spec.ts │ │ │ ├── SUNIONSTORE.ts │ │ │ ├── SWAPDB.spec.ts │ │ │ ├── SWAPDB.ts │ │ │ ├── TIME.spec.ts │ │ │ ├── TIME.ts │ │ │ ├── TOUCH.spec.ts │ │ │ ├── TOUCH.ts │ │ │ ├── TTL.spec.ts │ │ │ ├── TTL.ts │ │ │ ├── TYPE.spec.ts │ │ │ ├── TYPE.ts │ │ │ ├── UNLINK.spec.ts │ │ │ ├── UNLINK.ts │ │ │ ├── VADD.spec.ts │ │ │ ├── VADD.ts │ │ │ ├── VCARD.spec.ts │ │ │ ├── VCARD.ts │ │ │ ├── VDIM.spec.ts │ │ │ ├── VDIM.ts │ │ │ ├── VEMB.spec.ts │ │ │ ├── VEMB.ts │ │ │ ├── VEMB_RAW.spec.ts │ │ │ ├── VEMB_RAW.ts │ │ │ ├── VGETATTR.spec.ts │ │ │ ├── VGETATTR.ts │ │ │ ├── VINFO.spec.ts │ │ │ ├── VINFO.ts │ │ │ ├── VLINKS.spec.ts │ │ │ ├── VLINKS.ts │ │ │ ├── VLINKS_WITHSCORES.spec.ts │ │ │ ├── VLINKS_WITHSCORES.ts │ │ │ ├── VRANDMEMBER.spec.ts │ │ │ ├── VRANDMEMBER.ts │ │ │ ├── VREM.spec.ts │ │ │ ├── VREM.ts │ │ │ ├── VSETATTR.spec.ts │ │ │ ├── VSETATTR.ts │ │ │ ├── VSIM.spec.ts │ │ │ ├── VSIM.ts │ │ │ ├── VSIM_WITHSCORES.spec.ts │ │ │ ├── VSIM_WITHSCORES.ts │ │ │ ├── WAIT.spec.ts │ │ │ ├── WAIT.ts │ │ │ ├── XACK.spec.ts │ │ │ ├── XACK.ts │ │ │ ├── XADD.spec.ts │ │ │ ├── XADD.ts │ │ │ ├── XADD_NOMKSTREAM.spec.ts │ │ │ ├── XADD_NOMKSTREAM.ts │ │ │ ├── XAUTOCLAIM.spec.ts │ │ │ ├── XAUTOCLAIM.ts │ │ │ ├── XAUTOCLAIM_JUSTID.spec.ts │ │ │ ├── XAUTOCLAIM_JUSTID.ts │ │ │ ├── XCLAIM.spec.ts │ │ │ ├── XCLAIM.ts │ │ │ ├── XCLAIM_JUSTID.spec.ts │ │ │ ├── XCLAIM_JUSTID.ts │ │ │ ├── XDEL.spec.ts │ │ │ ├── XDEL.ts │ │ │ ├── XGROUP_CREATE.spec.ts │ │ │ ├── XGROUP_CREATE.ts │ │ │ ├── XGROUP_CREATECONSUMER.spec.ts │ │ │ ├── XGROUP_CREATECONSUMER.ts │ │ │ ├── XGROUP_DELCONSUMER.spec.ts │ │ │ ├── XGROUP_DELCONSUMER.ts │ │ │ ├── XGROUP_DESTROY.spec.ts │ │ │ ├── XGROUP_DESTROY.ts │ │ │ ├── XGROUP_SETID.spec.ts │ │ │ ├── XGROUP_SETID.ts │ │ │ ├── XINFO_CONSUMERS.spec.ts │ │ │ ├── XINFO_CONSUMERS.ts │ │ │ ├── XINFO_GROUPS.spec.ts │ │ │ ├── XINFO_GROUPS.ts │ │ │ ├── XINFO_STREAM.spec.ts │ │ │ ├── XINFO_STREAM.ts │ │ │ ├── XLEN.spec.ts │ │ │ ├── XLEN.ts │ │ │ ├── XPENDING.spec.ts │ │ │ ├── XPENDING.ts │ │ │ ├── XPENDING_RANGE.spec.ts │ │ │ ├── XPENDING_RANGE.ts │ │ │ ├── XRANGE.spec.ts │ │ │ ├── XRANGE.ts │ │ │ ├── XREAD.spec.ts │ │ │ ├── XREAD.ts │ │ │ ├── XREADGROUP.spec.ts │ │ │ ├── XREADGROUP.ts │ │ │ ├── XREVRANGE.spec.ts │ │ │ ├── XREVRANGE.ts │ │ │ ├── XSETID.spec.ts │ │ │ ├── XSETID.ts │ │ │ ├── XTRIM.spec.ts │ │ │ ├── XTRIM.ts │ │ │ ├── ZADD.spec.ts │ │ │ ├── ZADD.ts │ │ │ ├── ZADD_INCR.spec.ts │ │ │ ├── ZADD_INCR.ts │ │ │ ├── ZCARD.spec.ts │ │ │ ├── ZCARD.ts │ │ │ ├── ZCOUNT.spec.ts │ │ │ ├── ZCOUNT.ts │ │ │ ├── ZDIFF.spec.ts │ │ │ ├── ZDIFF.ts │ │ │ ├── ZDIFFSTORE.spec.ts │ │ │ ├── ZDIFFSTORE.ts │ │ │ ├── ZDIFF_WITHSCORES.spec.ts │ │ │ ├── ZDIFF_WITHSCORES.ts │ │ │ ├── ZINCRBY.spec.ts │ │ │ ├── ZINCRBY.ts │ │ │ ├── ZINTER.spec.ts │ │ │ ├── ZINTER.ts │ │ │ ├── ZINTERCARD.spec.ts │ │ │ ├── ZINTERCARD.ts │ │ │ ├── ZINTERSTORE.spec.ts │ │ │ ├── ZINTERSTORE.ts │ │ │ ├── ZINTER_WITHSCORES.spec.ts │ │ │ ├── ZINTER_WITHSCORES.ts │ │ │ ├── ZLEXCOUNT.spec.ts │ │ │ ├── ZLEXCOUNT.ts │ │ │ ├── ZMPOP.spec.ts │ │ │ ├── ZMPOP.ts │ │ │ ├── ZMSCORE.spec.ts │ │ │ ├── ZMSCORE.ts │ │ │ ├── ZPOPMAX.spec.ts │ │ │ ├── ZPOPMAX.ts │ │ │ ├── ZPOPMAX_COUNT.spec.ts │ │ │ ├── ZPOPMAX_COUNT.ts │ │ │ ├── ZPOPMIN.spec.ts │ │ │ ├── ZPOPMIN.ts │ │ │ ├── ZPOPMIN_COUNT.spec.ts │ │ │ ├── ZPOPMIN_COUNT.ts │ │ │ ├── ZRANDMEMBER.spec.ts │ │ │ ├── ZRANDMEMBER.ts │ │ │ ├── ZRANDMEMBER_COUNT.spec.ts │ │ │ ├── ZRANDMEMBER_COUNT.ts │ │ │ ├── ZRANDMEMBER_COUNT_WITHSCORES.spec.ts │ │ │ ├── ZRANDMEMBER_COUNT_WITHSCORES.ts │ │ │ ├── ZRANGE.spec.ts │ │ │ ├── ZRANGE.ts │ │ │ ├── ZRANGEBYLEX.spec.ts │ │ │ ├── ZRANGEBYLEX.ts │ │ │ ├── ZRANGEBYSCORE.spec.ts │ │ │ ├── ZRANGEBYSCORE.ts │ │ │ ├── ZRANGEBYSCORE_WITHSCORES.spec.ts │ │ │ ├── ZRANGEBYSCORE_WITHSCORES.ts │ │ │ ├── ZRANGESTORE.spec.ts │ │ │ ├── ZRANGESTORE.ts │ │ │ ├── ZRANGE_WITHSCORES.spec.ts │ │ │ ├── ZRANGE_WITHSCORES.ts │ │ │ ├── ZRANK.spec.ts │ │ │ ├── ZRANK.ts │ │ │ ├── ZRANK_WITHSCORE.spec.ts │ │ │ ├── ZRANK_WITHSCORE.ts │ │ │ ├── ZREM.spec.ts │ │ │ ├── ZREM.ts │ │ │ ├── ZREMRANGEBYLEX.spec.ts │ │ │ ├── ZREMRANGEBYLEX.ts │ │ │ ├── ZREMRANGEBYRANK.spec.ts │ │ │ ├── ZREMRANGEBYRANK.ts │ │ │ ├── ZREMRANGEBYSCORE.spec.ts │ │ │ ├── ZREMRANGEBYSCORE.ts │ │ │ ├── ZREVRANK.spec.ts │ │ │ ├── ZREVRANK.ts │ │ │ ├── ZSCAN.spec.ts │ │ │ ├── ZSCAN.ts │ │ │ ├── ZSCORE.spec.ts │ │ │ ├── ZSCORE.ts │ │ │ ├── ZUNION.spec.ts │ │ │ ├── ZUNION.ts │ │ │ ├── ZUNIONSTORE.spec.ts │ │ │ ├── ZUNIONSTORE.ts │ │ │ ├── ZUNION_WITHSCORES.spec.ts │ │ │ ├── ZUNION_WITHSCORES.ts │ │ │ ├── generic-transformers.spec.ts │ │ │ ├── generic-transformers.ts │ │ │ └── index.ts │ │ ├── errors.ts │ │ ├── lua-script.ts │ │ ├── multi-command.spec.ts │ │ ├── multi-command.ts │ │ ├── sentinel │ │ │ ├── commands │ │ │ │ ├── SENTINEL_MASTER.ts │ │ │ │ ├── SENTINEL_MONITOR.ts │ │ │ │ ├── SENTINEL_REPLICAS.ts │ │ │ │ ├── SENTINEL_SENTINELS.ts │ │ │ │ ├── SENTINEL_SET.ts │ │ │ │ └── index.ts │ │ │ ├── index.spec.ts │ │ │ ├── index.ts │ │ │ ├── module.ts │ │ │ ├── multi-commands.ts │ │ │ ├── pub-sub-proxy.ts │ │ │ ├── test-util.ts │ │ │ ├── types.ts │ │ │ ├── utils.ts │ │ │ └── wait-queue.ts │ │ ├── single-entry-cache.spec.ts │ │ ├── single-entry-cache.ts │ │ └── test-utils.ts │ ├── package.json │ └── tsconfig.json ├── entraid │ ├── .nycrc.json │ ├── .release-it.json │ ├── README.md │ ├── index.ts │ ├── integration-tests │ │ └── entraid-integration.spec.ts │ ├── lib │ │ ├── azure-identity-provider.ts │ │ ├── entra-id-credentials-provider-factory.ts │ │ ├── entraid-credentials-provider.spec.ts │ │ ├── entraid-credentials-provider.ts │ │ ├── index.ts │ │ ├── msal-identity-provider.ts │ │ └── test-utils.ts │ ├── package.json │ ├── samples │ │ ├── auth-code-pkce │ │ │ └── index.ts │ │ └── interactive-browser │ │ │ └── index.ts │ ├── tsconfig.integration-tests.json │ ├── tsconfig.json │ └── tsconfig.samples.json ├── json │ ├── .nycrc.json │ ├── .release-it.json │ ├── README.md │ ├── lib │ │ ├── commands │ │ │ ├── ARRAPPEND.spec.ts │ │ │ ├── ARRAPPEND.ts │ │ │ ├── ARRINDEX.spec.ts │ │ │ ├── ARRINDEX.ts │ │ │ ├── ARRINSERT.spec.ts │ │ │ ├── ARRINSERT.ts │ │ │ ├── ARRLEN.spec.ts │ │ │ ├── ARRLEN.ts │ │ │ ├── ARRPOP.spec.ts │ │ │ ├── ARRPOP.ts │ │ │ ├── ARRTRIM.spec.ts │ │ │ ├── ARRTRIM.ts │ │ │ ├── CLEAR.spec.ts │ │ │ ├── CLEAR.ts │ │ │ ├── DEBUG_MEMORY.spec.ts │ │ │ ├── DEBUG_MEMORY.ts │ │ │ ├── DEL.spec.ts │ │ │ ├── DEL.ts │ │ │ ├── FORGET.spec.ts │ │ │ ├── FORGET.ts │ │ │ ├── GET.spec.ts │ │ │ ├── GET.ts │ │ │ ├── MERGE.spec.ts │ │ │ ├── MERGE.ts │ │ │ ├── MGET.spec.ts │ │ │ ├── MGET.ts │ │ │ ├── MSET.spec.ts │ │ │ ├── MSET.ts │ │ │ ├── NUMINCRBY.spec.ts │ │ │ ├── NUMINCRBY.ts │ │ │ ├── NUMMULTBY.spec.ts │ │ │ ├── NUMMULTBY.ts │ │ │ ├── OBJKEYS.spec.ts │ │ │ ├── OBJKEYS.ts │ │ │ ├── OBJLEN.spec.ts │ │ │ ├── OBJLEN.ts │ │ │ ├── RESP.spec.ts │ │ │ ├── RESP.ts │ │ │ ├── SET.spec.ts │ │ │ ├── SET.ts │ │ │ ├── STRAPPEND.spec.ts │ │ │ ├── STRAPPEND.ts │ │ │ ├── STRLEN.spec.ts │ │ │ ├── STRLEN.ts │ │ │ ├── TOGGLE.spec.ts │ │ │ ├── TOGGLE.ts │ │ │ ├── TYPE.spec.ts │ │ │ ├── TYPE.ts │ │ │ └── index.ts │ │ ├── index.ts │ │ └── test-utils.ts │ ├── package.json │ └── tsconfig.json ├── redis │ ├── .release-it.json │ ├── README.md │ ├── index.ts │ ├── package.json │ └── tsconfig.json ├── search │ ├── .nycrc.json │ ├── .release-it.json │ ├── README.md │ ├── lib │ │ ├── commands │ │ │ ├── AGGREGATE.spec.ts │ │ │ ├── AGGREGATE.ts │ │ │ ├── AGGREGATE_WITHCURSOR.spec.ts │ │ │ ├── AGGREGATE_WITHCURSOR.ts │ │ │ ├── ALIASADD.spec.ts │ │ │ ├── ALIASADD.ts │ │ │ ├── ALIASDEL.spec.ts │ │ │ ├── ALIASDEL.ts │ │ │ ├── ALIASUPDATE.spec.ts │ │ │ ├── ALIASUPDATE.ts │ │ │ ├── ALTER.spec.ts │ │ │ ├── ALTER.ts │ │ │ ├── CONFIG_GET.spec.ts │ │ │ ├── CONFIG_GET.ts │ │ │ ├── CONFIG_SET.spec.ts │ │ │ ├── CONFIG_SET.ts │ │ │ ├── CREATE.spec.ts │ │ │ ├── CREATE.ts │ │ │ ├── CURSOR_DEL.spec.ts │ │ │ ├── CURSOR_DEL.ts │ │ │ ├── CURSOR_READ.spec.ts │ │ │ ├── CURSOR_READ.ts │ │ │ ├── DICTADD.spec.ts │ │ │ ├── DICTADD.ts │ │ │ ├── DICTDEL.spec.ts │ │ │ ├── DICTDEL.ts │ │ │ ├── DICTDUMP.spec.ts │ │ │ ├── DICTDUMP.ts │ │ │ ├── DROPINDEX.spec.ts │ │ │ ├── DROPINDEX.ts │ │ │ ├── EXPLAIN.spec.ts │ │ │ ├── EXPLAIN.ts │ │ │ ├── EXPLAINCLI.spec.ts │ │ │ ├── EXPLAINCLI.ts │ │ │ ├── INFO.spec.ts │ │ │ ├── INFO.ts │ │ │ ├── PROFILE_AGGREGATE.spec.ts │ │ │ ├── PROFILE_AGGREGATE.ts │ │ │ ├── PROFILE_SEARCH.spec.ts │ │ │ ├── PROFILE_SEARCH.ts │ │ │ ├── SEARCH.spec.ts │ │ │ ├── SEARCH.ts │ │ │ ├── SEARCH_NOCONTENT.spec.ts │ │ │ ├── SEARCH_NOCONTENT.ts │ │ │ ├── SPELLCHECK.spec.ts │ │ │ ├── SPELLCHECK.ts │ │ │ ├── SUGADD.spec.ts │ │ │ ├── SUGADD.ts │ │ │ ├── SUGDEL.spec.ts │ │ │ ├── SUGDEL.ts │ │ │ ├── SUGGET.spec.ts │ │ │ ├── SUGGET.ts │ │ │ ├── SUGGET_WITHPAYLOADS.spec.ts │ │ │ ├── SUGGET_WITHPAYLOADS.ts │ │ │ ├── SUGGET_WITHSCORES.spec.ts │ │ │ ├── SUGGET_WITHSCORES.ts │ │ │ ├── SUGGET_WITHSCORES_WITHPAYLOADS.spec.ts │ │ │ ├── SUGGET_WITHSCORES_WITHPAYLOADS.ts │ │ │ ├── SUGLEN.spec.ts │ │ │ ├── SUGLEN.ts │ │ │ ├── SYNDUMP.spec.ts │ │ │ ├── SYNDUMP.ts │ │ │ ├── SYNUPDATE.spec.ts │ │ │ ├── SYNUPDATE.ts │ │ │ ├── TAGVALS.spec.ts │ │ │ ├── TAGVALS.ts │ │ │ ├── _LIST.spec.ts │ │ │ ├── _LIST.ts │ │ │ ├── index.spec.ts │ │ │ └── index.ts │ │ ├── dialect │ │ │ └── default.ts │ │ ├── index.ts │ │ └── test-utils.ts │ ├── package.json │ └── tsconfig.json ├── test-utils │ ├── docker │ │ ├── Dockerfile │ │ └── entrypoint.sh │ ├── lib │ │ ├── cae-client-testing.ts │ │ ├── dockers.ts │ │ ├── index.spec.ts │ │ └── index.ts │ ├── package.json │ └── tsconfig.json └── time-series │ ├── .nycrc.json │ ├── .release-it.json │ ├── README.md │ ├── lib │ ├── commands │ │ ├── ADD.spec.ts │ │ ├── ADD.ts │ │ ├── ALTER.spec.ts │ │ ├── ALTER.ts │ │ ├── CREATE.spec.ts │ │ ├── CREATE.ts │ │ ├── CREATERULE.spec.ts │ │ ├── CREATERULE.ts │ │ ├── DECRBY.spec.ts │ │ ├── DECRBY.ts │ │ ├── DEL.spec.ts │ │ ├── DEL.ts │ │ ├── DELETERULE.spec.ts │ │ ├── DELETERULE.ts │ │ ├── GET.spec.ts │ │ ├── GET.ts │ │ ├── INCRBY.spec.ts │ │ ├── INCRBY.ts │ │ ├── INFO.spec.ts │ │ ├── INFO.ts │ │ ├── INFO_DEBUG.spec.ts │ │ ├── INFO_DEBUG.ts │ │ ├── MADD.spec.ts │ │ ├── MADD.ts │ │ ├── MGET.spec.ts │ │ ├── MGET.ts │ │ ├── MGET_SELECTED_LABELS.spec.ts │ │ ├── MGET_SELECTED_LABELS.ts │ │ ├── MGET_WITHLABELS.spec.ts │ │ ├── MGET_WITHLABELS.ts │ │ ├── MRANGE.spec.ts │ │ ├── MRANGE.ts │ │ ├── MRANGE_GROUPBY.spec.ts │ │ ├── MRANGE_GROUPBY.ts │ │ ├── MRANGE_SELECTED_LABELS.spec.ts │ │ ├── MRANGE_SELECTED_LABELS.ts │ │ ├── MRANGE_SELECTED_LABELS_GROUPBY.spec.ts │ │ ├── MRANGE_SELECTED_LABELS_GROUPBY.ts │ │ ├── MRANGE_WITHLABELS.spec.ts │ │ ├── MRANGE_WITHLABELS.ts │ │ ├── MRANGE_WITHLABELS_GROUPBY.spec.ts │ │ ├── MRANGE_WITHLABELS_GROUPBY.ts │ │ ├── MREVRANGE.spec.ts │ │ ├── MREVRANGE.ts │ │ ├── MREVRANGE_GROUPBY.spec.ts │ │ ├── MREVRANGE_GROUPBY.ts │ │ ├── MREVRANGE_SELECTED_LABELS.spec.ts │ │ ├── MREVRANGE_SELECTED_LABELS.ts │ │ ├── MREVRANGE_SELECTED_LABELS_GROUPBY.spec.ts │ │ ├── MREVRANGE_SELECTED_LABELS_GROUPBY.ts │ │ ├── MREVRANGE_WITHLABELS.spec.ts │ │ ├── MREVRANGE_WITHLABELS.ts │ │ ├── MREVRANGE_WITHLABELS_GROUPBY.spec.ts │ │ ├── MREVRANGE_WITHLABELS_GROUPBY.ts │ │ ├── QUERYINDEX.spec.ts │ │ ├── QUERYINDEX.ts │ │ ├── RANGE.spec.ts │ │ ├── RANGE.ts │ │ ├── REVRANGE.spec.ts │ │ ├── REVRANGE.ts │ │ ├── helpers.ts │ │ ├── index.spec.ts │ │ └── index.ts │ ├── index.ts │ └── test-utils.ts │ ├── package.json │ └── tsconfig.json ├── tsconfig.base.json └── tsconfig.json /.deepsource.toml: -------------------------------------------------------------------------------- 1 | version = 1 2 | 3 | [[analyzers]] 4 | name = "javascript" 5 | enabled = true 6 | 7 | [analyzers.meta] 8 | environment = ["nodejs"] 9 | dialect = "typescript" 10 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/DOCUMENTATION.yml: -------------------------------------------------------------------------------- 1 | name: Documentation 2 | description: Any questions or issues relating to the project documentation. 3 | labels: [Documentation] 4 | body: 5 | - type: textarea 6 | id: description 7 | attributes: 8 | label: Description 9 | description: Ask your question or describe your issue here. 10 | validations: 11 | required: true 12 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/FEATURE-REQUEST.yml: -------------------------------------------------------------------------------- 1 | name: Feature Request 2 | description: Suggest an idea for this project 3 | labels: [Feature] 4 | body: 5 | - type: textarea 6 | id: motivation 7 | attributes: 8 | label: Motivation 9 | description: How would Node Redis users benefit from this feature? 10 | validations: 11 | required: true 12 | - type: textarea 13 | id: basic-code-example 14 | attributes: 15 | label: Basic Code Example 16 | description: Provide examples of how you imagine the API for this feature might be implemented. This will be automatically formatted into code, so no need for backticks. 17 | render: JavaScript 18 | validations: 19 | required: false 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .nyc_output/ 3 | .vscode/ 4 | coverage/ 5 | dist/ 6 | node_modules/ 7 | .DS_Store 8 | dump.rdb 9 | documentation/ 10 | tsconfig.tsbuildinfo 11 | -------------------------------------------------------------------------------- /benchmark/.gitignore: -------------------------------------------------------------------------------- 1 | *.js.json 2 | -------------------------------------------------------------------------------- /benchmark/lib/defaults.yml: -------------------------------------------------------------------------------- 1 | version: 0.1 2 | 3 | remote: 4 | - type: oss-standalone 5 | - setup: redis-small 6 | 7 | setups: 8 | - oss-standalone 9 | 10 | spec: 11 | setups: 12 | - name: oss-standalone 13 | type: oss-standalone 14 | redis_topology: 15 | primaries: 1 16 | replicas: 0 17 | resources: 18 | requests: 19 | cpus: "1" 20 | memory: "10g" 21 | 22 | exporter: 23 | output_path: "./*.js.json" 24 | redistimeseries: 25 | timemetric: "$.timestamp" 26 | metrics: 27 | - "$.p0" 28 | - "$.p50" 29 | - "$.p95" 30 | - "$.p99" 31 | - "$.p100" 32 | - "$.operationsPerSecond" -------------------------------------------------------------------------------- /benchmark/lib/ping/ioredis-auto-pipeline.js: -------------------------------------------------------------------------------- 1 | import Redis from 'ioredis'; 2 | 3 | export default async (host) => { 4 | const client = new Redis({ 5 | host, 6 | lazyConnect: true, 7 | enableAutoPipelining: true 8 | }); 9 | 10 | await client.connect(); 11 | 12 | return { 13 | benchmark() { 14 | return client.ping(); 15 | }, 16 | teardown() { 17 | return client.disconnect(); 18 | } 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /benchmark/lib/ping/ioredis.js: -------------------------------------------------------------------------------- 1 | import Redis from 'ioredis'; 2 | 3 | export default async (host) => { 4 | const client = new Redis({ 5 | host, 6 | lazyConnect: true 7 | }); 8 | 9 | await client.connect(); 10 | 11 | return { 12 | benchmark() { 13 | return client.ping(); 14 | }, 15 | teardown() { 16 | return client.disconnect(); 17 | } 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /benchmark/lib/ping/local-resp2.js: -------------------------------------------------------------------------------- 1 | import { createClient } from 'redis-local'; 2 | 3 | export default async (host) => { 4 | const client = createClient({ 5 | socket: { 6 | host 7 | }, 8 | RESP: 2 9 | }); 10 | 11 | await client.connect(); 12 | 13 | return { 14 | benchmark() { 15 | return client.ping(); 16 | }, 17 | teardown() { 18 | return client.disconnect(); 19 | } 20 | }; 21 | }; 22 | -------------------------------------------------------------------------------- /benchmark/lib/ping/local-resp3-buffer-proxy.js: -------------------------------------------------------------------------------- 1 | import { createClient, RESP_TYPES } from 'redis-local'; 2 | 3 | export default async (host) => { 4 | const client = createClient({ 5 | socket: { 6 | host 7 | }, 8 | RESP: 3 9 | }).withTypeMapping({ 10 | [RESP_TYPES.SIMPLE_STRING]: Buffer 11 | }); 12 | 13 | await client.connect(); 14 | 15 | return { 16 | benchmark() { 17 | return client.ping(); 18 | }, 19 | teardown() { 20 | return client.disconnect(); 21 | } 22 | }; 23 | }; 24 | -------------------------------------------------------------------------------- /benchmark/lib/ping/local-resp3-buffer.js: -------------------------------------------------------------------------------- 1 | import { createClient, RESP_TYPES } from 'redis-local'; 2 | 3 | export default async (host) => { 4 | const client = createClient({ 5 | socket: { 6 | host 7 | }, 8 | commandOptions: { 9 | [RESP_TYPES.SIMPLE_STRING]: Buffer 10 | }, 11 | RESP: 3 12 | }); 13 | 14 | await client.connect(); 15 | 16 | return { 17 | benchmark() { 18 | return client.ping(); 19 | }, 20 | teardown() { 21 | return client.disconnect(); 22 | } 23 | }; 24 | }; 25 | -------------------------------------------------------------------------------- /benchmark/lib/ping/local-resp3-module-with-flags.js: -------------------------------------------------------------------------------- 1 | import { createClient } from 'redis-local'; 2 | import PING from 'redis-local/dist/lib/commands/PING.js'; 3 | 4 | export default async (host) => { 5 | const client = createClient({ 6 | socket: { 7 | host 8 | }, 9 | RESP: 3, 10 | modules: { 11 | module: { 12 | ping: PING.default 13 | } 14 | } 15 | }); 16 | 17 | await client.connect(); 18 | 19 | return { 20 | benchmark() { 21 | return client.withTypeMapping({}).module.ping(); 22 | }, 23 | teardown() { 24 | return client.disconnect(); 25 | } 26 | }; 27 | }; 28 | -------------------------------------------------------------------------------- /benchmark/lib/ping/local-resp3-module.js: -------------------------------------------------------------------------------- 1 | import { createClient } from 'redis-local'; 2 | import PING from 'redis-local/dist/lib/commands/PING.js'; 3 | 4 | export default async (host) => { 5 | const client = createClient({ 6 | socket: { 7 | host 8 | }, 9 | RESP: 3, 10 | modules: { 11 | module: { 12 | ping: PING.default 13 | } 14 | } 15 | }); 16 | 17 | await client.connect(); 18 | 19 | return { 20 | benchmark() { 21 | return client.module.ping(); 22 | }, 23 | teardown() { 24 | return client.disconnect(); 25 | } 26 | }; 27 | }; 28 | -------------------------------------------------------------------------------- /benchmark/lib/ping/local-resp3.js: -------------------------------------------------------------------------------- 1 | import { createClient } from 'redis-local'; 2 | 3 | export default async (host) => { 4 | const client = createClient({ 5 | socket: { 6 | host 7 | }, 8 | RESP: 3 9 | }); 10 | 11 | await client.connect(); 12 | 13 | return { 14 | benchmark() { 15 | return client.ping(); 16 | }, 17 | teardown() { 18 | return client.disconnect(); 19 | } 20 | }; 21 | }; 22 | -------------------------------------------------------------------------------- /benchmark/lib/ping/ping.yml: -------------------------------------------------------------------------------- 1 | name: "ping" 2 | 3 | clientconfig: 4 | - command: | 5 | npm install -ws 6 | npm run build:tests-tools 7 | cd benchmark 8 | npm install 9 | npm run start -- --name ping --redis-server-host ${server_private_ip} 10 | -------------------------------------------------------------------------------- /benchmark/lib/ping/v3.js: -------------------------------------------------------------------------------- 1 | import { createClient } from 'redis-v3'; 2 | import { once } from 'node:events'; 3 | import { promisify } from 'node:util'; 4 | 5 | export default async (host) => { 6 | const client = createClient({ host }), 7 | pingAsync = promisify(client.ping).bind(client), 8 | quitAsync = promisify(client.quit).bind(client); 9 | 10 | await once(client, 'connect'); 11 | 12 | return { 13 | benchmark() { 14 | return pingAsync(); 15 | }, 16 | teardown() { 17 | return quitAsync(); 18 | } 19 | }; 20 | 21 | }; 22 | -------------------------------------------------------------------------------- /benchmark/lib/ping/v4.js: -------------------------------------------------------------------------------- 1 | import { createClient } from 'redis-v4'; 2 | 3 | export default async (host) => { 4 | const client = createClient({ 5 | socket: { 6 | host 7 | } 8 | }); 9 | 10 | await client.connect(); 11 | 12 | return { 13 | benchmark() { 14 | return client.ping(); 15 | }, 16 | teardown() { 17 | return client.disconnect(); 18 | } 19 | }; 20 | }; 21 | -------------------------------------------------------------------------------- /benchmark/lib/set-get-delete-string/1KB.yml: -------------------------------------------------------------------------------- 1 | name: "set-get-delete-string-1KB" 2 | 3 | clientconfig: 4 | - command: | 5 | npm install -ws 6 | npm run build:tests-tools 7 | cd benchmark 8 | npm install 9 | npm run start -- --name set-get-delete-string --size 1024 --redis-server-host ${server_private_ip} 10 | -------------------------------------------------------------------------------- /benchmark/lib/set-get-delete-string/1MB.yml: -------------------------------------------------------------------------------- 1 | name: "set-get-delete-string-1MB" 2 | 3 | clientconfig: 4 | - command: | 5 | npm install -ws 6 | npm run build:tests-tools 7 | cd benchmark 8 | npm install 9 | npm run start -- --name set-get-delete-string --size 1048576 --redis-server-host ${server_private_ip} 10 | -------------------------------------------------------------------------------- /benchmark/lib/set-get-delete-string/8B.yml: -------------------------------------------------------------------------------- 1 | name: "set-get-delete-string-8B" 2 | 3 | clientconfig: 4 | - command: | 5 | npm install -ws 6 | npm run build:tests-tools 7 | cd benchmark 8 | npm install 9 | npm run start -- --name set-get-delete-string --size 8 --redis-server-host ${server_private_ip} 10 | -------------------------------------------------------------------------------- /benchmark/lib/set-get-delete-string/index.js: -------------------------------------------------------------------------------- 1 | import yargs from 'yargs'; 2 | import { hideBin } from 'yargs/helpers'; 3 | import { randomBytes } from 'node:crypto'; 4 | 5 | const { size } = yargs(hideBin(process.argv)) 6 | .option('size', { 7 | type: 'number', 8 | default: 1024, 9 | demandOption: true 10 | }) 11 | .parseSync(); 12 | 13 | export const randomString = randomBytes(size).toString('ascii'); 14 | -------------------------------------------------------------------------------- /benchmark/lib/set-get-delete-string/ioredis.js: -------------------------------------------------------------------------------- 1 | import Redis from 'ioredis'; 2 | 3 | export default async (host, { randomString }) => { 4 | const client = new Redis({ 5 | host, 6 | lazyConnect: true 7 | }); 8 | 9 | await client.connect(); 10 | 11 | return { 12 | benchmark() { 13 | return Promise.all([ 14 | client.set(randomString, randomString), 15 | client.get(randomString), 16 | client.del(randomString) 17 | ]); 18 | }, 19 | teardown() { 20 | return client.disconnect(); 21 | } 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /benchmark/lib/set-get-delete-string/v4.js: -------------------------------------------------------------------------------- 1 | import { createClient } from '@redis/client'; 2 | 3 | export default async (host, { randomString }) => { 4 | const client = createClient({ 5 | socket: { 6 | host 7 | } 8 | }); 9 | 10 | await client.connect(); 11 | 12 | return { 13 | benchmark() { 14 | return Promise.all([ 15 | client.set(randomString, randomString), 16 | client.get(randomString), 17 | client.del(randomString) 18 | ]); 19 | }, 20 | teardown() { 21 | return client.disconnect(); 22 | } 23 | }; 24 | }; 25 | -------------------------------------------------------------------------------- /benchmark/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@redis/client-benchmark", 3 | "private": true, 4 | "main": "./lib", 5 | "type": "module", 6 | "scripts": { 7 | "start": "node ." 8 | }, 9 | "dependencies": { 10 | "hdr-histogram-js": "3.0.0", 11 | "ioredis": "5", 12 | "redis-local": "file:../packages/client", 13 | "redis-v3": "npm:redis@3", 14 | "redis-v4": "npm:redis@4", 15 | "yargs": "17.7.1" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /benchmark/requirements.txt: -------------------------------------------------------------------------------- 1 | redisbench_admin>=0.5.24 2 | -------------------------------------------------------------------------------- /docs/todo.md: -------------------------------------------------------------------------------- 1 | - "Isolation Pool" -> pool 2 | - Cluster request response policies (either implement, or block "server" commands in cluster) 3 | 4 | Docs: 5 | - [Command Options](./command-options.md) 6 | - [RESP](./RESP.md) 7 | -------------------------------------------------------------------------------- /examples/.gitignore: -------------------------------------------------------------------------------- 1 | package-lock.json 2 | -------------------------------------------------------------------------------- /examples/command-with-modifiers.js: -------------------------------------------------------------------------------- 1 | // Define a custom script that shows example of SET command 2 | // with several modifiers. 3 | 4 | import { createClient } from 'redis'; 5 | 6 | const client = createClient(); 7 | 8 | await client.connect(); 9 | await client.del('mykey'); 10 | 11 | console.log( 12 | await client.set('mykey', 'myvalue', { 13 | expiration: { 14 | type: 'EX', 15 | value: 60 16 | }, 17 | GET: true 18 | }) 19 | ); // null 20 | 21 | console.log( 22 | await client.set('mykey', 'newvalue', { 23 | expiration: { 24 | type: 'EX', 25 | value: 60 26 | }, 27 | GET: true 28 | }) 29 | ); // 'myvalue' 30 | 31 | await client.close(); 32 | -------------------------------------------------------------------------------- /examples/get-server-time.js: -------------------------------------------------------------------------------- 1 | // Get the time from the Redis Server. 2 | 3 | import { createClient } from 'redis'; 4 | 5 | const client = createClient(); 6 | await client.connect(); 7 | 8 | const serverTime = await client.time(); 9 | // In v5, TIME returns [unixTimestamp: string, microseconds: string] instead of Date 10 | // Example: ['1708956789', '123456'] 11 | console.log(serverTime); 12 | 13 | // Convert to JavaScript Date if needed 14 | const [seconds, microseconds] = serverTime; 15 | const date = new Date(parseInt(seconds) * 1000 + parseInt(microseconds) / 1000); 16 | console.log('Converted to Date:', date); 17 | 18 | client.close(); 19 | -------------------------------------------------------------------------------- /examples/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-redis-examples", 3 | "version": "1.0.0", 4 | "description": "node-redis 5 example script", 5 | "main": "index.js", 6 | "private": true, 7 | "type": "module", 8 | "dependencies": { 9 | "redis": "../packages/redis" 10 | } 11 | } 12 | 13 | -------------------------------------------------------------------------------- /examples/set-scan.js: -------------------------------------------------------------------------------- 1 | // An example script that shows how to use the SSCAN iterator functionality to retrieve the contents of a Redis set. 2 | // Create the set in redis-cli with this command: 3 | // sadd setName a b c d e f g h i j k l m n o p q 4 | 5 | import { createClient } from 'redis'; 6 | 7 | const client = createClient(); 8 | await client.connect(); 9 | 10 | const setName = 'setName'; 11 | 12 | for await (const members of client.sScanIterator(setName)) { 13 | console.log('Batch of members:', members); 14 | 15 | // Process each member in the batch if needed 16 | for (const member of members) { 17 | console.log('Individual member:', member); 18 | } 19 | } 20 | 21 | client.close(); 22 | -------------------------------------------------------------------------------- /packages/bloom/.nycrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@istanbuljs/nyc-config-typescript", 3 | "exclude": ["dist", "**/*.spec.ts", "lib/test-utils.ts"] 4 | } 5 | -------------------------------------------------------------------------------- /packages/bloom/.release-it.json: -------------------------------------------------------------------------------- 1 | { 2 | "npm": { 3 | "publish": true, 4 | "publishArgs": ["--access", "public"] 5 | }, 6 | "git": { 7 | "tagName": "bloom@${version}", 8 | "tagMatch": "bloom@*", 9 | "commitMessage": "Release ${tagName}", 10 | "tagAnnotation": "Release ${tagName}", 11 | "commitArgs": "--all" 12 | }, 13 | "plugins": { 14 | "@release-it/bumper": { 15 | "out": { 16 | "file": "package.json", 17 | "path": ["peerDependencies.@redis/client"], 18 | "versionPrefix": "^" 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/bloom/lib/commands/bloom/ADD.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../../test-utils'; 3 | import ADD from './ADD'; 4 | import { parseArgs } from '@redis/client/lib/commands/generic-transformers'; 5 | 6 | describe('BF.ADD', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(ADD, 'key', 'item'), 10 | ['BF.ADD', 'key', 'item'] 11 | ); 12 | }); 13 | 14 | testUtils.testWithClient('client.bf.add', async client => { 15 | assert.equal( 16 | await client.bf.add('key', 'item'), 17 | true 18 | ); 19 | }, GLOBAL.SERVERS.OPEN); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/bloom/lib/commands/bloom/CARD.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../../test-utils'; 3 | import CARD from './CARD'; 4 | import { parseArgs } from '@redis/client/lib/commands/generic-transformers'; 5 | 6 | describe('BF.CARD', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(CARD, 'bloom'), 10 | ['BF.CARD', 'bloom'] 11 | ); 12 | }); 13 | 14 | testUtils.testWithClient('client.bf.card', async client => { 15 | assert.equal( 16 | await client.bf.card('key'), 17 | 0 18 | ); 19 | }, GLOBAL.SERVERS.OPEN); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/bloom/lib/commands/bloom/CARD.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '@redis/client/dist/lib/client/parser'; 2 | import { RedisArgument, NumberReply, Command } from '@redis/client/dist/lib/RESP/types'; 3 | 4 | export default { 5 | IS_READ_ONLY: true, 6 | /** 7 | * Returns the cardinality (number of items) in a Bloom Filter 8 | * @param parser - The command parser 9 | * @param key - The name of the Bloom filter to query 10 | */ 11 | parseCommand(parser: CommandParser, key: RedisArgument) { 12 | parser.push('BF.CARD'); 13 | parser.pushKey(key); 14 | }, 15 | transformReply: undefined as unknown as () => NumberReply 16 | } as const satisfies Command; 17 | -------------------------------------------------------------------------------- /packages/bloom/lib/commands/bloom/EXISTS.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../../test-utils'; 3 | import EXISTS from './EXISTS'; 4 | import { parseArgs } from '@redis/client/lib/commands/generic-transformers'; 5 | 6 | describe('BF.EXISTS', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(EXISTS, 'key', 'item'), 10 | ['BF.EXISTS', 'key', 'item'] 11 | ); 12 | }); 13 | 14 | testUtils.testWithClient('client.bf.exists', async client => { 15 | assert.equal( 16 | await client.bf.exists('key', 'item'), 17 | false 18 | ); 19 | }, GLOBAL.SERVERS.OPEN); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/bloom/lib/commands/bloom/MADD.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../../test-utils'; 3 | import MADD from './MADD'; 4 | import { parseArgs } from '@redis/client/lib/commands/generic-transformers'; 5 | 6 | describe('BF.MADD', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(MADD, 'key', ['1', '2']), 10 | ['BF.MADD', 'key', '1', '2'] 11 | ); 12 | }); 13 | 14 | testUtils.testWithClient('client.ts.mAdd', async client => { 15 | assert.deepEqual( 16 | await client.bf.mAdd('key', ['1', '2']), 17 | [true, true] 18 | ); 19 | }, GLOBAL.SERVERS.OPEN); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/bloom/lib/commands/bloom/MEXISTS.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../../test-utils'; 3 | import MEXISTS from './MEXISTS'; 4 | import { parseArgs } from '@redis/client/lib/commands/generic-transformers'; 5 | 6 | describe('BF.MEXISTS', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(MEXISTS, 'key', ['1', '2']), 10 | ['BF.MEXISTS', 'key', '1', '2'] 11 | ); 12 | }); 13 | 14 | testUtils.testWithClient('client.bf.mExists', async client => { 15 | assert.deepEqual( 16 | await client.bf.mExists('key', ['1', '2']), 17 | [false, false] 18 | ); 19 | }, GLOBAL.SERVERS.OPEN); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/bloom/lib/commands/count-min-sketch/INITBYDIM.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../../test-utils'; 3 | import INITBYDIM from './INITBYDIM'; 4 | import { parseArgs } from '@redis/client/lib/commands/generic-transformers'; 5 | 6 | describe('CMS.INITBYDIM', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(INITBYDIM, 'key', 1000, 5), 10 | ['CMS.INITBYDIM', 'key', '1000', '5'] 11 | ); 12 | }); 13 | 14 | testUtils.testWithClient('client.cms.initByDim', async client => { 15 | assert.equal( 16 | await client.cms.initByDim('key', 1000, 5), 17 | 'OK' 18 | ); 19 | }, GLOBAL.SERVERS.OPEN); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/bloom/lib/commands/count-min-sketch/index.ts: -------------------------------------------------------------------------------- 1 | import type { RedisCommands } from '@redis/client/dist/lib/RESP/types'; 2 | import INCRBY from './INCRBY'; 3 | import INFO from './INFO'; 4 | import INITBYDIM from './INITBYDIM'; 5 | import INITBYPROB from './INITBYPROB'; 6 | import MERGE from './MERGE'; 7 | import QUERY from './QUERY'; 8 | 9 | export default { 10 | INCRBY, 11 | incrBy: INCRBY, 12 | INFO, 13 | info: INFO, 14 | INITBYDIM, 15 | initByDim: INITBYDIM, 16 | INITBYPROB, 17 | initByProb: INITBYPROB, 18 | MERGE, 19 | merge: MERGE, 20 | QUERY, 21 | query: QUERY 22 | } as const satisfies RedisCommands; 23 | -------------------------------------------------------------------------------- /packages/bloom/lib/commands/cuckoo/ADD.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../../test-utils'; 3 | import ADD from './ADD'; 4 | import { parseArgs } from '@redis/client/lib/commands/generic-transformers'; 5 | 6 | describe('CF.ADD', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(ADD, 'key', 'item'), 10 | ['CF.ADD', 'key', 'item'] 11 | ); 12 | }); 13 | 14 | testUtils.testWithClient('client.cf.add', async client => { 15 | assert.equal( 16 | await client.cf.add('key', 'item'), 17 | true 18 | ); 19 | }, GLOBAL.SERVERS.OPEN); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/bloom/lib/commands/cuckoo/ADDNX.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../../test-utils'; 3 | import ADDNX from './ADDNX'; 4 | import { parseArgs } from '@redis/client/lib/commands/generic-transformers'; 5 | 6 | describe('CF.ADDNX', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(ADDNX, 'key', 'item'), 10 | ['CF.ADDNX', 'key', 'item'] 11 | ); 12 | }); 13 | 14 | testUtils.testWithClient('client.cf.add', async client => { 15 | assert.equal( 16 | await client.cf.addNX('key', 'item'), 17 | true 18 | ); 19 | }, GLOBAL.SERVERS.OPEN); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/bloom/lib/commands/cuckoo/COUNT.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../../test-utils'; 3 | import COUNT from './COUNT'; 4 | import { parseArgs } from '@redis/client/lib/commands/generic-transformers'; 5 | 6 | describe('CF.COUNT', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(COUNT, 'key', 'item'), 10 | ['CF.COUNT', 'key', 'item'] 11 | ); 12 | }); 13 | 14 | testUtils.testWithClient('client.cf.count', async client => { 15 | assert.equal( 16 | await client.cf.count('key', 'item'), 17 | 0 18 | ); 19 | }, GLOBAL.SERVERS.OPEN); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/bloom/lib/commands/cuckoo/EXISTS.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../../test-utils'; 3 | import EXISTS from './EXISTS'; 4 | import { parseArgs } from '@redis/client/lib/commands/generic-transformers'; 5 | 6 | describe('CF.EXISTS', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(EXISTS, 'key', 'item'), 10 | ['CF.EXISTS', 'key', 'item'] 11 | ); 12 | }); 13 | 14 | testUtils.testWithClient('client.cf.exists', async client => { 15 | assert.equal( 16 | await client.cf.exists('key', 'item'), 17 | false 18 | ); 19 | }, GLOBAL.SERVERS.OPEN); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/bloom/lib/commands/index.ts: -------------------------------------------------------------------------------- 1 | import { RedisModules } from '@redis/client'; 2 | import bf from './bloom'; 3 | import cms from './count-min-sketch'; 4 | import cf from './cuckoo'; 5 | import tDigest from './t-digest'; 6 | import topK from './top-k'; 7 | 8 | export default { 9 | bf, 10 | cms, 11 | cf, 12 | tDigest, 13 | topK 14 | } as const satisfies RedisModules; 15 | -------------------------------------------------------------------------------- /packages/bloom/lib/commands/t-digest/MAX.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '@redis/client/dist/lib/client/parser'; 2 | import { RedisArgument, Command } from '@redis/client/dist/lib/RESP/types'; 3 | import { transformDoubleReply } from '@redis/client/dist/lib/commands/generic-transformers'; 4 | 5 | export default { 6 | IS_READ_ONLY: true, 7 | /** 8 | * Returns the maximum value from a t-digest sketch 9 | * @param parser - The command parser 10 | * @param key - The name of the t-digest sketch 11 | */ 12 | parseCommand(parser: CommandParser, key: RedisArgument) { 13 | parser.push('TDIGEST.MAX'); 14 | parser.pushKey(key); 15 | }, 16 | transformReply: transformDoubleReply 17 | } as const satisfies Command; 18 | -------------------------------------------------------------------------------- /packages/bloom/lib/commands/t-digest/MIN.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '@redis/client/dist/lib/client/parser'; 2 | import { RedisArgument, Command } from '@redis/client/dist/lib/RESP/types'; 3 | import { transformDoubleReply } from '@redis/client/dist/lib/commands/generic-transformers'; 4 | 5 | export default { 6 | IS_READ_ONLY: true, 7 | /** 8 | * Returns the minimum value from a t-digest sketch 9 | * @param parser - The command parser 10 | * @param key - The name of the t-digest sketch 11 | */ 12 | parseCommand(parser: CommandParser, key: RedisArgument) { 13 | parser.push('TDIGEST.MIN'); 14 | parser.pushKey(key); 15 | }, 16 | transformReply: transformDoubleReply 17 | } as const satisfies Command; 18 | -------------------------------------------------------------------------------- /packages/bloom/lib/commands/t-digest/RESET.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '@redis/client/dist/lib/client/parser'; 2 | import { RedisArgument, SimpleStringReply, Command } from '@redis/client/dist/lib/RESP/types'; 3 | 4 | export default { 5 | IS_READ_ONLY: false, 6 | /** 7 | * Resets a t-digest sketch, clearing all previously added observations 8 | * @param parser - The command parser 9 | * @param key - The name of the t-digest sketch to reset 10 | */ 11 | parseCommand(parser: CommandParser, key: RedisArgument) { 12 | parser.push('TDIGEST.RESET'); 13 | parser.pushKey(key); 14 | }, 15 | transformReply: undefined as unknown as () => SimpleStringReply<'OK'> 16 | } as const satisfies Command; 17 | -------------------------------------------------------------------------------- /packages/bloom/lib/commands/top-k/LIST.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '@redis/client/dist/lib/client/parser'; 2 | import { RedisArgument, ArrayReply, BlobStringReply, Command } from '@redis/client/dist/lib/RESP/types'; 3 | 4 | export default { 5 | IS_READ_ONLY: true, 6 | /** 7 | * Returns all items in a Top-K filter 8 | * @param parser - The command parser 9 | * @param key - The name of the Top-K filter 10 | */ 11 | parseCommand(parser: CommandParser, key: RedisArgument) { 12 | parser.push('TOPK.LIST'); 13 | parser.pushKey(key); 14 | }, 15 | transformReply: undefined as unknown as () => ArrayReply<BlobStringReply> 16 | } as const satisfies Command; 17 | -------------------------------------------------------------------------------- /packages/bloom/lib/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './commands'; 2 | -------------------------------------------------------------------------------- /packages/bloom/lib/test-utils.ts: -------------------------------------------------------------------------------- 1 | import TestUtils from '@redis/test-utils'; 2 | import RedisBloomModules from '.'; 3 | 4 | export default TestUtils.createFromConfig({ 5 | dockerImageName: 'redislabs/client-libs-test', 6 | dockerImageVersionArgument: 'redis-version', 7 | defaultDockerVersion: '8.2-M01-pre' 8 | }); 9 | 10 | export const GLOBAL = { 11 | SERVERS: { 12 | OPEN: { 13 | serverArguments: [], 14 | clientOptions: { 15 | modules: RedisBloomModules 16 | } 17 | } 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /packages/bloom/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "outDir": "./dist" 5 | }, 6 | "include": [ 7 | "./lib/**/*.ts" 8 | ], 9 | "exclude": [ 10 | "./lib/test-utils.ts", 11 | "./lib/**/*.spec.ts" 12 | ], 13 | "typedocOptions": { 14 | "entryPoints": [ 15 | "./lib" 16 | ], 17 | "entryPointStrategy": "expand", 18 | "out": "../../documentation/bloom" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /packages/client/.nycrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@istanbuljs/nyc-config-typescript", 3 | "exclude": ["dist", "**/*.spec.ts", "lib/test-utils.ts", "examples/*"] 4 | } 5 | -------------------------------------------------------------------------------- /packages/client/.release-it.json: -------------------------------------------------------------------------------- 1 | { 2 | "npm": { 3 | "publish": true, 4 | "publishArgs": ["--access", "public"] 5 | }, 6 | "git": { 7 | "tagName": "client@${version}", 8 | "tagMatch": "client@*", 9 | "commitMessage": "Release ${tagName}", 10 | "tagAnnotation": "Release ${tagName}", 11 | "commitArgs": "--all" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/client/README.md: -------------------------------------------------------------------------------- 1 | # @redis/client 2 | 3 | The source code and documentation for this package are in the main [node-redis](https://github.com/redis/node-redis) repo. 4 | -------------------------------------------------------------------------------- /packages/client/lib/RESP/verbatim-string.ts: -------------------------------------------------------------------------------- 1 | export class VerbatimString extends String { 2 | constructor( 3 | public format: string, 4 | value: string 5 | ) { 6 | super(value); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /packages/client/lib/authx/disposable.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Represents a resource that can be disposed. 3 | */ 4 | export interface Disposable { 5 | dispose(): void; 6 | } -------------------------------------------------------------------------------- /packages/client/lib/authx/index.ts: -------------------------------------------------------------------------------- 1 | export { TokenManager, TokenManagerConfig, TokenStreamListener, RetryPolicy, IDPError } from './token-manager'; 2 | export { 3 | CredentialsProvider, 4 | StreamingCredentialsProvider, 5 | UnableToObtainNewCredentialsError, 6 | CredentialsError, 7 | StreamingCredentialsListener, 8 | AsyncCredentialsProvider, 9 | ReAuthenticationError, 10 | BasicAuth 11 | } from './credentials-provider'; 12 | export { Token } from './token'; 13 | export { IdentityProvider, TokenResponse } from './identity-provider'; 14 | 15 | export { Disposable } from './disposable' -------------------------------------------------------------------------------- /packages/client/lib/client/pool.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | 4 | describe('RedisClientPool', () => { 5 | testUtils.testWithClientPool('sendCommand', async pool => { 6 | assert.equal( 7 | await pool.sendCommand(['PING']), 8 | 'PONG' 9 | ); 10 | }, GLOBAL.SERVERS.OPEN); 11 | }); 12 | -------------------------------------------------------------------------------- /packages/client/lib/commands/ACL_DELUSER.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { NumberReply, Command } from '../RESP/types'; 3 | import { RedisVariadicArgument } from './generic-transformers'; 4 | 5 | export default { 6 | NOT_KEYED_COMMAND: true, 7 | IS_READ_ONLY: true, 8 | /** 9 | * Deletes one or more users from the ACL 10 | * @param parser - The Redis command parser 11 | * @param username - Username(s) to delete 12 | */ 13 | parseCommand(parser: CommandParser, username: RedisVariadicArgument) { 14 | parser.push('ACL', 'DELUSER'); 15 | parser.pushVariadic(username); 16 | }, 17 | transformReply: undefined as unknown as () => NumberReply 18 | } as const satisfies Command; 19 | -------------------------------------------------------------------------------- /packages/client/lib/commands/ACL_GENPASS.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { BlobStringReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Generates a secure password for ACL users 9 | * @param parser - The Redis command parser 10 | * @param bits - Optional number of bits for password entropy 11 | */ 12 | parseCommand(parser: CommandParser, bits?: number) { 13 | parser.push('ACL', 'GENPASS'); 14 | if (bits) { 15 | parser.push(bits.toString()); 16 | } 17 | }, 18 | transformReply: undefined as unknown as () => BlobStringReply 19 | } as const satisfies Command; 20 | 21 | -------------------------------------------------------------------------------- /packages/client/lib/commands/ACL_LIST.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { ArrayReply, BlobStringReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Returns all configured ACL users and their permissions 9 | * @param parser - The Redis command parser 10 | */ 11 | parseCommand(parser: CommandParser) { 12 | parser.push('ACL', 'LIST'); 13 | }, 14 | transformReply: undefined as unknown as () => ArrayReply<BlobStringReply> 15 | } as const satisfies Command; 16 | -------------------------------------------------------------------------------- /packages/client/lib/commands/ACL_LOAD.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils from '../test-utils'; 3 | import ACL_LOAD from './ACL_LOAD'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('ACL LOAD', () => { 7 | testUtils.isVersionGreaterThanHook([6]); 8 | 9 | it('transformArguments', () => { 10 | assert.deepEqual( 11 | parseArgs(ACL_LOAD), 12 | ['ACL', 'LOAD'] 13 | ); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /packages/client/lib/commands/ACL_LOAD.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { SimpleStringReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Reloads ACL configuration from the ACL file 9 | * @param parser - The Redis command parser 10 | */ 11 | parseCommand(parser: CommandParser) { 12 | parser.push('ACL', 'LOAD'); 13 | }, 14 | transformReply: undefined as unknown as () => SimpleStringReply<'OK'> 15 | } as const satisfies Command; 16 | -------------------------------------------------------------------------------- /packages/client/lib/commands/ACL_LOG_RESET.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import ACL_LOG_RESET from './ACL_LOG_RESET'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('ACL LOG RESET', () => { 7 | testUtils.isVersionGreaterThanHook([6]); 8 | 9 | it('transformArguments', () => { 10 | assert.deepEqual( 11 | parseArgs(ACL_LOG_RESET), 12 | ['ACL', 'LOG', 'RESET'] 13 | ); 14 | }); 15 | 16 | testUtils.testWithClient('client.aclLogReset', async client => { 17 | assert.equal( 18 | await client.aclLogReset(), 19 | 'OK' 20 | ); 21 | }, GLOBAL.SERVERS.OPEN); 22 | }); 23 | -------------------------------------------------------------------------------- /packages/client/lib/commands/ACL_LOG_RESET.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { SimpleStringReply, Command } from '../RESP/types'; 3 | import ACL_LOG from './ACL_LOG'; 4 | 5 | export default { 6 | NOT_KEYED_COMMAND: true, 7 | IS_READ_ONLY: ACL_LOG.IS_READ_ONLY, 8 | /** 9 | * Clears the ACL security events log 10 | * @param parser - The Redis command parser 11 | */ 12 | parseCommand(parser: CommandParser) { 13 | parser.push('ACL', 'LOG', 'RESET'); 14 | }, 15 | transformReply: undefined as unknown as () => SimpleStringReply<'OK'> 16 | } as const satisfies Command; 17 | -------------------------------------------------------------------------------- /packages/client/lib/commands/ACL_SAVE.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils from '../test-utils'; 3 | import ACL_SAVE from './ACL_SAVE'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('ACL SAVE', () => { 7 | testUtils.isVersionGreaterThanHook([6]); 8 | 9 | it('transformArguments', () => { 10 | assert.deepEqual( 11 | parseArgs(ACL_SAVE), 12 | ['ACL', 'SAVE'] 13 | ); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /packages/client/lib/commands/ACL_SAVE.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { SimpleStringReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Saves the current ACL configuration to the ACL file 9 | * @param parser - The Redis command parser 10 | */ 11 | parseCommand(parser: CommandParser) { 12 | parser.push('ACL', 'SAVE'); 13 | }, 14 | transformReply: undefined as unknown as () => SimpleStringReply<'OK'> 15 | } as const satisfies Command; 16 | -------------------------------------------------------------------------------- /packages/client/lib/commands/ACL_USERS.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils from '../test-utils'; 3 | import ACL_USERS from './ACL_USERS'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('ACL USERS', () => { 7 | testUtils.isVersionGreaterThanHook([6]); 8 | 9 | it('transformArguments', () => { 10 | assert.deepEqual( 11 | parseArgs(ACL_USERS), 12 | ['ACL', 'USERS'] 13 | ); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /packages/client/lib/commands/ACL_USERS.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { ArrayReply, BlobStringReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Returns a list of all configured ACL usernames 9 | * @param parser - The Redis command parser 10 | */ 11 | parseCommand(parser: CommandParser) { 12 | parser.push('ACL', 'USERS'); 13 | }, 14 | transformReply: undefined as unknown as () => ArrayReply<BlobStringReply> 15 | } as const satisfies Command; 16 | -------------------------------------------------------------------------------- /packages/client/lib/commands/ACL_WHOAMI.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils from '../test-utils'; 3 | import ACL_WHOAMI from './ACL_WHOAMI'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('ACL WHOAMI', () => { 7 | testUtils.isVersionGreaterThanHook([6]); 8 | 9 | it('transformArguments', () => { 10 | assert.deepEqual( 11 | parseArgs(ACL_WHOAMI), 12 | ['ACL', 'WHOAMI'] 13 | ); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /packages/client/lib/commands/ACL_WHOAMI.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { BlobStringReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Returns the username of the current connection 9 | * @param parser - The Redis command parser 10 | */ 11 | parseCommand(parser: CommandParser) { 12 | parser.push('ACL', 'WHOAMI'); 13 | }, 14 | transformReply: undefined as unknown as () => BlobStringReply 15 | } as const satisfies Command; 16 | -------------------------------------------------------------------------------- /packages/client/lib/commands/APPEND.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import APPEND from './APPEND'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('APPEND', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(APPEND, 'key', 'value'), 10 | ['APPEND', 'key', 'value'] 11 | ); 12 | }); 13 | 14 | testUtils.testAll('append', async client => { 15 | assert.equal( 16 | await client.append('key', 'value'), 17 | 5 18 | ); 19 | }, { 20 | client: GLOBAL.SERVERS.OPEN, 21 | cluster: GLOBAL.CLUSTERS.OPEN 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/client/lib/commands/APPEND.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { RedisArgument, NumberReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | IS_READ_ONLY: false, 6 | /** 7 | * Appends a value to a string key 8 | * @param parser - The Redis command parser 9 | * @param key - The key to append to 10 | * @param value - The value to append 11 | */ 12 | parseCommand(parser: CommandParser, key: RedisArgument, value: RedisArgument) { 13 | parser.push('APPEND', key, value); 14 | }, 15 | 16 | transformReply: undefined as unknown as () => NumberReply 17 | } as const satisfies Command; 18 | -------------------------------------------------------------------------------- /packages/client/lib/commands/ASKING.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import ASKING from './ASKING'; 3 | import { parseArgs } from './generic-transformers'; 4 | 5 | describe('ASKING', () => { 6 | it('transformArguments', () => { 7 | assert.deepEqual( 8 | parseArgs(ASKING), 9 | ['ASKING'] 10 | ); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /packages/client/lib/commands/ASKING.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { SimpleStringReply, Command } from '../RESP/types'; 3 | 4 | export const ASKING_CMD = 'ASKING'; 5 | 6 | export default { 7 | NOT_KEYED_COMMAND: true, 8 | IS_READ_ONLY: true, 9 | /** 10 | * Tells a Redis cluster node that the client is ok receiving such redirects 11 | * @param parser - The Redis command parser 12 | */ 13 | parseCommand(parser: CommandParser) { 14 | parser.push(ASKING_CMD); 15 | }, 16 | transformReply: undefined as unknown as () => SimpleStringReply<'OK'> 17 | } as const satisfies Command; 18 | -------------------------------------------------------------------------------- /packages/client/lib/commands/BGREWRITEAOF.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import BGREWRITEAOF from './BGREWRITEAOF'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('BGREWRITEAOF', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(BGREWRITEAOF), 10 | ['BGREWRITEAOF'] 11 | ); 12 | }); 13 | 14 | testUtils.testWithClient('client.bgRewriteAof', async client => { 15 | assert.equal( 16 | typeof await client.bgRewriteAof(), 17 | 'string' 18 | ); 19 | }, GLOBAL.SERVERS.OPEN); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/client/lib/commands/BGREWRITEAOF.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { SimpleStringReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Asynchronously rewrites the append-only file 9 | * @param parser - The Redis command parser 10 | */ 11 | parseCommand(parser: CommandParser) { 12 | parser.push('BGREWRITEAOF'); 13 | }, 14 | transformReply: undefined as unknown as () => SimpleStringReply 15 | } as const satisfies Command; 16 | -------------------------------------------------------------------------------- /packages/client/lib/commands/CLIENT_CACHING.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import CLIENT_CACHING from './CLIENT_CACHING'; 3 | import { parseArgs } from './generic-transformers'; 4 | 5 | describe('CLIENT CACHING', () => { 6 | describe('transformArguments', () => { 7 | it('true', () => { 8 | assert.deepEqual( 9 | parseArgs(CLIENT_CACHING, true), 10 | ['CLIENT', 'CACHING', 'YES'] 11 | ); 12 | }); 13 | 14 | it('false', () => { 15 | assert.deepEqual( 16 | parseArgs(CLIENT_CACHING, false), 17 | ['CLIENT', 'CACHING', 'NO'] 18 | ); 19 | }); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /packages/client/lib/commands/CLIENT_GETNAME.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import CLIENT_GETNAME from './CLIENT_GETNAME'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('CLIENT GETNAME', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(CLIENT_GETNAME), 10 | ['CLIENT', 'GETNAME'] 11 | ); 12 | }); 13 | 14 | testUtils.testWithClient('client.clientGetName', async client => { 15 | assert.equal( 16 | await client.clientGetName(), 17 | null 18 | ); 19 | }, GLOBAL.SERVERS.OPEN); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/client/lib/commands/CLIENT_GETNAME.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { BlobStringReply, NullReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Returns the name of the current connection 9 | * @param parser - The Redis command parser 10 | */ 11 | parseCommand(parser: CommandParser) { 12 | parser.push('CLIENT', 'GETNAME'); 13 | }, 14 | transformReply: undefined as unknown as () => BlobStringReply | NullReply 15 | } as const satisfies Command; 16 | -------------------------------------------------------------------------------- /packages/client/lib/commands/CLIENT_GETREDIR.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import CLIENT_GETREDIR from './CLIENT_GETREDIR'; 3 | import { parseArgs } from './generic-transformers'; 4 | 5 | describe('CLIENT GETREDIR', () => { 6 | it('transformArguments', () => { 7 | assert.deepEqual( 8 | parseArgs(CLIENT_GETREDIR), 9 | ['CLIENT', 'GETREDIR'] 10 | ); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /packages/client/lib/commands/CLIENT_GETREDIR.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { NumberReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Returns the ID of the client to which the current client is redirecting tracking notifications 9 | * @param parser - The Redis command parser 10 | */ 11 | parseCommand(parser: CommandParser) { 12 | parser.push('CLIENT', 'GETREDIR'); 13 | }, 14 | transformReply: undefined as unknown as () => NumberReply 15 | } as const satisfies Command; 16 | -------------------------------------------------------------------------------- /packages/client/lib/commands/CLIENT_ID.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import CLIENT_ID from './CLIENT_ID'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('CLIENT ID', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(CLIENT_ID), 10 | ['CLIENT', 'ID'] 11 | ); 12 | }); 13 | 14 | testUtils.testWithClient('client.clientId', async client => { 15 | assert.equal( 16 | typeof (await client.clientId()), 17 | 'number' 18 | ); 19 | }, GLOBAL.SERVERS.OPEN); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/client/lib/commands/CLIENT_ID.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { NumberReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Returns the client ID for the current connection 9 | * @param parser - The Redis command parser 10 | */ 11 | parseCommand(parser: CommandParser) { 12 | parser.push('CLIENT', 'ID'); 13 | }, 14 | transformReply: undefined as unknown as () => NumberReply 15 | } as const satisfies Command; 16 | -------------------------------------------------------------------------------- /packages/client/lib/commands/CLIENT_SETNAME.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | 4 | import CLIENT_SETNAME from './CLIENT_SETNAME'; 5 | import { parseArgs } from './generic-transformers'; 6 | 7 | describe('CLIENT SETNAME', () => { 8 | it('transformArguments', () => { 9 | assert.deepEqual( 10 | parseArgs(CLIENT_SETNAME, 'name'), 11 | ['CLIENT', 'SETNAME', 'name'] 12 | ); 13 | }); 14 | 15 | testUtils.testWithClient('client.clientSetName', async client => { 16 | assert.equal( 17 | await client.clientSetName('name'), 18 | 'OK' 19 | ); 20 | }, GLOBAL.SERVERS.OPEN); 21 | }); 22 | -------------------------------------------------------------------------------- /packages/client/lib/commands/CLIENT_SETNAME.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { RedisArgument, SimpleStringReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Assigns a name to the current connection 9 | * @param parser - The Redis command parser 10 | * @param name - The name to assign to the connection 11 | */ 12 | parseCommand(parser: CommandParser, name: RedisArgument) { 13 | parser.push('CLIENT', 'SETNAME', name); 14 | }, 15 | transformReply: undefined as unknown as () => SimpleStringReply<'OK'> 16 | } as const satisfies Command; 17 | -------------------------------------------------------------------------------- /packages/client/lib/commands/CLIENT_UNPAUSE.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import CLIENT_UNPAUSE from './CLIENT_UNPAUSE'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('CLIENT UNPAUSE', () => { 7 | testUtils.isVersionGreaterThanHook([6, 2]); 8 | 9 | it('transformArguments', () => { 10 | assert.deepEqual( 11 | parseArgs(CLIENT_UNPAUSE), 12 | ['CLIENT', 'UNPAUSE'] 13 | ); 14 | }); 15 | 16 | testUtils.testWithClient('client.clientUnpause', async client => { 17 | assert.equal( 18 | await client.clientUnpause(), 19 | 'OK' 20 | ); 21 | }, GLOBAL.SERVERS.OPEN); 22 | }); 23 | -------------------------------------------------------------------------------- /packages/client/lib/commands/CLIENT_UNPAUSE.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { SimpleStringReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Resumes processing of client commands after a CLIENT PAUSE 9 | * @param parser - The Redis command parser 10 | */ 11 | parseCommand(parser: CommandParser) { 12 | parser.push('CLIENT', 'UNPAUSE'); 13 | }, 14 | transformReply: undefined as unknown as () => SimpleStringReply<'OK'> 15 | } as const satisfies Command; 16 | -------------------------------------------------------------------------------- /packages/client/lib/commands/CLUSTER_ADDSLOTS.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import CLUSTER_ADDSLOTS from './CLUSTER_ADDSLOTS'; 3 | import { parseArgs } from './generic-transformers'; 4 | 5 | describe('CLUSTER ADDSLOTS', () => { 6 | describe('transformArguments', () => { 7 | it('single', () => { 8 | assert.deepEqual( 9 | parseArgs(CLUSTER_ADDSLOTS, 0), 10 | ['CLUSTER', 'ADDSLOTS', '0'] 11 | ); 12 | }); 13 | 14 | it('multiple', () => { 15 | assert.deepEqual( 16 | parseArgs(CLUSTER_ADDSLOTS, [0, 1]), 17 | ['CLUSTER', 'ADDSLOTS', '0', '1'] 18 | ); 19 | }); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /packages/client/lib/commands/CLUSTER_ADDSLOTS.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { SimpleStringReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Assigns hash slots to the current node in a Redis Cluster 9 | * @param parser - The Redis command parser 10 | * @param slots - One or more hash slots to be assigned 11 | */ 12 | parseCommand(parser: CommandParser, slots: number | Array<number>) { 13 | parser.push('CLUSTER', 'ADDSLOTS'); 14 | parser.pushVariadicNumber(slots); 15 | }, 16 | transformReply: undefined as unknown as () => SimpleStringReply<'OK'> 17 | } as const satisfies Command; 18 | -------------------------------------------------------------------------------- /packages/client/lib/commands/CLUSTER_BUMPEPOCH.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { SimpleStringReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Advances the cluster config epoch 9 | * @param parser - The Redis command parser 10 | */ 11 | parseCommand(parser: CommandParser) { 12 | parser.push('CLUSTER', 'BUMPEPOCH'); 13 | }, 14 | transformReply: undefined as unknown as () => SimpleStringReply<'BUMPED' | 'STILL'> 15 | } as const satisfies Command; 16 | -------------------------------------------------------------------------------- /packages/client/lib/commands/CLUSTER_COUNT-FAILURE-REPORTS.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { RedisArgument, NumberReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Returns the number of failure reports for a given node 9 | * @param parser - The Redis command parser 10 | * @param nodeId - The ID of the node to check 11 | */ 12 | parseCommand(parser: CommandParser, nodeId: RedisArgument) { 13 | parser.push('CLUSTER', 'COUNT-FAILURE-REPORTS', nodeId); 14 | }, 15 | transformReply: undefined as unknown as () => NumberReply 16 | } as const satisfies Command; 17 | -------------------------------------------------------------------------------- /packages/client/lib/commands/CLUSTER_COUNTKEYSINSLOT.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { NumberReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Returns the number of keys in the specified hash slot 9 | * @param parser - The Redis command parser 10 | * @param slot - The hash slot to check 11 | */ 12 | parseCommand(parser: CommandParser, slot: number) { 13 | parser.push('CLUSTER', 'COUNTKEYSINSLOT', slot.toString()); 14 | }, 15 | transformReply: undefined as unknown as () => NumberReply 16 | } as const satisfies Command; 17 | -------------------------------------------------------------------------------- /packages/client/lib/commands/CLUSTER_DELSLOTS.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import CLUSTER_DELSLOTS from './CLUSTER_DELSLOTS'; 3 | import { parseArgs } from './generic-transformers'; 4 | 5 | describe('CLUSTER DELSLOTS', () => { 6 | describe('transformArguments', () => { 7 | it('single', () => { 8 | assert.deepEqual( 9 | parseArgs(CLUSTER_DELSLOTS, 0), 10 | ['CLUSTER', 'DELSLOTS', '0'] 11 | ); 12 | }); 13 | 14 | it('multiple', () => { 15 | assert.deepEqual( 16 | parseArgs(CLUSTER_DELSLOTS, [0, 1]), 17 | ['CLUSTER', 'DELSLOTS', '0', '1'] 18 | ); 19 | }); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /packages/client/lib/commands/CLUSTER_DELSLOTS.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { SimpleStringReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Removes hash slots from the current node in a Redis Cluster 9 | * @param parser - The Redis command parser 10 | * @param slots - One or more hash slots to be removed 11 | */ 12 | parseCommand(parser: CommandParser, slots: number | Array<number>) { 13 | parser.push('CLUSTER', 'DELSLOTS'); 14 | parser.pushVariadicNumber(slots); 15 | }, 16 | transformReply: undefined as unknown as () => SimpleStringReply<'OK'> 17 | } as const satisfies Command; 18 | -------------------------------------------------------------------------------- /packages/client/lib/commands/CLUSTER_FAILOVER.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import CLUSTER_FAILOVER, { FAILOVER_MODES } from './CLUSTER_FAILOVER'; 3 | import { parseArgs } from './generic-transformers'; 4 | 5 | describe('CLUSTER FAILOVER', () => { 6 | describe('transformArguments', () => { 7 | it('simple', () => { 8 | assert.deepEqual( 9 | parseArgs(CLUSTER_FAILOVER), 10 | ['CLUSTER', 'FAILOVER'] 11 | ); 12 | }); 13 | 14 | it('with mode', () => { 15 | assert.deepEqual( 16 | parseArgs(CLUSTER_FAILOVER, { 17 | mode: FAILOVER_MODES.FORCE 18 | }), 19 | ['CLUSTER', 'FAILOVER', 'FORCE'] 20 | ); 21 | }); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/client/lib/commands/CLUSTER_FLUSHSLOTS.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import CLUSTER_FLUSHSLOTS from './CLUSTER_FLUSHSLOTS'; 3 | import { parseArgs } from './generic-transformers'; 4 | 5 | describe('CLUSTER FLUSHSLOTS', () => { 6 | it('transformArguments', () => { 7 | assert.deepEqual( 8 | parseArgs(CLUSTER_FLUSHSLOTS), 9 | ['CLUSTER', 'FLUSHSLOTS'] 10 | ); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /packages/client/lib/commands/CLUSTER_FLUSHSLOTS.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { SimpleStringReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Deletes all hash slots from the current node in a Redis Cluster 9 | * @param parser - The Redis command parser 10 | */ 11 | parseCommand(parser: CommandParser) { 12 | parser.push('CLUSTER', 'FLUSHSLOTS'); 13 | }, 14 | transformReply: undefined as unknown as () => SimpleStringReply<'OK'> 15 | } as const satisfies Command; 16 | -------------------------------------------------------------------------------- /packages/client/lib/commands/CLUSTER_FORGET.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import CLUSTER_FORGET from './CLUSTER_FORGET'; 3 | import { parseArgs } from './generic-transformers'; 4 | 5 | describe('CLUSTER FORGET', () => { 6 | it('transformArguments', () => { 7 | assert.deepEqual( 8 | parseArgs(CLUSTER_FORGET, '0'), 9 | ['CLUSTER', 'FORGET', '0'] 10 | ); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /packages/client/lib/commands/CLUSTER_FORGET.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { RedisArgument, SimpleStringReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Removes a node from the cluster 9 | * @param parser - The Redis command parser 10 | * @param nodeId - The ID of the node to remove 11 | */ 12 | parseCommand(parser: CommandParser, nodeId: RedisArgument) { 13 | parser.push('CLUSTER', 'FORGET', nodeId); 14 | }, 15 | transformReply: undefined as unknown as () => SimpleStringReply<'OK'> 16 | } as const satisfies Command; 17 | -------------------------------------------------------------------------------- /packages/client/lib/commands/CLUSTER_INFO.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import CLUSTER_INFO from './CLUSTER_INFO'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('CLUSTER INFO', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(CLUSTER_INFO), 10 | ['CLUSTER', 'INFO'] 11 | ); 12 | }); 13 | 14 | testUtils.testWithCluster('clusterNode.clusterInfo', async cluster => { 15 | const client = await cluster.nodeClient(cluster.masters[0]); 16 | assert.equal( 17 | typeof await client.clusterInfo(), 18 | 'string' 19 | ); 20 | }, GLOBAL.CLUSTERS.OPEN); 21 | }); 22 | -------------------------------------------------------------------------------- /packages/client/lib/commands/CLUSTER_INFO.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { VerbatimStringReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Returns information about the state of a Redis Cluster 9 | * @param parser - The Redis command parser 10 | */ 11 | parseCommand(parser: CommandParser) { 12 | parser.push('CLUSTER', 'INFO'); 13 | }, 14 | transformReply: undefined as unknown as () => VerbatimStringReply 15 | } as const satisfies Command; 16 | -------------------------------------------------------------------------------- /packages/client/lib/commands/CLUSTER_KEYSLOT.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { Command, NumberReply, RedisArgument } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Returns the hash slot number for a given key 9 | * @param parser - The Redis command parser 10 | * @param key - The key to get the hash slot for 11 | */ 12 | parseCommand(parser: CommandParser, key: RedisArgument) { 13 | parser.push('CLUSTER', 'KEYSLOT', key); 14 | }, 15 | transformReply: undefined as unknown as () => NumberReply 16 | } as const satisfies Command; 17 | -------------------------------------------------------------------------------- /packages/client/lib/commands/CLUSTER_MEET.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import CLUSTER_MEET from './CLUSTER_MEET'; 3 | import { parseArgs } from './generic-transformers'; 4 | 5 | describe('CLUSTER MEET', () => { 6 | it('transformArguments', () => { 7 | assert.deepEqual( 8 | parseArgs(CLUSTER_MEET, '127.0.0.1', 6379), 9 | ['CLUSTER', 'MEET', '127.0.0.1', '6379'] 10 | ); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /packages/client/lib/commands/CLUSTER_MEET.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { SimpleStringReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Initiates a handshake with another node in the cluster 9 | * @param parser - The Redis command parser 10 | * @param host - Host name or IP address of the node 11 | * @param port - TCP port of the node 12 | */ 13 | parseCommand(parser: CommandParser, host: string, port: number) { 14 | parser.push('CLUSTER', 'MEET', host, port.toString()); 15 | }, 16 | transformReply: undefined as unknown as () => SimpleStringReply<'OK'> 17 | } as const satisfies Command; 18 | -------------------------------------------------------------------------------- /packages/client/lib/commands/CLUSTER_MYID.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { BlobStringReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Returns the node ID of the current Redis Cluster node 9 | * @param parser - The Redis command parser 10 | */ 11 | parseCommand(parser: CommandParser) { 12 | parser.push('CLUSTER', 'MYID'); 13 | }, 14 | transformReply: undefined as unknown as () => BlobStringReply 15 | } as const satisfies Command; 16 | -------------------------------------------------------------------------------- /packages/client/lib/commands/CLUSTER_MYSHARDID.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { BlobStringReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Returns the shard ID of the current Redis Cluster node 9 | * @param parser - The Redis command parser 10 | */ 11 | parseCommand(parser: CommandParser) { 12 | parser.push('CLUSTER', 'MYSHARDID'); 13 | }, 14 | transformReply: undefined as unknown as () => BlobStringReply 15 | } as const satisfies Command; 16 | 17 | -------------------------------------------------------------------------------- /packages/client/lib/commands/CLUSTER_NODES.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { VerbatimStringReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Returns serialized information about the nodes in a Redis Cluster 9 | * @param parser - The Redis command parser 10 | */ 11 | parseCommand(parser: CommandParser) { 12 | parser.push('CLUSTER', 'NODES'); 13 | }, 14 | transformReply: undefined as unknown as () => VerbatimStringReply 15 | } as const satisfies Command; 16 | -------------------------------------------------------------------------------- /packages/client/lib/commands/CLUSTER_REPLICAS.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { RedisArgument, ArrayReply, BlobStringReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Returns the replica nodes replicating from the specified primary node 9 | * @param parser - The Redis command parser 10 | * @param nodeId - Node ID of the primary node 11 | */ 12 | parseCommand(parser: CommandParser, nodeId: RedisArgument) { 13 | parser.push('CLUSTER', 'REPLICAS', nodeId); 14 | }, 15 | transformReply: undefined as unknown as () => ArrayReply<BlobStringReply> 16 | } as const satisfies Command; 17 | -------------------------------------------------------------------------------- /packages/client/lib/commands/CLUSTER_REPLICATE.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import CLUSTER_REPLICATE from './CLUSTER_REPLICATE'; 3 | import { parseArgs } from './generic-transformers'; 4 | 5 | describe('CLUSTER REPLICATE', () => { 6 | it('transformArguments', () => { 7 | assert.deepEqual( 8 | parseArgs(CLUSTER_REPLICATE, '0'), 9 | ['CLUSTER', 'REPLICATE', '0'] 10 | ); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /packages/client/lib/commands/CLUSTER_REPLICATE.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { RedisArgument, SimpleStringReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Reconfigures a node as a replica of the specified primary node 9 | * @param parser - The Redis command parser 10 | * @param nodeId - Node ID of the primary node to replicate 11 | */ 12 | parseCommand(parser: CommandParser, nodeId: RedisArgument) { 13 | parser.push('CLUSTER', 'REPLICATE', nodeId); 14 | }, 15 | transformReply: undefined as unknown as () => SimpleStringReply 16 | } as const satisfies Command; 17 | -------------------------------------------------------------------------------- /packages/client/lib/commands/CLUSTER_RESET.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import CLUSTER_RESET from './CLUSTER_RESET'; 3 | import { parseArgs } from './generic-transformers'; 4 | 5 | describe('CLUSTER RESET', () => { 6 | describe('transformArguments', () => { 7 | it('simple', () => { 8 | assert.deepEqual( 9 | parseArgs(CLUSTER_RESET), 10 | ['CLUSTER', 'RESET'] 11 | ); 12 | }); 13 | 14 | it('with mode', () => { 15 | assert.deepEqual( 16 | parseArgs(CLUSTER_RESET, { 17 | mode: 'HARD' 18 | }), 19 | ['CLUSTER', 'RESET', 'HARD'] 20 | ); 21 | }); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/client/lib/commands/CLUSTER_SAVECONFIG.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { SimpleStringReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Forces a Redis Cluster node to save the cluster configuration to disk 9 | * @param parser - The Redis command parser 10 | */ 11 | parseCommand(parser: CommandParser) { 12 | parser.push('CLUSTER', 'SAVECONFIG'); 13 | }, 14 | transformReply: undefined as unknown as () => SimpleStringReply<'OK'> 15 | } as const satisfies Command; 16 | 17 | -------------------------------------------------------------------------------- /packages/client/lib/commands/CLUSTER_SET-CONFIG-EPOCH.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import CLUSTER_SET_CONFIG_EPOCH from './CLUSTER_SET-CONFIG-EPOCH'; 3 | import { parseArgs } from './generic-transformers'; 4 | 5 | describe('CLUSTER SET-CONFIG-EPOCH', () => { 6 | it('transformArguments', () => { 7 | assert.deepEqual( 8 | parseArgs(CLUSTER_SET_CONFIG_EPOCH, 0), 9 | ['CLUSTER', 'SET-CONFIG-EPOCH', '0'] 10 | ); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /packages/client/lib/commands/CLUSTER_SET-CONFIG-EPOCH.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { SimpleStringReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Sets the configuration epoch for a Redis Cluster node 9 | * @param parser - The Redis command parser 10 | * @param configEpoch - The configuration epoch to set 11 | */ 12 | parseCommand(parser: CommandParser, configEpoch: number) { 13 | parser.push('CLUSTER', 'SET-CONFIG-EPOCH', configEpoch.toString()); 14 | }, 15 | transformReply: undefined as unknown as () => SimpleStringReply<'OK'> 16 | } as const satisfies Command; 17 | -------------------------------------------------------------------------------- /packages/client/lib/commands/COMMAND.spec.ts: -------------------------------------------------------------------------------- 1 | // import { strict as assert } from 'node:assert'; 2 | // import testUtils, { GLOBAL } from '../test-utils'; 3 | // import { transformArguments } from './COMMAND'; 4 | // import { assertPingCommand } from './COMMAND_INFO.spec'; 5 | 6 | // describe('COMMAND', () => { 7 | // it('transformArguments', () => { 8 | // assert.deepEqual( 9 | // transformArguments(), 10 | // ['COMMAND'] 11 | // ); 12 | // }); 13 | 14 | // testUtils.testWithClient('client.command', async client => { 15 | // assertPingCommand((await client.command()).find(command => command.name === 'ping')); 16 | // }, GLOBAL.SERVERS.OPEN); 17 | // }); 18 | -------------------------------------------------------------------------------- /packages/client/lib/commands/COMMAND_COUNT.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import COMMAND_COUNT from './COMMAND_COUNT'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('COMMAND COUNT', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(COMMAND_COUNT), 10 | ['COMMAND', 'COUNT'] 11 | ); 12 | }); 13 | 14 | testUtils.testWithClient('client.commandCount', async client => { 15 | assert.equal( 16 | typeof await client.commandCount(), 17 | 'number' 18 | ); 19 | }, GLOBAL.SERVERS.OPEN); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/client/lib/commands/COMMAND_COUNT.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { NumberReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Returns the total number of commands available in the Redis server 9 | * @param parser - The Redis command parser 10 | */ 11 | parseCommand(parser: CommandParser) { 12 | parser.push('COMMAND', 'COUNT'); 13 | }, 14 | transformReply: undefined as unknown as () => NumberReply 15 | } as const satisfies Command; 16 | -------------------------------------------------------------------------------- /packages/client/lib/commands/COMMAND_GETKEYS.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import COMMAND_GETKEYS from './COMMAND_GETKEYS'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('COMMAND GETKEYS', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(COMMAND_GETKEYS, ['GET', 'key']), 10 | ['COMMAND', 'GETKEYS', 'GET', 'key'] 11 | ); 12 | }); 13 | 14 | testUtils.testWithClient('client.commandGetKeys', async client => { 15 | assert.deepEqual( 16 | await client.commandGetKeys(['GET', 'key']), 17 | ['key'] 18 | ); 19 | }, GLOBAL.SERVERS.OPEN); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/client/lib/commands/COMMAND_GETKEYS.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { RedisArgument, ArrayReply, BlobStringReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Extracts the key names from a Redis command 9 | * @param parser - The Redis command parser 10 | * @param args - Command arguments to analyze 11 | */ 12 | parseCommand(parser: CommandParser, args: Array<RedisArgument>) { 13 | parser.push('COMMAND', 'GETKEYS'); 14 | parser.push(...args); 15 | }, 16 | transformReply: undefined as unknown as () => ArrayReply<BlobStringReply> 17 | } as const satisfies Command; 18 | -------------------------------------------------------------------------------- /packages/client/lib/commands/CONFIG_RESETSTAT.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import CONFIG_RESETSTAT from './CONFIG_RESETSTAT'; 3 | import { parseArgs } from './generic-transformers'; 4 | 5 | describe('CONFIG RESETSTAT', () => { 6 | it('transformArguments', () => { 7 | assert.deepEqual( 8 | parseArgs(CONFIG_RESETSTAT), 9 | ['CONFIG', 'RESETSTAT'] 10 | ); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /packages/client/lib/commands/CONFIG_RESETSTAT.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { SimpleStringReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Resets the statistics reported by Redis using the INFO command 9 | * @param parser - The Redis command parser 10 | */ 11 | parseCommand(parser: CommandParser) { 12 | parser.push('CONFIG', 'RESETSTAT'); 13 | }, 14 | transformReply: undefined as unknown as () => SimpleStringReply 15 | } as const satisfies Command; 16 | -------------------------------------------------------------------------------- /packages/client/lib/commands/CONFIG_REWRITE.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import CONFIG_REWRITE from './CONFIG_REWRITE'; 3 | import { parseArgs } from './generic-transformers'; 4 | 5 | describe('CONFIG REWRITE', () => { 6 | it('transformArguments', () => { 7 | assert.deepEqual( 8 | parseArgs(CONFIG_REWRITE), 9 | ['CONFIG', 'REWRITE'] 10 | ); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /packages/client/lib/commands/CONFIG_REWRITE.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { SimpleStringReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Rewrites the Redis configuration file with the current configuration 9 | * @param parser - The Redis command parser 10 | */ 11 | parseCommand(parser: CommandParser) { 12 | parser.push('CONFIG', 'REWRITE'); 13 | }, 14 | transformReply: undefined as unknown as () => SimpleStringReply 15 | } as const satisfies Command; 16 | -------------------------------------------------------------------------------- /packages/client/lib/commands/DBSIZE.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import DBSIZE from './DBSIZE'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('DBSIZE', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(DBSIZE), 10 | ['DBSIZE'] 11 | ); 12 | }); 13 | 14 | testUtils.testWithClient('client.dbSize', async client => { 15 | assert.equal( 16 | await client.dbSize(), 17 | 0 18 | ); 19 | }, GLOBAL.SERVERS.OPEN); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/client/lib/commands/DBSIZE.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { NumberReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Returns the number of keys in the current database 9 | * @param parser - The Redis command parser 10 | */ 11 | parseCommand(parser: CommandParser) { 12 | parser.push('DBSIZE'); 13 | }, 14 | transformReply: undefined as unknown as () => NumberReply 15 | } as const satisfies Command; 16 | -------------------------------------------------------------------------------- /packages/client/lib/commands/DECR.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import DECR from './DECR'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('DECR', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(DECR, 'key'), 10 | ['DECR', 'key'] 11 | ); 12 | }); 13 | 14 | testUtils.testAll('decr', async client => { 15 | assert.equal( 16 | await client.decr('key'), 17 | -1 18 | ); 19 | }, { 20 | client: GLOBAL.SERVERS.OPEN, 21 | cluster: GLOBAL.CLUSTERS.OPEN 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/client/lib/commands/DECR.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { RedisArgument, NumberReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | /** 6 | * Decrements the integer value of a key by one 7 | * @param parser - The Redis command parser 8 | * @param key - Key to decrement 9 | */ 10 | parseCommand(parser: CommandParser, key: RedisArgument) { 11 | parser.push('DECR'); 12 | parser.pushKey(key); 13 | }, 14 | transformReply: undefined as unknown as () => NumberReply 15 | } as const satisfies Command; 16 | -------------------------------------------------------------------------------- /packages/client/lib/commands/DECRBY.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import DECRBY from './DECRBY'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('DECRBY', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(DECRBY, 'key', 2), 10 | ['DECRBY', 'key', '2'] 11 | ); 12 | }); 13 | 14 | testUtils.testAll('decrBy', async client => { 15 | assert.equal( 16 | await client.decrBy('key', 2), 17 | -2 18 | ); 19 | }, { 20 | client: GLOBAL.SERVERS.OPEN, 21 | cluster: GLOBAL.CLUSTERS.OPEN 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/client/lib/commands/DECRBY.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { RedisArgument, NumberReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | /** 6 | * Decrements the integer value of a key by the given number 7 | * @param parser - The Redis command parser 8 | * @param key - Key to decrement 9 | * @param decrement - Decrement amount 10 | */ 11 | parseCommand(parser: CommandParser, key: RedisArgument, decrement: number) { 12 | parser.push('DECRBY'); 13 | parser.pushKey(key); 14 | parser.push(decrement.toString()); 15 | }, 16 | transformReply: undefined as unknown as () => NumberReply 17 | } as const satisfies Command; 18 | -------------------------------------------------------------------------------- /packages/client/lib/commands/DEL.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { NumberReply, Command } from '../RESP/types'; 3 | import { RedisVariadicArgument } from './generic-transformers'; 4 | 5 | export default { 6 | IS_READ_ONLY: false, 7 | /** 8 | * Removes the specified keys. A key is ignored if it does not exist 9 | * @param parser - The Redis command parser 10 | * @param keys - One or more keys to delete 11 | */ 12 | parseCommand(parser: CommandParser, keys: RedisVariadicArgument) { 13 | parser.push('DEL'); 14 | parser.pushKeys(keys); 15 | }, 16 | transformReply: undefined as unknown as () => NumberReply 17 | } as const satisfies Command; 18 | -------------------------------------------------------------------------------- /packages/client/lib/commands/DISCARD.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import DISCARD from './DISCARD'; 3 | import { parseArgs } from './generic-transformers'; 4 | 5 | describe('DISCARD', () => { 6 | it('transformArguments', () => { 7 | assert.deepEqual( 8 | parseArgs(DISCARD), 9 | ['DISCARD'] 10 | ); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /packages/client/lib/commands/DISCARD.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { SimpleStringReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | /** 6 | * Discards a transaction, forgetting all queued commands 7 | * @param parser - The Redis command parser 8 | */ 9 | parseCommand(parser: CommandParser) { 10 | parser.push('DISCARD'); 11 | }, 12 | transformReply: undefined as unknown as () => SimpleStringReply 13 | } as const satisfies Command; 14 | -------------------------------------------------------------------------------- /packages/client/lib/commands/DUMP.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import DUMP from './DUMP'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('DUMP', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(DUMP, 'key'), 10 | ['DUMP', 'key'] 11 | ); 12 | }); 13 | 14 | testUtils.testAll('client.dump', async client => { 15 | assert.equal( 16 | await client.dump('key'), 17 | null 18 | ); 19 | }, { 20 | client: GLOBAL.SERVERS.OPEN, 21 | cluster: GLOBAL.CLUSTERS.OPEN 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/client/lib/commands/DUMP.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { RedisArgument, BlobStringReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | IS_READ_ONLY: true, 6 | /** 7 | * Returns a serialized version of the value stored at the key 8 | * @param parser - The Redis command parser 9 | * @param key - Key to dump 10 | */ 11 | parseCommand(parser: CommandParser, key: RedisArgument) { 12 | parser.push('DUMP'); 13 | parser.pushKey(key); 14 | }, 15 | transformReply: undefined as unknown as () => BlobStringReply 16 | } as const satisfies Command; 17 | -------------------------------------------------------------------------------- /packages/client/lib/commands/ECHO.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import ECHO from './ECHO'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('ECHO', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(ECHO, 'message'), 10 | ['ECHO', 'message'] 11 | ); 12 | }); 13 | 14 | testUtils.testWithClient('client.echo', async client => { 15 | assert.equal( 16 | await client.echo('message'), 17 | 'message' 18 | ); 19 | }, GLOBAL.SERVERS.OPEN); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/client/lib/commands/ECHO.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { RedisArgument, BlobStringReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Returns the given string 9 | * @param parser - The Redis command parser 10 | * @param message - Message to echo back 11 | */ 12 | parseCommand(parser: CommandParser, message: RedisArgument) { 13 | parser.push('ECHO', message); 14 | }, 15 | transformReply: undefined as unknown as () => BlobStringReply 16 | } as const satisfies Command; 17 | -------------------------------------------------------------------------------- /packages/client/lib/commands/EVALSHA.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import EVALSHA from './EVALSHA'; 3 | import { parseArgs } from './generic-transformers'; 4 | 5 | describe('EVALSHA', () => { 6 | it('transformArguments', () => { 7 | assert.deepEqual( 8 | parseArgs(EVALSHA, 'sha1', { 9 | keys: ['key'], 10 | arguments: ['argument'] 11 | }), 12 | ['EVALSHA', 'sha1', '1', 'key', 'argument'] 13 | ); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /packages/client/lib/commands/EVALSHA.ts: -------------------------------------------------------------------------------- 1 | import { Command } from '../RESP/types'; 2 | import EVAL, { parseEvalArguments } from './EVAL'; 3 | 4 | export default { 5 | IS_READ_ONLY: false, 6 | /** 7 | * Executes a Lua script server side using the script's SHA1 digest 8 | * @param parser - The Redis command parser 9 | * @param sha1 - SHA1 digest of the script 10 | * @param options - Script execution options including keys and arguments 11 | */ 12 | parseCommand(...args: Parameters<typeof parseEvalArguments>) { 13 | args[0].push('EVALSHA'); 14 | parseEvalArguments(...args); 15 | }, 16 | transformReply: EVAL.transformReply 17 | } as const satisfies Command; 18 | -------------------------------------------------------------------------------- /packages/client/lib/commands/EVALSHA_RO.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils from '../test-utils'; 3 | import EVALSHA_RO from './EVALSHA_RO'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('EVALSHA_RO', () => { 7 | testUtils.isVersionGreaterThanHook([7]); 8 | 9 | it('transformArguments', () => { 10 | assert.deepEqual( 11 | parseArgs(EVALSHA_RO, 'sha1', { 12 | keys: ['key'], 13 | arguments: ['argument'] 14 | }), 15 | ['EVALSHA_RO', 'sha1', '1', 'key', 'argument'] 16 | ); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /packages/client/lib/commands/EVALSHA_RO.ts: -------------------------------------------------------------------------------- 1 | import { Command } from '../RESP/types'; 2 | import EVAL, { parseEvalArguments } from './EVAL'; 3 | 4 | export default { 5 | IS_READ_ONLY: true, 6 | /** 7 | * Executes a read-only Lua script server side using the script's SHA1 digest 8 | * @param parser - The Redis command parser 9 | * @param sha1 - SHA1 digest of the script 10 | * @param options - Script execution options including keys and arguments 11 | */ 12 | parseCommand(...args: Parameters<typeof parseEvalArguments>) { 13 | args[0].push('EVALSHA_RO'); 14 | parseEvalArguments(...args); 15 | }, 16 | transformReply: EVAL.transformReply 17 | } as const satisfies Command; 18 | -------------------------------------------------------------------------------- /packages/client/lib/commands/EVAL_RO.ts: -------------------------------------------------------------------------------- 1 | import { Command } from '../RESP/types'; 2 | import EVAL, { parseEvalArguments } from './EVAL'; 3 | 4 | export default { 5 | IS_READ_ONLY: true, 6 | /** 7 | * Executes a read-only Lua script server side 8 | * @param parser - The Redis command parser 9 | * @param script - Lua script to execute 10 | * @param options - Script execution options including keys and arguments 11 | */ 12 | parseCommand(...args: Parameters<typeof parseEvalArguments>) { 13 | args[0].push('EVAL_RO'); 14 | parseEvalArguments(...args); 15 | }, 16 | transformReply: EVAL.transformReply 17 | } as const satisfies Command; 18 | -------------------------------------------------------------------------------- /packages/client/lib/commands/EXISTS.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { NumberReply, Command } from '../RESP/types'; 3 | import { RedisVariadicArgument } from './generic-transformers'; 4 | 5 | export default { 6 | CACHEABLE: true, 7 | IS_READ_ONLY: true, 8 | /** 9 | * Determines if the specified keys exist 10 | * @param parser - The Redis command parser 11 | * @param keys - One or more keys to check 12 | */ 13 | parseCommand(parser: CommandParser, keys: RedisVariadicArgument) { 14 | parser.push('EXISTS'); 15 | parser.pushKeys(keys); 16 | }, 17 | transformReply: undefined as unknown as () => NumberReply 18 | } as const satisfies Command; 19 | -------------------------------------------------------------------------------- /packages/client/lib/commands/EXPIRETIME.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { RedisArgument, NumberReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | IS_READ_ONLY: true, 6 | /** 7 | * Returns the absolute Unix timestamp (since January 1, 1970) at which the given key will expire 8 | * @param parser - The Redis command parser 9 | * @param key - Key to check expiration time 10 | */ 11 | parseCommand(parser: CommandParser, key: RedisArgument) { 12 | parser.push('EXPIRETIME'); 13 | parser.pushKey(key); 14 | }, 15 | transformReply: undefined as unknown as () => NumberReply 16 | } as const satisfies Command; 17 | -------------------------------------------------------------------------------- /packages/client/lib/commands/FCALL.ts: -------------------------------------------------------------------------------- 1 | import { Command } from '../RESP/types'; 2 | import EVAL, { parseEvalArguments } from './EVAL'; 3 | 4 | export default { 5 | IS_READ_ONLY: false, 6 | /** 7 | * Invokes a Redis function 8 | * @param parser - The Redis command parser 9 | * @param functionName - Name of the function to call 10 | * @param options - Function execution options including keys and arguments 11 | */ 12 | parseCommand(...args: Parameters<typeof parseEvalArguments>) { 13 | args[0].push('FCALL'); 14 | parseEvalArguments(...args); 15 | }, 16 | transformReply: EVAL.transformReply 17 | } as const satisfies Command; 18 | -------------------------------------------------------------------------------- /packages/client/lib/commands/FCALL_RO.ts: -------------------------------------------------------------------------------- 1 | import { Command } from '../RESP/types'; 2 | import EVAL, { parseEvalArguments } from './EVAL'; 3 | 4 | export default { 5 | IS_READ_ONLY: false, 6 | /** 7 | * Invokes a read-only Redis function 8 | * @param parser - The Redis command parser 9 | * @param functionName - Name of the function to call 10 | * @param options - Function execution options including keys and arguments 11 | */ 12 | parseCommand(...args: Parameters<typeof parseEvalArguments>) { 13 | args[0].push('FCALL_RO'); 14 | parseEvalArguments(...args); 15 | }, 16 | transformReply: EVAL.transformReply 17 | } as const satisfies Command; 18 | -------------------------------------------------------------------------------- /packages/client/lib/commands/FLUSHDB.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { SimpleStringReply, Command } from '../RESP/types'; 3 | import { RedisFlushMode } from './FLUSHALL'; 4 | 5 | export default { 6 | NOT_KEYED_COMMAND: true, 7 | IS_READ_ONLY: false, 8 | /** 9 | * Removes all keys from the current database 10 | * @param parser - The Redis command parser 11 | * @param mode - Optional flush mode (ASYNC or SYNC) 12 | */ 13 | parseCommand(parser: CommandParser, mode?: RedisFlushMode) { 14 | parser.push('FLUSHDB'); 15 | if (mode) { 16 | parser.push(mode); 17 | } 18 | }, 19 | transformReply: undefined as unknown as () => SimpleStringReply 20 | } as const satisfies Command; 21 | -------------------------------------------------------------------------------- /packages/client/lib/commands/FUNCTION_DELETE.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { RedisArgument, SimpleStringReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: false, 7 | /** 8 | * Deletes a library and all its functions 9 | * @param parser - The Redis command parser 10 | * @param library - Name of the library to delete 11 | */ 12 | parseCommand(parser: CommandParser, library: RedisArgument) { 13 | parser.push('FUNCTION', 'DELETE', library); 14 | }, 15 | transformReply: undefined as unknown as () => SimpleStringReply 16 | } as const satisfies Command; 17 | -------------------------------------------------------------------------------- /packages/client/lib/commands/FUNCTION_DUMP.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import FUNCTION_DUMP from './FUNCTION_DUMP'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('FUNCTION DUMP', () => { 7 | testUtils.isVersionGreaterThanHook([7]); 8 | 9 | it('transformArguments', () => { 10 | assert.deepEqual( 11 | parseArgs(FUNCTION_DUMP), 12 | ['FUNCTION', 'DUMP'] 13 | ); 14 | }); 15 | 16 | testUtils.testWithClient('client.functionDump', async client => { 17 | assert.equal( 18 | typeof await client.functionDump(), 19 | 'string' 20 | ); 21 | }, GLOBAL.SERVERS.OPEN); 22 | }); 23 | -------------------------------------------------------------------------------- /packages/client/lib/commands/FUNCTION_DUMP.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { BlobStringReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Returns a serialized payload representing the current functions loaded in the server 9 | * @param parser - The Redis command parser 10 | */ 11 | parseCommand(parser: CommandParser) { 12 | parser.push('FUNCTION', 'DUMP') 13 | }, 14 | transformReply: undefined as unknown as () => BlobStringReply 15 | } as const satisfies Command; 16 | -------------------------------------------------------------------------------- /packages/client/lib/commands/FUNCTION_KILL.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils from '../test-utils'; 3 | import FUNCTION_KILL from './FUNCTION_KILL'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('FUNCTION KILL', () => { 7 | testUtils.isVersionGreaterThanHook([7]); 8 | 9 | it('transformArguments', () => { 10 | assert.deepEqual( 11 | parseArgs(FUNCTION_KILL), 12 | ['FUNCTION', 'KILL'] 13 | ); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /packages/client/lib/commands/FUNCTION_KILL.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { SimpleStringReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Kills a function that is currently executing 9 | * @param parser - The Redis command parser 10 | */ 11 | parseCommand(parser: CommandParser) { 12 | parser.push('FUNCTION', 'KILL'); 13 | }, 14 | transformReply: undefined as unknown as () => SimpleStringReply 15 | } as const satisfies Command; 16 | -------------------------------------------------------------------------------- /packages/client/lib/commands/GET.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import { parseArgs } from './generic-transformers'; 4 | import GET from './GET'; 5 | 6 | describe('GET', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(GET, 'key'), 10 | ['GET', 'key'] 11 | ); 12 | }); 13 | 14 | testUtils.testAll('get', async client => { 15 | assert.equal( 16 | await client.get('key'), 17 | null 18 | ); 19 | }, { 20 | client: GLOBAL.SERVERS.OPEN, 21 | cluster: GLOBAL.CLUSTERS.OPEN 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/client/lib/commands/GET.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { RedisArgument, BlobStringReply, NullReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | CACHEABLE: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Gets the value of a key 9 | * @param parser - The Redis command parser 10 | * @param key - Key to get the value of 11 | */ 12 | parseCommand(parser: CommandParser, key: RedisArgument) { 13 | parser.push('GET'); 14 | parser.pushKey(key); 15 | }, 16 | transformReply: undefined as unknown as () => BlobStringReply | NullReply 17 | } as const satisfies Command; 18 | -------------------------------------------------------------------------------- /packages/client/lib/commands/GETBIT.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import GETBIT from './GETBIT'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('GETBIT', () => { 7 | it('processCommand', () => { 8 | assert.deepEqual( 9 | parseArgs(GETBIT, 'key', 0), 10 | ['GETBIT', 'key', '0'] 11 | ); 12 | }); 13 | 14 | testUtils.testAll('getBit', async client => { 15 | assert.equal( 16 | await client.getBit('key', 0), 17 | 0 18 | ); 19 | }, { 20 | client: GLOBAL.SERVERS.OPEN, 21 | cluster: GLOBAL.CLUSTERS.OPEN 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/client/lib/commands/GETDEL.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import GETDEL from './GETDEL'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('GETDEL', () => { 7 | testUtils.isVersionGreaterThanHook([6, 2]); 8 | 9 | it('transformArguments', () => { 10 | assert.deepEqual( 11 | parseArgs(GETDEL, 'key'), 12 | ['GETDEL', 'key'] 13 | ); 14 | }); 15 | 16 | testUtils.testAll('getDel', async client => { 17 | assert.equal( 18 | await client.getDel('key'), 19 | null 20 | ); 21 | }, { 22 | client: GLOBAL.SERVERS.OPEN, 23 | cluster: GLOBAL.CLUSTERS.OPEN 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /packages/client/lib/commands/GETDEL.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { RedisArgument, BlobStringReply, NullReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | IS_READ_ONLY: true, 6 | /** 7 | * Gets the value of a key and deletes the key 8 | * @param parser - The Redis command parser 9 | * @param key - Key to get and delete 10 | */ 11 | parseCommand(parser: CommandParser, key: RedisArgument) { 12 | parser.push('GETDEL'); 13 | parser.pushKey(key); 14 | }, 15 | transformReply: undefined as unknown as () => BlobStringReply | NullReply 16 | } as const satisfies Command; 17 | -------------------------------------------------------------------------------- /packages/client/lib/commands/GETRANGE.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import GETRANGE from './GETRANGE'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('GETRANGE', () => { 7 | it('processCommand', () => { 8 | assert.deepEqual( 9 | parseArgs(GETRANGE, 'key', 0, -1), 10 | ['GETRANGE', 'key', '0', '-1'] 11 | ); 12 | }); 13 | 14 | testUtils.testAll('getRange', async client => { 15 | assert.equal( 16 | await client.getRange('key', 0, -1), 17 | '' 18 | ); 19 | }, { 20 | client: GLOBAL.SERVERS.OPEN, 21 | cluster: GLOBAL.CLUSTERS.OPEN 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/client/lib/commands/GETSET.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import GETSET from './GETSET'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('GETSET', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(GETSET, 'key', 'value'), 10 | ['GETSET', 'key', 'value'] 11 | ); 12 | }); 13 | 14 | testUtils.testAll('getSet', async client => { 15 | assert.equal( 16 | await client.getSet('key', 'value'), 17 | null 18 | ); 19 | }, { 20 | client: GLOBAL.SERVERS.OPEN, 21 | cluster: GLOBAL.CLUSTERS.OPEN 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/client/lib/commands/GETSET.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { RedisArgument, BlobStringReply, NullReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | IS_READ_ONLY: true, 6 | /** 7 | * Sets a key to a new value and returns its old value 8 | * @param parser - The Redis command parser 9 | * @param key - Key to set 10 | * @param value - Value to set 11 | */ 12 | parseCommand(parser: CommandParser, key: RedisArgument, value: RedisArgument) { 13 | parser.push('GETSET'); 14 | parser.pushKey(key); 15 | parser.push(value); 16 | }, 17 | transformReply: undefined as unknown as () => BlobStringReply | NullReply 18 | } as const satisfies Command; 19 | -------------------------------------------------------------------------------- /packages/client/lib/commands/HEXISTS.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import HEXISTS from './HEXISTS'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('HEXISTS', () => { 7 | it('processCommand', () => { 8 | assert.deepEqual( 9 | parseArgs(HEXISTS, 'key', 'field'), 10 | ['HEXISTS', 'key', 'field'] 11 | ); 12 | }); 13 | 14 | testUtils.testAll('hExists', async client => { 15 | assert.equal( 16 | await client.hExists('key', 'field'), 17 | 0 18 | ); 19 | }, { 20 | client: GLOBAL.SERVERS.OPEN, 21 | cluster: GLOBAL.CLUSTERS.OPEN 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/client/lib/commands/HEXISTS.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { RedisArgument, NumberReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | CACHEABLE: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Determines whether a field exists in a hash 9 | * @param parser - The Redis command parser 10 | * @param key - Key of the hash 11 | * @param field - Field to check 12 | */ 13 | parseCommand(parser: CommandParser, key: RedisArgument, field: RedisArgument) { 14 | parser.push('HEXISTS'); 15 | parser.pushKey(key); 16 | parser.push(field); 17 | }, 18 | transformReply: undefined as unknown as () => NumberReply<0 | 1> 19 | } as const satisfies Command; 20 | -------------------------------------------------------------------------------- /packages/client/lib/commands/HGET.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import HGET from './HGET'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('HGET', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(HGET, 'key', 'field'), 10 | ['HGET', 'key', 'field'] 11 | ); 12 | }); 13 | 14 | testUtils.testAll('hGet', async client => { 15 | assert.equal( 16 | await client.hGet('key', 'field'), 17 | null 18 | ); 19 | }, { 20 | client: GLOBAL.SERVERS.OPEN, 21 | cluster: GLOBAL.CLUSTERS.OPEN 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/client/lib/commands/HINCRBY.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import HINCRBY from './HINCRBY'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('HINCRBY', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(HINCRBY, 'key', 'field', 1), 10 | ['HINCRBY', 'key', 'field', '1'] 11 | ); 12 | }); 13 | 14 | testUtils.testAll('hIncrBy', async client => { 15 | assert.equal( 16 | await client.hIncrBy('key', 'field', 1), 17 | 1 18 | ); 19 | }, { 20 | client: GLOBAL.SERVERS.OPEN, 21 | cluster: GLOBAL.CLUSTERS.OPEN 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/client/lib/commands/HKEYS.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import HKEYS from './HKEYS'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('HKEYS', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(HKEYS, 'key'), 10 | ['HKEYS', 'key'] 11 | ); 12 | }); 13 | 14 | testUtils.testAll('hKeys', async client => { 15 | assert.deepEqual( 16 | await client.hKeys('key'), 17 | [] 18 | ); 19 | }, { 20 | client: GLOBAL.SERVERS.OPEN, 21 | cluster: GLOBAL.CLUSTERS.OPEN 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/client/lib/commands/HKEYS.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { RedisArgument, ArrayReply, BlobStringReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | CACHEABLE: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Gets all field names in a hash 9 | * @param parser - The Redis command parser 10 | * @param key - Key of the hash 11 | */ 12 | parseCommand(parser: CommandParser, key: RedisArgument) { 13 | parser.push('HKEYS') 14 | parser.pushKey(key); 15 | }, 16 | transformReply: undefined as unknown as () => ArrayReply<BlobStringReply> 17 | } as const satisfies Command; 18 | -------------------------------------------------------------------------------- /packages/client/lib/commands/HLEN.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import HLEN from './HLEN'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('HLEN', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(HLEN, 'key'), 10 | ['HLEN', 'key'] 11 | ); 12 | }); 13 | 14 | testUtils.testAll('hLen', async client => { 15 | assert.equal( 16 | await client.hLen('key'), 17 | 0 18 | ); 19 | }, { 20 | client: GLOBAL.SERVERS.OPEN, 21 | cluster: GLOBAL.CLUSTERS.OPEN 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/client/lib/commands/HLEN.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { RedisArgument, NumberReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | CACHEABLE: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Gets the number of fields in a hash. 9 | * @param parser - The Redis command parser. 10 | * @param key - Key of the hash. 11 | */ 12 | parseCommand(parser: CommandParser, key: RedisArgument) { 13 | parser.push('HLEN'); 14 | parser.pushKey(key); 15 | }, 16 | transformReply: undefined as unknown as () => NumberReply 17 | } as const satisfies Command; 18 | -------------------------------------------------------------------------------- /packages/client/lib/commands/HRANDFIELD.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { RedisArgument, BlobStringReply, NullReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | IS_READ_ONLY: true, 6 | /** 7 | * Constructs the HRANDFIELD command 8 | * 9 | * @param parser - The command parser 10 | * @param key - The key of the hash to get a random field from 11 | * @see https://redis.io/commands/hrandfield/ 12 | */ 13 | parseCommand(parser: CommandParser, key: RedisArgument) { 14 | parser.push('HRANDFIELD'); 15 | parser.pushKey(key); 16 | }, 17 | transformReply: undefined as unknown as () => BlobStringReply | NullReply 18 | } as const satisfies Command; 19 | -------------------------------------------------------------------------------- /packages/client/lib/commands/HRANDFIELD_COUNT_WITHVALUES.spec.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redis/node-redis/987515c69b51bf4ed4eca718a38c7ed2ef49c9b4/packages/client/lib/commands/HRANDFIELD_COUNT_WITHVALUES.spec.ts -------------------------------------------------------------------------------- /packages/client/lib/commands/HSETNX.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import HSETNX from './HSETNX'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('HSETNX', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(HSETNX, 'key', 'field', 'value'), 10 | ['HSETNX', 'key', 'field', 'value'] 11 | ); 12 | }); 13 | 14 | testUtils.testAll('hSetNX', async client => { 15 | assert.equal( 16 | await client.hSetNX('key', 'field', 'value'), 17 | 1 18 | ); 19 | }, { 20 | client: GLOBAL.SERVERS.OPEN, 21 | cluster: GLOBAL.CLUSTERS.OPEN 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/client/lib/commands/HSTRLEN.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import HSTRLEN from './HSTRLEN'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('HSTRLEN', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(HSTRLEN, 'key', 'field'), 10 | ['HSTRLEN', 'key', 'field'] 11 | ); 12 | }); 13 | 14 | testUtils.testAll('hStrLen', async client => { 15 | assert.equal( 16 | await client.hStrLen('key', 'field'), 17 | 0 18 | ); 19 | }, { 20 | client: GLOBAL.SERVERS.OPEN, 21 | cluster: GLOBAL.CLUSTERS.OPEN 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/client/lib/commands/HVALS.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import HVALS from './HVALS'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('HVALS', () => { 7 | it('processCommand', () => { 8 | assert.deepEqual( 9 | parseArgs(HVALS, 'key'), 10 | ['HVALS', 'key'] 11 | ); 12 | }); 13 | 14 | testUtils.testAll('hVals', async client => { 15 | assert.deepEqual( 16 | await client.hVals('key'), 17 | [] 18 | ); 19 | }, { 20 | client: GLOBAL.SERVERS.OPEN, 21 | cluster: GLOBAL.CLUSTERS.OPEN 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/client/lib/commands/HVALS.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { RedisArgument, ArrayReply, BlobStringReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | CACHEABLE: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Gets all values in a hash. 9 | * @param parser - The Redis command parser. 10 | * @param key - Key of the hash. 11 | */ 12 | parseCommand(parser: CommandParser, key: RedisArgument) { 13 | parser.push('HVALS'); 14 | parser.pushKey(key); 15 | }, 16 | transformReply: undefined as unknown as () => ArrayReply<BlobStringReply> 17 | } as const satisfies Command; 18 | -------------------------------------------------------------------------------- /packages/client/lib/commands/INCR.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import INCR from './INCR'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('INCR', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(INCR, 'key'), 10 | ['INCR', 'key'] 11 | ); 12 | }); 13 | 14 | testUtils.testAll('incr', async client => { 15 | assert.equal( 16 | await client.incr('key'), 17 | 1 18 | ); 19 | }, { 20 | client: GLOBAL.SERVERS.OPEN, 21 | cluster: GLOBAL.CLUSTERS.OPEN 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/client/lib/commands/INCR.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { RedisArgument, NumberReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | /** 6 | * Constructs the INCR command 7 | * 8 | * @param parser - The command parser 9 | * @param key - The key to increment 10 | * @see https://redis.io/commands/incr/ 11 | */ 12 | parseCommand(parser: CommandParser, key: RedisArgument) { 13 | parser.push('INCR'); 14 | parser.pushKey(key); 15 | }, 16 | transformReply: undefined as unknown as () => NumberReply 17 | } as const satisfies Command; 18 | -------------------------------------------------------------------------------- /packages/client/lib/commands/INCRBY.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import INCRBY from './INCRBY'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('INCRBY', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(INCRBY, 'key', 1), 10 | ['INCRBY', 'key', '1'] 11 | ); 12 | }); 13 | 14 | testUtils.testAll('incrBy', async client => { 15 | assert.equal( 16 | await client.incrBy('key', 1), 17 | 1 18 | ); 19 | }, { 20 | client: GLOBAL.SERVERS.OPEN, 21 | cluster: GLOBAL.CLUSTERS.OPEN 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/client/lib/commands/INCRBY.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { RedisArgument, NumberReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | /** 6 | * Constructs the INCRBY command 7 | * 8 | * @param parser - The command parser 9 | * @param key - The key to increment 10 | * @param increment - The amount to increment by 11 | * @see https://redis.io/commands/incrby/ 12 | */ 13 | parseCommand(parser: CommandParser, key: RedisArgument, increment: number) { 14 | parser.push('INCRBY'); 15 | parser.pushKey(key); 16 | parser.push(increment.toString()); 17 | }, 18 | transformReply: undefined as unknown as () => NumberReply 19 | } as const satisfies Command; 20 | -------------------------------------------------------------------------------- /packages/client/lib/commands/INCRBYFLOAT.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import INCRBYFLOAT from './INCRBYFLOAT'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('INCRBYFLOAT', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(INCRBYFLOAT, 'key', 1.5), 10 | ['INCRBYFLOAT', 'key', '1.5'] 11 | ); 12 | }); 13 | 14 | testUtils.testAll('incrByFloat', async client => { 15 | assert.equal( 16 | await client.incrByFloat('key', 1.5), 17 | '1.5' 18 | ); 19 | }, { 20 | client: GLOBAL.SERVERS.OPEN, 21 | cluster: GLOBAL.CLUSTERS.OPEN 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/client/lib/commands/KEYS.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | 4 | describe('KEYS', () => { 5 | testUtils.testWithClient('keys', async client => { 6 | assert.deepEqual( 7 | await client.keys('pattern'), 8 | [] 9 | ); 10 | }, GLOBAL.SERVERS.OPEN); 11 | }); 12 | -------------------------------------------------------------------------------- /packages/client/lib/commands/KEYS.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { RedisArgument, ArrayReply, BlobStringReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Constructs the KEYS command 9 | * 10 | * @param parser - The command parser 11 | * @param pattern - The pattern to match keys against 12 | * @see https://redis.io/commands/keys/ 13 | */ 14 | parseCommand(parser: CommandParser, pattern: RedisArgument) { 15 | parser.push('KEYS', pattern); 16 | }, 17 | transformReply: undefined as unknown as () => ArrayReply<BlobStringReply> 18 | } as const satisfies Command; 19 | -------------------------------------------------------------------------------- /packages/client/lib/commands/LASTSAVE.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import LASTSAVE from './LASTSAVE'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('LASTSAVE', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(LASTSAVE), 10 | ['LASTSAVE'] 11 | ); 12 | }); 13 | 14 | testUtils.testWithClient('client.lastSave', async client => { 15 | assert.equal( 16 | typeof await client.lastSave(), 17 | 'number' 18 | ); 19 | }, GLOBAL.SERVERS.OPEN); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/client/lib/commands/LASTSAVE.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { NumberReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Constructs the LASTSAVE command 9 | * 10 | * @param parser - The command parser 11 | * @see https://redis.io/commands/lastsave/ 12 | */ 13 | parseCommand(parser: CommandParser) { 14 | parser.push('LASTSAVE'); 15 | }, 16 | transformReply: undefined as unknown as () => NumberReply 17 | } as const satisfies Command; 18 | -------------------------------------------------------------------------------- /packages/client/lib/commands/LATENCY_DOCTOR.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import LATENCY_DOCTOR from './LATENCY_DOCTOR'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('LATENCY DOCTOR', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(LATENCY_DOCTOR), 10 | ['LATENCY', 'DOCTOR'] 11 | ); 12 | }); 13 | 14 | testUtils.testWithClient('client.latencyDoctor', async client => { 15 | assert.equal( 16 | typeof await client.latencyDoctor(), 17 | 'string' 18 | ); 19 | }, GLOBAL.SERVERS.OPEN); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/client/lib/commands/LATENCY_DOCTOR.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { BlobStringReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Constructs the LATENCY DOCTOR command 9 | * 10 | * @param parser - The command parser 11 | * @see https://redis.io/commands/latency-doctor/ 12 | */ 13 | parseCommand(parser: CommandParser) { 14 | parser.push('LATENCY', 'DOCTOR'); 15 | }, 16 | transformReply: undefined as unknown as () => BlobStringReply 17 | } as const satisfies Command; 18 | -------------------------------------------------------------------------------- /packages/client/lib/commands/LCS.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import LCS from './LCS'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('LCS', () => { 7 | testUtils.isVersionGreaterThanHook([7]); 8 | 9 | it('transformArguments', () => { 10 | assert.deepEqual( 11 | parseArgs(LCS, '1', '2'), 12 | ['LCS', '1', '2'] 13 | ); 14 | }); 15 | 16 | testUtils.testAll('lcs', async client => { 17 | assert.equal( 18 | await client.lcs('{tag}1', '{tag}2'), 19 | '' 20 | ); 21 | }, { 22 | client: GLOBAL.SERVERS.OPEN, 23 | cluster: GLOBAL.CLUSTERS.OPEN 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /packages/client/lib/commands/LCS_LEN.ts: -------------------------------------------------------------------------------- 1 | import { NumberReply, Command } from '../RESP/types'; 2 | import LCS from './LCS'; 3 | 4 | export default { 5 | IS_READ_ONLY: LCS.IS_READ_ONLY, 6 | /** 7 | * Constructs the LCS command with LEN option 8 | * 9 | * @param args - The same parameters as LCS command 10 | * @see https://redis.io/commands/lcs/ 11 | */ 12 | parseCommand(...args: Parameters<typeof LCS.parseCommand>) { 13 | const parser = args[0]; 14 | 15 | LCS.parseCommand(...args); 16 | parser.push('LEN'); 17 | }, 18 | transformReply: undefined as unknown as () => NumberReply 19 | } as const satisfies Command; 20 | -------------------------------------------------------------------------------- /packages/client/lib/commands/LINDEX.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import LINDEX from './LINDEX'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('LINDEX', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(LINDEX, 'key', 0), 10 | ['LINDEX', 'key', '0'] 11 | ); 12 | }); 13 | 14 | testUtils.testAll('lIndex', async client => { 15 | assert.equal( 16 | await client.lIndex('key', 0), 17 | null 18 | ); 19 | }, { 20 | client: GLOBAL.SERVERS.OPEN, 21 | cluster: GLOBAL.CLUSTERS.OPEN 22 | }); 23 | }); -------------------------------------------------------------------------------- /packages/client/lib/commands/LLEN.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import LLEN from './LLEN'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('LLEN', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(LLEN, 'key'), 10 | ['LLEN', 'key'] 11 | ); 12 | }); 13 | 14 | testUtils.testAll('lLen', async client => { 15 | assert.equal( 16 | await client.lLen('key'), 17 | 0 18 | ); 19 | }, { 20 | client: GLOBAL.SERVERS.OPEN, 21 | cluster: GLOBAL.CLUSTERS.OPEN 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/client/lib/commands/LLEN.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { RedisArgument, NumberReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | CACHEABLE: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Constructs the LLEN command 9 | * 10 | * @param parser - The command parser 11 | * @param key - The key of the list to get the length of 12 | * @see https://redis.io/commands/llen/ 13 | */ 14 | parseCommand(parser: CommandParser, key: RedisArgument) { 15 | parser.push('LLEN'); 16 | parser.pushKey(key); 17 | }, 18 | transformReply: undefined as unknown as () => NumberReply 19 | } as const satisfies Command; 20 | -------------------------------------------------------------------------------- /packages/client/lib/commands/LPOP.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import LPOP from './LPOP'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('LPOP', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(LPOP, 'key'), 10 | ['LPOP', 'key'] 11 | ); 12 | }); 13 | 14 | testUtils.testAll('lPop', async client => { 15 | assert.equal( 16 | await client.lPop('key'), 17 | null 18 | ); 19 | }, { 20 | client: GLOBAL.SERVERS.OPEN, 21 | cluster: GLOBAL.CLUSTERS.OPEN 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/client/lib/commands/LPOP.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { RedisArgument, BlobStringReply, NullReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | /** 6 | * Constructs the LPOP command 7 | * 8 | * @param parser - The command parser 9 | * @param key - The key of the list to pop from 10 | * @see https://redis.io/commands/lpop/ 11 | */ 12 | parseCommand(parser: CommandParser, key: RedisArgument) { 13 | parser.push('LPOP'); 14 | parser.pushKey(key); 15 | }, 16 | transformReply: undefined as unknown as () => BlobStringReply | NullReply 17 | } as const satisfies Command; 18 | -------------------------------------------------------------------------------- /packages/client/lib/commands/LRANGE.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import LRANGE from './LRANGE'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('LRANGE', () => { 7 | it('processCommand', () => { 8 | assert.deepEqual( 9 | parseArgs(LRANGE, 'key', 0, -1), 10 | ['LRANGE', 'key', '0', '-1'] 11 | ); 12 | }); 13 | 14 | testUtils.testAll('lRange', async client => { 15 | assert.deepEqual( 16 | await client.lRange('key', 0, -1), 17 | [] 18 | ); 19 | }, { 20 | client: GLOBAL.SERVERS.OPEN, 21 | cluster: GLOBAL.CLUSTERS.OPEN 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/client/lib/commands/LREM.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import LREM from './LREM'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('LREM', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(LREM, 'key', 0, 'element'), 10 | ['LREM', 'key', '0', 'element'] 11 | ); 12 | }); 13 | 14 | testUtils.testAll('lRem', async client => { 15 | assert.equal( 16 | await client.lRem('key', 0, 'element'), 17 | 0 18 | ); 19 | }, { 20 | client: GLOBAL.SERVERS.OPEN, 21 | cluster: GLOBAL.CLUSTERS.OPEN 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/client/lib/commands/LTRIM.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import LTRIM from './LTRIM'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('LTRIM', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(LTRIM, 'key', 0, -1), 10 | ['LTRIM', 'key', '0', '-1'] 11 | ); 12 | }); 13 | 14 | testUtils.testAll('lTrim', async client => { 15 | assert.equal( 16 | await client.lTrim('key', 0, -1), 17 | 'OK' 18 | ); 19 | }, { 20 | client: GLOBAL.SERVERS.OPEN, 21 | cluster: GLOBAL.CLUSTERS.OPEN 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/client/lib/commands/MEMORY_DOCTOR.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import MEMORY_DOCTOR from './MEMORY_DOCTOR'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('MEMORY DOCTOR', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(MEMORY_DOCTOR), 10 | ['MEMORY', 'DOCTOR'] 11 | ); 12 | }); 13 | 14 | testUtils.testWithClient('client.memoryDoctor', async client => { 15 | assert.equal( 16 | typeof (await client.memoryDoctor()), 17 | 'string' 18 | ); 19 | }, GLOBAL.SERVERS.OPEN); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/client/lib/commands/MEMORY_DOCTOR.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { BlobStringReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Constructs the MEMORY DOCTOR command 9 | * 10 | * @param parser - The command parser 11 | * @see https://redis.io/commands/memory-doctor/ 12 | */ 13 | parseCommand(parser: CommandParser) { 14 | parser.push('MEMORY', 'DOCTOR'); 15 | }, 16 | transformReply: undefined as unknown as () => BlobStringReply 17 | } as const satisfies Command; 18 | -------------------------------------------------------------------------------- /packages/client/lib/commands/MEMORY_MALLOC-STATS.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import MEMORY_MALLOC_STATS from './MEMORY_MALLOC-STATS'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('MEMORY MALLOC-STATS', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(MEMORY_MALLOC_STATS), 10 | ['MEMORY', 'MALLOC-STATS'] 11 | ); 12 | }); 13 | 14 | testUtils.testWithClient('client.memoryMallocStats', async client => { 15 | assert.equal( 16 | typeof (await client.memoryMallocStats()), 17 | 'string' 18 | ); 19 | }, GLOBAL.SERVERS.OPEN); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/client/lib/commands/MEMORY_MALLOC-STATS.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { BlobStringReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Constructs the MEMORY MALLOC-STATS command 9 | * 10 | * @param parser - The command parser 11 | * @see https://redis.io/commands/memory-malloc-stats/ 12 | */ 13 | parseCommand(parser: CommandParser) { 14 | parser.push('MEMORY', 'MALLOC-STATS'); 15 | }, 16 | transformReply: undefined as unknown as () => BlobStringReply 17 | } as const satisfies Command; 18 | 19 | -------------------------------------------------------------------------------- /packages/client/lib/commands/MEMORY_PURGE.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import MEMORY_PURGE from './MEMORY_PURGE'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('MEMORY PURGE', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(MEMORY_PURGE), 10 | ['MEMORY', 'PURGE'] 11 | ); 12 | }); 13 | 14 | testUtils.testWithClient('client.memoryPurge', async client => { 15 | assert.equal( 16 | await client.memoryPurge(), 17 | 'OK' 18 | ); 19 | }, GLOBAL.SERVERS.OPEN); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/client/lib/commands/MEMORY_PURGE.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { SimpleStringReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: false, 7 | /** 8 | * Constructs the MEMORY PURGE command 9 | * 10 | * @param parser - The command parser 11 | * @see https://redis.io/commands/memory-purge/ 12 | */ 13 | parseCommand(parser: CommandParser) { 14 | parser.push('MEMORY', 'PURGE'); 15 | }, 16 | transformReply: undefined as unknown as () => SimpleStringReply<'OK'> 17 | } as const satisfies Command; 18 | 19 | -------------------------------------------------------------------------------- /packages/client/lib/commands/MGET.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import MGET from './MGET'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('MGET', () => { 7 | it('processCommand', () => { 8 | assert.deepEqual( 9 | parseArgs(MGET, ['1', '2']), 10 | ['MGET', '1', '2'] 11 | ); 12 | }); 13 | 14 | testUtils.testAll('mGet', async client => { 15 | assert.deepEqual( 16 | await client.mGet(['key']), 17 | [null] 18 | ); 19 | }, { 20 | client: GLOBAL.SERVERS.OPEN, 21 | cluster: GLOBAL.CLUSTERS.OPEN 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/client/lib/commands/MGET.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { RedisArgument, BlobStringReply, NullReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | CACHEABLE: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Constructs the MGET command 9 | * 10 | * @param parser - The command parser 11 | * @param keys - Array of keys to get 12 | * @see https://redis.io/commands/mget/ 13 | */ 14 | parseCommand(parser: CommandParser, keys: Array<RedisArgument>) { 15 | parser.push('MGET'); 16 | parser.pushKeys(keys); 17 | }, 18 | transformReply: undefined as unknown as () => Array<BlobStringReply | NullReply> 19 | } as const satisfies Command; 20 | -------------------------------------------------------------------------------- /packages/client/lib/commands/MODULE_LIST.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import MODULE_LIST from './MODULE_LIST'; 3 | import { parseArgs } from './generic-transformers'; 4 | 5 | describe('MODULE LIST', () => { 6 | it('transformArguments', () => { 7 | assert.deepEqual( 8 | parseArgs(MODULE_LIST), 9 | ['MODULE', 'LIST'] 10 | ); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /packages/client/lib/commands/MODULE_LOAD.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import MODULE_LOAD from './MODULE_LOAD'; 3 | import { parseArgs } from './generic-transformers'; 4 | 5 | describe('MODULE LOAD', () => { 6 | describe('transformArguments', () => { 7 | it('simple', () => { 8 | assert.deepEqual( 9 | parseArgs(MODULE_LOAD, 'path'), 10 | ['MODULE', 'LOAD', 'path'] 11 | ); 12 | }); 13 | 14 | it('with module args', () => { 15 | assert.deepEqual( 16 | parseArgs(MODULE_LOAD, 'path', ['1', '2']), 17 | ['MODULE', 'LOAD', 'path', '1', '2'] 18 | ); 19 | }); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /packages/client/lib/commands/MODULE_UNLOAD.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import MODULE_UNLOAD from './MODULE_UNLOAD'; 3 | import { parseArgs } from './generic-transformers'; 4 | 5 | describe('MODULE UNLOAD', () => { 6 | it('transformArguments', () => { 7 | assert.deepEqual( 8 | parseArgs(MODULE_UNLOAD, 'name'), 9 | ['MODULE', 'UNLOAD', 'name'] 10 | ); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /packages/client/lib/commands/MODULE_UNLOAD.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { RedisArgument, SimpleStringReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Constructs the MODULE UNLOAD command 9 | * 10 | * @param parser - The command parser 11 | * @param name - The name of the module to unload 12 | * @see https://redis.io/commands/module-unload/ 13 | */ 14 | parseCommand(parser: CommandParser, name: RedisArgument) { 15 | parser.push('MODULE', 'UNLOAD', name); 16 | }, 17 | transformReply: undefined as unknown as () => SimpleStringReply<'OK'> 18 | } as const satisfies Command; 19 | -------------------------------------------------------------------------------- /packages/client/lib/commands/MOVE.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import MOVE from './MOVE'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('MOVE', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(MOVE, 'key', 1), 10 | ['MOVE', 'key', '1'] 11 | ); 12 | }); 13 | 14 | testUtils.testWithClient('client.move', async client => { 15 | assert.equal( 16 | await client.move('key', 1), 17 | 0 18 | ); 19 | }, GLOBAL.SERVERS.OPEN); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/client/lib/commands/MOVE.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { RedisArgument, NumberReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | /** 6 | * Constructs the MOVE command 7 | * 8 | * @param parser - The command parser 9 | * @param key - The key to move 10 | * @param db - The destination database index 11 | * @see https://redis.io/commands/move/ 12 | */ 13 | parseCommand(parser: CommandParser, key: RedisArgument, db: number) { 14 | parser.push('MOVE'); 15 | parser.pushKey(key); 16 | parser.push(db.toString()); 17 | }, 18 | transformReply: undefined as unknown as () => NumberReply 19 | } as const satisfies Command; 20 | -------------------------------------------------------------------------------- /packages/client/lib/commands/OBJECT_ENCODING.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { RedisArgument, BlobStringReply, NullReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | IS_READ_ONLY: true, 6 | /** 7 | * Constructs the OBJECT ENCODING command 8 | * 9 | * @param parser - The command parser 10 | * @param key - The key to get the internal encoding for 11 | * @see https://redis.io/commands/object-encoding/ 12 | */ 13 | parseCommand(parser: CommandParser, key: RedisArgument) { 14 | parser.push('OBJECT', 'ENCODING'); 15 | parser.pushKey(key); 16 | }, 17 | transformReply: undefined as unknown as () => BlobStringReply | NullReply 18 | } as const satisfies Command; 19 | -------------------------------------------------------------------------------- /packages/client/lib/commands/OBJECT_FREQ.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import OBJECT_FREQ from './OBJECT_FREQ'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('OBJECT FREQ', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(OBJECT_FREQ, 'key'), 10 | ['OBJECT', 'FREQ', 'key'] 11 | ); 12 | }); 13 | 14 | testUtils.testAll('client.objectFreq', async client => { 15 | assert.equal( 16 | await client.objectFreq('key'), 17 | null 18 | ); 19 | }, { 20 | client: GLOBAL.SERVERS.OPEN, 21 | cluster: GLOBAL.CLUSTERS.OPEN 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/client/lib/commands/OBJECT_FREQ.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { RedisArgument, NumberReply, NullReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | IS_READ_ONLY: true, 6 | /** 7 | * Constructs the OBJECT FREQ command 8 | * 9 | * @param parser - The command parser 10 | * @param key - The key to get the access frequency for 11 | * @see https://redis.io/commands/object-freq/ 12 | */ 13 | parseCommand(parser: CommandParser, key: RedisArgument) { 14 | parser.push('OBJECT', 'FREQ'); 15 | parser.pushKey(key); 16 | }, 17 | transformReply: undefined as unknown as () => NumberReply | NullReply 18 | } as const satisfies Command; 19 | -------------------------------------------------------------------------------- /packages/client/lib/commands/OBJECT_IDLETIME.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { RedisArgument, NumberReply, NullReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | IS_READ_ONLY: true, 6 | /** 7 | * Constructs the OBJECT IDLETIME command 8 | * 9 | * @param parser - The command parser 10 | * @param key - The key to get the idle time for 11 | * @see https://redis.io/commands/object-idletime/ 12 | */ 13 | parseCommand(parser: CommandParser, key: RedisArgument) { 14 | parser.push('OBJECT', 'IDLETIME'); 15 | parser.pushKey(key); 16 | }, 17 | transformReply: undefined as unknown as () => NumberReply | NullReply 18 | } as const satisfies Command; 19 | -------------------------------------------------------------------------------- /packages/client/lib/commands/OBJECT_REFCOUNT.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { RedisArgument, NumberReply, NullReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | IS_READ_ONLY: true, 6 | /** 7 | * Constructs the OBJECT REFCOUNT command 8 | * 9 | * @param parser - The command parser 10 | * @param key - The key to get the reference count for 11 | * @see https://redis.io/commands/object-refcount/ 12 | */ 13 | parseCommand(parser: CommandParser, key: RedisArgument) { 14 | parser.push('OBJECT', 'REFCOUNT'); 15 | parser.pushKey(key); 16 | }, 17 | transformReply: undefined as unknown as () => NumberReply | NullReply 18 | } as const satisfies Command; 19 | -------------------------------------------------------------------------------- /packages/client/lib/commands/PERSIST.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import PERSIST from './PERSIST'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('PERSIST', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(PERSIST, 'key'), 10 | ['PERSIST', 'key'] 11 | ); 12 | }); 13 | 14 | testUtils.testAll('persist', async client => { 15 | assert.equal( 16 | await client.persist('key'), 17 | 0 18 | ); 19 | }, { 20 | client: GLOBAL.SERVERS.OPEN, 21 | cluster: GLOBAL.CLUSTERS.OPEN 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/client/lib/commands/PERSIST.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { RedisArgument, NumberReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | /** 6 | * Constructs the PERSIST command 7 | * 8 | * @param parser - The command parser 9 | * @param key - The key to remove the expiration from 10 | * @see https://redis.io/commands/persist/ 11 | */ 12 | parseCommand(parser: CommandParser, key: RedisArgument) { 13 | parser.push('PERSIST'); 14 | parser.pushKey(key); 15 | }, 16 | transformReply: undefined as unknown as () => NumberReply 17 | } as const satisfies Command; 18 | -------------------------------------------------------------------------------- /packages/client/lib/commands/PEXPIRETIME.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { RedisArgument, NumberReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | IS_READ_ONLY: true, 6 | /** 7 | * Constructs the PEXPIRETIME command 8 | * 9 | * @param parser - The command parser 10 | * @param key - The key to get the expiration time for in milliseconds 11 | * @see https://redis.io/commands/pexpiretime/ 12 | */ 13 | parseCommand(parser: CommandParser, key: RedisArgument) { 14 | parser.push('PEXPIRETIME'); 15 | parser.pushKey(key); 16 | }, 17 | transformReply: undefined as unknown as () => NumberReply 18 | } as const satisfies Command; 19 | -------------------------------------------------------------------------------- /packages/client/lib/commands/PSETEX.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import PSETEX from './PSETEX'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('PSETEX', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(PSETEX, 'key', 1, 'value'), 10 | ['PSETEX', 'key', '1', 'value'] 11 | ); 12 | }); 13 | 14 | testUtils.testAll('pSetEx', async client => { 15 | assert.equal( 16 | await client.pSetEx('key', 1, 'value'), 17 | 'OK' 18 | ); 19 | }, { 20 | client: GLOBAL.SERVERS.OPEN, 21 | cluster: GLOBAL.CLUSTERS.OPEN 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/client/lib/commands/PTTL.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import PTTL from './PTTL'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('PTTL', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(PTTL, 'key'), 10 | ['PTTL', 'key'] 11 | ); 12 | }); 13 | 14 | testUtils.testAll('pTTL', async client => { 15 | assert.equal( 16 | await client.pTTL('key'), 17 | -2 18 | ); 19 | }, { 20 | client: GLOBAL.SERVERS.OPEN, 21 | cluster: GLOBAL.CLUSTERS.OPEN 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/client/lib/commands/PTTL.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { RedisArgument, NumberReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | IS_READ_ONLY: true, 6 | /** 7 | * Constructs the PTTL command 8 | * 9 | * @param parser - The command parser 10 | * @param key - The key to get the time to live in milliseconds 11 | * @see https://redis.io/commands/pttl/ 12 | */ 13 | parseCommand(parser: CommandParser, key: RedisArgument) { 14 | parser.push('PTTL'); 15 | parser.pushKey(key); 16 | }, 17 | transformReply: undefined as unknown as () => NumberReply 18 | } as const satisfies Command; 19 | -------------------------------------------------------------------------------- /packages/client/lib/commands/PUBLISH.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import PUBLISH from './PUBLISH'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('PUBLISH', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(PUBLISH, 'channel', 'message'), 10 | ['PUBLISH', 'channel', 'message'] 11 | ); 12 | }); 13 | 14 | testUtils.testWithClient('client.publish', async client => { 15 | assert.equal( 16 | await client.publish('channel', 'message'), 17 | 0 18 | ); 19 | }, GLOBAL.SERVERS.OPEN); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/client/lib/commands/PUBSUB_NUMPAT.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import PUBSUB_NUMPAT from './PUBSUB_NUMPAT'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('PUBSUB NUMPAT', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(PUBSUB_NUMPAT), 10 | ['PUBSUB', 'NUMPAT'] 11 | ); 12 | }); 13 | 14 | testUtils.testWithClient('client.pubSubNumPat', async client => { 15 | assert.equal( 16 | await client.pubSubNumPat(), 17 | 0 18 | ); 19 | }, GLOBAL.SERVERS.OPEN); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/client/lib/commands/PUBSUB_NUMPAT.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { NumberReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Constructs the PUBSUB NUMPAT command 9 | * 10 | * @param parser - The command parser 11 | * @see https://redis.io/commands/pubsub-numpat/ 12 | */ 13 | parseCommand(parser: CommandParser) { 14 | parser.push('PUBSUB', 'NUMPAT'); 15 | }, 16 | transformReply: undefined as unknown as () => NumberReply 17 | } as const satisfies Command; 18 | -------------------------------------------------------------------------------- /packages/client/lib/commands/RANDOMKEY.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import RANDOMKEY from './RANDOMKEY'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('RANDOMKEY', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(RANDOMKEY), 10 | ['RANDOMKEY'] 11 | ); 12 | }); 13 | 14 | testUtils.testAll('randomKey', async client => { 15 | assert.equal( 16 | await client.randomKey(), 17 | null 18 | ); 19 | }, { 20 | client: GLOBAL.SERVERS.OPEN, 21 | cluster: GLOBAL.CLUSTERS.OPEN 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/client/lib/commands/RANDOMKEY.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { NumberReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Constructs the RANDOMKEY command 9 | * 10 | * @param parser - The command parser 11 | * @see https://redis.io/commands/randomkey/ 12 | */ 13 | parseCommand(parser: CommandParser) { 14 | parser.push('RANDOMKEY'); 15 | }, 16 | transformReply: undefined as unknown as () => NumberReply 17 | } as const satisfies Command; 18 | -------------------------------------------------------------------------------- /packages/client/lib/commands/READONLY.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import READONLY from './READONLY'; 3 | import { parseArgs } from './generic-transformers'; 4 | 5 | describe('READONLY', () => { 6 | it('transformArguments', () => { 7 | assert.deepEqual( 8 | parseArgs(READONLY), 9 | ['READONLY'] 10 | ); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /packages/client/lib/commands/READONLY.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { SimpleStringReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Constructs the READONLY command 9 | * 10 | * @param parser - The command parser 11 | * @see https://redis.io/commands/readonly/ 12 | */ 13 | parseCommand(parser: CommandParser) { 14 | parser.push('READONLY'); 15 | }, 16 | transformReply: undefined as unknown as () => SimpleStringReply 17 | } as const satisfies Command; 18 | -------------------------------------------------------------------------------- /packages/client/lib/commands/READWRITE.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import READWRITE from './READWRITE'; 3 | import { parseArgs } from './generic-transformers'; 4 | 5 | describe('READWRITE', () => { 6 | it('transformArguments', () => { 7 | assert.deepEqual( 8 | parseArgs(READWRITE), 9 | ['READWRITE'] 10 | ); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /packages/client/lib/commands/READWRITE.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { SimpleStringReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Constructs the READWRITE command 9 | * 10 | * @param parser - The command parser 11 | * @see https://redis.io/commands/readwrite/ 12 | */ 13 | parseCommand(parser: CommandParser) { 14 | parser.push('READWRITE'); 15 | }, 16 | transformReply: undefined as unknown as () => SimpleStringReply 17 | } as const satisfies Command; 18 | -------------------------------------------------------------------------------- /packages/client/lib/commands/RENAME.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { RedisArgument, SimpleStringReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | IS_READ_ONLY: true, 6 | /** 7 | * Constructs the RENAME command 8 | * 9 | * @param parser - The command parser 10 | * @param key - The key to rename 11 | * @param newKey - The new key name 12 | * @see https://redis.io/commands/rename/ 13 | */ 14 | parseCommand(parser: CommandParser, key: RedisArgument, newKey: RedisArgument) { 15 | parser.push('RENAME'); 16 | parser.pushKeys([key, newKey]); 17 | }, 18 | transformReply: undefined as unknown as () => SimpleStringReply 19 | } as const satisfies Command; 20 | -------------------------------------------------------------------------------- /packages/client/lib/commands/REPLICAOF.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import REPLICAOF from './REPLICAOF'; 3 | import { parseArgs } from './generic-transformers'; 4 | 5 | describe('REPLICAOF', () => { 6 | it('transformArguments', () => { 7 | assert.deepEqual( 8 | parseArgs(REPLICAOF, 'host', 1), 9 | ['REPLICAOF', 'host', '1'] 10 | ); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /packages/client/lib/commands/RESTORE-ASKING.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import RESTORE_ASKING from './RESTORE-ASKING'; 3 | import { parseArgs } from './generic-transformers'; 4 | 5 | describe('RESTORE-ASKING', () => { 6 | it('transformArguments', () => { 7 | assert.deepEqual( 8 | parseArgs(RESTORE_ASKING), 9 | ['RESTORE-ASKING'] 10 | ); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /packages/client/lib/commands/RESTORE-ASKING.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { SimpleStringReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Constructs the RESTORE-ASKING command 9 | * 10 | * @param parser - The command parser 11 | * @see https://redis.io/commands/restore-asking/ 12 | */ 13 | parseCommand(parser: CommandParser) { 14 | parser.push('RESTORE-ASKING'); 15 | }, 16 | transformReply: undefined as unknown as () => SimpleStringReply 17 | } as const satisfies Command; 18 | -------------------------------------------------------------------------------- /packages/client/lib/commands/RPOP.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import RPOP from './RPOP'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('RPOP', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(RPOP, 'key'), 10 | ['RPOP', 'key'] 11 | ); 12 | }); 13 | 14 | testUtils.testAll('rPop', async client => { 15 | assert.equal( 16 | await client.rPop('key'), 17 | null 18 | ); 19 | }, { 20 | client: GLOBAL.SERVERS.OPEN, 21 | cluster: GLOBAL.CLUSTERS.OPEN 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/client/lib/commands/RPOP.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { RedisArgument, BlobStringReply, NullReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | /** 6 | * Constructs the RPOP command 7 | * 8 | * @param parser - The command parser 9 | * @param key - The list key to pop from 10 | * @see https://redis.io/commands/rpop/ 11 | */ 12 | parseCommand(parser: CommandParser, key: RedisArgument) { 13 | parser.push('RPOP'); 14 | parser.pushKey(key); 15 | }, 16 | transformReply: undefined as unknown as () => BlobStringReply | NullReply 17 | } as const satisfies Command; 18 | -------------------------------------------------------------------------------- /packages/client/lib/commands/SAVE.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import SAVE from './SAVE'; 3 | import { parseArgs } from './generic-transformers'; 4 | 5 | describe('SAVE', () => { 6 | it('transformArguments', () => { 7 | assert.deepEqual( 8 | parseArgs(SAVE), 9 | ['SAVE'] 10 | ); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /packages/client/lib/commands/SAVE.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { SimpleStringReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Constructs the SAVE command 9 | * 10 | * @param parser - The command parser 11 | * @see https://redis.io/commands/save/ 12 | */ 13 | parseCommand(parser: CommandParser) { 14 | parser.push('SAVE'); 15 | }, 16 | transformReply: undefined as unknown as () => SimpleStringReply 17 | } as const satisfies Command; 18 | -------------------------------------------------------------------------------- /packages/client/lib/commands/SCARD.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import { parseArgs } from './generic-transformers'; 4 | import SCARD from './SCARD'; 5 | 6 | describe('SCARD', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(SCARD, 'key'), 10 | ['SCARD', 'key'] 11 | ); 12 | }); 13 | 14 | testUtils.testAll('sCard', async client => { 15 | assert.equal( 16 | await client.sCard('key'), 17 | 0 18 | ); 19 | }, { 20 | client: GLOBAL.SERVERS.OPEN, 21 | cluster: GLOBAL.CLUSTERS.OPEN 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/client/lib/commands/SCARD.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { RedisArgument, NumberReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | CACHEABLE: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Constructs the SCARD command 9 | * 10 | * @param parser - The command parser 11 | * @param key - The set key to get the cardinality of 12 | * @see https://redis.io/commands/scard/ 13 | */ 14 | parseCommand(parser: CommandParser, key: RedisArgument) { 15 | parser.push('SCARD'); 16 | parser.pushKey(key); 17 | }, 18 | transformReply: undefined as unknown as () => NumberReply 19 | } as const satisfies Command; 20 | -------------------------------------------------------------------------------- /packages/client/lib/commands/SCRIPT_DEBUG.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import SCRIPT_DEBUG from './SCRIPT_DEBUG'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('SCRIPT DEBUG', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(SCRIPT_DEBUG, 'NO'), 10 | ['SCRIPT', 'DEBUG', 'NO'] 11 | ); 12 | }); 13 | 14 | testUtils.testWithClient('client.scriptDebug', async client => { 15 | assert.equal( 16 | await client.scriptDebug('NO'), 17 | 'OK' 18 | ); 19 | }, GLOBAL.SERVERS.OPEN); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/client/lib/commands/SCRIPT_DEBUG.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { SimpleStringReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Constructs the SCRIPT DEBUG command 9 | * 10 | * @param parser - The command parser 11 | * @param mode - Debug mode: YES, SYNC, or NO 12 | * @see https://redis.io/commands/script-debug/ 13 | */ 14 | parseCommand(parser: CommandParser, mode: 'YES' | 'SYNC' | 'NO') { 15 | parser.push('SCRIPT', 'DEBUG', mode); 16 | }, 17 | transformReply: undefined as unknown as () => SimpleStringReply<'OK'> 18 | } as const satisfies Command; 19 | -------------------------------------------------------------------------------- /packages/client/lib/commands/SCRIPT_KILL.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import SCRIPT_KILL from './SCRIPT_KILL'; 3 | import { parseArgs } from './generic-transformers'; 4 | 5 | describe('SCRIPT KILL', () => { 6 | it('transformArguments', () => { 7 | assert.deepEqual( 8 | parseArgs(SCRIPT_KILL), 9 | ['SCRIPT', 'KILL'] 10 | ); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /packages/client/lib/commands/SCRIPT_KILL.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { SimpleStringReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Constructs the SCRIPT KILL command 9 | * 10 | * @param parser - The command parser 11 | * @see https://redis.io/commands/script-kill/ 12 | */ 13 | parseCommand(parser: CommandParser) { 14 | parser.push('SCRIPT', 'KILL'); 15 | }, 16 | transformReply: undefined as unknown as () => SimpleStringReply<'OK'> 17 | } as const satisfies Command; 18 | -------------------------------------------------------------------------------- /packages/client/lib/commands/SCRIPT_LOAD.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { BlobStringReply, Command, RedisArgument } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Constructs the SCRIPT LOAD command 9 | * 10 | * @param parser - The command parser 11 | * @param script - The Lua script to load 12 | * @see https://redis.io/commands/script-load/ 13 | */ 14 | parseCommand(parser: CommandParser, script: RedisArgument) { 15 | parser.push('SCRIPT', 'LOAD', script); 16 | }, 17 | transformReply: undefined as unknown as () => BlobStringReply 18 | } as const satisfies Command; 19 | -------------------------------------------------------------------------------- /packages/client/lib/commands/SETBIT.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import SETBIT from './SETBIT'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('SETBIT', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(SETBIT, 'key', 0, 1), 10 | ['SETBIT', 'key', '0', '1'] 11 | ); 12 | }); 13 | 14 | testUtils.testAll('setBit', async client => { 15 | assert.equal( 16 | await client.setBit('key', 0, 1), 17 | 0 18 | ); 19 | }, { 20 | client: GLOBAL.SERVERS.OPEN, 21 | cluster: GLOBAL.CLUSTERS.OPEN 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/client/lib/commands/SETEX.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import SETEX from './SETEX'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('SETEX', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(SETEX, 'key', 1, 'value'), 10 | ['SETEX', 'key', '1', 'value'] 11 | ); 12 | }); 13 | 14 | testUtils.testAll('setEx', async client => { 15 | assert.equal( 16 | await client.setEx('key', 1, 'value'), 17 | 'OK' 18 | ); 19 | }, { 20 | client: GLOBAL.SERVERS.OPEN, 21 | cluster: GLOBAL.CLUSTERS.OPEN 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/client/lib/commands/SETNX .spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import SETNX from './SETNX'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('SETNX', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(SETNX, 'key', 'value'), 10 | ['SETNX', 'key', 'value'] 11 | ); 12 | }); 13 | 14 | testUtils.testAll('setNX', async client => { 15 | assert.equal( 16 | await client.setNX('key', 'value'), 17 | 1 18 | ); 19 | }, { 20 | client: GLOBAL.SERVERS.OPEN, 21 | cluster: GLOBAL.CLUSTERS.OPEN 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/client/lib/commands/SETNX.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { RedisArgument, NumberReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | /** 6 | * Constructs the SETNX command 7 | * 8 | * @param parser - The command parser 9 | * @param key - The key to set if it doesn't exist 10 | * @param value - The value to set 11 | * @see https://redis.io/commands/setnx/ 12 | */ 13 | parseCommand(parser: CommandParser, key: RedisArgument, value: RedisArgument) { 14 | parser.push('SETNX'); 15 | parser.pushKey(key); 16 | parser.push(value); 17 | }, 18 | transformReply: undefined as unknown as () => NumberReply 19 | } as const satisfies Command; 20 | -------------------------------------------------------------------------------- /packages/client/lib/commands/SETRANGE.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import SETRANGE from './SETRANGE'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('SETRANGE', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(SETRANGE, 'key', 0, 'value'), 10 | ['SETRANGE', 'key', '0', 'value'] 11 | ); 12 | }); 13 | 14 | testUtils.testAll('setRange', async client => { 15 | assert.equal( 16 | await client.setRange('key', 0, 'value'), 17 | 5 18 | ); 19 | }, { 20 | client: GLOBAL.SERVERS.OPEN, 21 | cluster: GLOBAL.CLUSTERS.OPEN 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/client/lib/commands/SISMEMBER.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import SISMEMBER from './SISMEMBER'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('SISMEMBER', () => { 7 | it('processCommand', () => { 8 | assert.deepEqual( 9 | parseArgs(SISMEMBER, 'key', 'member'), 10 | ['SISMEMBER', 'key', 'member'] 11 | ); 12 | }); 13 | 14 | testUtils.testAll('sIsMember', async client => { 15 | assert.equal( 16 | await client.sIsMember('key', 'member'), 17 | 0 18 | ); 19 | }, { 20 | client: GLOBAL.SERVERS.OPEN, 21 | cluster: GLOBAL.CLUSTERS.OPEN 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/client/lib/commands/SMEMBERS.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import SMEMBERS from './SMEMBERS'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('SMEMBERS', () => { 7 | it('processCommand', () => { 8 | assert.deepEqual( 9 | parseArgs(SMEMBERS, 'key'), 10 | ['SMEMBERS', 'key'] 11 | ); 12 | }); 13 | 14 | testUtils.testAll('sMembers', async client => { 15 | assert.deepEqual( 16 | await client.sMembers('key'), 17 | [] 18 | ); 19 | }, { 20 | client: GLOBAL.SERVERS.OPEN, 21 | cluster: GLOBAL.CLUSTERS.OPEN 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/client/lib/commands/SORT_RO.ts: -------------------------------------------------------------------------------- 1 | import { Command } from '../RESP/types'; 2 | import SORT, { parseSortArguments } from './SORT'; 3 | 4 | export default { 5 | IS_READ_ONLY: true, 6 | /** 7 | * Read-only variant of SORT that sorts the elements in a list, set or sorted set. 8 | * @param args - Same parameters as the SORT command. 9 | */ 10 | parseCommand(...args: Parameters<typeof parseSortArguments>) { 11 | const parser = args[0]; 12 | 13 | parser.push('SORT_RO'); 14 | parseSortArguments(...args); 15 | }, 16 | transformReply: SORT.transformReply 17 | } as const satisfies Command; 18 | -------------------------------------------------------------------------------- /packages/client/lib/commands/SPOP.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { RedisArgument, BlobStringReply, NullReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | IS_READ_ONLY: false, 6 | /** 7 | * Constructs the SPOP command to remove and return a random member from a set 8 | * 9 | * @param parser - The command parser 10 | * @param key - The key of the set to pop from 11 | * @see https://redis.io/commands/spop/ 12 | */ 13 | parseCommand(parser: CommandParser, key: RedisArgument) { 14 | parser.push('SPOP'); 15 | parser.pushKey(key); 16 | }, 17 | transformReply: undefined as unknown as () => BlobStringReply | NullReply 18 | } as const satisfies Command; 19 | -------------------------------------------------------------------------------- /packages/client/lib/commands/SRANDMEMBER.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import SRANDMEMBER from './SRANDMEMBER'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('SRANDMEMBER', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(SRANDMEMBER, 'key'), 10 | ['SRANDMEMBER', 'key'] 11 | ); 12 | }); 13 | 14 | testUtils.testAll('sRandMember', async client => { 15 | assert.equal( 16 | await client.sRandMember('key'), 17 | null 18 | ); 19 | }, { 20 | client: GLOBAL.SERVERS.OPEN, 21 | cluster: GLOBAL.CLUSTERS.OPEN 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/client/lib/commands/STRLEN.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import STRLEN from './STRLEN'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('STRLEN', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(STRLEN, 'key'), 10 | ['STRLEN', 'key'] 11 | ); 12 | }); 13 | 14 | testUtils.testAll('strLen', async client => { 15 | assert.equal( 16 | await client.strLen('key'), 17 | 0 18 | ); 19 | }, { 20 | client: GLOBAL.SERVERS.OPEN, 21 | cluster: GLOBAL.CLUSTERS.OPEN 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/client/lib/commands/SWAPDB.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import SWAPDB from './SWAPDB'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('SWAPDB', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(SWAPDB, 0, 1), 10 | ['SWAPDB', '0', '1'] 11 | ); 12 | }); 13 | 14 | testUtils.testWithClient('client.swapDb', async client => { 15 | assert.equal( 16 | await client.swapDb(0, 1), 17 | 'OK' 18 | ); 19 | }, GLOBAL.SERVERS.OPEN); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/client/lib/commands/SWAPDB.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { SimpleStringReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: false, 7 | /** 8 | * Swaps the data of two Redis databases. 9 | * @param parser - The Redis command parser. 10 | * @param index1 - First database index. 11 | * @param index2 - Second database index. 12 | */ 13 | parseCommand(parser: CommandParser, index1: number, index2: number) { 14 | parser.push('SWAPDB', index1.toString(), index2.toString()); 15 | }, 16 | transformReply: undefined as unknown as () => SimpleStringReply<'OK'> 17 | } as const satisfies Command; 18 | 19 | -------------------------------------------------------------------------------- /packages/client/lib/commands/TIME.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import TIME from './TIME'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('TIME', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(TIME), 10 | ['TIME'] 11 | ); 12 | }); 13 | 14 | testUtils.testWithClient('client.time', async client => { 15 | const reply = await client.time(); 16 | assert.ok(Array.isArray(reply)); 17 | assert.equal(typeof reply[0], 'string'); 18 | assert.equal(typeof reply[1], 'string'); 19 | }, GLOBAL.SERVERS.OPEN); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/client/lib/commands/TTL.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import TTL from './TTL'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('TTL', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(TTL, 'key'), 10 | ['TTL', 'key'] 11 | ); 12 | }); 13 | 14 | testUtils.testAll('ttl', async client => { 15 | assert.equal( 16 | await client.ttl('key'), 17 | -2 18 | ); 19 | }, { 20 | client: GLOBAL.SERVERS.OPEN, 21 | cluster: GLOBAL.CLUSTERS.OPEN 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/client/lib/commands/TYPE.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import TYPE from './TYPE'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('TYPE', () => { 7 | it('processCommand', () => { 8 | assert.deepEqual( 9 | parseArgs(TYPE, 'key'), 10 | ['TYPE', 'key'] 11 | ); 12 | }); 13 | 14 | testUtils.testAll('type', async client => { 15 | assert.equal( 16 | await client.type('key'), 17 | 'none' 18 | ); 19 | }, { 20 | client: GLOBAL.SERVERS.OPEN, 21 | cluster: GLOBAL.CLUSTERS.OPEN 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/client/lib/commands/VCARD.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { RedisArgument, NumberReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | IS_READ_ONLY: true, 6 | /** 7 | * Retrieve the number of elements in a vector set 8 | * 9 | * @param parser - The command parser 10 | * @param key - The key of the vector set 11 | * @see https://redis.io/commands/vcard/ 12 | */ 13 | parseCommand(parser: CommandParser, key: RedisArgument) { 14 | parser.push('VCARD'); 15 | parser.pushKey(key); 16 | }, 17 | transformReply: undefined as unknown as () => NumberReply 18 | } as const satisfies Command; 19 | -------------------------------------------------------------------------------- /packages/client/lib/commands/VDIM.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { RedisArgument, NumberReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | IS_READ_ONLY: true, 6 | /** 7 | * Retrieve the dimension of the vectors in a vector set 8 | * 9 | * @param parser - The command parser 10 | * @param key - The key of the vector set 11 | * @see https://redis.io/commands/vdim/ 12 | */ 13 | parseCommand(parser: CommandParser, key: RedisArgument) { 14 | parser.push('VDIM'); 15 | parser.pushKey(key); 16 | }, 17 | transformReply: undefined as unknown as () => NumberReply 18 | } as const satisfies Command; 19 | -------------------------------------------------------------------------------- /packages/client/lib/commands/WAIT.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import WAIT from './WAIT'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('WAIT', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(WAIT, 0, 1), 10 | ['WAIT', '0', '1'] 11 | ); 12 | }); 13 | 14 | testUtils.testWithClient('client.wait', async client => { 15 | assert.equal( 16 | await client.wait(0, 1), 17 | 0 18 | ); 19 | }, GLOBAL.SERVERS.OPEN); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/client/lib/commands/XLEN.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import XLEN from './XLEN'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('XLEN', () => { 7 | it('processCommand', () => { 8 | assert.deepEqual( 9 | parseArgs(XLEN, 'key'), 10 | ['XLEN', 'key'] 11 | ); 12 | }); 13 | 14 | testUtils.testAll('xLen', async client => { 15 | assert.equal( 16 | await client.xLen('key'), 17 | 0 18 | ); 19 | }, { 20 | client: GLOBAL.SERVERS.OPEN, 21 | cluster: GLOBAL.CLUSTERS.OPEN 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/client/lib/commands/ZCARD.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import ZCARD from './ZCARD'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('ZCARD', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(ZCARD, 'key'), 10 | ['ZCARD', 'key'] 11 | ); 12 | }); 13 | 14 | testUtils.testAll('zCard', async client => { 15 | assert.equal( 16 | await client.zCard('key'), 17 | 0 18 | ); 19 | }, { 20 | client: GLOBAL.SERVERS.OPEN, 21 | cluster: GLOBAL.CLUSTERS.OPEN 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/client/lib/commands/ZCOUNT.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import ZCOUNT from './ZCOUNT'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('ZCOUNT', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(ZCOUNT, 'key', 0, 1), 10 | ['ZCOUNT', 'key', '0', '1'] 11 | ); 12 | }); 13 | 14 | testUtils.testAll('zCount', async client => { 15 | assert.equal( 16 | await client.zCount('key', 0, 1), 17 | 0 18 | ); 19 | }, { 20 | client: GLOBAL.SERVERS.OPEN, 21 | cluster: GLOBAL.SERVERS.OPEN 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/client/lib/commands/ZINCRBY.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import ZINCRBY from './ZINCRBY'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('ZINCRBY', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(ZINCRBY, 'key', 1, 'member'), 10 | ['ZINCRBY', 'key', '1', 'member'] 11 | ); 12 | }); 13 | 14 | testUtils.testAll('zIncrBy', async client => { 15 | assert.equal( 16 | await client.zIncrBy('destination', 1, 'member'), 17 | 1 18 | ); 19 | }, { 20 | client: GLOBAL.SERVERS.OPEN, 21 | cluster: GLOBAL.CLUSTERS.OPEN 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/client/lib/commands/ZINTER_WITHSCORES.ts: -------------------------------------------------------------------------------- 1 | import { Command } from '../RESP/types'; 2 | import { transformSortedSetReply } from './generic-transformers'; 3 | import ZINTER from './ZINTER'; 4 | 5 | 6 | export default { 7 | IS_READ_ONLY: ZINTER.IS_READ_ONLY, 8 | /** 9 | * Intersects multiple sorted sets and returns the result with scores. 10 | * @param args - Same parameters as ZINTER command. 11 | */ 12 | parseCommand(...args: Parameters<typeof ZINTER.parseCommand>) { 13 | ZINTER.parseCommand(...args); 14 | args[0].push('WITHSCORES'); 15 | }, 16 | transformReply: transformSortedSetReply 17 | } as const satisfies Command; 18 | -------------------------------------------------------------------------------- /packages/client/lib/commands/ZLEXCOUNT.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import ZLEXCOUNT from './ZLEXCOUNT'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('ZLEXCOUNT', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(ZLEXCOUNT, 'key', '[a', '[b'), 10 | ['ZLEXCOUNT', 'key', '[a', '[b'] 11 | ); 12 | }); 13 | 14 | testUtils.testAll('zLexCount', async client => { 15 | assert.equal( 16 | await client.zLexCount('key', '[a', '[b'), 17 | 0 18 | ); 19 | }, { 20 | client: GLOBAL.SERVERS.OPEN, 21 | cluster: GLOBAL.CLUSTERS.OPEN 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/client/lib/commands/ZPOPMIN.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { RedisArgument, Command } from '../RESP/types'; 3 | import ZPOPMAX from './ZPOPMAX'; 4 | 5 | export default { 6 | IS_READ_ONLY: false, 7 | /** 8 | * Removes and returns the member with the lowest score in the sorted set. 9 | * @param parser - The Redis command parser. 10 | * @param key - Key of the sorted set. 11 | */ 12 | parseCommand(parser: CommandParser, key: RedisArgument) { 13 | parser.push('ZPOPMIN'); 14 | parser.pushKey(key); 15 | }, 16 | transformReply: ZPOPMAX.transformReply 17 | } as const satisfies Command; 18 | -------------------------------------------------------------------------------- /packages/client/lib/commands/ZRANDMEMBER.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '../client/parser'; 2 | import { RedisArgument, BlobStringReply, NullReply, Command } from '../RESP/types'; 3 | 4 | export default { 5 | IS_READ_ONLY: true, 6 | /** 7 | * Returns a random member from a sorted set. 8 | * @param parser - The Redis command parser. 9 | * @param key - Key of the sorted set. 10 | */ 11 | parseCommand(parser: CommandParser, key: RedisArgument) { 12 | parser.push('ZRANDMEMBER'); 13 | parser.pushKey(key); 14 | }, 15 | transformReply: undefined as unknown as () => BlobStringReply | NullReply 16 | } as const satisfies Command; 17 | -------------------------------------------------------------------------------- /packages/client/lib/commands/ZRANK.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import ZRANK from './ZRANK'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('ZRANK', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(ZRANK, 'key', 'member'), 10 | ['ZRANK', 'key', 'member'] 11 | ); 12 | }); 13 | 14 | testUtils.testAll('zRank', async client => { 15 | assert.equal( 16 | await client.zRank('key', 'member'), 17 | null 18 | ); 19 | }, { 20 | client: GLOBAL.SERVERS.OPEN, 21 | cluster: GLOBAL.CLUSTERS.OPEN 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/client/lib/commands/ZREVRANK.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import { parseArgs } from './generic-transformers'; 4 | import ZREVRANK from './ZREVRANK'; 5 | 6 | describe('ZREVRANK', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(ZREVRANK, 'key', 'member'), 10 | ['ZREVRANK', 'key', 'member'] 11 | ); 12 | }); 13 | 14 | testUtils.testAll('zRevRank', async client => { 15 | assert.equal( 16 | await client.zRevRank('key', 'member'), 17 | null 18 | ); 19 | }, { 20 | client: GLOBAL.SERVERS.OPEN, 21 | cluster: GLOBAL.CLUSTERS.OPEN 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/client/lib/commands/ZSCORE.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import ZSCORE from './ZSCORE'; 4 | import { parseArgs } from './generic-transformers'; 5 | 6 | describe('ZSCORE', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(ZSCORE, 'key', 'member'), 10 | ['ZSCORE', 'key', 'member'] 11 | ); 12 | }); 13 | 14 | testUtils.testAll('zScore', async client => { 15 | assert.equal( 16 | await client.zScore('key', 'member'), 17 | null 18 | ); 19 | }, { 20 | client: GLOBAL.SERVERS.OPEN, 21 | cluster: GLOBAL.CLUSTERS.OPEN 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/client/lib/commands/ZUNION_WITHSCORES.ts: -------------------------------------------------------------------------------- 1 | import { Command } from '../RESP/types'; 2 | import { transformSortedSetReply } from './generic-transformers'; 3 | import ZUNION from './ZUNION'; 4 | 5 | 6 | export default { 7 | IS_READ_ONLY: ZUNION.IS_READ_ONLY, 8 | /** 9 | * Returns the union of multiple sorted sets with their scores. 10 | * @param args - Same parameters as the ZUNION command. 11 | */ 12 | parseCommand(...args: Parameters<typeof ZUNION.parseCommand>) { 13 | const parser = args[0]; 14 | 15 | ZUNION.parseCommand(...args); 16 | parser.push('WITHSCORES'); 17 | }, 18 | transformReply: transformSortedSetReply 19 | } as const satisfies Command; 20 | -------------------------------------------------------------------------------- /packages/client/lib/lua-script.ts: -------------------------------------------------------------------------------- 1 | import { createHash } from 'node:crypto'; 2 | import { Command } from './RESP/types'; 3 | 4 | export type RedisScriptConfig = Command & { 5 | SCRIPT: string | Buffer; 6 | NUMBER_OF_KEYS?: number; 7 | } 8 | 9 | export interface SHA1 { 10 | SHA1: string; 11 | } 12 | 13 | export function defineScript<S extends RedisScriptConfig>(script: S): S & SHA1 { 14 | return { 15 | ...script, 16 | SHA1: scriptSha1(script.SCRIPT) 17 | }; 18 | } 19 | 20 | export function scriptSha1(script: RedisScriptConfig['SCRIPT']): string { 21 | return createHash('sha1').update(script).digest('hex'); 22 | } 23 | -------------------------------------------------------------------------------- /packages/client/lib/sentinel/module.ts: -------------------------------------------------------------------------------- 1 | 2 | import { RedisModules } from '../RESP/types'; 3 | import sentinel from './commands'; 4 | 5 | export default { 6 | sentinel 7 | } as const satisfies RedisModules; 8 | -------------------------------------------------------------------------------- /packages/client/lib/sentinel/wait-queue.ts: -------------------------------------------------------------------------------- 1 | import { SinglyLinkedList } from '../client/linked-list'; 2 | 3 | export class WaitQueue<T> { 4 | #list = new SinglyLinkedList<T>(); 5 | #queue = new SinglyLinkedList<(item: T) => unknown>(); 6 | 7 | push(value: T) { 8 | const resolve = this.#queue.shift(); 9 | if (resolve !== undefined) { 10 | resolve(value); 11 | return; 12 | } 13 | 14 | this.#list.push(value); 15 | } 16 | 17 | shift() { 18 | return this.#list.shift(); 19 | } 20 | 21 | wait() { 22 | return new Promise<T>(resolve => this.#queue.push(resolve)); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /packages/client/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "outDir": "./dist", 5 | }, 6 | "include": [ 7 | "./index.ts", 8 | "./lib/**/*.ts", 9 | "./package.json" 10 | ], 11 | "exclude": [ 12 | "./lib/test-utils.ts", 13 | "./lib/**/*.spec.ts", 14 | "./lib/sentinel/test-util.ts" 15 | ], 16 | "typedocOptions": { 17 | "entryPoints": [ 18 | "./index.ts", 19 | "./lib" 20 | ], 21 | "entryPointStrategy": "expand", 22 | "out": "../../documentation/client", 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /packages/entraid/.nycrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@istanbuljs/nyc-config-typescript", 3 | "exclude": [ 4 | "integration-tests", 5 | "samples", 6 | "dist", 7 | "**/*.spec.ts", 8 | "lib/test-utils.ts" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /packages/entraid/.release-it.json: -------------------------------------------------------------------------------- 1 | { 2 | "npm": { 3 | "publish": true, 4 | "publishArgs": ["--access", "public"] 5 | }, 6 | "git": { 7 | "tagName": "entraid@${version}", 8 | "tagMatch": "entraid@*", 9 | "commitMessage": "Release ${tagName}", 10 | "tagAnnotation": "Release ${tagName}", 11 | "commitArgs": "--all" 12 | }, 13 | "plugins": { 14 | "@release-it/bumper": { 15 | "out": { 16 | "file": "package.json", 17 | "path": ["peerDependencies.@redis/client"], 18 | "versionPrefix": "^" 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/entraid/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib/index' -------------------------------------------------------------------------------- /packages/entraid/lib/azure-identity-provider.ts: -------------------------------------------------------------------------------- 1 | import type { AccessToken } from '@azure/core-auth'; 2 | 3 | import { IdentityProvider, TokenResponse } from '@redis/client/dist/lib/authx'; 4 | 5 | export class AzureIdentityProvider implements IdentityProvider<AccessToken> { 6 | private readonly getToken: () => Promise<AccessToken>; 7 | 8 | constructor(getToken: () => Promise<AccessToken>) { 9 | this.getToken = getToken; 10 | } 11 | 12 | async requestToken(): Promise<TokenResponse<AccessToken>> { 13 | const result = await this.getToken(); 14 | return { 15 | token: result, 16 | ttlMs: result.expiresOnTimestamp - Date.now() 17 | }; 18 | } 19 | 20 | } 21 | 22 | 23 | -------------------------------------------------------------------------------- /packages/entraid/lib/index.ts: -------------------------------------------------------------------------------- 1 | export * from './entra-id-credentials-provider-factory'; 2 | export * from './entraid-credentials-provider'; 3 | export * from './msal-identity-provider'; -------------------------------------------------------------------------------- /packages/entraid/tsconfig.integration-tests.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "include": [ 4 | "./integration-tests/**/*.ts", 5 | "./lib/**/*.ts" 6 | ], 7 | "compilerOptions": { 8 | "noEmit": true 9 | }, 10 | } -------------------------------------------------------------------------------- /packages/entraid/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "outDir": "./dist" 5 | }, 6 | "include": [ 7 | "./lib/**/*.ts", 8 | "./index.ts" 9 | ], 10 | "exclude": [ 11 | "./lib/**/*.spec.ts", 12 | "./lib/test-util.ts", 13 | ], 14 | "typedocOptions": { 15 | "entryPoints": [ 16 | "./lib" 17 | ], 18 | "entryPointStrategy": "expand", 19 | "out": "../../documentation/entraid" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /packages/entraid/tsconfig.samples.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "include": [ 4 | "./samples/**/*.ts", 5 | "./lib/**/*.ts" 6 | ], 7 | "compilerOptions": { 8 | "noEmit": true 9 | } 10 | } -------------------------------------------------------------------------------- /packages/json/.nycrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@istanbuljs/nyc-config-typescript", 3 | "exclude": ["dist", "**/*.spec.ts", "lib/test-utils.ts"] 4 | } 5 | -------------------------------------------------------------------------------- /packages/json/.release-it.json: -------------------------------------------------------------------------------- 1 | { 2 | "npm": { 3 | "publish": true, 4 | "publishArgs": ["--access", "public"] 5 | }, 6 | "git": { 7 | "tagName": "json@${version}", 8 | "tagMatch": "json@*", 9 | "commitMessage": "Release ${tagName}", 10 | "tagAnnotation": "Release ${tagName}", 11 | "commitArgs": "--all" 12 | }, 13 | "plugins": { 14 | "@release-it/bumper": { 15 | "out": { 16 | "file": "package.json", 17 | "path": ["peerDependencies.@redis/client"], 18 | "versionPrefix": "^" 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/json/lib/commands/MERGE.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import MERGE from './MERGE'; 4 | import { parseArgs } from '@redis/client/lib/commands/generic-transformers'; 5 | 6 | describe('JSON.MERGE', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(MERGE, 'key', '#39;, 'value'), 10 | ['JSON.MERGE', 'key', '#39;, '"value"'] 11 | ); 12 | }); 13 | 14 | testUtils.testWithClient('client.json.merge', async client => { 15 | assert.equal( 16 | await client.json.merge('key', '#39;, 'value'), 17 | 'OK' 18 | ); 19 | }, GLOBAL.SERVERS.OPEN); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/json/lib/commands/MGET.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import MGET from './MGET'; 4 | import { parseArgs } from '@redis/client/lib/commands/generic-transformers'; 5 | 6 | describe('JSON.MGET', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(MGET, ['1', '2'], '#39;), 10 | ['JSON.MGET', '1', '2', '#39;] 11 | ); 12 | }); 13 | 14 | testUtils.testWithClient('client.json.mGet', async client => { 15 | assert.deepEqual( 16 | await client.json.mGet(['1', '2'], '#39;), 17 | [null, null] 18 | ); 19 | }, GLOBAL.SERVERS.OPEN); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/json/lib/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './commands'; 2 | -------------------------------------------------------------------------------- /packages/json/lib/test-utils.ts: -------------------------------------------------------------------------------- 1 | import TestUtils from '@redis/test-utils'; 2 | import RedisJSON from '.'; 3 | 4 | export default TestUtils.createFromConfig({ 5 | dockerImageName: 'redislabs/client-libs-test', 6 | dockerImageVersionArgument: 'redis-version', 7 | defaultDockerVersion: '8.2-M01-pre' 8 | }); 9 | 10 | export const GLOBAL = { 11 | SERVERS: { 12 | OPEN: { 13 | serverArguments: [], 14 | clientOptions: { 15 | modules: { 16 | json: RedisJSON 17 | } 18 | } 19 | } 20 | } 21 | }; 22 | -------------------------------------------------------------------------------- /packages/json/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "outDir": "./dist" 5 | }, 6 | "include": [ 7 | "./lib/**/*.ts" 8 | ], 9 | "exclude": [ 10 | "./lib/test-utils.ts", 11 | "./lib/**/*.spec.ts" 12 | ], 13 | "typedocOptions": { 14 | "entryPoints": [ 15 | "./lib" 16 | ], 17 | "entryPointStrategy": "expand", 18 | "out": "../../documentation/json" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /packages/redis/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "outDir": "./dist" 5 | }, 6 | "include": [ 7 | "./index.ts" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /packages/search/.nycrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@istanbuljs/nyc-config-typescript", 3 | "exclude": ["dist", "**/*.spec.ts", "lib/test-utils.ts"] 4 | } 5 | -------------------------------------------------------------------------------- /packages/search/.release-it.json: -------------------------------------------------------------------------------- 1 | { 2 | "npm": { 3 | "publish": true, 4 | "publishArgs": ["--access", "public"] 5 | }, 6 | "git": { 7 | "tagName": "search@${version}", 8 | "tagMatch": "search@*", 9 | "commitMessage": "Release ${tagName}", 10 | "tagAnnotation": "Release ${tagName}", 11 | "commitArgs": "--all" 12 | }, 13 | "plugins": { 14 | "@release-it/bumper": { 15 | "out": { 16 | "file": "package.json", 17 | "path": ["peerDependencies.@redis/client"], 18 | "versionPrefix": "^" 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/search/lib/commands/ALIASDEL.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '@redis/client/dist/lib/client/parser'; 2 | import { RedisArgument, SimpleStringReply, Command } from '@redis/client/dist/lib/RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Removes an existing alias from a RediSearch index. 9 | * @param parser - The command parser 10 | * @param alias - The alias to remove 11 | */ 12 | parseCommand(parser: CommandParser, alias: RedisArgument) { 13 | parser.push('FT.ALIASDEL', alias); 14 | }, 15 | transformReply: undefined as unknown as () => SimpleStringReply<'OK'> 16 | } as const satisfies Command; 17 | -------------------------------------------------------------------------------- /packages/search/lib/commands/EXPLAINCLI.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import EXPLAINCLI from './EXPLAINCLI'; 3 | import { parseArgs } from '@redis/client/lib/commands/generic-transformers'; 4 | import { DEFAULT_DIALECT } from '../dialect/default'; 5 | 6 | describe('EXPLAINCLI', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(EXPLAINCLI, 'index', '*'), 10 | ['FT.EXPLAINCLI', 'index', '*', 'DIALECT', DEFAULT_DIALECT] 11 | ); 12 | }); 13 | 14 | it('with dialect', () => { 15 | assert.deepEqual( 16 | parseArgs(EXPLAINCLI, 'index', '*', {DIALECT: 1}), 17 | ['FT.EXPLAINCLI', 'index', '*', 'DIALECT', '1'] 18 | ); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/search/lib/commands/SUGDEL.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import SUGDEL from './SUGDEL'; 4 | import { parseArgs } from '@redis/client/lib/commands/generic-transformers'; 5 | 6 | describe('FT.SUGDEL', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(SUGDEL, 'key', 'string'), 10 | ['FT.SUGDEL', 'key', 'string'] 11 | ); 12 | }); 13 | 14 | testUtils.testWithClient('client.ft.sugDel', async client => { 15 | assert.equal( 16 | await client.ft.sugDel('key', 'string'), 17 | 0 18 | ); 19 | }, GLOBAL.SERVERS.OPEN); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/search/lib/commands/SUGLEN.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import SUGLEN from './SUGLEN'; 4 | import { parseArgs } from '@redis/client/lib/commands/generic-transformers'; 5 | 6 | describe('FT.SUGLEN', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(SUGLEN, 'key'), 10 | ['FT.SUGLEN', 'key'] 11 | ); 12 | }); 13 | 14 | testUtils.testWithClient('client.ft.sugLen', async client => { 15 | assert.equal( 16 | await client.ft.sugLen('key'), 17 | 0 18 | ); 19 | }, GLOBAL.SERVERS.OPEN); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/search/lib/commands/SUGLEN.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '@redis/client/dist/lib/client/parser'; 2 | import { RedisArgument, NumberReply, Command } from '@redis/client/dist/lib/RESP/types'; 3 | 4 | export default { 5 | IS_READ_ONLY: true, 6 | /** 7 | * Gets the size of a suggestion dictionary. 8 | * @param parser - The command parser 9 | * @param key - The suggestion dictionary key 10 | */ 11 | parseCommand(parser: CommandParser, key: RedisArgument) { 12 | parser.push('FT.SUGLEN', key); 13 | }, 14 | transformReply: undefined as unknown as () => NumberReply 15 | } as const satisfies Command; 16 | -------------------------------------------------------------------------------- /packages/search/lib/commands/_LIST.spec.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'node:assert'; 2 | import testUtils, { GLOBAL } from '../test-utils'; 3 | import _LIST from './_LIST'; 4 | import { parseArgs } from '@redis/client/lib/commands/generic-transformers'; 5 | 6 | describe('_LIST', () => { 7 | it('transformArguments', () => { 8 | assert.deepEqual( 9 | parseArgs(_LIST), 10 | ['FT._LIST'] 11 | ); 12 | }); 13 | 14 | testUtils.testWithClient('client.ft._list', async client => { 15 | assert.deepEqual( 16 | await client.ft._list(), 17 | [] 18 | ); 19 | }, GLOBAL.SERVERS.OPEN); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/search/lib/commands/_LIST.ts: -------------------------------------------------------------------------------- 1 | import { CommandParser } from '@redis/client/dist/lib/client/parser'; 2 | import { ArrayReply, SetReply, BlobStringReply, Command } from '@redis/client/dist/lib/RESP/types'; 3 | 4 | export default { 5 | NOT_KEYED_COMMAND: true, 6 | IS_READ_ONLY: true, 7 | /** 8 | * Lists all existing indexes in the database. 9 | * @param parser - The command parser 10 | */ 11 | parseCommand(parser: CommandParser) { 12 | parser.push('FT._LIST'); 13 | }, 14 | transformReply: { 15 | 2: undefined as unknown as () => ArrayReply<BlobStringReply>, 16 | 3: undefined as unknown as () => SetReply<BlobStringReply> 17 | } 18 | } as const satisfies Command; 19 | -------------------------------------------------------------------------------- /packages/search/lib/dialect/default.ts: -------------------------------------------------------------------------------- 1 | export const DEFAULT_DIALECT = '2'; 2 | -------------------------------------------------------------------------------- /packages/search/lib/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './commands' 2 | 3 | export { SearchReply } from './commands/SEARCH' 4 | export { RediSearchSchema } from './commands/CREATE' 5 | export { 6 | REDISEARCH_LANGUAGE, 7 | RediSearchLanguage, 8 | SCHEMA_FIELD_TYPE, 9 | SchemaFieldType, 10 | SCHEMA_TEXT_FIELD_PHONETIC, 11 | SchemaTextFieldPhonetic, 12 | SCHEMA_VECTOR_FIELD_ALGORITHM, 13 | SchemaVectorFieldAlgorithm 14 | } from './commands/CREATE' 15 | export { 16 | FT_AGGREGATE_GROUP_BY_REDUCERS, 17 | FtAggregateGroupByReducer, 18 | FT_AGGREGATE_STEPS, 19 | FtAggregateStep 20 | } from './commands/AGGREGATE' 21 | export { FtSearchOptions } from './commands/SEARCH' 22 | -------------------------------------------------------------------------------- /packages/search/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "outDir": "./dist" 5 | }, 6 | "include": [ 7 | "./lib/**/*.ts" 8 | ], 9 | "exclude": [ 10 | "./lib/test-utils.ts", 11 | "./lib/**/*.spec.ts" 12 | ], 13 | "typedocOptions": { 14 | "entryPoints": [ 15 | "./lib" 16 | ], 17 | "entryPointStrategy": "expand", 18 | "out": "../../documentation/search" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /packages/test-utils/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG IMAGE 2 | FROM ${IMAGE} 3 | 4 | ARG REDIS_ARGUMENTS 5 | ENV REDIS_ARGUMENTS=${REDIS_ARGUMENTS} 6 | 7 | COPY ./entrypoint.sh / 8 | 9 | ENTRYPOINT ["/entrypoint.sh"] 10 | -------------------------------------------------------------------------------- /packages/test-utils/docker/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | redis-server $REDIS_ARGUMENTS 4 | -------------------------------------------------------------------------------- /packages/test-utils/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@redis/test-utils", 3 | "private": true, 4 | "main": "./dist/lib/index.js", 5 | "types": "./dist/lib/index.d.ts", 6 | "scripts": { 7 | "test": "nyc -r text-summary -r lcov mocha -r tsx './lib/**/*.spec.ts'" 8 | }, 9 | "peerDependencies": { 10 | "@redis/client": "*" 11 | }, 12 | "devDependencies": { 13 | "@types/yargs": "^17.0.32", 14 | "yargs": "^17.7.2" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/test-utils/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "outDir": "./dist" 5 | }, 6 | "include": [ 7 | "./lib/**/*.ts" 8 | ], 9 | "references": [{ 10 | "path": "../client" 11 | }] 12 | } 13 | -------------------------------------------------------------------------------- /packages/time-series/.nycrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@istanbuljs/nyc-config-typescript", 3 | "exclude": ["dist", "**/*.spec.ts", "lib/test-utils.ts"] 4 | } 5 | -------------------------------------------------------------------------------- /packages/time-series/.release-it.json: -------------------------------------------------------------------------------- 1 | { 2 | "npm": { 3 | "publish": true, 4 | "publishArgs": ["--access", "public"] 5 | }, 6 | "git": { 7 | "tagName": "time-series@${version}", 8 | "tagMatch": "time-series@*", 9 | "commitMessage": "Release ${tagName}", 10 | "tagAnnotation": "Release ${tagName}", 11 | "commitArgs": "--all" 12 | }, 13 | "plugins": { 14 | "@release-it/bumper": { 15 | "out": { 16 | "file": "package.json", 17 | "path": ["peerDependencies.@redis/client"], 18 | "versionPrefix": "^" 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/time-series/lib/commands/DECRBY.ts: -------------------------------------------------------------------------------- 1 | import { Command } from '@redis/client/dist/lib/RESP/types'; 2 | import INCRBY, { parseIncrByArguments } from './INCRBY'; 3 | 4 | export default { 5 | IS_READ_ONLY: INCRBY.IS_READ_ONLY, 6 | /** 7 | * Decreases the value of a time series by a given amount 8 | * @param args - Arguments passed to the parseIncrByArguments function 9 | */ 10 | parseCommand(...args: Parameters<typeof parseIncrByArguments>) { 11 | const parser = args[0]; 12 | 13 | parser.push('TS.DECRBY'); 14 | parseIncrByArguments(...args); 15 | }, 16 | transformReply: INCRBY.transformReply 17 | } as const satisfies Command; 18 | -------------------------------------------------------------------------------- /packages/time-series/lib/commands/REVRANGE.ts: -------------------------------------------------------------------------------- 1 | import { Command } from '@redis/client/dist/lib/RESP/types'; 2 | import RANGE, { transformRangeArguments } from './RANGE'; 3 | 4 | export default { 5 | IS_READ_ONLY: RANGE.IS_READ_ONLY, 6 | /** 7 | * Gets samples from a time series within a time range (in reverse order) 8 | * @param args - Arguments passed to the {@link transformRangeArguments} function 9 | */ 10 | parseCommand(...args: Parameters<typeof transformRangeArguments>) { 11 | const parser = args[0]; 12 | 13 | parser.push('TS.REVRANGE'); 14 | transformRangeArguments(...args); 15 | }, 16 | transformReply: RANGE.transformReply 17 | } as const satisfies Command; 18 | -------------------------------------------------------------------------------- /packages/time-series/lib/index.ts: -------------------------------------------------------------------------------- 1 | export { 2 | default, 3 | TIME_SERIES_ENCODING, TimeSeriesEncoding, 4 | TIME_SERIES_DUPLICATE_POLICIES, TimeSeriesDuplicatePolicies 5 | } from './commands'; 6 | export { TIME_SERIES_AGGREGATION_TYPE, TimeSeriesAggregationType } from './commands/CREATERULE'; 7 | export { TIME_SERIES_BUCKET_TIMESTAMP, TimeSeriesBucketTimestamp } from './commands/RANGE'; 8 | export { TIME_SERIES_REDUCERS, TimeSeriesReducer } from './commands/MRANGE_GROUPBY'; 9 | -------------------------------------------------------------------------------- /packages/time-series/lib/test-utils.ts: -------------------------------------------------------------------------------- 1 | import TestUtils from '@redis/test-utils'; 2 | import TimeSeries from '.'; 3 | 4 | export default TestUtils.createFromConfig({ 5 | dockerImageName: 'redislabs/client-libs-test', 6 | dockerImageVersionArgument: 'redis-version', 7 | defaultDockerVersion: '8.2-M01-pre' 8 | }); 9 | 10 | export const GLOBAL = { 11 | SERVERS: { 12 | OPEN: { 13 | serverArguments: [], 14 | clientOptions: { 15 | modules: { 16 | ts: TimeSeries 17 | } 18 | } 19 | } 20 | } 21 | }; 22 | -------------------------------------------------------------------------------- /packages/time-series/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "outDir": "./dist" 5 | }, 6 | "include": [ 7 | "./lib/**/*.ts" 8 | ], 9 | "exclude": [ 10 | "./lib/test-utils.ts", 11 | "./lib/**/*.spec.ts" 12 | ], 13 | "typedocOptions": { 14 | "entryPoints": [ 15 | "./lib" 16 | ], 17 | "entryPointStrategy": "expand", 18 | "out": "../../documentation/time-series" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tsconfig.base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["ES2023"], 4 | "module": "NodeNext", 5 | "moduleResolution": "NodeNext", 6 | "target": "ES2022", 7 | 8 | "strict": true, 9 | "forceConsistentCasingInFileNames": true, 10 | "noUnusedLocals": true, 11 | "esModuleInterop": true, 12 | "skipLibCheck": true, 13 | 14 | "composite": true, 15 | "sourceMap": true, 16 | "declaration": true, 17 | "declarationMap": true, 18 | "allowJs": true, 19 | "resolveJsonModule": true 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [ 4 | { 5 | "path": "./packages/client" 6 | }, 7 | { 8 | "path": "./packages/test-utils" 9 | }, 10 | { 11 | "path": "./packages/bloom" 12 | }, 13 | { 14 | "path": "./packages/json" 15 | }, 16 | { 17 | "path": "./packages/search" 18 | }, 19 | { 20 | "path": "./packages/time-series" 21 | }, 22 | { 23 | "path": "./packages/entraid" 24 | }, 25 | { 26 | "path": "./packages/redis" 27 | } 28 | ] 29 | } 30 | --------------------------------------------------------------------------------