diff --git a/packages/memcache-client/src/lib/client.ts b/packages/memcache-client/src/lib/client.ts index a012081..cb896c2 100644 --- a/packages/memcache-client/src/lib/client.ts +++ b/packages/memcache-client/src/lib/client.ts @@ -1,4 +1,3 @@ -/* eslint-disable max-params */ import assert from "assert"; import { Socket } from "net"; @@ -102,6 +101,29 @@ export type MetaResult = { type SocketCallback = (socket?: Socket) => void; type OperationCallback = (error?: Error | null, data?: Data) => void; + +// Shared arg types for methods with common signatures +type StoreMethodArgs = { + key: string; + value: StoreParams; + options?: StoreCommandOptions; + callback?: OperationCallback; +}; + +type IncrDecrArgs = { + key: string; + value: number; + options?: StoreCommandOptions; + callback?: OperationCallback; +}; + +type XRetrieveArgs = { + cmd: RetrieveCommands; + key: string[] | string; + options?: StoreCommandOptions; + metaFlags?: string; +}; + export type RetrievalCommandResponse = { tokens: string[]; casUniq?: number | string; @@ -209,21 +231,21 @@ export class MemcacheClient extends EventEmitter { // doesn't apply if you send a command like get/gets/stats, which don't // have the noreply option. // - send( - data: StoreParams | SocketCallback, - key: string, - options: CommonCommandOption = {}, - callback?: ErrorFirstCallback - ): Promise { - return this._callbackSend(data, key, options, callback); + send({ data, key, options = {}, callback }: { + data: StoreParams | SocketCallback; + key: string; + options?: CommonCommandOption; + callback?: ErrorFirstCallback; + }): Promise { + return this._callbackSend({ data, key, options, callback }); } // the promise only version of send - xsend( - data: StoreParams | SocketCallback, - key: string, - options: StoreCommandOptions = {} - ): Promise { + xsend({ data, key, options = {} }: { + data: StoreParams | SocketCallback; + key: string; + options?: StoreCommandOptions; + }): Promise { return this._servers.doCmd( (c: MemcacheConnection) => this._send(c, data, options), key @@ -232,80 +254,54 @@ export class MemcacheClient extends EventEmitter { // a convenient method to send a single line as a command to the server // with \r\n appended for you automatically - cmd( - data: string, - key?: string, - options?: CommonCommandOption, - callback?: ErrorFirstCallback - ): Promise { - return this.send( - (socket) => { + cmd({ data, key, options, callback }: { + data: string; + key?: string; + options?: CommonCommandOption; + callback?: ErrorFirstCallback; + }): Promise { + return this.send({ + data: (socket) => { let line = data; if (options?.noreply) { line += " noreply"; } socket?.write(`${line}\r\n`); }, - key || "", + key: key || "", options, - callback - ); + callback, + }); } // "set" means "store this data". - set( - key: string, - value: StoreParams, - options?: StoreCommandOptions, - callback?: OperationCallback - ): Promise { - options = options || {}; + set({ key, value, options = {}, callback }: StoreMethodArgs): Promise { if (options.ignoreNotStored === undefined) { options.ignoreNotStored = this.options.ignoreNotStored; } - return this.store("set", key, value, options, callback); + return this.store({ cmd: "set", key, value, options, callback }); } // "add" means "store this data, but only if the server *doesn't* already // hold data for this key". - add( - key: string, - value: StoreParams, - options?: StoreCommandOptions, - callback?: OperationCallback - ): Promise { - return this.store("add", key, value, options, callback); + add({ key, value, options, callback }: StoreMethodArgs): Promise { + return this.store({ cmd: "add", key, value, options, callback }); } // "replace" means "store this data, but only if the server *does* // already hold data for this key". - replace( - key: string, - value: StoreParams, - options?: StoreCommandOptions, - callback?: OperationCallback - ): Promise { - return this.store("replace", key, value, options, callback); + replace({ key, value, options, callback }: StoreMethodArgs): Promise { + return this.store({ cmd: "replace", key, value, options, callback }); } // "append" means "add this data to an existing key after existing data". - append( - key: string, - value: StoreParams, - options?: StoreCommandOptions, - callback?: OperationCallback - ): Promise { - return this.store("append", key, value, options, callback); + append({ key, value, options, callback }: StoreMethodArgs): Promise { + return this.store({ cmd: "append", key, value, options, callback }); } // "prepend" means "add this data to an existing key before existing data". - prepend( - key: string, - value: StoreParams, - options?: StoreCommandOptions, - callback?: OperationCallback - ): Promise { - return this.store("prepend", key, value, options, callback); + prepend({ key, value, options, callback }: StoreMethodArgs): Promise { + return this.store({ cmd: "prepend", key, value, options, callback }); } // "cas" is a check and set operation which means "store this data but @@ -313,84 +309,70 @@ export class MemcacheClient extends EventEmitter { // // cas unique must be passed in options.casUniq // - cas( - key: string, - value: StoreParams, - options: CasCommandOptions, - callback?: OperationCallback - ): Promise { + cas({ key, value, options, callback }: StoreMethodArgs & { options: CasCommandOptions }): Promise { assert(options?.casUniq, "Must provide options.casUniq for cas store command"); - return this.store("cas", key, value, options, callback); + return this.store({ cmd: "cas", key, value, options, callback }); } // delete key, fire & forget with options.noreply - delete( - key: string, - options?: CommonCommandOption, - callback?: OperationCallback - ): Promise { - return this.cmd(`delete ${key}`, key, options, callback); + delete({ key, options, callback }: { + key: string; + options?: CommonCommandOption; + callback?: OperationCallback; + }): Promise { + return this.cmd({ data: `delete ${key}`, key, options, callback }); } // incr key by value, fire & forget with options.noreply - incr( - key: string, - value: number, - options?: StoreCommandOptions, - callback?: OperationCallback - ): Promise { - return this.cmd(`incr ${key} ${value}`, key, options, callback); + incr({ key, value, options, callback }: IncrDecrArgs): Promise { + return this.cmd({ data: `incr ${key} ${value}`, key, options, callback }); } // decrease key by value, fire & forget with options.noreply - decr( - key: string, - value: number, - options?: StoreCommandOptions, - callback?: OperationCallback - ): Promise { - return this.cmd(`decr ${key} ${value}`, key, options, callback); + decr({ key, value, options, callback }: IncrDecrArgs): Promise { + return this.cmd({ data: `decr ${key} ${value}`, key, options, callback }); } // touch key with exp time, fire & forget with options.noreply - touch( - key: string, - exptime: string | number, - options?: CommonCommandOption, - callback?: OperationCallback - ): Promise { - return this.cmd(`touch ${key} ${exptime}`, key, options, callback); + touch({ key, exptime, options, callback }: { + key: string; + exptime: string | number; + options?: CommonCommandOption; + callback?: OperationCallback; + }): Promise { + return this.cmd({ data: `touch ${key} ${exptime}`, key, options, callback }); } // get version of server - version(callback?: OperationCallback): Promise { - return this.cmd(`version`, "", {}, callback); + version({ callback }: { callback?: OperationCallback } = {}): Promise { + return this.cmd({ data: `version`, key: "", callback }); } // flush all keys from the server, optionally after a delay in seconds - flush( - exptime?: number, - options?: CommonCommandOption, - callback?: OperationCallback - ): Promise { + flush({ exptime, options, callback }: { + exptime?: number; + options?: CommonCommandOption; + callback?: OperationCallback; + } = {}): Promise { const cmd = exptime !== undefined ? `flush_all ${exptime}` : "flush_all"; - return this.cmd(cmd, "", options, callback) as Promise; + return this.cmd({ data: cmd, key: "", options, callback }) as Promise; } - async versionAll( + async versionAll({ trackingCallbacks, callback }: { trackingCallbacks?: { beforePing?: (serverKey: string) => void; afterPing?: (serverKey: string, error?: Error) => void; - }, + }; callback?: OperationCallback< - Record - >): Promise<{ - values: Record + Record + >; + } = {}): Promise<{ + values: Record; }> { const versionObjects = await Promise.all(this._servers._servers.map(async (server: SingleServerEntry) => { trackingCallbacks?.beforePing?.(server.server); try { - const response = await this.cmd(`version`, server.server, {}, callback) as string[]; + const response = await this.cmd({ data: `version`, key: server.server, callback }) as string[]; trackingCallbacks?.afterPing?.(server.server); return { server: server.server, value: { version: response } }; } catch (error) { @@ -405,13 +387,13 @@ export class MemcacheClient extends EventEmitter { } // a generic API for issuing one of the store commands - store( - cmd: StoreCommands, - key: string, - value: StoreParams, - options: Partial = {}, - callback?: OperationCallback - ): Promise { + store({ cmd, key, value, options = {}, callback }: { + cmd: StoreCommands; + key: string; + value: StoreParams; + options?: Partial; + callback?: OperationCallback; + }): Promise { const lifetime = options.lifetime !== undefined ? options.lifetime : this.options.lifetime || 60; const casUniq = options.casUniq ? ` ${options.casUniq}` : ""; @@ -433,22 +415,22 @@ export class MemcacheClient extends EventEmitter { ); }; - return this._callbackSend(sendData, key, options, callback) as Promise; + return this._callbackSend({ data: sendData, key, options, callback }) as Promise; } - get( - key: string | string[], - options?: StoreCommandOptions, - callback?: OperationCallback> - ): Promise> { - return this.retrieve("get", key, options, callback); + get({ key, options, callback }: { + key: string | string[]; + options?: StoreCommandOptions; + callback?: OperationCallback>; + }): Promise> { + return this.retrieve({ cmd: "get", key, options, callback }); } - mg( - key: string | string[], - options?: MetaGetOptions, - callback?: OperationCallback> - ): Promise> { + mg({ key, options, callback }: { + key: string | string[]; + options?: MetaGetOptions; + callback?: OperationCallback>; + }): Promise> { // always request value and flags // key is only requested when there is an array to identify the responses by key const metaFlagParts = [Array.isArray(key) ? "v k f" : "v f"]; @@ -471,57 +453,52 @@ export class MemcacheClient extends EventEmitter { metaFlagParts.push(`N${options.vivifyOnMiss}`); } - return this.retrieve("mg", key, options, callback, metaFlagParts.join(" ")); + return this.retrieve({ cmd: "mg", key, options, callback, metaFlags: metaFlagParts.join(" ") }); } - gets( - key: string | string[], - options?: StoreCommandOptions, - callback?: OperationCallback> - ): Promise> { - return this.retrieve("gets", key, options, callback); + gets({ key, options, callback }: { + key: string | string[]; + options?: StoreCommandOptions; + callback?: OperationCallback>; + }): Promise> { + return this.retrieve({ cmd: "gets", key, options, callback }); } // Like gets, but catches errors per-server instead of failing fast. // Returns partial results along with error information for failed servers. - getsWithErrors( - keys: Keys[], - options?: StoreCommandOptions - ): Promise> { - return this.xretrieveWithErrors("gets", keys, options) as Promise< + getsWithErrors({ keys, options }: { + keys: Keys[]; + options?: StoreCommandOptions; + }): Promise> { + return this.xretrieveWithErrors({ cmd: "gets", keys, options }) as Promise< MultiCasRetrievalWithErrorsResponse >; } // Like get, but catches errors per-server instead of failing fast. // Returns partial results along with error information for failed servers. - getWithErrors( - keys: Keys[], - options?: StoreCommandOptions - ): Promise> { - return this.xretrieveWithErrors("get", keys, options) as Promise< + getWithErrors({ keys, options }: { + keys: Keys[]; + options?: StoreCommandOptions; + }): Promise> { + return this.xretrieveWithErrors({ cmd: "get", keys, options }) as Promise< MultiRetrievalWithErrorsResponse >; } // A generic API for issuing get or gets command - retrieve( - cmd: RetrieveCommands, - key: string[] | string, - options: StoreCommandOptions = {}, - callback?: ErrorFirstCallback, - metaFlags?: string - ): Promise { - return nodeify(this.xretrieve(cmd, key, options, metaFlags), callback) as Promise; + retrieve({ cmd, key, options = {}, callback, metaFlags }: { + cmd: RetrieveCommands; + key: string[] | string; + options?: StoreCommandOptions; + callback?: ErrorFirstCallback; + metaFlags?: string; + }): Promise { + return nodeify(this.xretrieve({ cmd, key, options, metaFlags }), callback) as Promise; } // the promise only version of retrieve - xretrieve( - cmd: RetrieveCommands, - key: string | string[], - options?: StoreCommandOptions, - metaFlags?: string - ): Promise { + xretrieve({ cmd, key, options, metaFlags }: XRetrieveArgs): Promise { // split into requests by consistently hashed server if necessary const serverManager = this._servers; if (serverManager instanceof ConsistentlyHashedServers && Array.isArray(key)) { @@ -535,20 +512,15 @@ export class MemcacheClient extends EventEmitter { } return Promise.all( Array.from(serverKeys.values()).map((keys) => - this._xretrieveByServer(cmd, keys, options, metaFlags) + this._xretrieveByServer({ cmd, key: keys, options, metaFlags }) ) ); } - return this._xretrieveByServer(cmd, key, options, metaFlags); + return this._xretrieveByServer({ cmd, key, options, metaFlags }); } // retrieve one or more keys from a single server - _xretrieveByServer( - cmd: RetrieveCommands, - key: string | string[], - options?: StoreCommandOptions, - metaFlags?: string - ): Promise { + _xretrieveByServer({ cmd, key, options, metaFlags }: XRetrieveArgs): Promise { // // get *\r\n // gets *\r\n @@ -560,34 +532,38 @@ export class MemcacheClient extends EventEmitter { // sending multiple keys works differently for meta protocol // e.g. "mg foo v\r\nmg bar v\r\nmg baz v\r\n" instead of "mg foo bar baz v\r\n" return Array.isArray(key) - ? this.xsend(key.map((k) => `${cmd} ${k} ${metaFlags}\r\n`).join(""), key[0], { - ...options, - expectedResponses: key.length, + ? this.xsend({ + data: key.map((k) => `${cmd} ${k} ${metaFlags}\r\n`).join(""), + key: key[0], + options: { + ...options, + expectedResponses: key.length, + }, }) - : this.xsend(`${cmd} ${key} ${metaFlags}\r\n`, key, options).then((r: unknown) => + : this.xsend({ data: `${cmd} ${key} ${metaFlags}\r\n`, key, options }).then((r: unknown) => Object.values(r as Record).shift() ); } return Array.isArray(key) - ? this.xsend(`${cmd} ${key.join(" ")}\r\n`, key[0], options) - : this.xsend(`${cmd} ${key}\r\n`, key, options).then( + ? this.xsend({ data: `${cmd} ${key.join(" ")}\r\n`, key: key[0], options }) + : this.xsend({ data: `${cmd} ${key}\r\n`, key, options }).then( (r: unknown) => (r as Record)[key] ); } // the promise only version of retrieve that catches errors per-server // instead of failing fast, allowing partial results to be returned - async xretrieveWithErrors( - cmd: RetrieveCommands, - keys: Keys[], - options?: StoreCommandOptions - ): Promise> { + async xretrieveWithErrors({ cmd, keys, options }: { + cmd: RetrieveCommands; + keys: Keys[]; + options?: StoreCommandOptions; + }): Promise> { const serverManager = this._servers; // If not using consistently hashed servers, just do a single request if (!(serverManager instanceof ConsistentlyHashedServers)) { try { - const result = await this._xretrieveByServer(cmd, keys, options); + const result = await this._xretrieveByServer({ cmd, key: keys, options }); return { result: result as MultiCasRetrievalResponse, errors: [] }; } catch (error) { return { @@ -611,7 +587,7 @@ export class MemcacheClient extends EventEmitter { const results = await Promise.all( Array.from(serverKeysMap.entries()).map(async ([serverKey, serverKeys]) => { try { - return await this._xretrieveByServer(cmd, serverKeys, options); + return await this._xretrieveByServer({ cmd, key: serverKeys, options }); } catch (error) { errors.push({ error: error as Error, @@ -678,13 +654,13 @@ export class MemcacheClient extends EventEmitter { } // internal send that expects all params passed (even if they are undefined) - _callbackSend( - data: StoreParams | SocketCallback, - key: string, - options?: Partial, - callback?: ErrorFirstCallback - ): Promise { - return nodeify(this.xsend(data, key, options), callback); + _callbackSend({ data, key, options, callback }: { + data: StoreParams | SocketCallback; + key: string; + options?: Partial; + callback?: ErrorFirstCallback; + }): Promise { + return nodeify(this.xsend({ data, key, options }), callback); } _unpackValue(result: PackedData): number | string | Record | Buffer { diff --git a/packages/memcache-client/src/test/spec/client.spec.ts b/packages/memcache-client/src/test/spec/client.spec.ts index 215f64d..7ff57d5 100644 --- a/packages/memcache-client/src/test/spec/client.spec.ts +++ b/packages/memcache-client/src/test/spec/client.spec.ts @@ -76,7 +76,7 @@ describe("memcache client", function () { it.skip("should handle ECONNREFUSED", (done) => { const x = new MemcacheClient({ server: { server: "localhost:65000" } }); let testError: Error; - x.cmd("stats") + x.cmd({ data: "stats" }) .catch((err: Error) => (testError = err)) .then(() => { expect(testError.message).toContain("ECONNREFUSED"); @@ -87,7 +87,7 @@ describe("memcache client", function () { it("should handle ENOTFOUND", (done) => { const x = new MemcacheClient({ server: { server: "badhost.baddomain.com:65000" } }); let testError: Error; - x.cmd("stats") + x.cmd({ data: "stats" }) .catch((err: Error) => (testError = err)) .then(() => { expect(testError.message).toContain("ENOTFOUND"); @@ -98,7 +98,7 @@ describe("memcache client", function () { it("should handle connection timeout", (done) => { const x = new MemcacheClient({ server: { server: "192.168.255.1:8181" }, connectTimeout: 50 }); let testError: Error; - x.cmd("stats") + x.cmd({ data: "stats" }) .catch((err: Error) => (testError = err)) .then(() => { expect(testError.message).toContain("connect timeout"); @@ -118,7 +118,7 @@ describe("memcache client", function () { let testError: Error; const start = Date.now(); - x.cmd("stats") + x.cmd({ data: "stats" }) .catch((err: Error) => (testError = err)) .then(() => { expect(testError.message).toContain("connect timeout"); @@ -152,7 +152,7 @@ describe("memcache client", function () { }); let testError: Error; - x.cmd("stats") + x.cmd({ data: "stats" }) .catch((err: Error) => (testError = err)) .then(() => { expect(testError.message).toContain("connect timeout"); @@ -174,7 +174,7 @@ describe("memcache client", function () { }); let testError: Error; - x.cmd("stats") + x.cmd({ data: "stats" }) .catch((err: Error) => (testError = err)) .then(() => { expect(testError.message).toContain("connect timeout"); @@ -198,48 +198,48 @@ describe("memcache client", function () { it("should use callback on get and set", (done) => { const x = new MemcacheClient({ server }); const key = `foo_${Date.now()}`; - x.set(key, "bar", {}, (err?: Error | null) => { + x.set({ key, value: "bar", callback: (err?: Error | null) => { expect(err).toBeNull(); - x.get(key, {}, (gerr, data) => { + x.get({ key, callback: (gerr, data) => { expect(gerr).toBeNull(); expect(data?.value).toEqual("bar"); x.shutdown(); done(); - }); - }); + }}); + }}); }); it("should use callback for send", (done) => { const x = new MemcacheClient({ server }); const key = `foo_${Date.now()}`; - x.send(`set ${key} 0 0 5\r\nhello\r\n`, "", {}, (err, data) => { + x.send({ data: `set ${key} 0 0 5\r\nhello\r\n`, key: "", callback: (err, data) => { expect(err).toBeNull(); expect(data).toEqual(["STORED"]); - x.send(`get ${key}\r\n`, "", {}, (gerr, v) => { + x.send({ data: `get ${key}\r\n`, key: "", callback: (gerr, v) => { expect(gerr).toBeNull(); expect(v[key].value).toEqual("hello"); x.shutdown(); done(); - }); - }); + }}); + }}); }); it("should set value with custom lifetime", () => { const x = new MemcacheClient({ server }); let testOptions: Partial = {}; - x._callbackSend = (data: unknown, key: string, options?: Partial): Promise => { + x._callbackSend = ({ data, key, options }: { data: unknown; key: string; options?: Partial }): Promise => { testOptions = options || {}; return Promise.resolve(); }; const key = `foo_${Date.now()}`; - x.set(key, "bar", { lifetime: 500 }); + x.set({ key, value: "bar", options: { lifetime: 500 } }); expect(testOptions?.lifetime).toEqual(500); }); it("should ignore NOT_STORED reply for set if client ignore option is true", (done) => { const x = new MemcacheClient({ server, ignoreNotStored: true }); memcachedServer.asyncMode(true); - x.set("key", "data").finally(() => { + x.set({ key: "key", value: "data" }).finally(() => { memcachedServer.asyncMode(false); done(); }); @@ -248,7 +248,7 @@ describe("memcache client", function () { it("should ignore NOT_STORED reply for set if command ignore option is true", (done) => { const x = new MemcacheClient({ server }); memcachedServer.asyncMode(true); - x.set("key", "data", { ignoreNotStored: true }).finally(() => { + x.set({ key: "key", value: "data", options: { ignoreNotStored: true } }).finally(() => { memcachedServer.asyncMode(false); done(); }); @@ -265,12 +265,12 @@ describe("memcache client", function () { let testErr: Error; // At least one command needs to be executed before calling a pause method as // any new connection can take 2ms to be added into server's array - x.set("foo", "bar") + x.set({ key: "foo", value: "bar" }) .then(() => { // if this pause is called before the first set, it would break very bad singleServer.server.pause(); - return x.set("key", "data"); + return x.set({ key: "key", value: "data" }); }) .catch((err: Error) => (testErr = err)) .then(() => { @@ -290,7 +290,7 @@ describe("memcache client", function () { try { Socket.prototype.setKeepAlive = mockKeepAlive; - await x.set("foo", "bar"); + await x.set({ key: "foo", value: "bar" }); } finally { Socket.prototype.setKeepAlive = _setKeepAlive; x.shutdown(); @@ -306,7 +306,7 @@ describe("memcache client", function () { try { Socket.prototype.setKeepAlive = mockKeepAlive; - await x.set("foo", "bar"); + await x.set({ key: "foo", value: "bar" }); } finally { Socket.prototype.setKeepAlive = _setKeepAlive; x.shutdown(); @@ -322,7 +322,7 @@ describe("memcache client", function () { try { Socket.prototype.setKeepAlive = mockKeepAlive; - await x.set("foo", "bar"); + await x.set({ key: "foo", value: "bar" }); } finally { Socket.prototype.setKeepAlive = _setKeepAlive; x.shutdown(); @@ -338,7 +338,7 @@ describe("memcache client", function () { try { Socket.prototype.setNoDelay = mockNoDelay; - await x.set("foo", "bar"); + await x.set({ key: "foo", value: "bar" }); } finally { Socket.prototype.setNoDelay = _setNoDelay; x.shutdown(); @@ -354,7 +354,7 @@ describe("memcache client", function () { try { Socket.prototype.setNoDelay = mockNoDelay; - await x.set("foo", "bar"); + await x.set({ key: "foo", value: "bar" }); } finally { Socket.prototype.setNoDelay = _setNoDelay; x.shutdown(); @@ -397,39 +397,39 @@ describe("memcache client", function () { return ( Promise.all([ - x.set(key1, text1, { compress: true }), - x.set(key2, "dingle", { compress: false }), - x.set(key3, jsonData, { compress: true }), - x.set(key4, numValue), - x.set(key5, binValue, { compress: true }), + x.set({ key: key1, value: text1, options: { compress: true } }), + x.set({ key: key2, value: "dingle", options: { compress: false } }), + x.set({ key: key3, value: jsonData, options: { compress: true } }), + x.set({ key: key4, value: numValue }), + x.set({ key: key5, value: binValue, options: { compress: true } }), ]) .then(() => - Promise.all([x.get(key1), x.get(key2), x.get(key3), x.get(key4), x.get(key5)]).then( + Promise.all([x.get({ key: key1 }), x.get({ key: key2 }), x.get({ key: key3 }), x.get({ key: key4 }), x.get({ key: key5 })]).then( verifyArrayResults ) ) // TODO: solve this any with a conditional type - .then(() => x.get([key1, key2, key3, key4, key5]).then(verifyResults as any)) + .then(() => x.get({ key: [key1, key2, key3, key4, key5] }).then(verifyResults as any)) .then(() => x - .send>( - `gets ${key1} ${key2} ${key3} ${key4} ${key5}\r\n`, - "" - ) + .send>({ + data: `gets ${key1} ${key2} ${key3} ${key4} ${key5}\r\n`, + key: "" + }) .then(verifyResults) ) .then(() => - Promise.all([x.mg(key1), x.mg(key2), x.mg(key3), x.mg(key4), x.mg(key5)]).then( + Promise.all([x.mg({ key: key1 }), x.mg({ key: key2 }), x.mg({ key: key3 }), x.mg({ key: key4 }), x.mg({ key: key5 })]).then( verifyArrayResults ) ) - .then(() => x.mg([key1, key2, key3, key4, key5]).then(verifyResults as any)) + .then(() => x.mg({ key: [key1, key2, key3, key4, key5] }).then(verifyResults as any)) .then(() => x - .send>( - (socket) => socket?.write(`gets ${key1} ${key2} ${key3} ${key4} ${key5}\r\n`), - "" - ) + .send>({ + data: (socket) => socket?.write(`gets ${key1} ${key2} ${key3} ${key4} ${key5}\r\n`), + key: "" + }) .then(verifyResults) ) .then(() => @@ -478,7 +478,7 @@ describe("memcache client", function () { const x = new MemcacheClient({ server }); let testError: Error; return x - .set("foo", a) + .set({ key: "foo", value: a }) .catch((err: Error) => (testError = err)) .then(() => { expect(testError.message).toContain("circular structure"); @@ -493,8 +493,8 @@ describe("memcache client", function () { const objFlag = ValueFlags.TYPE_JSON; let testError: Error; - x.send(`set foo ${objFlag} 60 5\r\nabcde\r\n`, "") - .then(() => x.get("foo")) + x.send({ data: `set foo ${objFlag} 60 5\r\nabcde\r\n`, key: "" }) + .then(() => x.get({ key: "foo" })) .catch((err: Error) => (testError = err)) .then(() => { expect(testError?.message).toContain("Unexpected token 'a'"); @@ -507,8 +507,8 @@ describe("memcache client", function () { const objFlag = ValueFlags.TYPE_JSON | ValueFlags.COMPRESS; let testError: Error; - x.send(`set foo ${objFlag} 60 5\r\nabcde\r\n`, "") - .then(() => x.get("foo")) + x.send({ data: `set foo ${objFlag} 60 5\r\nabcde\r\n`, key: "" }) + .then(() => x.get({ key: "foo" })) .catch((err) => (testError = err)) .then(() => { expect(testError?.message).toContain("unsupported format"); @@ -527,7 +527,7 @@ describe("memcache client", function () { const x = new MemcacheClient({ server, compressor }); const data = Buffer.allocUnsafe(200); let testError: Error; - x.set("foo", data, { compress: true }) + x.set({ key: "foo", value: data, options: { compress: true } }) .catch((err: Error) => (testError = err)) .then(() => { expect(testError?.message).toEqual("compress test failure"); @@ -547,7 +547,7 @@ describe("memcache client", function () { } let testErr: Error; const x = new MemcacheClient({ server: { servers }, cmdTimeout: 20000 }); - x.set("foo", "hello") + x.set({ key: "foo", value: "hello" }) .catch((err: Error) => (testErr = err)) .then(() => expect(testErr.message).toContain("ECONNREFUSED")) .then(() => expect(x._servers._servers).toHaveLength(1)) @@ -561,12 +561,12 @@ describe("memcache client", function () { const thumbsUp = Fs.readFileSync(Path.join(__dirname, "../data/thumbs-up.jpg")); const x = new MemcacheClient({ server }); - Promise.all([x.set(key1, thumbsUp), x.set(key2, thumbsUp), x.set(key3, thumbsUp)]) + Promise.all([x.set({ key: key1, value: thumbsUp }), x.set({ key: key2, value: thumbsUp }), x.set({ key: key3, value: thumbsUp })]) .then((v: string[]) => { expect(v).toEqual([["STORED"], ["STORED"], ["STORED"]]); }) .then(() => - Promise.all([x.get(key1), x.get(key2), x.get(key3)]).then( + Promise.all([x.get({ key: key1 }), x.get({ key: key2 }), x.get({ key: key3 })]).then( (r: Array>) => { expect(r[0].value).toEqual(thumbsUp); expect(r[1].value).toEqual(thumbsUp); @@ -588,12 +588,12 @@ describe("memcache client", function () { const thumbsUp = Fs.readFileSync(Path.join(__dirname, "../data/thumbs-up.jpg")); const x = new MemcacheClient({ server }); - Promise.all([x.set(key1, thumbsUp), x.set(key2, thumbsUp), x.set(key3, thumbsUp)]) + Promise.all([x.set({ key: key1, value: thumbsUp }), x.set({ key: key2, value: thumbsUp }), x.set({ key: key3, value: thumbsUp })]) .then((v: string[]) => { expect(v).toEqual([["STORED"], ["STORED"], ["STORED"]]); }) .then(() => - Promise.all([x.mg(key1), x.mg(key2), x.mg(key3)]).then( + Promise.all([x.mg({ key: key1 }), x.mg({ key: key2 }), x.mg({ key: key3 })]).then( (r: Array>) => { expect(r[0].value).toEqual(thumbsUp); expect(r[1].value).toEqual(thumbsUp); @@ -611,10 +611,10 @@ describe("memcache client", function () { let addErr: Error; const x = new MemcacheClient({ server }); const key = `poem1-风柔日薄春犹早_${Date.now()}`; - Promise.try(() => x.add(key, poem1)) - .then(() => x.mg(key)) + Promise.try(() => x.add({ key, value: poem1 })) + .then(() => x.mg({ key })) .then((r: RetrievalCommandResponse) => expect(r.value).toEqual(poem1)) - .then(() => x.add(key, poem1)) + .then(() => x.add({ key, value: poem1 })) .catch((err: Error) => (addErr = err)) .then(() => expect(addErr.message).toEqual("NOT_STORED")) .finally(() => { @@ -626,11 +626,11 @@ describe("memcache client", function () { const testReplace = (done: () => void, setCompress?: boolean, replaceCompress?: boolean) => { const x = new MemcacheClient({ server }); const key = `poem_${Date.now()}`; - return Promise.try(() => x.set(key, poem2, { compress: setCompress })) - .then(() => x.mg(key)) + return Promise.try(() => x.set({ key, value: poem2, options: { compress: setCompress } })) + .then(() => x.mg({ key })) .then((r: RetrievalCommandResponse) => expect(r.value).toEqual(poem2)) - .then(() => x.replace(key, poem3, { compress: replaceCompress })) - .then(() => x.mg(key)) + .then(() => x.replace({ key, value: poem3, options: { compress: replaceCompress } })) + .then(() => x.mg({ key })) .then((r: RetrievalCommandResponse) => expect(r.value).toEqual(poem3)) .finally(() => { x.shutdown(); @@ -650,7 +650,7 @@ describe("memcache client", function () { const x = new MemcacheClient({ server }); const key = `foo_${Date.now()}`; let testError: Error; - x.replace(key, "bar") + x.replace({ key, value: "bar" }) .catch((err: Error) => (testError = err)) .then(() => { expect(testError?.message).toEqual("NOT_STORED"); @@ -661,11 +661,11 @@ describe("memcache client", function () { it("should set an entry and then append to it", (done) => { const x = new MemcacheClient({ server }); const key = `poem_${Date.now()}`; - Promise.try(() => x.set(key, poem2)) - .then(() => x.get(key)) + Promise.try(() => x.set({ key, value: poem2 })) + .then(() => x.get({ key })) .then((r: RetrievalCommandResponse) => expect(r.value).toEqual(poem2)) - .then(() => x.append(key, poem3)) - .then(() => x.get(key)) + .then(() => x.append({ key, value: poem3 })) + .then(() => x.get({ key })) .then((r: RetrievalCommandResponse) => expect(r.value).toEqual(`${poem2}${poem3}`)) .finally(() => { x.shutdown(); @@ -676,11 +676,11 @@ describe("memcache client", function () { it("should set an entry and then prepend to it", (done) => { const x = new MemcacheClient({ server }); const key = `poem_${Date.now()}`; - Promise.try(() => x.set(key, poem4)) - .then(() => x.get(key)) + Promise.try(() => x.set({ key, value: poem4 })) + .then(() => x.get({ key })) .then((r: RetrievalCommandResponse) => expect(r.value).toEqual(poem4)) - .then(() => x.prepend(key, poem3)) - .then(() => x.get(key)) + .then(() => x.prepend({ key, value: poem3 })) + .then(() => x.get({ key })) .then((r: RetrievalCommandResponse) => expect(r.value).toEqual(`${poem3}${poem4}`)) .finally(() => { x.shutdown(); @@ -692,14 +692,14 @@ describe("memcache client", function () { const x = new MemcacheClient({ server }); const key = `poem_${Date.now()}`; - await x.set(key, poem4); - const getCasResult = await x.mg(key, { includeCasToken: true }); + await x.set({ key, value: poem4 }); + const getCasResult = await x.mg({ key, options: { includeCasToken: true } }); expect(getCasResult.value).toEqual(poem4); expect(getCasResult.casUniq).not.toBeNull(); - await x.cas(key, poem5, { casUniq: getCasResult.casUniq!, compress: true }); - const getResult = await x.mg(key); + await x.cas({ key, value: poem5, options: { casUniq: getCasResult.casUniq!, compress: true } }); + const getResult = await x.mg({ key }); expect(getResult.value).toEqual(poem5); @@ -710,18 +710,18 @@ describe("memcache client", function () { const x = new MemcacheClient({ server }); const key = `poem_${Date.now()}`; - const getMetaResult = await x.mg(key, { + const getMetaResult = await x.mg({ key, options: { vivifyOnMiss: 100, - }); + }}); console.log("getMetaResult", getMetaResult); expect(getMetaResult.value).toBeUndefined(); // first request should win the right to recache, the second should not expect(getMetaResult.wonRecache).toBe(true); - const getMetaResult2 = await x.mg(key, { + const getMetaResult2 = await x.mg({ key, options: { vivifyOnMiss: 100, - }); + }}); expect(getMetaResult2.value).toBeUndefined(); expect(getMetaResult2.wonRecache).toBe(false); @@ -734,14 +734,14 @@ describe("memcache client", function () { const key = `poem_${Date.now()}`; let casError: Error | undefined; - await x.set(key, poem4); - const getCasResult = await x.mg(key, { includeCasToken: true }); + await x.set({ key, value: poem4 }); + const getCasResult = await x.mg({ key, options: { includeCasToken: true } }); expect(getCasResult.value).toEqual(poem4); expect(getCasResult.casUniq).not.toBeNull(); const casUniq = getCasResult.casUniq!; try { - await x.cas(key, poem3, { casUniq: casUniq + 500 }); + await x.cas({ key, value: poem3, options: { casUniq: casUniq + 500 } }); } catch (ex: unknown) { casError = ex as Error; } @@ -753,10 +753,10 @@ describe("memcache client", function () { it("should incr and decr value", (done) => { const x = new MemcacheClient({ server }); const key = `num_${Date.now()}`; - Promise.try(() => x.set(key, "12345")) - .then(() => x.incr(key, 5)) + Promise.try(() => x.set({ key, value: "12345" })) + .then(() => x.incr({ key, value: 5 })) .then((v: RetrievalCommandResponse) => expect(v).toEqual("12350")) - .then(() => x.decr(key, 12355)) + .then(() => x.decr({ key, value: 12355 })) .then((v: string) => expect(v).toEqual("0")) .finally(() => { x.shutdown(); @@ -767,13 +767,13 @@ describe("memcache client", function () { it("should set and delete a key", (done) => { const x = new MemcacheClient({ server }); const key = `num_${Date.now()}`; - Promise.try(() => x.set(key, "12345")) + Promise.try(() => x.set({ key, value: "12345" })) .then((r: string[]) => expect(r).toEqual(["STORED"])) - .then(() => x.mg(key)) + .then(() => x.mg({ key })) .then((v: RetrievalCommandResponse) => expect(v.value).toEqual("12345")) - .then(() => x.delete(key)) + .then(() => x.delete({ key })) .then((r: string[]) => expect(r).toEqual(["DELETED"])) - .then(() => x.mg(key)) + .then(() => x.mg({ key })) .then((v: undefined) => expect(v).toBeUndefined()) .finally(() => { x.shutdown(); @@ -784,9 +784,9 @@ describe("memcache client", function () { it("should fire and forget if noreply is set", (done) => { const x = new MemcacheClient({ server }); const key = `poem1_${Date.now()}`; - Promise.try(() => x.set(key, poem1, { noreply: true })) + Promise.try(() => x.set({ key, value: poem1, options: { noreply: true } })) .then((v?: string[]) => expect(v).toBeUndefined()) - .then(() => x.mg(key)) + .then(() => x.mg({ key })) .then((v: MetaRetrievalCommandResponse) => expect(v.value).toEqual(poem1)) .finally(() => { x.shutdown(); @@ -797,13 +797,13 @@ describe("memcache client", function () { it("should send cmd with fire and forget if noreply is set", (done) => { const x = new MemcacheClient({ server }); const key = `foo_${Date.now()}`; - Promise.try(() => x.set(key, "1", { noreply: true })) + Promise.try(() => x.set({ key, value: "1", options: { noreply: true } })) .then((v?: string[]) => expect(v).toBeUndefined()) - .then(() => x.mg(key)) + .then(() => x.mg({ key })) .then((v: MetaRetrievalCommandResponse) => expect(v.value).toEqual("1")) - .then(() => x.cmd(`incr ${key} 5`, "", { noreply: true })) + .then(() => x.cmd({ data: `incr ${key} 5`, key: "", options: { noreply: true } })) .then((v?: string[]) => expect(v).toBeUndefined()) - .then(() => x.mg(key)) + .then(() => x.mg({ key })) .then((v: MetaRetrievalCommandResponse) => expect(v.value).toEqual("6")) .finally(() => { x.shutdown(); @@ -816,10 +816,10 @@ describe("memcache client", function () { let addErr: Error; const x = new MemcacheClient({ server }); const key = `poem1-风柔日薄春犹早_${Date.now()}`; - Promise.try(() => x.add(key, poem1)) - .then(() => x.get(key)) + Promise.try(() => x.add({ key, value: poem1 })) + .then(() => x.get({ key })) .then((r: RetrievalCommandResponse) => expect(r.value).toEqual(poem1)) - .then(() => x.add(key, poem1)) + .then(() => x.add({ key, value: poem1 })) .catch((err: Error) => (addErr = err)) .then(() => expect(addErr.message).toEqual("NOT_STORED")) .finally(() => { @@ -831,11 +831,11 @@ describe("memcache client", function () { const testReplace = (done: () => void, setCompress?: boolean, replaceCompress?: boolean) => { const x = new MemcacheClient({ server }); const key = `poem_${Date.now()}`; - return Promise.try(() => x.set(key, poem2, { compress: setCompress })) - .then(() => x.get(key)) + return Promise.try(() => x.set({ key, value: poem2, options: { compress: setCompress } })) + .then(() => x.get({ key })) .then((r: RetrievalCommandResponse) => expect(r.value).toEqual(poem2)) - .then(() => x.replace(key, poem3, { compress: replaceCompress })) - .then(() => x.get(key)) + .then(() => x.replace({ key, value: poem3, options: { compress: replaceCompress } })) + .then(() => x.get({ key })) .then((r: RetrievalCommandResponse) => expect(r.value).toEqual(poem3)) .finally(() => { x.shutdown(); @@ -855,7 +855,7 @@ describe("memcache client", function () { const x = new MemcacheClient({ server }); const key = `foo_${Date.now()}`; let testError: Error; - x.replace(key, "bar") + x.replace({ key, value: "bar" }) .catch((err: Error) => (testError = err)) .then(() => { expect(testError?.message).toEqual("NOT_STORED"); @@ -866,11 +866,11 @@ describe("memcache client", function () { it("should set an entry and then append to it", (done) => { const x = new MemcacheClient({ server }); const key = `poem_${Date.now()}`; - Promise.try(() => x.set(key, poem2)) - .then(() => x.get(key)) + Promise.try(() => x.set({ key, value: poem2 })) + .then(() => x.get({ key })) .then((r: RetrievalCommandResponse) => expect(r.value).toEqual(poem2)) - .then(() => x.append(key, poem3)) - .then(() => x.get(key)) + .then(() => x.append({ key, value: poem3 })) + .then(() => x.get({ key })) .then((r: RetrievalCommandResponse) => expect(r.value).toEqual(`${poem2}${poem3}`)) .finally(() => { x.shutdown(); @@ -881,11 +881,11 @@ describe("memcache client", function () { it("should set an entry and then prepend to it", (done) => { const x = new MemcacheClient({ server }); const key = `poem_${Date.now()}`; - Promise.try(() => x.set(key, poem4)) - .then(() => x.get(key)) + Promise.try(() => x.set({ key, value: poem4 })) + .then(() => x.get({ key })) .then((r: RetrievalCommandResponse) => expect(r.value).toEqual(poem4)) - .then(() => x.prepend(key, poem3)) - .then(() => x.get(key)) + .then(() => x.prepend({ key, value: poem3 })) + .then(() => x.get({ key })) .then((r: RetrievalCommandResponse) => expect(r.value).toEqual(`${poem3}${poem4}`)) .finally(() => { x.shutdown(); @@ -898,14 +898,14 @@ describe("memcache client", function () { const key = `poem_${Date.now()}`; try { - await x.set(key, poem4); - const getCasResult = await x.gets(key); + await x.set({ key, value: poem4 }); + const getCasResult = await x.gets({ key }); expect(getCasResult.value).toEqual(poem4); expect(getCasResult.casUniq).not.toBeNull(); - await x.cas(key, poem5, { casUniq: getCasResult.casUniq, compress: true }); - const getResult = await x.get(key); + await x.cas({ key, value: poem5, options: { casUniq: getCasResult.casUniq, compress: true } }); + const getResult = await x.get({ key }); expect(getResult.value).toEqual(poem5); } catch (ex) { @@ -920,13 +920,13 @@ describe("memcache client", function () { const key = `poem_${Date.now()}`; let casError: Error | undefined; - await x.set(key, poem4); - const getCasResult = await x.gets(key); + await x.set({ key, value: poem4 }); + const getCasResult = await x.gets({ key }); expect(getCasResult.value).toEqual(poem4); expect(getCasResult.casUniq).not.toBeNull(); try { - await x.cas(key, poem3, { casUniq: (getCasResult.casUniq as number) + 500 }); + await x.cas({ key, value: poem3, options: { casUniq: (getCasResult.casUniq as number) + 500 } }); } catch (ex: unknown) { casError = ex as Error; } @@ -938,10 +938,10 @@ describe("memcache client", function () { it("should incr and decr value", (done) => { const x = new MemcacheClient({ server }); const key = `num_${Date.now()}`; - Promise.try(() => x.set(key, "12345")) - .then(() => x.incr(key, 5)) + Promise.try(() => x.set({ key, value: "12345" })) + .then(() => x.incr({ key, value: 5 })) .then((v: RetrievalCommandResponse) => expect(v).toEqual("12350")) - .then(() => x.decr(key, 12355)) + .then(() => x.decr({ key, value: 12355 })) .then((v: string) => expect(v).toEqual("0")) .finally(() => { x.shutdown(); @@ -952,13 +952,13 @@ describe("memcache client", function () { it("should set and delete a key", (done) => { const x = new MemcacheClient({ server }); const key = `num_${Date.now()}`; - Promise.try(() => x.set(key, "12345")) + Promise.try(() => x.set({ key, value: "12345" })) .then((r: string[]) => expect(r).toEqual(["STORED"])) - .then(() => x.get(key)) + .then(() => x.get({ key })) .then((v: RetrievalCommandResponse) => expect(v.value).toEqual("12345")) - .then(() => x.delete(key)) + .then(() => x.delete({ key })) .then((r: string[]) => expect(r).toEqual(["DELETED"])) - .then(() => x.get(key)) + .then(() => x.get({ key })) .then((v: undefined) => expect(v).toBeUndefined()) .finally(() => { x.shutdown(); @@ -968,7 +968,7 @@ describe("memcache client", function () { it("should receive stats", (done) => { const x = new MemcacheClient({ server }); - Promise.try(() => x.cmd(`stats`)) + Promise.try(() => x.cmd({ data: `stats` })) .then((r: StatsCommandResponse) => { const stat = r.STAT; expect(stat).not.toBeNull(); @@ -984,9 +984,9 @@ describe("memcache client", function () { it("should fire and forget if noreply is set", (done) => { const x = new MemcacheClient({ server }); const key = `poem1_${Date.now()}`; - Promise.try(() => x.set(key, poem1, { noreply: true })) + Promise.try(() => x.set({ key, value: poem1, options: { noreply: true } })) .then((v?: string[]) => expect(v).toBeUndefined()) - .then(() => x.get(key)) + .then(() => x.get({ key })) .then((v: RetrievalCommandResponse) => expect(v.value).toEqual(poem1)) .finally(() => { x.shutdown(); @@ -997,13 +997,13 @@ describe("memcache client", function () { it("should send cmd with fire and forget if noreply is set", (done) => { const x = new MemcacheClient({ server }); const key = `foo_${Date.now()}`; - Promise.try(() => x.set(key, "1", { noreply: true })) + Promise.try(() => x.set({ key, value: "1", options: { noreply: true } })) .then((v?: string[]) => expect(v).toBeUndefined()) - .then(() => x.get(key)) + .then(() => x.get({ key })) .then((v: RetrievalCommandResponse) => expect(v.value).toEqual("1")) - .then(() => x.cmd(`incr ${key} 5`, "", { noreply: true })) + .then(() => x.cmd({ data: `incr ${key} 5`, key: "", options: { noreply: true } })) .then((v?: string[]) => expect(v).toBeUndefined()) - .then(() => x.get(key)) + .then(() => x.get({ key })) .then((v: RetrievalCommandResponse) => expect(v.value).toEqual("6")) .finally(() => { x.shutdown(); @@ -1014,9 +1014,9 @@ describe("memcache client", function () { it("should update exptime with touch", (done) => { const x = new MemcacheClient({ server }); const key = `poem1_${Date.now()}`; - Promise.try(() => x.set(key, poem1, { noreply: true })) + Promise.try(() => x.set({ key, value: poem1, options: { noreply: true } })) .then((v?: string[]) => expect(v).toBeUndefined()) - .then(() => x.touch(key, "500")) + .then(() => x.touch({ key, exptime: "500" })) .then((r: string[]) => expect(r).toEqual(["TOUCHED"])) .finally(() => { x.shutdown(); @@ -1044,12 +1044,12 @@ describe("memcache client", function () { } let firstConnId = "0"; const x = new MemcacheClient({ server }); - x.cmd("stats") + x.cmd({ data: "stats" }) .then((v) => { firstConnId = v.STAT[2][1]; x._servers._getNode("").connections[0].socket?.emit("error", new Error("ECONNRESET")); }) - .then(() => x.cmd("stats")) + .then(() => x.cmd({ data: "stats" })) .then((v) => { expect(firstConnId).not.toBe(0); expect(firstConnId).not.toBe(v.STAT[2][1]); @@ -1067,12 +1067,12 @@ describe("memcache client", function () { } let firstConnId = "0"; const x = new MemcacheClient({ server }); - x.cmd("stats") + x.cmd({ data: "stats" }) .then((v) => { firstConnId = v.STAT[2][1]; x._servers._getNode("").connections[0].socket?.emit("timeout"); }) - .then(() => x.cmd("stats")) + .then(() => x.cmd({ data: "stats" })) .then((v) => { expect(firstConnId).not.toBe(0); expect(firstConnId).not.toBe(v.STAT[2][1]); @@ -1085,19 +1085,19 @@ describe("memcache client", function () { let firstConnId = "0"; let timeoutError: Error; const x = new MemcacheClient({ server: { server: singleServer.serverUrl }, cmdTimeout: 100 }); - x.cmd("stats") + x.cmd({ data: "stats" }) .then((v) => { firstConnId = v.STAT[2][1]; singleServer.server.pause(); }) - .then(() => Promise.all([x.cmd("stats"), x.get("foo"), x.set("test", "data")])) + .then(() => Promise.all([x.cmd({ data: "stats" }), x.get({ key: "foo" }), x.set({ key: "test", value: "data" })])) .catch((err: Error) => (timeoutError = err)) .then(async () => { expect(timeoutError).not.toBeNull(); expect(timeoutError?.message).toEqual("Command timeout"); singleServer.server.unpause(); - return x.cmd("stats"); + return x.cmd({ data: "stats" }); }) .then((v) => { expect(x._servers._getNode("").connections[0]._cmdTimeout).toEqual(100); @@ -1122,13 +1122,13 @@ describe("memcache client", function () { memcachedServer.shutdown(); const x = new MemcacheClient({ server }); let testErr: Error; - x.set("test", "hello") + x.set({ key: "test", value: "hello" }) .catch((err: Error) => (testErr = err)) //.then(() => expect(testErr.message).toContain("ECONNREFUSED")) .then(() => restartMemcachedServer(port)) - .then(() => x.set("test", "hello")) + .then(() => x.set({ key: "test", value: "hello" })) .then(() => - x.get("test").then((r) => { + x.get({ key: "test" }).then((r) => { expect(r.value).toEqual("hello"); done(); }) diff --git a/packages/memcache-client/src/test/spec/client_tls.spec.ts b/packages/memcache-client/src/test/spec/client_tls.spec.ts index 0f40609..a000afb 100644 --- a/packages/memcache-client/src/test/spec/client_tls.spec.ts +++ b/packages/memcache-client/src/test/spec/client_tls.spec.ts @@ -51,7 +51,7 @@ describe("memcache TLS client", function () { .catch(done); const x = new MemcacheClient({ server: { server: "localhost:65000" }, tls: {} }); let testError: Error; - x.cmd("stats") + x.cmd({ data: "stats" }) .catch((err: Error) => (testError = err)) .then(() => { expect(testError.message).toContain("ECONNREFUSED"); @@ -62,7 +62,7 @@ describe("memcache TLS client", function () { it("TLS handles ENOTFOUND", (done) => { const x = new MemcacheClient({ server: { server: "badhost.baddomain.com:65000" }, tls: {} }); let testError: Error; - x.cmd("stats") + x.cmd({ data: "stats" }) .catch((err: Error) => (testError = err)) .then(() => { expect(testError.message).toContain("ENOTFOUND"); @@ -86,9 +86,9 @@ describe("memcache TLS client", function () { expect(v[0]).toEqual("VERSION"); expect(v[1]).not.toBe(""); }) - .then(() => c.set("key", text1)) + .then(() => c.set({ key: "key", value: text1 })) .then(() => - c.get("key").then((r) => { + c.get({ key: "key" }).then((r) => { expect(r.value).toEqual(text1); done(); }) @@ -114,9 +114,9 @@ describe("memcache TLS client", function () { expect(v[0]).toEqual("VERSION"); expect(v[1]).not.toBe(""); }) - .then(() => c.set("key", text2)) + .then(() => c.set({ key: "key", value: text2 })) .then(() => - c.get("key").then((r) => { + c.get({ key: "key" }).then((r) => { expect(r.value).toEqual(text2); done(); }) diff --git a/packages/memcache-client/src/test/spec/consistently-hashed-servers.spec.ts b/packages/memcache-client/src/test/spec/consistently-hashed-servers.spec.ts index 3f11ff5..bea985a 100644 --- a/packages/memcache-client/src/test/spec/consistently-hashed-servers.spec.ts +++ b/packages/memcache-client/src/test/spec/consistently-hashed-servers.spec.ts @@ -74,14 +74,14 @@ describe("consistently hashed servers", function () { // 'a' = 97, 97 % 3 = 1 -> servers[1] // 'b' = 98, 98 % 3 = 2 -> servers[2] // 'c' = 99, 99 % 3 = 0 -> servers[0] - await x.set("aaa", "value-a"); - await x.set("bbb", "value-b"); - await x.set("ccc", "value-c"); + await x.set({ key: "aaa", value: "value-a" }); + await x.set({ key: "bbb", value: "value-b" }); + await x.set({ key: "ccc", value: "value-c" }); // Verify values can be retrieved - const resultA = await x.get("aaa"); - const resultB = await x.get("bbb"); - const resultC = await x.get("ccc"); + const resultA = await x.get({ key: "aaa" }); + const resultB = await x.get({ key: "bbb" }); + const resultC = await x.get({ key: "ccc" }); expect(resultA.value).toEqual("value-a"); expect(resultB.value).toEqual("value-b"); @@ -138,11 +138,11 @@ describe("consistently hashed servers", function () { const testKey = "consistent-key"; // Perform multiple operations on the same key - await x.set(testKey, "value1"); - await x.get(testKey); - await x.set(testKey, "value2"); - await x.get(testKey); - await x.set(testKey, "value3"); + await x.set({ key: testKey, value: "value1" }); + await x.get({ key: testKey }); + await x.set({ key: testKey, value: "value2" }); + await x.get({ key: testKey }); + await x.set({ key: testKey, value: "value3" }); // Verify all operations went to the same server const keyRouting = routingLog.get(testKey) || []; @@ -208,16 +208,16 @@ describe("consistently hashed servers", function () { try { // Set values that route to different servers - await x.set("server0:key1", "value-0-1"); - await x.set("server1:key1", "value-1-1"); - await x.set("server2:key1", "value-2-1"); - await x.set("server3:key1", "value-3-1"); + await x.set({ key: "server0:key1", value: "value-0-1" }); + await x.set({ key: "server1:key1", value: "value-1-1" }); + await x.set({ key: "server2:key1", value: "value-2-1" }); + await x.set({ key: "server3:key1", value: "value-3-1" }); // Verify each key can be retrieved correctly - const result0 = await x.get("server0:key1"); - const result1 = await x.get("server1:key1"); - const result2 = await x.get("server2:key1"); - const result3 = await x.get("server3:key1"); + const result0 = await x.get({ key: "server0:key1" }); + const result1 = await x.get({ key: "server1:key1" }); + const result2 = await x.get({ key: "server2:key1" }); + const result3 = await x.get({ key: "server3:key1" }); expect(result0.value).toEqual("value-0-1"); expect(result1.value).toEqual("value-1-1"); @@ -270,14 +270,14 @@ describe("consistently hashed servers", function () { try { // Set multiple values that should all go to server0 - await x.set("server0:key1", "value1"); - await x.set("server0:key2", "value2"); - await x.set("server0:key3", "value3"); + await x.set({ key: "server0:key1", value: "value1" }); + await x.set({ key: "server0:key2", value: "value2" }); + await x.set({ key: "server0:key3", value: "value3" }); // Verify individual gets work - const r1 = await x.get("server0:key1"); - const r2 = await x.get("server0:key2"); - const r3 = await x.get("server0:key3"); + const r1 = await x.get({ key: "server0:key1" }); + const r2 = await x.get({ key: "server0:key2" }); + const r3 = await x.get({ key: "server0:key3" }); expect(r1.value).toEqual("value1"); expect(r2.value).toEqual("value2"); @@ -316,12 +316,12 @@ describe("consistently hashed servers", function () { }); try { - await x.set("server0:meta-key", "meta-value-0"); - await x.set("server1:meta-key", "meta-value-1"); + await x.set({ key: "server0:meta-key", value: "meta-value-0" }); + await x.set({ key: "server1:meta-key", value: "meta-value-1" }); // Verify individual mg works - const mg0 = await x.mg("server0:meta-key"); - const mg1 = await x.mg("server1:meta-key"); + const mg0 = await x.mg({ key: "server0:meta-key" }); + const mg1 = await x.mg({ key: "server1:meta-key" }); expect(mg0.value).toEqual("meta-value-0"); expect(mg1.value).toEqual("meta-value-1"); @@ -367,13 +367,13 @@ describe("consistently hashed servers", function () { try { // First verify all servers are working - await x.set("server0:key", "value0"); - await x.set("server1:key", "value1"); - await x.set("server2:key", "value2"); + await x.set({ key: "server0:key", value: "value0" }); + await x.set({ key: "server1:key", value: "value1" }); + await x.set({ key: "server2:key", value: "value2" }); - const r0 = await x.get("server0:key"); - const r1 = await x.get("server1:key"); - const r2 = await x.get("server2:key"); + const r0 = await x.get({ key: "server0:key" }); + const r1 = await x.get({ key: "server1:key" }); + const r2 = await x.get({ key: "server2:key" }); expect(r0.value).toEqual("value0"); expect(r1.value).toEqual("value1"); @@ -447,10 +447,10 @@ describe("consistently hashed servers", function () { const afterPingCalls: Array<{ server: string; error?: Error }> = []; try { - await x.versionAll({ + await x.versionAll({ trackingCallbacks: { beforePing: (serverKey) => beforePingCalls.push(serverKey), afterPing: (serverKey, error) => afterPingCalls.push({ server: serverKey, error }), - }); + }}); expect(beforePingCalls.length).toBe(2); expect(afterPingCalls.length).toBe(2); @@ -477,8 +477,8 @@ describe("consistently hashed servers", function () { }); try { - await x.set("test-key", "test-value"); - const result = await x.get("test-key"); + await x.set({ key: "test-key", value: "test-value" }); + const result = await x.get({ key: "test-key" }); expect(result.value).toEqual("test-value"); } finally { x.shutdown(); @@ -503,8 +503,8 @@ describe("consistently hashed servers", function () { }); try { - await x.set("test-key", "test-value"); - const result = await x.get("test-key"); + await x.set({ key: "test-key", value: "test-value" }); + const result = await x.get({ key: "test-key" }); expect(result.value).toEqual("test-value"); // Verify config was applied @@ -560,10 +560,10 @@ describe("consistently hashed servers", function () { try { // Set value using client1 (goes to server 0) - await client1.set("isolated-key", "isolated-value"); + await client1.set({ key: "isolated-key", value: "isolated-value" }); // Verify client1 can get it - const result1 = await client1.get("isolated-key"); + const result1 = await client1.get({ key: "isolated-key" }); expect(result1.value).toEqual("isolated-value"); // Verify client1 routed to server 0 @@ -571,7 +571,7 @@ describe("consistently hashed servers", function () { expect(client1Routing[0]).toEqual(serversUrls[0].server); // Client2 should not find it (looks on server 1) - const result2 = await client2.get("isolated-key"); + const result2 = await client2.get({ key: "isolated-key" }); expect(result2).toBeUndefined(); // Verify client2 routed to server 1 (different server) diff --git a/packages/memcache-client/src/test/spec/redundant-servers.spec.ts b/packages/memcache-client/src/test/spec/redundant-servers.spec.ts index fc0948b..2c019f2 100644 --- a/packages/memcache-client/src/test/spec/redundant-servers.spec.ts +++ b/packages/memcache-client/src/test/spec/redundant-servers.spec.ts @@ -41,7 +41,7 @@ describe("redundant servers", function () { return Promise.resolve([...Array(8)]) .then((baseArray) => Promise.resolve( - baseArray.map(() => x.cmd("stats"), { concurrency: 8 }) + baseArray.map(() => x.cmd({ data: "stats" }), { concurrency: 8 }) ) ) .then(async (r) => { @@ -82,7 +82,7 @@ describe("redundant servers", function () { return Promise.resolve([...Array(8)]) .then((baseArray) => Promise.resolve( - baseArray.map(() => x.cmd("stats"), { concurrency: 8 }) + baseArray.map(() => x.cmd({ data: "stats" }), { concurrency: 8 }) ) ) .then(async (r) => { @@ -120,7 +120,7 @@ describe("redundant servers", function () { let testErr: Error; memcachedServers.forEach((s) => s.pause()); return Promise.resolve([...Array(8)]) - .then((baseArray) => Promise.all(baseArray.map(() => x.get("blah"), { concurrency: 8 }))) + .then((baseArray) => Promise.all(baseArray.map(() => x.get({ key: "blah" }), { concurrency: 8 }))) .catch((err: Error) => (testErr = err)) .then(() => expect(testErr.message).toEqual("Command timeout")); }) @@ -154,7 +154,7 @@ describe("redundant servers", function () { memcachedServers[3].shutdown(); const connectionsBaseArray = await Promise.resolve([...Array(8)]); - await Promise.all(connectionsBaseArray.map(() => x.cmd("stats"), { concurrency: 8 })); + await Promise.all(connectionsBaseArray.map(() => x.cmd({ data: "stats" }), { concurrency: 8 })); expect(x._servers._exServers.length).toBe(3); await new Promise((r) => setTimeout(r, 1000)); @@ -169,7 +169,7 @@ describe("redundant servers", function () { ); const connectionPromises = await Promise.resolve( - connectionsBaseArray.map(() => x.cmd("stats"), { concurrency: 8 }) + connectionsBaseArray.map(() => x.cmd({ data: "stats" }), { concurrency: 8 }) ); expect(x._servers._exServers.length).toBe(0); @@ -202,7 +202,7 @@ describe("redundant servers", function () { let testErr: Error; return x - .cmd("stats") + .cmd({ data: "stats" }) .catch((err: Error) => (testErr = err)) .then(() => expect(testErr.message).toEqual("No more valid servers left")); });