Skip to main content
Module

x/redis/redis.ts

πŸ¦• Redis client for Deno πŸ•
Very Popular
Latest
File
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495
import type { ACLLogMode, BitfieldOpts, BitfieldWithOverflowOpts, ClientCachingMode, ClientKillOpts, ClientListOpts, ClientPauseMode, ClientTrackingOpts, ClientUnblockingBehaviour, ClusterFailoverMode, ClusterResetMode, ClusterSetSlotSubcommand, GeoRadiusOpts, GeoUnit, HScanOpts, LInsertLocation, LPosOpts, LPosWithCountOpts, MemoryUsageOpts, MigrateOpts, RedisCommands, RestoreOpts, ScanOpts, ScriptDebugMode, SetOpts, SetWithModeOpts, ShutdownMode, SortOpts, SortWithDestinationOpts, SScanOpts, StralgoAlgorithm, StralgoOpts, StralgoTarget, ZAddOpts, ZInterOpts, ZInterstoreOpts, ZRangeByLexOpts, ZRangeByScoreOpts, ZRangeOpts, ZScanOpts, ZUnionstoreOpts,} from "./command.ts";import { RedisConnection } from "./connection.ts";import type { Connection, SendCommandOptions } from "./connection.ts";import type { RedisConnectionOptions } from "./connection.ts";import { CommandExecutor, DefaultExecutor } from "./executor.ts";import type { Binary, Bulk, BulkNil, BulkString, ConditionalArray, Integer, Raw, RedisReply, RedisValue, SimpleString,} from "./protocol/shared/types.ts";import { createRedisPipeline } from "./pipeline.ts";import type { RedisSubscription } from "./pubsub.ts";import { psubscribe, subscribe } from "./pubsub.ts";import { convertMap, isCondArray, isNumber, isString, parseXGroupDetail, parseXId, parseXMessage, parseXPendingConsumers, parseXPendingCounts, parseXReadReply, rawnum, rawstr, StartEndCount, XAddFieldValues, XClaimJustXId, XClaimMessages, XClaimOpts, XId, XIdAdd, XIdInput, XIdNeg, XIdPos, xidstr, XKeyId, XKeyIdGroup, XKeyIdGroupLike, XKeyIdLike, XMaxlen, XReadGroupOpts, XReadIdData, XReadOpts, XReadStreamRaw,} from "./stream.ts";
const binaryCommandOptions = { returnUint8Arrays: true,};
export interface Redis extends RedisCommands { readonly isClosed: boolean; readonly isConnected: boolean;
/** * Low level interface for Redis server */ sendCommand( command: string, args?: RedisValue[], options?: SendCommandOptions, ): Promise<RedisReply>; connect(): Promise<void>; close(): void; [Symbol.dispose](): void;}
class RedisImpl implements Redis { private readonly executor: CommandExecutor;
get isClosed() { return this.executor.connection.isClosed; }
get isConnected() { return this.executor.connection.isConnected; }
constructor(executor: CommandExecutor) { this.executor = executor; }
sendCommand( command: string, args?: RedisValue[], options?: SendCommandOptions, ) { return this.executor.sendCommand(command, args, options); }
connect(): Promise<void> { return this.executor.connection.connect(); }
close(): void { return this.executor.close(); }
[Symbol.dispose](): void { return this.close(); }
async execReply<T extends Raw = Raw>( command: string, ...args: RedisValue[] ): Promise<T> { const reply = await this.executor.exec( command, ...args, ); return reply as T; }
async execStatusReply( command: string, ...args: RedisValue[] ): Promise<SimpleString> { const reply = await this.executor.exec(command, ...args); return reply as SimpleString; }
async execIntegerReply( command: string, ...args: RedisValue[] ): Promise<Integer> { const reply = await this.executor.exec(command, ...args); return reply as Integer; }
async execBinaryReply( command: string, ...args: RedisValue[] ): Promise<Binary | BulkNil> { const reply = await this.executor.sendCommand( command, args, binaryCommandOptions, ); return reply as Binary | BulkNil; }
async execBulkReply<T extends Bulk = Bulk>( command: string, ...args: RedisValue[] ): Promise<T> { const reply = await this.executor.exec(command, ...args); return reply as T; }
async execArrayReply<T extends Raw = Raw>( command: string, ...args: RedisValue[] ): Promise<T[]> { const reply = await this.executor.exec(command, ...args); return reply as Array<T>; }
async execIntegerOrNilReply( command: string, ...args: RedisValue[] ): Promise<Integer | BulkNil> { const reply = await this.executor.exec(command, ...args); return reply as Integer | BulkNil; }
async execStatusOrNilReply( command: string, ...args: RedisValue[] ): Promise<SimpleString | BulkNil> { const reply = await this.executor.exec(command, ...args); return reply as SimpleString | BulkNil; }
aclCat(categoryname?: string) { if (categoryname !== undefined) { return this.execArrayReply<BulkString>("ACL", "CAT", categoryname); } return this.execArrayReply<BulkString>("ACL", "CAT"); }
aclDelUser(...usernames: string[]) { return this.execIntegerReply("ACL", "DELUSER", ...usernames); }
aclGenPass(bits?: number) { if (bits !== undefined) { return this.execBulkReply<BulkString>("ACL", "GENPASS", bits); } return this.execBulkReply<BulkString>("ACL", "GENPASS"); }
aclGetUser(username: string) { return this.execArrayReply<BulkString | BulkString[]>( "ACL", "GETUSER", username, ); }
aclHelp() { return this.execArrayReply<BulkString>("ACL", "HELP"); }
aclList() { return this.execArrayReply<BulkString>("ACL", "LIST"); }
aclLoad() { return this.execStatusReply("ACL", "LOAD"); }
aclLog(count: number): Promise<BulkString[]>; aclLog(mode: ACLLogMode): Promise<SimpleString>; aclLog(param: number | ACLLogMode) { if (param === "RESET") { return this.execStatusReply("ACL", "LOG", "RESET"); } return this.execArrayReply<BulkString>("ACL", "LOG", param); }
aclSave() { return this.execStatusReply("ACL", "SAVE"); }
aclSetUser(username: string, ...rules: string[]) { return this.execStatusReply("ACL", "SETUSER", username, ...rules); }
aclUsers() { return this.execArrayReply<BulkString>("ACL", "USERS"); }
aclWhoami() { return this.execBulkReply<BulkString>("ACL", "WHOAMI"); }
append(key: string, value: RedisValue) { return this.execIntegerReply("APPEND", key, value); }
auth(param1: RedisValue, param2?: RedisValue) { if (param2 !== undefined) { return this.execStatusReply("AUTH", param1, param2); } return this.execStatusReply("AUTH", param1); }
bgrewriteaof() { return this.execStatusReply("BGREWRITEAOF"); }
bgsave() { return this.execStatusReply("BGSAVE"); }
bitcount(key: string, start?: number, end?: number) { if (start !== undefined && end !== undefined) { return this.execIntegerReply("BITCOUNT", key, start, end); } return this.execIntegerReply("BITCOUNT", key); }
bitfield( key: string, opts?: BitfieldOpts | BitfieldWithOverflowOpts, ) { const args: (number | string)[] = [key]; if (opts?.get) { const { type, offset } = opts.get; args.push("GET", type, offset); } if (opts?.set) { const { type, offset, value } = opts.set; args.push("SET", type, offset, value); } if (opts?.incrby) { const { type, offset, increment } = opts.incrby; args.push("INCRBY", type, offset, increment); } if ((opts as BitfieldWithOverflowOpts)?.overflow) { args.push("OVERFLOW", (opts as BitfieldWithOverflowOpts).overflow); } return this.execArrayReply<Integer>("BITFIELD", ...args); }
bitop(operation: string, destkey: string, ...keys: string[]) { return this.execIntegerReply("BITOP", operation, destkey, ...keys); }
bitpos(key: string, bit: number, start?: number, end?: number) { if (start !== undefined && end !== undefined) { return this.execIntegerReply("BITPOS", key, bit, start, end); } if (start !== undefined) { return this.execIntegerReply("BITPOS", key, bit, start); } return this.execIntegerReply("BITPOS", key, bit); }
blpop(timeout: number, ...keys: string[]) { return this.execArrayReply("BLPOP", ...keys, timeout) as Promise< [BulkString, BulkString] | BulkNil >; }
brpop(timeout: number, ...keys: string[]) { return this.execArrayReply("BRPOP", ...keys, timeout) as Promise< [BulkString, BulkString] | BulkNil >; }
brpoplpush(source: string, destination: string, timeout: number) { return this.execBulkReply("BRPOPLPUSH", source, destination, timeout); }
bzpopmin(timeout: number, ...keys: string[]) { return this.execArrayReply("BZPOPMIN", ...keys, timeout) as Promise< [BulkString, BulkString, BulkString] | BulkNil >; }
bzpopmax(timeout: number, ...keys: string[]) { return this.execArrayReply("BZPOPMAX", ...keys, timeout) as Promise< [BulkString, BulkString, BulkString] | BulkNil >; }
clientCaching(mode: ClientCachingMode) { return this.execStatusReply("CLIENT", "CACHING", mode); }
clientGetName() { return this.execBulkReply("CLIENT", "GETNAME"); }
clientGetRedir() { return this.execIntegerReply("CLIENT", "GETREDIR"); }
clientID() { return this.execIntegerReply("CLIENT", "ID"); }
clientInfo() { return this.execBulkReply("CLIENT", "INFO"); }
clientKill(opts: ClientKillOpts) { const args: (string | number)[] = []; if (opts.addr) { args.push("ADDR", opts.addr); } if (opts.laddr) { args.push("LADDR", opts.laddr); } if (opts.id) { args.push("ID", opts.id); } if (opts.type) { args.push("TYPE", opts.type); } if (opts.user) { args.push("USER", opts.user); } if (opts.skipme) { args.push("SKIPME", opts.skipme); } return this.execIntegerReply("CLIENT", "KILL", ...args); }
clientList(opts?: ClientListOpts) { if (opts && opts.type && opts.ids) { throw new Error("only one of `type` or `ids` can be specified"); } if (opts && opts.type) { return this.execBulkReply("CLIENT", "LIST", "TYPE", opts.type); } if (opts && opts.ids) { return this.execBulkReply("CLIENT", "LIST", "ID", ...opts.ids); } return this.execBulkReply("CLIENT", "LIST"); }
clientPause(timeout: number, mode?: ClientPauseMode) { if (mode) { return this.execStatusReply("CLIENT", "PAUSE", timeout, mode); } return this.execStatusReply("CLIENT", "PAUSE", timeout); }
clientSetName(connectionName: string) { return this.execStatusReply("CLIENT", "SETNAME", connectionName); }
clientTracking(opts: ClientTrackingOpts) { const args: (number | string)[] = [opts.mode]; if (opts.redirect) { args.push("REDIRECT", opts.redirect); } if (opts.prefixes) { opts.prefixes.forEach((prefix) => { args.push("PREFIX"); args.push(prefix); }); } if (opts.bcast) { args.push("BCAST"); } if (opts.optIn) { args.push("OPTIN"); } if (opts.optOut) { args.push("OPTOUT"); } if (opts.noLoop) { args.push("NOLOOP"); } return this.execStatusReply("CLIENT", "TRACKING", ...args); }
clientTrackingInfo() { return this.execArrayReply("CLIENT", "TRACKINGINFO"); }
clientUnblock( id: number, behaviour?: ClientUnblockingBehaviour, ): Promise<Integer> { if (behaviour) { return this.execIntegerReply("CLIENT", "UNBLOCK", id, behaviour); } return this.execIntegerReply("CLIENT", "UNBLOCK", id); }
clientUnpause(): Promise<SimpleString> { return this.execStatusReply("CLIENT", "UNPAUSE"); }
asking() { return this.execStatusReply("ASKING"); }
clusterAddSlots(...slots: number[]) { return this.execStatusReply("CLUSTER", "ADDSLOTS", ...slots); }
clusterCountFailureReports(nodeId: string) { return this.execIntegerReply("CLUSTER", "COUNT-FAILURE-REPORTS", nodeId); }
clusterCountKeysInSlot(slot: number) { return this.execIntegerReply("CLUSTER", "COUNTKEYSINSLOT", slot); }
clusterDelSlots(...slots: number[]) { return this.execStatusReply("CLUSTER", "DELSLOTS", ...slots); }
clusterFailover(mode?: ClusterFailoverMode) { if (mode) { return this.execStatusReply("CLUSTER", "FAILOVER", mode); } return this.execStatusReply("CLUSTER", "FAILOVER"); }
clusterFlushSlots() { return this.execStatusReply("CLUSTER", "FLUSHSLOTS"); }
clusterForget(nodeId: string) { return this.execStatusReply("CLUSTER", "FORGET", nodeId); }
clusterGetKeysInSlot(slot: number, count: number) { return this.execArrayReply<BulkString>( "CLUSTER", "GETKEYSINSLOT", slot, count, ); }
clusterInfo() { return this.execStatusReply("CLUSTER", "INFO"); }
clusterKeySlot(key: string) { return this.execIntegerReply("CLUSTER", "KEYSLOT", key); }
clusterMeet(ip: string, port: number) { return this.execStatusReply("CLUSTER", "MEET", ip, port); }
clusterMyID() { return this.execStatusReply("CLUSTER", "MYID"); }
clusterNodes() { return this.execBulkReply<BulkString>("CLUSTER", "NODES"); }
clusterReplicas(nodeId: string) { return this.execArrayReply<BulkString>("CLUSTER", "REPLICAS", nodeId); }
clusterReplicate(nodeId: string) { return this.execStatusReply("CLUSTER", "REPLICATE", nodeId); }
clusterReset(mode?: ClusterResetMode) { if (mode) { return this.execStatusReply("CLUSTER", "RESET", mode); } return this.execStatusReply("CLUSTER", "RESET"); }
clusterSaveConfig() { return this.execStatusReply("CLUSTER", "SAVECONFIG"); }
clusterSetSlot( slot: number, subcommand: ClusterSetSlotSubcommand, nodeId?: string, ) { if (nodeId !== undefined) { return this.execStatusReply( "CLUSTER", "SETSLOT", slot, subcommand, nodeId, ); } return this.execStatusReply("CLUSTER", "SETSLOT", slot, subcommand); }
clusterSlaves(nodeId: string) { return this.execArrayReply<BulkString>("CLUSTER", "SLAVES", nodeId); }
clusterSlots() { return this.execArrayReply("CLUSTER", "SLOTS"); }
command() { return this.execArrayReply("COMMAND") as Promise< [BulkString, Integer, BulkString[], Integer, Integer, Integer][] >; }
commandCount() { return this.execIntegerReply("COMMAND", "COUNT"); }
commandGetKeys() { return this.execArrayReply<BulkString>("COMMAND", "GETKEYS"); }
commandInfo(...commandNames: string[]) { return this.execArrayReply("COMMAND", "INFO", ...commandNames) as Promise< ( | [BulkString, Integer, BulkString[], Integer, Integer, Integer] | BulkNil )[] >; }
configGet(parameter: string) { return this.execArrayReply<BulkString>("CONFIG", "GET", parameter); }
configResetStat() { return this.execStatusReply("CONFIG", "RESETSTAT"); }
configRewrite() { return this.execStatusReply("CONFIG", "REWRITE"); }
configSet(parameter: string, value: string | number) { return this.execStatusReply("CONFIG", "SET", parameter, value); }
dbsize() { return this.execIntegerReply("DBSIZE"); }
debugObject(key: string) { return this.execStatusReply("DEBUG", "OBJECT", key); }
debugSegfault() { return this.execStatusReply("DEBUG", "SEGFAULT"); }
decr(key: string) { return this.execIntegerReply("DECR", key); }
decrby(key: string, decrement: number) { return this.execIntegerReply("DECRBY", key, decrement); }
del(...keys: string[]) { return this.execIntegerReply("DEL", ...keys); }
discard() { return this.execStatusReply("DISCARD"); }
dump(key: string) { return this.execBinaryReply("DUMP", key); }
echo(message: RedisValue) { return this.execBulkReply<BulkString>("ECHO", message); }
eval(script: string, keys: string[], args: string[]) { return this.execReply( "EVAL", script, keys.length, ...keys, ...args, ); }
evalsha(sha1: string, keys: string[], args: string[]) { return this.execReply( "EVALSHA", sha1, keys.length, ...keys, ...args, ); }
exec() { return this.execArrayReply("EXEC"); }
exists(...keys: string[]) { return this.execIntegerReply("EXISTS", ...keys); }
expire(key: string, seconds: number) { return this.execIntegerReply("EXPIRE", key, seconds); }
expireat(key: string, timestamp: string) { return this.execIntegerReply("EXPIREAT", key, timestamp); }
flushall(async?: boolean) { if (async) { return this.execStatusReply("FLUSHALL", "ASYNC"); } return this.execStatusReply("FLUSHALL"); }
flushdb(async?: boolean) { if (async) { return this.execStatusReply("FLUSHDB", "ASYNC"); } return this.execStatusReply("FLUSHDB"); }
// deno-lint-ignore no-explicit-any geoadd(key: string, ...params: any[]) { const args: (string | number)[] = [key]; if (Array.isArray(params[0])) { args.push(...params.flatMap((e) => e)); } else if (typeof params[0] === "object") { for (const [member, lnglat] of Object.entries(params[0])) { args.push(...(lnglat as [number, number]), member); } } else { args.push(...params); } return this.execIntegerReply("GEOADD", ...args); }
geohash(key: string, ...members: string[]) { return this.execArrayReply<Bulk>("GEOHASH", key, ...members); }
geopos(key: string, ...members: string[]) { return this.execArrayReply("GEOPOS", key, ...members) as Promise< ([BulkString, BulkString] | BulkNil | [])[] >; }
geodist( key: string, member1: string, member2: string, unit?: GeoUnit, ) { if (unit) { return this.execBulkReply("GEODIST", key, member1, member2, unit); } return this.execBulkReply("GEODIST", key, member1, member2); }
georadius( key: string, longitude: number, latitude: number, radius: number, unit: "m" | "km" | "ft" | "mi", opts?: GeoRadiusOpts, ) { const args = this.pushGeoRadiusOpts( [key, longitude, latitude, radius, unit], opts, ); return this.execArrayReply("GEORADIUS", ...args); }
georadiusbymember( key: string, member: string, radius: number, unit: GeoUnit, opts?: GeoRadiusOpts, ) { const args = this.pushGeoRadiusOpts([key, member, radius, unit], opts); return this.execArrayReply("GEORADIUSBYMEMBER", ...args); }
private pushGeoRadiusOpts( args: (string | number)[], opts?: GeoRadiusOpts, ) { if (opts?.withCoord) { args.push("WITHCOORD"); } if (opts?.withDist) { args.push("WITHDIST"); } if (opts?.withHash) { args.push("WITHHASH"); } if (opts?.count !== undefined) { args.push(opts.count); } if (opts?.sort) { args.push(opts.sort); } if (opts?.store !== undefined) { args.push(opts.store); } if (opts?.storeDist !== undefined) { args.push(opts.storeDist); } return args; }
get(key: string) { return this.execBulkReply("GET", key); }
getbit(key: string, offset: number) { return this.execIntegerReply("GETBIT", key, offset); }
getrange(key: string, start: number, end: number) { return this.execBulkReply<BulkString>("GETRANGE", key, start, end); }
getset(key: string, value: RedisValue) { return this.execBulkReply("GETSET", key, value); }
hdel(key: string, ...fields: string[]) { return this.execIntegerReply("HDEL", key, ...fields); }
hexists(key: string, field: string) { return this.execIntegerReply("HEXISTS", key, field); }
hget(key: string, field: string) { return this.execBulkReply("HGET", key, field); }
hgetall(key: string) { return this.execArrayReply<BulkString>("HGETALL", key); }
hincrby(key: string, field: string, increment: number) { return this.execIntegerReply("HINCRBY", key, field, increment); }
hincrbyfloat(key: string, field: string, increment: number) { return this.execBulkReply<BulkString>( "HINCRBYFLOAT", key, field, increment, ); }
hkeys(key: string) { return this.execArrayReply<BulkString>("HKEYS", key); }
hlen(key: string) { return this.execIntegerReply("HLEN", key); }
hmget(key: string, ...fields: string[]) { return this.execArrayReply<Bulk>("HMGET", key, ...fields); }
// deno-lint-ignore no-explicit-any hmset(key: string, ...params: any[]) { const args = [key] as RedisValue[]; if (Array.isArray(params[0])) { args.push(...params.flatMap((e) => e)); } else if (typeof params[0] === "object") { for (const [field, value] of Object.entries(params[0])) { args.push(field, value as RedisValue); } } else { args.push(...params); } return this.execStatusReply("HMSET", ...args); }
// deno-lint-ignore no-explicit-any hset(key: string, ...params: any[]) { const args = [key] as RedisValue[]; if (Array.isArray(params[0])) { args.push(...params.flatMap((e) => e)); } else if (typeof params[0] === "object") { for (const [field, value] of Object.entries(params[0])) { args.push(field, value as RedisValue); } } else { args.push(...params); } return this.execIntegerReply("HSET", ...args); }
hsetnx(key: string, field: string, value: RedisValue) { return this.execIntegerReply("HSETNX", key, field, value); }
hstrlen(key: string, field: string) { return this.execIntegerReply("HSTRLEN", key, field); }
hvals(key: string) { return this.execArrayReply<BulkString>("HVALS", key); }
incr(key: string) { return this.execIntegerReply("INCR", key); }
incrby(key: string, increment: number) { return this.execIntegerReply("INCRBY", key, increment); }
incrbyfloat(key: string, increment: number) { return this.execBulkReply<BulkString>("INCRBYFLOAT", key, increment); }
info(section?: string) { if (section !== undefined) { return this.execStatusReply("INFO", section); } return this.execStatusReply("INFO"); }
keys(pattern: string) { return this.execArrayReply<BulkString>("KEYS", pattern); }
lastsave() { return this.execIntegerReply("LASTSAVE"); }
lindex(key: string, index: number) { return this.execBulkReply("LINDEX", key, index); }
linsert(key: string, loc: LInsertLocation, pivot: string, value: RedisValue) { return this.execIntegerReply("LINSERT", key, loc, pivot, value); }
llen(key: string) { return this.execIntegerReply("LLEN", key); }
lpop(key: string) { return this.execBulkReply("LPOP", key); }
lpos( key: string, element: RedisValue, opts?: LPosOpts, ): Promise<Integer | BulkNil>;
lpos( key: string, element: RedisValue, opts: LPosWithCountOpts, ): Promise<Integer[]>;
lpos( key: string, element: RedisValue, opts?: LPosOpts | LPosWithCountOpts, ): Promise<Integer | BulkNil | Integer[]> { const args = [element]; if (opts?.rank != null) { args.push("RANK", String(opts.rank)); }
if (opts?.count != null) { args.push("COUNT", String(opts.count)); }
if (opts?.maxlen != null) { args.push("MAXLEN", String(opts.maxlen)); }
return opts?.count == null ? this.execIntegerReply("LPOS", key, ...args) : this.execArrayReply<Integer>("LPOS", key, ...args); }
lpush(key: string, ...elements: RedisValue[]) { return this.execIntegerReply("LPUSH", key, ...elements); }
lpushx(key: string, ...elements: RedisValue[]) { return this.execIntegerReply("LPUSHX", key, ...elements); }
lrange(key: string, start: number, stop: number) { return this.execArrayReply<BulkString>("LRANGE", key, start, stop); }
lrem(key: string, count: number, element: string | number) { return this.execIntegerReply("LREM", key, count, element); }
lset(key: string, index: number, element: string | number) { return this.execStatusReply("LSET", key, index, element); }
ltrim(key: string, start: number, stop: number) { return this.execStatusReply("LTRIM", key, start, stop); }
memoryDoctor() { return this.execBulkReply<BulkString>("MEMORY", "DOCTOR"); }
memoryHelp() { return this.execArrayReply<BulkString>("MEMORY", "HELP"); }
memoryMallocStats() { return this.execBulkReply<BulkString>("MEMORY", "MALLOC", "STATS"); }
memoryPurge() { return this.execStatusReply("MEMORY", "PURGE"); }
memoryStats() { return this.execArrayReply("MEMORY", "STATS"); }
memoryUsage(key: string, opts?: MemoryUsageOpts) { const args: (number | string)[] = [key]; if (opts?.samples !== undefined) { args.push("SAMPLES", opts.samples); } return this.execIntegerReply("MEMORY", "USAGE", ...args); }
mget(...keys: string[]) { return this.execArrayReply<Bulk>("MGET", ...keys); }
migrate( host: string, port: number, key: string, destinationDB: string, timeout: number, opts?: MigrateOpts, ) { const args = [host, port, key, destinationDB, timeout]; if (opts?.copy) { args.push("COPY"); } if (opts?.replace) { args.push("REPLACE"); } if (opts?.auth !== undefined) { args.push("AUTH", opts.auth); } if (opts?.keys) { args.push("KEYS", ...opts.keys); } return this.execStatusReply("MIGRATE", ...args); }
moduleList() { return this.execArrayReply<BulkString>("MODULE", "LIST"); }
moduleLoad(path: string, ...args: string[]) { return this.execStatusReply("MODULE", "LOAD", path, ...args); }
moduleUnload(name: string) { return this.execStatusReply("MODULE", "UNLOAD", name); }
monitor() { throw new Error("not supported yet"); }
move(key: string, db: string) { return this.execIntegerReply("MOVE", key, db); }
// deno-lint-ignore no-explicit-any mset(...params: any[]) { const args: RedisValue[] = []; if (Array.isArray(params[0])) { args.push(...params.flatMap((e) => e)); } else if (typeof params[0] === "object") { for (const [key, value] of Object.entries(params[0])) { args.push(key, value as RedisValue); } } else { args.push(...params); } return this.execStatusReply("MSET", ...args); }
// deno-lint-ignore no-explicit-any msetnx(...params: any[]) { const args: RedisValue[] = []; if (Array.isArray(params[0])) { args.push(...params.flatMap((e) => e)); } else if (typeof params[0] === "object") { for (const [key, value] of Object.entries(params[0])) { args.push(key, value as RedisValue); } } else { args.push(...params); } return this.execIntegerReply("MSETNX", ...args); }
multi() { return this.execStatusReply("MULTI"); }
objectEncoding(key: string) { return this.execBulkReply("OBJECT", "ENCODING", key); }
objectFreq(key: string) { return this.execIntegerOrNilReply("OBJECT", "FREQ", key); }
objectHelp() { return this.execArrayReply<BulkString>("OBJECT", "HELP"); }
objectIdletime(key: string) { return this.execIntegerOrNilReply("OBJECT", "IDLETIME", key); }
objectRefCount(key: string) { return this.execIntegerOrNilReply("OBJECT", "REFCOUNT", key); }
persist(key: string) { return this.execIntegerReply("PERSIST", key); }
pexpire(key: string, milliseconds: number) { return this.execIntegerReply("PEXPIRE", key, milliseconds); }
pexpireat(key: string, millisecondsTimestamp: number) { return this.execIntegerReply("PEXPIREAT", key, millisecondsTimestamp); }
pfadd(key: string, ...elements: string[]) { return this.execIntegerReply("PFADD", key, ...elements); }
pfcount(...keys: string[]) { return this.execIntegerReply("PFCOUNT", ...keys); }
pfmerge(destkey: string, ...sourcekeys: string[]) { return this.execStatusReply("PFMERGE", destkey, ...sourcekeys); }
ping(message?: RedisValue) { if (message) { return this.execBulkReply<BulkString>("PING", message); } return this.execStatusReply("PING"); }
psetex(key: string, milliseconds: number, value: RedisValue) { return this.execStatusReply("PSETEX", key, milliseconds, value); }
publish(channel: string, message: string) { return this.execIntegerReply("PUBLISH", channel, message); }
// deno-lint-ignore no-explicit-any #subscription?: RedisSubscription<any>; async subscribe<TMessage extends string | string[] = string>( ...channels: string[] ) { if (this.#subscription) { await this.#subscription.subscribe(...channels); return this.#subscription; } const subscription = await subscribe<TMessage>(this.executor, ...channels); this.#subscription = subscription; return subscription; }
async psubscribe<TMessage extends string | string[] = string>( ...patterns: string[] ) { if (this.#subscription) { await this.#subscription.psubscribe(...patterns); return this.#subscription; } const subscription = await psubscribe<TMessage>(this.executor, ...patterns); this.#subscription = subscription; return subscription; }
pubsubChannels(pattern?: string) { if (pattern !== undefined) { return this.execArrayReply<BulkString>("PUBSUB", "CHANNELS", pattern); } return this.execArrayReply<BulkString>("PUBSUB", "CHANNELS"); }
pubsubNumpat() { return this.execIntegerReply("PUBSUB", "NUMPAT"); }
pubsubNumsub(...channels: string[]) { return this.execArrayReply<BulkString | Integer>( "PUBSUB", "NUMSUB", ...channels, ); }
pttl(key: string) { return this.execIntegerReply("PTTL", key); }
quit() { return this.execStatusReply("QUIT").finally(() => this.close()); }
randomkey() { return this.execBulkReply("RANDOMKEY"); }
readonly() { return this.execStatusReply("READONLY"); }
readwrite() { return this.execStatusReply("READWRITE"); }
rename(key: string, newkey: string) { return this.execStatusReply("RENAME", key, newkey); }
renamenx(key: string, newkey: string) { return this.execIntegerReply("RENAMENX", key, newkey); }
restore( key: string, ttl: number, serializedValue: Binary, opts?: RestoreOpts, ) { const args = [key, ttl, serializedValue]; if (opts?.replace) { args.push("REPLACE"); } if (opts?.absttl) { args.push("ABSTTL"); } if (opts?.idletime !== undefined) { args.push("IDLETIME", opts.idletime); } if (opts?.freq !== undefined) { args.push("FREQ", opts.freq); } return this.execStatusReply("RESTORE", ...args); }
role() { return this.execArrayReply("ROLE") as Promise< | ["master", Integer, BulkString[][]] | ["slave", BulkString, Integer, BulkString, Integer] | ["sentinel", BulkString[]] >; }
rpop(key: string) { return this.execBulkReply("RPOP", key); }
rpoplpush(source: string, destination: string) { return this.execBulkReply("RPOPLPUSH", source, destination); }
rpush(key: string, ...elements: RedisValue[]) { return this.execIntegerReply("RPUSH", key, ...elements); }
rpushx(key: string, ...elements: RedisValue[]) { return this.execIntegerReply("RPUSHX", key, ...elements); }
sadd(key: string, ...members: string[]) { return this.execIntegerReply("SADD", key, ...members); }
save() { return this.execStatusReply("SAVE"); }
scard(key: string) { return this.execIntegerReply("SCARD", key); }
scriptDebug(mode: ScriptDebugMode) { return this.execStatusReply("SCRIPT", "DEBUG", mode); }
scriptExists(...sha1s: string[]) { return this.execArrayReply<Integer>("SCRIPT", "EXISTS", ...sha1s); }
scriptFlush() { return this.execStatusReply("SCRIPT", "FLUSH"); }
scriptKill() { return this.execStatusReply("SCRIPT", "KILL"); }
scriptLoad(script: string) { return this.execStatusReply("SCRIPT", "LOAD", script); }
sdiff(...keys: string[]) { return this.execArrayReply<BulkString>("SDIFF", ...keys); }
sdiffstore(destination: string, ...keys: string[]) { return this.execIntegerReply("SDIFFSTORE", destination, ...keys); }
select(index: number) { return this.execStatusReply("SELECT", index); }
set( key: string, value: RedisValue, opts?: SetOpts, ): Promise<SimpleString>; set( key: string, value: RedisValue, opts?: SetWithModeOpts, ): Promise<SimpleString | BulkNil>; set( key: string, value: RedisValue, opts?: SetOpts | SetWithModeOpts, ) { const args: RedisValue[] = [key, value]; if (opts?.ex !== undefined) { args.push("EX", opts.ex); } else if (opts?.px !== undefined) { args.push("PX", opts.px); } if (opts?.keepttl) { args.push("KEEPTTL"); } if ((opts as SetWithModeOpts)?.mode) { args.push((opts as SetWithModeOpts).mode); return this.execStatusOrNilReply("SET", ...args); } return this.execStatusReply("SET", ...args); }
setbit(key: string, offset: number, value: RedisValue) { return this.execIntegerReply("SETBIT", key, offset, value); }
setex(key: string, seconds: number, value: RedisValue) { return this.execStatusReply("SETEX", key, seconds, value); }
setnx(key: string, value: RedisValue) { return this.execIntegerReply("SETNX", key, value); }
setrange(key: string, offset: number, value: RedisValue) { return this.execIntegerReply("SETRANGE", key, offset, value); }
shutdown(mode?: ShutdownMode) { if (mode) { return this.execStatusReply("SHUTDOWN", mode); } return this.execStatusReply("SHUTDOWN"); }
sinter(...keys: string[]) { return this.execArrayReply<BulkString>("SINTER", ...keys); }
sinterstore(destination: string, ...keys: string[]) { return this.execIntegerReply("SINTERSTORE", destination, ...keys); }
sismember(key: string, member: string) { return this.execIntegerReply("SISMEMBER", key, member); }
slaveof(host: string, port: number) { return this.execStatusReply("SLAVEOF", host, port); }
slaveofNoOne() { return this.execStatusReply("SLAVEOF", "NO ONE"); }
replicaof(host: string, port: number) { return this.execStatusReply("REPLICAOF", host, port); }
replicaofNoOne() { return this.execStatusReply("REPLICAOF", "NO ONE"); }
slowlog(subcommand: string, ...args: string[]) { return this.execArrayReply("SLOWLOG", subcommand, ...args); }
smembers(key: string) { return this.execArrayReply<BulkString>("SMEMBERS", key); }
smove(source: string, destination: string, member: string) { return this.execIntegerReply("SMOVE", source, destination, member); }
sort( key: string, opts?: SortOpts, ): Promise<BulkString[]>; sort( key: string, opts?: SortWithDestinationOpts, ): Promise<Integer>; sort( key: string, opts?: SortOpts | SortWithDestinationOpts, ) { const args: (number | string)[] = [key]; if (opts?.by !== undefined) { args.push("BY", opts.by); } if (opts?.limit) { args.push("LIMIT", opts.limit.offset, opts.limit.count); } if (opts?.patterns) { args.push(...opts.patterns.flatMap((pattern) => ["GET", pattern])); } if (opts?.order) { args.push(opts.order); } if (opts?.alpha) { args.push("ALPHA"); } if ((opts as SortWithDestinationOpts)?.destination !== undefined) { args.push("STORE", (opts as SortWithDestinationOpts).destination); return this.execIntegerReply("SORT", ...args); } return this.execArrayReply<BulkString>("SORT", ...args); }
spop(key: string): Promise<Bulk>; spop(key: string, count: number): Promise<BulkString[]>; spop(key: string, count?: number) { if (count !== undefined) { return this.execArrayReply<BulkString>("SPOP", key, count); } return this.execBulkReply("SPOP", key); }
srandmember(key: string): Promise<Bulk>; srandmember(key: string, count: number): Promise<BulkString[]>; srandmember(key: string, count?: number) { if (count !== undefined) { return this.execArrayReply<BulkString>("SRANDMEMBER", key, count); } return this.execBulkReply("SRANDMEMBER", key); }
srem(key: string, ...members: string[]) { return this.execIntegerReply("SREM", key, ...members); }
stralgo( algorithm: StralgoAlgorithm, target: StralgoTarget, a: string, b: string, ): Promise<Bulk>;
stralgo( algorithm: StralgoAlgorithm, target: StralgoTarget, a: string, b: string, opts?: { len: true }, ): Promise<Integer>;
stralgo( algorithm: StralgoAlgorithm, target: StralgoTarget, a: string, b: string, opts?: { idx: true }, ): Promise< [ string, //`"matches"` Array<[[number, number], [number, number]]>, string, // `"len"` Integer, ] >;
stralgo( algorithm: StralgoAlgorithm, target: StralgoTarget, a: string, b: string, opts?: { idx: true; withmatchlen: true }, ): Promise< [ string, // `"matches"` Array<[[number, number], [number, number], number]>, string, // `"len"` Integer, ] >;
stralgo( algorithm: StralgoAlgorithm, target: StralgoTarget, a: string, b: string, opts?: StralgoOpts, ) { const args: (number | string)[] = []; if (opts?.idx) { args.push("IDX"); } if (opts?.len) { args.push("LEN"); } if (opts?.withmatchlen) { args.push("WITHMATCHLEN"); } if (opts?.minmatchlen) { args.push("MINMATCHLEN"); args.push(opts.minmatchlen); } return this.execReply<Bulk | Integer | ConditionalArray>( "STRALGO", algorithm, target, a, b, ...args, ); }
strlen(key: string) { return this.execIntegerReply("STRLEN", key); }
sunion(...keys: string[]) { return this.execArrayReply<BulkString>("SUNION", ...keys); }
sunionstore(destination: string, ...keys: string[]) { return this.execIntegerReply("SUNIONSTORE", destination, ...keys); }
swapdb(index1: number, index2: number) { return this.execStatusReply("SWAPDB", index1, index2); }
sync() { throw new Error("not implemented"); }
time() { return this.execArrayReply("TIME") as Promise<[BulkString, BulkString]>; }
touch(...keys: string[]) { return this.execIntegerReply("TOUCH", ...keys); }
ttl(key: string) { return this.execIntegerReply("TTL", key); }
type(key: string) { return this.execStatusReply("TYPE", key); }
unlink(...keys: string[]) { return this.execIntegerReply("UNLINK", ...keys); }
unwatch() { return this.execStatusReply("UNWATCH"); }
wait(numreplicas: number, timeout: number) { return this.execIntegerReply("WAIT", numreplicas, timeout); }
watch(...keys: string[]) { return this.execStatusReply("WATCH", ...keys); }
xack(key: string, group: string, ...xids: XIdInput[]) { return this.execIntegerReply( "XACK", key, group, ...xids.map((xid) => xidstr(xid)), ); }
xadd( key: string, xid: XIdAdd, fieldValues: XAddFieldValues, maxlen: XMaxlen | undefined = undefined, ) { const args: RedisValue[] = [key];
if (maxlen) { args.push("MAXLEN"); if (maxlen.approx) { args.push("~"); } args.push(maxlen.elements.toString()); }
args.push(xidstr(xid));
if (fieldValues instanceof Map) { for (const [f, v] of fieldValues) { args.push(f); args.push(v); } } else { for (const [f, v] of Object.entries(fieldValues)) { args.push(f); args.push(v); } }
return this.execBulkReply<BulkString>( "XADD", ...args, ).then((rawId) => parseXId(rawId)); }
xclaim(key: string, opts: XClaimOpts, ...xids: XIdInput[]) { const args = []; if (opts.idle) { args.push("IDLE"); args.push(opts.idle); }
if (opts.time) { args.push("TIME"); args.push(opts.time); }
if (opts.retryCount) { args.push("RETRYCOUNT"); args.push(opts.retryCount); }
if (opts.force) { args.push("FORCE"); }
if (opts.justXId) { args.push("JUSTID"); }
return this.execArrayReply<XReadIdData | BulkString>( "XCLAIM", key, opts.group, opts.consumer, opts.minIdleTime, ...xids.map((xid) => xidstr(xid)), ...args, ).then((raw) => { if (opts.justXId) { const xids = []; for (const r of raw) { if (typeof r === "string") { xids.push(parseXId(r)); } } const payload: XClaimJustXId = { kind: "justxid", xids }; return payload; }
const messages = []; for (const r of raw) { if (typeof r !== "string") { messages.push(parseXMessage(r)); } } const payload: XClaimMessages = { kind: "messages", messages }; return payload; }); }
xdel(key: string, ...xids: XIdInput[]) { return this.execIntegerReply( "XDEL", key, ...xids.map((rawId) => xidstr(rawId)), ); }
xlen(key: string) { return this.execIntegerReply("XLEN", key); }
xgroupCreate( key: string, groupName: string, xid: XIdInput | "$", mkstream?: boolean, ) { const args = []; if (mkstream) { args.push("MKSTREAM"); }
return this.execStatusReply( "XGROUP", "CREATE", key, groupName, xidstr(xid), ...args, ); }
xgroupDelConsumer( key: string, groupName: string, consumerName: string, ) { return this.execIntegerReply( "XGROUP", "DELCONSUMER", key, groupName, consumerName, ); }
xgroupDestroy(key: string, groupName: string) { return this.execIntegerReply("XGROUP", "DESTROY", key, groupName); }
xgroupHelp() { return this.execBulkReply<BulkString>("XGROUP", "HELP"); }
xgroupSetID( key: string, groupName: string, xid: XId, ) { return this.execStatusReply( "XGROUP", "SETID", key, groupName, xidstr(xid), ); }
xinfoStream(key: string) { return this.execArrayReply<Raw>("XINFO", "STREAM", key).then( (raw) => { // Note that you should not rely on the fields // exact position, nor on the number of fields, // new fields may be added in the future. const data: Map<string, Raw> = convertMap(raw);
const firstEntry = parseXMessage( data.get("first-entry") as XReadIdData, ); const lastEntry = parseXMessage( data.get("last-entry") as XReadIdData, );
return { length: rawnum(data.get("length") ?? null), radixTreeKeys: rawnum(data.get("radix-tree-keys") ?? null), radixTreeNodes: rawnum(data.get("radix-tree-nodes") ?? null), groups: rawnum(data.get("groups") ?? null), lastGeneratedId: parseXId( rawstr(data.get("last-generated-id") ?? null), ), firstEntry, lastEntry, }; }, ); }
xinfoStreamFull(key: string, count?: number) { const args = []; if (count) { args.push("COUNT"); args.push(count); } return this.execArrayReply<Raw>("XINFO", "STREAM", key, "FULL", ...args) .then( (raw) => { // Note that you should not rely on the fields // exact position, nor on the number of fields, // new fields may be added in the future. if (raw == null) throw "no data";
const data: Map<string, Raw> = convertMap(raw); if (data === undefined) throw "no data converted";
const entries = (data.get("entries") as ConditionalArray).map(( raw: Raw, ) => parseXMessage(raw as XReadIdData)); return { length: rawnum(data.get("length") ?? null), radixTreeKeys: rawnum(data.get("radix-tree-keys") ?? null), radixTreeNodes: rawnum(data.get("radix-tree-nodes") ?? null), lastGeneratedId: parseXId( rawstr(data.get("last-generated-id") ?? null), ), entries, groups: parseXGroupDetail(data.get("groups") as ConditionalArray), }; }, ); }
xinfoGroups(key: string) { return this.execArrayReply<ConditionalArray>("XINFO", "GROUPS", key).then( (raws) => raws.map((raw) => { const data = convertMap(raw); return { name: rawstr(data.get("name") ?? null), consumers: rawnum(data.get("consumers") ?? null), pending: rawnum(data.get("pending") ?? null), lastDeliveredId: parseXId( rawstr(data.get("last-delivered-id") ?? null), ), }; }), ); }
xinfoConsumers(key: string, group: string) { return this.execArrayReply<ConditionalArray>( "XINFO", "CONSUMERS", key, group, ).then( (raws) => raws.map((raw) => { const data = convertMap(raw); return { name: rawstr(data.get("name") ?? null), pending: rawnum(data.get("pending") ?? null), idle: rawnum(data.get("idle") ?? null), }; }), ); }
xpending( key: string, group: string, ) { return this.execArrayReply<Raw>("XPENDING", key, group) .then((raw) => { if ( isNumber(raw[0]) && isString(raw[1]) && isString(raw[2]) && isCondArray(raw[3]) ) { return { count: raw[0], startId: parseXId(raw[1]), endId: parseXId(raw[2]), consumers: parseXPendingConsumers(raw[3]), }; } else { throw "parse err"; } }); }
xpendingCount( key: string, group: string, startEndCount: StartEndCount, consumer?: string, ) { const args = []; args.push(startEndCount.start); args.push(startEndCount.end); args.push(startEndCount.count);
if (consumer) { args.push(consumer); }
return this.execArrayReply<Raw>("XPENDING", key, group, ...args) .then((raw) => parseXPendingCounts(raw)); }
xrange( key: string, start: XIdNeg, end: XIdPos, count?: number, ) { const args: (string | number)[] = [key, xidstr(start), xidstr(end)]; if (count) { args.push("COUNT"); args.push(count); } return this.execArrayReply<XReadIdData>("XRANGE", ...args).then( (raw) => raw.map((m) => parseXMessage(m)), ); }
xrevrange( key: string, start: XIdPos, end: XIdNeg, count?: number, ) { const args: (string | number)[] = [key, xidstr(start), xidstr(end)]; if (count) { args.push("COUNT"); args.push(count); } return this.execArrayReply<XReadIdData>("XREVRANGE", ...args).then( (raw) => raw.map((m) => parseXMessage(m)), ); }
xread( keyXIds: (XKeyId | XKeyIdLike)[], opts?: XReadOpts, ) { const args = []; if (opts) { if (opts.count) { args.push("COUNT"); args.push(opts.count); } if (opts.block) { args.push("BLOCK"); args.push(opts.block); } } args.push("STREAMS");
const theKeys = []; const theXIds = [];
for (const a of keyXIds) { if (a instanceof Array) { // XKeyIdLike theKeys.push(a[0]); theXIds.push(xidstr(a[1])); } else { // XKeyId theKeys.push(a.key); theXIds.push(xidstr(a.xid)); } }
return this.execArrayReply<XReadStreamRaw>( "XREAD", ...args.concat(theKeys).concat(theXIds), ).then((raw) => parseXReadReply(raw)); }
xreadgroup( keyXIds: (XKeyIdGroup | XKeyIdGroupLike)[], { group, consumer, count, block }: XReadGroupOpts, ) { const args: (string | number)[] = [ "GROUP", group, consumer, ];
if (count) { args.push("COUNT"); args.push(count); } if (block) { args.push("BLOCK"); args.push(block); }
args.push("STREAMS");
const theKeys = []; const theXIds = [];
for (const a of keyXIds) { if (a instanceof Array) { // XKeyIdGroupLike theKeys.push(a[0]); theXIds.push(a[1] === ">" ? ">" : xidstr(a[1])); } else { // XKeyIdGroup theKeys.push(a.key); theXIds.push(a.xid === ">" ? ">" : xidstr(a.xid)); } }
return this.execArrayReply<XReadStreamRaw>( "XREADGROUP", ...args.concat(theKeys).concat(theXIds), ).then((raw) => parseXReadReply(raw)); }
xtrim(key: string, maxlen: XMaxlen) { const args = []; if (maxlen.approx) { args.push("~"); }
args.push(maxlen.elements);
return this.execIntegerReply("XTRIM", key, "MAXLEN", ...args); }
zadd( key: string, score: number, member: string, opts?: ZAddOpts, ): Promise<Integer>; zadd( key: string, scoreMembers: [number, string][], opts?: ZAddOpts, ): Promise<Integer>; zadd( key: string, memberScores: Record<string, number>, opts?: ZAddOpts, ): Promise<Integer>; zadd( key: string, param1: number | [number, string][] | Record<string, number>, param2?: string | ZAddOpts, opts?: ZAddOpts, ) { const args: (string | number)[] = [key]; if (Array.isArray(param1)) { this.pushZAddOpts(args, param2 as ZAddOpts); args.push(...param1.flatMap((e) => e)); opts = param2 as ZAddOpts; } else if (typeof param1 === "object") { this.pushZAddOpts(args, param2 as ZAddOpts); for (const [member, score] of Object.entries(param1)) { args.push(score as number, member); } } else { this.pushZAddOpts(args, opts); args.push(param1, param2 as string); } return this.execIntegerReply("ZADD", ...args); }
private pushZAddOpts( args: (string | number)[], opts?: ZAddOpts, ): void { if (opts?.mode) { args.push(opts.mode); } if (opts?.ch) { args.push("CH"); } }
zaddIncr( key: string, score: number, member: string, opts?: ZAddOpts, ) { const args: (string | number)[] = [key]; this.pushZAddOpts(args, opts); args.push("INCR", score, member); return this.execBulkReply("ZADD", ...args); }
zcard(key: string) { return this.execIntegerReply("ZCARD", key); }
zcount(key: string, min: number, max: number) { return this.execIntegerReply("ZCOUNT", key, min, max); }
zincrby(key: string, increment: number, member: string) { return this.execBulkReply<BulkString>("ZINCRBY", key, increment, member); }
zinter( keys: string[] | [string, number][] | Record<string, number>, opts?: ZInterOpts, ) { const args = this.pushZStoreArgs([], keys, opts); if (opts?.withScore) { args.push("WITHSCORES"); } return this.execArrayReply("ZINTER", ...args); }
zinterstore( destination: string, keys: string[] | [string, number][] | Record<string, number>, opts?: ZInterstoreOpts, ) { const args = this.pushZStoreArgs([destination], keys, opts); return this.execIntegerReply("ZINTERSTORE", ...args); }
zunionstore( destination: string, keys: string[] | [string, number][] | Record<string, number>, opts?: ZUnionstoreOpts, ) { const args = this.pushZStoreArgs([destination], keys, opts); return this.execIntegerReply("ZUNIONSTORE", ...args); }
private pushZStoreArgs( args: (number | string)[], keys: string[] | [string, number][] | Record<string, number>, opts?: ZInterstoreOpts | ZUnionstoreOpts, ) { if (Array.isArray(keys)) { args.push(keys.length); if (Array.isArray(keys[0])) { keys = keys as [string, number][]; args.push(...keys.map((e) => e[0])); args.push("WEIGHTS"); args.push(...keys.map((e) => e[1])); } else { args.push(...(keys as string[])); } } else { args.push(Object.keys(keys).length); args.push(...Object.keys(keys)); args.push("WEIGHTS"); args.push(...Object.values(keys)); } if (opts?.aggregate) { args.push("AGGREGATE", opts.aggregate); } return args; }
zlexcount(key: string, min: string, max: string) { return this.execIntegerReply("ZLEXCOUNT", key, min, max); }
zpopmax(key: string, count?: number) { if (count !== undefined) { return this.execArrayReply<BulkString>("ZPOPMAX", key, count); } return this.execArrayReply<BulkString>("ZPOPMAX", key); }
zpopmin(key: string, count?: number) { if (count !== undefined) { return this.execArrayReply<BulkString>("ZPOPMIN", key, count); } return this.execArrayReply<BulkString>("ZPOPMIN", key); }
zrange( key: string, start: number, stop: number, opts?: ZRangeOpts, ) { const args = this.pushZRangeOpts([key, start, stop], opts); return this.execArrayReply<BulkString>("ZRANGE", ...args); }
zrangebylex( key: string, min: string, max: string, opts?: ZRangeByLexOpts, ) { const args = this.pushZRangeOpts([key, min, max], opts); return this.execArrayReply<BulkString>("ZRANGEBYLEX", ...args); }
zrangebyscore( key: string, min: number | string, max: number | string, opts?: ZRangeByScoreOpts, ) { const args = this.pushZRangeOpts([key, min, max], opts); return this.execArrayReply<BulkString>("ZRANGEBYSCORE", ...args); }
zrank(key: string, member: string) { return this.execIntegerOrNilReply("ZRANK", key, member); }
zrem(key: string, ...members: string[]) { return this.execIntegerReply("ZREM", key, ...members); }
zremrangebylex(key: string, min: string, max: string) { return this.execIntegerReply("ZREMRANGEBYLEX", key, min, max); }
zremrangebyrank(key: string, start: number, stop: number) { return this.execIntegerReply("ZREMRANGEBYRANK", key, start, stop); }
zremrangebyscore(key: string, min: number | string, max: number | string) { return this.execIntegerReply("ZREMRANGEBYSCORE", key, min, max); }
zrevrange( key: string, start: number, stop: number, opts?: ZRangeOpts, ) { const args = this.pushZRangeOpts([key, start, stop], opts); return this.execArrayReply<BulkString>("ZREVRANGE", ...args); }
zrevrangebylex( key: string, max: string, min: string, opts?: ZRangeByLexOpts, ) { const args = this.pushZRangeOpts([key, min, max], opts); return this.execArrayReply<BulkString>("ZREVRANGEBYLEX", ...args); }
zrevrangebyscore( key: string, max: number, min: number, opts?: ZRangeByScoreOpts, ) { const args = this.pushZRangeOpts([key, max, min], opts); return this.execArrayReply<BulkString>("ZREVRANGEBYSCORE", ...args); }
private pushZRangeOpts( args: (number | string)[], opts?: ZRangeOpts | ZRangeByLexOpts | ZRangeByScoreOpts, ) { if ((opts as ZRangeByScoreOpts)?.withScore) { args.push("WITHSCORES"); } if ((opts as ZRangeByScoreOpts)?.limit) { args.push( "LIMIT", (opts as ZRangeByScoreOpts).limit!.offset, (opts as ZRangeByScoreOpts).limit!.count, ); } return args; }
zrevrank(key: string, member: string) { return this.execIntegerOrNilReply("ZREVRANK", key, member); }
zscore(key: string, member: string) { return this.execBulkReply("ZSCORE", key, member); }
scan( cursor: number, opts?: ScanOpts, ) { const args = this.pushScanOpts([cursor], opts); return this.execArrayReply("SCAN", ...args) as Promise< [BulkString, BulkString[]] >; }
sscan( key: string, cursor: number, opts?: SScanOpts, ) { const args = this.pushScanOpts([key, cursor], opts); return this.execArrayReply("SSCAN", ...args) as Promise< [BulkString, BulkString[]] >; }
hscan( key: string, cursor: number, opts?: HScanOpts, ) { const args = this.pushScanOpts([key, cursor], opts); return this.execArrayReply("HSCAN", ...args) as Promise< [BulkString, BulkString[]] >; }
zscan( key: string, cursor: number, opts?: ZScanOpts, ) { const args = this.pushScanOpts([key, cursor], opts); return this.execArrayReply("ZSCAN", ...args) as Promise< [BulkString, BulkString[]] >; }
private pushScanOpts( args: (number | string)[], opts?: ScanOpts | HScanOpts | ZScanOpts | SScanOpts, ) { if (opts?.pattern !== undefined) { args.push("MATCH", opts.pattern); } if (opts?.count !== undefined) { args.push("COUNT", opts.count); } if ((opts as ScanOpts)?.type !== undefined) { args.push("TYPE", (opts as ScanOpts).type!); } return args; }
tx() { return createRedisPipeline(this.executor.connection, true); }
pipeline() { return createRedisPipeline(this.executor.connection); }}
export interface RedisConnectOptions extends RedisConnectionOptions { hostname: string; port?: number | string;}
/** * Connect to Redis server * @param options * @example * ```ts * import { connect } from "./mod.ts"; * const conn1 = await connect({hostname: "127.0.0.1", port: 6379}); // -> TCP, 127.0.0.1:6379 * const conn2 = await connect({hostname: "redis.proxy", port: 443, tls: true}); // -> TLS, redis.proxy:443 * ``` */export async function connect(options: RedisConnectOptions): Promise<Redis> { const connection = createRedisConnection(options); await connection.connect(); const executor = new DefaultExecutor(connection); return create(executor);}
/** * Create a lazy Redis client that will not establish a connection until a command is actually executed. * * ```ts * import { createLazyClient } from "./mod.ts"; * * const client = createLazyClient({ hostname: "127.0.0.1", port: 6379 }); * console.assert(!client.isConnected); * await client.get("foo"); * console.assert(client.isConnected); * ``` */export function createLazyClient(options: RedisConnectOptions): Redis { const connection = createRedisConnection(options); const executor = createLazyExecutor(connection); return create(executor);}
/** * Create a redis client from `CommandExecutor` */export function create(executor: CommandExecutor): Redis { return new RedisImpl(executor);}
/** * Extract RedisConnectOptions from redis URL * @param url * @example * ```ts * import { parseURL } from "./mod.ts"; * * parseURL("redis://foo:bar@localhost:6379/1"); // -> {hostname: "localhost", port: "6379", tls: false, db: 1, name: foo, password: bar} * parseURL("rediss://127.0.0.1:443/?db=2&password=bar"); // -> {hostname: "127.0.0.1", port: "443", tls: true, db: 2, name: undefined, password: bar} * ``` */export function parseURL(url: string): RedisConnectOptions { const { protocol, hostname, port, username, password, pathname, searchParams, } = new URL(url); const db = pathname.replace("/", "") !== "" ? pathname.replace("/", "") : searchParams.get("db") ?? undefined; return { hostname: hostname !== "" ? hostname : "localhost", port: port !== "" ? parseInt(port, 10) : 6379, tls: protocol == "rediss:" ? true : searchParams.get("ssl") === "true", db: db ? parseInt(db, 10) : undefined, name: username !== "" ? username : undefined, password: password !== "" ? password : searchParams.get("password") ?? undefined, };}
function createRedisConnection(options: RedisConnectOptions): Connection { const { hostname, port = 6379, ...opts } = options; return new RedisConnection(hostname, port, opts);}
function createLazyExecutor(connection: Connection): CommandExecutor { let executor: CommandExecutor | null = null; return { get connection() { return connection; }, exec(command, ...args) { return this.sendCommand(command, args); }, async sendCommand(command, args, options) { if (!executor) { executor = new DefaultExecutor(connection); if (!connection.isConnected) { await connection.connect(); } } return executor.sendCommand(command, args, options); }, close() { if (executor) { return executor.close(); } }, };}