From 955fa1f5e649e11e457968b4af9bcc83743e5384 Mon Sep 17 00:00:00 2001 From: ogzhanolguncu Date: Tue, 17 Oct 2023 14:31:34 +0300 Subject: [PATCH 1/2] Add length to pipeline --- pkg/pipeline.test.ts | 21 +++++++ pkg/pipeline.ts | 145 ++++++++++++++++--------------------------- 2 files changed, 73 insertions(+), 93 deletions(-) diff --git a/pkg/pipeline.test.ts b/pkg/pipeline.test.ts index 8f6ad3b2..c471eb35 100644 --- a/pkg/pipeline.test.ts +++ b/pkg/pipeline.test.ts @@ -67,6 +67,27 @@ Deno.test("when no commands were added", async (t) => { }); }); +Deno.test("when length called", async (t) => { + await t.step("before exec()", () => { + const key = newKey(); + const p = new Pipeline({ client }); + for (let i = 0; i < 10; i++) { + p.set(key, randomID()); + } + assertEquals(p.length(), 10); + }); + + await t.step("after exec()", async () => { + const key = newKey(); + const p = new Pipeline({ client }); + for (let i = 0; i < 10; i++) { + p.set(key, randomID()); + } + await p.exec(); + assertEquals(p.length(), 10); + }); +}); + Deno.test("when one command throws an error", async (t) => { await t.step("throws", async () => { const p = new Pipeline({ client }).set("key", "value").hget("key", "field"); diff --git a/pkg/pipeline.ts b/pkg/pipeline.ts index 7f675d26..9e1bb306 100644 --- a/pkg/pipeline.ts +++ b/pkg/pipeline.ts @@ -207,7 +207,7 @@ export class Pipeline[] = []> { }) { this.client = opts.client; - this.commands = ([] as unknown) as TCommands; // the TCommands generic in the class definition is only used for carrying through chained command types and should never be explicitly set when instantiating the class + this.commands = [] as unknown as TCommands; // the TCommands generic in the class definition is only used for carrying through chained command types and should never be explicitly set when instantiating the class this.commandOptions = opts.commandOptions; this.multiExec = opts.multiExec ?? false; } @@ -225,8 +225,9 @@ export class Pipeline[] = []> { * ``` */ exec = async < - TCommandResults extends unknown[] = [] extends TCommands ? unknown[] - : InferResponseData, + TCommandResults extends unknown[] = [] extends TCommands + ? unknown[] + : InferResponseData >(): Promise => { if (this.commands.length === 0) { throw new Error("Pipeline is empty"); @@ -240,9 +241,7 @@ export class Pipeline[] = []> { return res.map(({ error, result }, i) => { if (error) { throw new UpstashError( - `Command ${i + 1} [ ${ - this.commands[i].command[0] - } ] failed: ${error}`, + `Command ${i + 1} [ ${this.commands[i].command[0]} ] failed: ${error}` ); } @@ -250,13 +249,19 @@ export class Pipeline[] = []> { }) as TCommandResults; }; + /** + * Returns the length of pipeline before the execution + * + */ + length(): number { + return this.commands.length; + } + /** * Pushes a command into the pipeline and returns a chainable instance of the * pipeline */ - private chain( - command: Command, - ): Pipeline<[...TCommands, Command]> { + private chain(command: Command): Pipeline<[...TCommands, Command]> { this.commands.push(command); return this as any; // TS thinks we're returning Pipeline<[]> here, because we're not creating a new instance of the class, hence the cast } @@ -283,11 +288,7 @@ export class Pipeline[] = []> { sourceKey: string, ...sourceKeys: string[] ): Pipeline<[...TCommands, BitOpCommand]>; - ( - op: "not", - destinationKey: string, - sourceKey: string, - ): Pipeline<[...TCommands, BitOpCommand]>; + (op: "not", destinationKey: string, sourceKey: string): Pipeline<[...TCommands, BitOpCommand]>; } = ( op: "and" | "or" | "xor" | "not", destinationKey: string, @@ -295,10 +296,7 @@ export class Pipeline[] = []> { ...sourceKeys: string[] ) => this.chain( - new BitOpCommand( - [op as any, destinationKey, sourceKey, ...sourceKeys], - this.commandOptions, - ), + new BitOpCommand([op as any, destinationKey, sourceKey, ...sourceKeys], this.commandOptions) ); /** @@ -435,9 +433,8 @@ export class Pipeline[] = []> { /** * @see https://redis.io/commands/hgetall */ - hgetall = >( - ...args: CommandArgs - ) => this.chain(new HGetAllCommand(args, this.commandOptions)); + hgetall = >(...args: CommandArgs) => + this.chain(new HGetAllCommand(args, this.commandOptions)); /** * @see https://redis.io/commands/hincrby @@ -466,9 +463,8 @@ export class Pipeline[] = []> { /** * @see https://redis.io/commands/hmget */ - hmget = >( - ...args: CommandArgs - ) => this.chain(new HMGetCommand(args, this.commandOptions)); + hmget = >(...args: CommandArgs) => + this.chain(new HMGetCommand(args, this.commandOptions)); /** * @see https://redis.io/commands/hmset @@ -482,14 +478,9 @@ export class Pipeline[] = []> { hrandfield = >( key: string, count?: number, - withValues?: boolean, + withValues?: boolean ) => - this.chain( - new HRandFieldCommand( - [key, count, withValues] as any, - this.commandOptions, - ), - ); + this.chain(new HRandFieldCommand([key, count, withValues] as any, this.commandOptions)); /** * @see https://redis.io/commands/hscan @@ -507,9 +498,7 @@ export class Pipeline[] = []> { * @see https://redis.io/commands/hsetnx */ hsetnx = (key: string, field: string, value: TData) => - this.chain( - new HSetNXCommand([key, field, value], this.commandOptions), - ); + this.chain(new HSetNXCommand([key, field, value], this.commandOptions)); /** * @see https://redis.io/commands/hstrlen @@ -556,18 +545,8 @@ export class Pipeline[] = []> { /** * @see https://redis.io/commands/linsert */ - linsert = ( - key: string, - direction: "before" | "after", - pivot: TData, - value: TData, - ) => - this.chain( - new LInsertCommand( - [key, direction, pivot, value], - this.commandOptions, - ), - ); + linsert = (key: string, direction: "before" | "after", pivot: TData, value: TData) => + this.chain(new LInsertCommand([key, direction, pivot, value], this.commandOptions)); /** * @see https://redis.io/commands/llen @@ -597,17 +576,13 @@ export class Pipeline[] = []> { * @see https://redis.io/commands/lpush */ lpush = (key: string, ...elements: TData[]) => - this.chain( - new LPushCommand([key, ...elements], this.commandOptions), - ); + this.chain(new LPushCommand([key, ...elements], this.commandOptions)); /** * @see https://redis.io/commands/lpushx */ lpushx = (key: string, ...elements: TData[]) => - this.chain( - new LPushXCommand([key, ...elements], this.commandOptions), - ); + this.chain(new LPushXCommand([key, ...elements], this.commandOptions)); /** * @see https://redis.io/commands/lrange @@ -679,9 +654,7 @@ export class Pipeline[] = []> { * @see https://redis.io/commands/psetex */ psetex = (key: string, ttl: number, value: TData) => - this.chain( - new PSetEXCommand([key, ttl, value], this.commandOptions), - ); + this.chain(new PSetEXCommand([key, ttl, value], this.commandOptions)); /** * @see https://redis.io/commands/pttl @@ -828,28 +801,20 @@ export class Pipeline[] = []> { /** * @see https://redis.io/commands/smembers */ - smembers = ( - ...args: CommandArgs - ) => this.chain(new SMembersCommand(args, this.commandOptions)); + smembers = (...args: CommandArgs) => + this.chain(new SMembersCommand(args, this.commandOptions)); /** * @see https://redis.io/commands/smismember */ smismember = (key: string, members: TMembers) => - this.chain( - new SMIsMemberCommand([key, members], this.commandOptions), - ); + this.chain(new SMIsMemberCommand([key, members], this.commandOptions)); /** * @see https://redis.io/commands/smove */ smove = (source: string, destination: string, member: TData) => - this.chain( - new SMoveCommand( - [source, destination, member], - this.commandOptions, - ), - ); + this.chain(new SMoveCommand([source, destination, member], this.commandOptions)); /** * @see https://redis.io/commands/spop @@ -927,31 +892,27 @@ export class Pipeline[] = []> { */ zadd = ( ...args: + | [key: string, scoreMember: ScoreMember, ...scoreMemberPairs: ScoreMember[]] | [ - key: string, - scoreMember: ScoreMember, - ...scoreMemberPairs: ScoreMember[], - ] - | [ - key: string, - opts: ZAddCommandOptions | ZAddCommandOptionsWithIncr, - ...scoreMemberPairs: [ScoreMember, ...ScoreMember[]], - ] + key: string, + opts: ZAddCommandOptions | ZAddCommandOptionsWithIncr, + ...scoreMemberPairs: [ScoreMember, ...ScoreMember[]] + ] ) => { if ("score" in args[1]) { return this.chain( new ZAddCommand( [args[0], args[1] as ScoreMember, ...(args.slice(2) as any)], - this.commandOptions, - ), + this.commandOptions + ) ); } return this.chain( new ZAddCommand( [args[0], args[1] as any, ...(args.slice(2) as any)], - this.commandOptions, - ), + this.commandOptions + ) ); }; @@ -971,9 +932,7 @@ export class Pipeline[] = []> { * @see https://redis.io/commands/zincrby */ zincrby = (key: string, increment: number, member: TData) => - this.chain( - new ZIncrByCommand([key, increment, member], this.commandOptions), - ); + this.chain(new ZIncrByCommand([key, increment, member], this.commandOptions)); /** * @see https://redis.io/commands/zinterstore @@ -1012,17 +971,17 @@ export class Pipeline[] = []> { ...args: | [key: string, min: number, max: number, opts?: ZRangeCommandOptions] | [ - key: string, - min: `(${string}` | `[${string}` | "-" | "+", - max: `(${string}` | `[${string}` | "-" | "+", - opts: { byLex: true } & ZRangeCommandOptions, - ] + key: string, + min: `(${string}` | `[${string}` | "-" | "+", + max: `(${string}` | `[${string}` | "-" | "+", + opts: { byLex: true } & ZRangeCommandOptions + ] | [ - key: string, - min: number | `(${number}` | "-inf" | "+inf", - max: number | `(${number}` | "-inf" | "+inf", - opts: { byScore: true } & ZRangeCommandOptions, - ] + key: string, + min: number | `(${number}` | "-inf" | "+inf", + max: number | `(${number}` | "-inf" | "+inf", + opts: { byScore: true } & ZRangeCommandOptions + ] ) => this.chain(new ZRangeCommand(args as any, this.commandOptions)); /** From 570e6e48267899096eb223534046aeaa9b8e1912 Mon Sep 17 00:00:00 2001 From: ogzhanolguncu Date: Tue, 17 Oct 2023 14:32:05 +0300 Subject: [PATCH 2/2] Run fmt on pipeline.ts --- .../README.md | 7 +- examples/google-cloud-functions/README.md | 7 +- pkg/pipeline.ts | 136 ++++++++++++------ 3 files changed, 100 insertions(+), 50 deletions(-) diff --git a/examples/google-cloud-functions-with-typescript/README.md b/examples/google-cloud-functions-with-typescript/README.md index 3dbabff7..8ae761bc 100644 --- a/examples/google-cloud-functions-with-typescript/README.md +++ b/examples/google-cloud-functions-with-typescript/README.md @@ -12,9 +12,10 @@ npm install 2. Create a free Database on [upstash.com](https://console.upstash.com/redis) 3. Copy the `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN` to - `Runtime, build, connections and security settings > Runtime environment variables` in GCP website when creating a new function or pass those keys when you are deploying from the CLI. - + `Runtime, build, connections and security settings > Runtime environment variables` + in GCP website when creating a new function or pass those keys when you are + deploying from the CLI. ## Work locally -Simply run `npm run start` \ No newline at end of file +Simply run `npm run start` diff --git a/examples/google-cloud-functions/README.md b/examples/google-cloud-functions/README.md index 9981304f..74c6d259 100644 --- a/examples/google-cloud-functions/README.md +++ b/examples/google-cloud-functions/README.md @@ -12,9 +12,10 @@ npm install 2. Create a free Database on [upstash.com](https://console.upstash.com/redis) 3. Copy the `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN` to - `Runtime, build, connections and security settings > Runtime environment variables` in GCP when creating a new function or pass those keys when you are deploying from the CLI. - + `Runtime, build, connections and security settings > Runtime environment variables` + in GCP when creating a new function or pass those keys when you are deploying + from the CLI. ## Work locally -Simply run `npm run start` \ No newline at end of file +Simply run `npm run start` diff --git a/pkg/pipeline.ts b/pkg/pipeline.ts index 9e1bb306..3d78e900 100644 --- a/pkg/pipeline.ts +++ b/pkg/pipeline.ts @@ -225,9 +225,8 @@ export class Pipeline[] = []> { * ``` */ exec = async < - TCommandResults extends unknown[] = [] extends TCommands - ? unknown[] - : InferResponseData + TCommandResults extends unknown[] = [] extends TCommands ? unknown[] + : InferResponseData, >(): Promise => { if (this.commands.length === 0) { throw new Error("Pipeline is empty"); @@ -241,7 +240,9 @@ export class Pipeline[] = []> { return res.map(({ error, result }, i) => { if (error) { throw new UpstashError( - `Command ${i + 1} [ ${this.commands[i].command[0]} ] failed: ${error}` + `Command ${i + 1} [ ${ + this.commands[i].command[0] + } ] failed: ${error}`, ); } @@ -251,7 +252,6 @@ export class Pipeline[] = []> { /** * Returns the length of pipeline before the execution - * */ length(): number { return this.commands.length; @@ -261,7 +261,9 @@ export class Pipeline[] = []> { * Pushes a command into the pipeline and returns a chainable instance of the * pipeline */ - private chain(command: Command): Pipeline<[...TCommands, Command]> { + private chain( + command: Command, + ): Pipeline<[...TCommands, Command]> { this.commands.push(command); return this as any; // TS thinks we're returning Pipeline<[]> here, because we're not creating a new instance of the class, hence the cast } @@ -288,7 +290,11 @@ export class Pipeline[] = []> { sourceKey: string, ...sourceKeys: string[] ): Pipeline<[...TCommands, BitOpCommand]>; - (op: "not", destinationKey: string, sourceKey: string): Pipeline<[...TCommands, BitOpCommand]>; + ( + op: "not", + destinationKey: string, + sourceKey: string, + ): Pipeline<[...TCommands, BitOpCommand]>; } = ( op: "and" | "or" | "xor" | "not", destinationKey: string, @@ -296,7 +302,10 @@ export class Pipeline[] = []> { ...sourceKeys: string[] ) => this.chain( - new BitOpCommand([op as any, destinationKey, sourceKey, ...sourceKeys], this.commandOptions) + new BitOpCommand( + [op as any, destinationKey, sourceKey, ...sourceKeys], + this.commandOptions, + ), ); /** @@ -433,8 +442,9 @@ export class Pipeline[] = []> { /** * @see https://redis.io/commands/hgetall */ - hgetall = >(...args: CommandArgs) => - this.chain(new HGetAllCommand(args, this.commandOptions)); + hgetall = >( + ...args: CommandArgs + ) => this.chain(new HGetAllCommand(args, this.commandOptions)); /** * @see https://redis.io/commands/hincrby @@ -463,8 +473,9 @@ export class Pipeline[] = []> { /** * @see https://redis.io/commands/hmget */ - hmget = >(...args: CommandArgs) => - this.chain(new HMGetCommand(args, this.commandOptions)); + hmget = >( + ...args: CommandArgs + ) => this.chain(new HMGetCommand(args, this.commandOptions)); /** * @see https://redis.io/commands/hmset @@ -478,9 +489,14 @@ export class Pipeline[] = []> { hrandfield = >( key: string, count?: number, - withValues?: boolean + withValues?: boolean, ) => - this.chain(new HRandFieldCommand([key, count, withValues] as any, this.commandOptions)); + this.chain( + new HRandFieldCommand( + [key, count, withValues] as any, + this.commandOptions, + ), + ); /** * @see https://redis.io/commands/hscan @@ -498,7 +514,9 @@ export class Pipeline[] = []> { * @see https://redis.io/commands/hsetnx */ hsetnx = (key: string, field: string, value: TData) => - this.chain(new HSetNXCommand([key, field, value], this.commandOptions)); + this.chain( + new HSetNXCommand([key, field, value], this.commandOptions), + ); /** * @see https://redis.io/commands/hstrlen @@ -545,8 +563,18 @@ export class Pipeline[] = []> { /** * @see https://redis.io/commands/linsert */ - linsert = (key: string, direction: "before" | "after", pivot: TData, value: TData) => - this.chain(new LInsertCommand([key, direction, pivot, value], this.commandOptions)); + linsert = ( + key: string, + direction: "before" | "after", + pivot: TData, + value: TData, + ) => + this.chain( + new LInsertCommand( + [key, direction, pivot, value], + this.commandOptions, + ), + ); /** * @see https://redis.io/commands/llen @@ -576,13 +604,17 @@ export class Pipeline[] = []> { * @see https://redis.io/commands/lpush */ lpush = (key: string, ...elements: TData[]) => - this.chain(new LPushCommand([key, ...elements], this.commandOptions)); + this.chain( + new LPushCommand([key, ...elements], this.commandOptions), + ); /** * @see https://redis.io/commands/lpushx */ lpushx = (key: string, ...elements: TData[]) => - this.chain(new LPushXCommand([key, ...elements], this.commandOptions)); + this.chain( + new LPushXCommand([key, ...elements], this.commandOptions), + ); /** * @see https://redis.io/commands/lrange @@ -654,7 +686,9 @@ export class Pipeline[] = []> { * @see https://redis.io/commands/psetex */ psetex = (key: string, ttl: number, value: TData) => - this.chain(new PSetEXCommand([key, ttl, value], this.commandOptions)); + this.chain( + new PSetEXCommand([key, ttl, value], this.commandOptions), + ); /** * @see https://redis.io/commands/pttl @@ -801,20 +835,28 @@ export class Pipeline[] = []> { /** * @see https://redis.io/commands/smembers */ - smembers = (...args: CommandArgs) => - this.chain(new SMembersCommand(args, this.commandOptions)); + smembers = ( + ...args: CommandArgs + ) => this.chain(new SMembersCommand(args, this.commandOptions)); /** * @see https://redis.io/commands/smismember */ smismember = (key: string, members: TMembers) => - this.chain(new SMIsMemberCommand([key, members], this.commandOptions)); + this.chain( + new SMIsMemberCommand([key, members], this.commandOptions), + ); /** * @see https://redis.io/commands/smove */ smove = (source: string, destination: string, member: TData) => - this.chain(new SMoveCommand([source, destination, member], this.commandOptions)); + this.chain( + new SMoveCommand( + [source, destination, member], + this.commandOptions, + ), + ); /** * @see https://redis.io/commands/spop @@ -892,27 +934,31 @@ export class Pipeline[] = []> { */ zadd = ( ...args: - | [key: string, scoreMember: ScoreMember, ...scoreMemberPairs: ScoreMember[]] | [ - key: string, - opts: ZAddCommandOptions | ZAddCommandOptionsWithIncr, - ...scoreMemberPairs: [ScoreMember, ...ScoreMember[]] - ] + key: string, + scoreMember: ScoreMember, + ...scoreMemberPairs: ScoreMember[], + ] + | [ + key: string, + opts: ZAddCommandOptions | ZAddCommandOptionsWithIncr, + ...scoreMemberPairs: [ScoreMember, ...ScoreMember[]], + ] ) => { if ("score" in args[1]) { return this.chain( new ZAddCommand( [args[0], args[1] as ScoreMember, ...(args.slice(2) as any)], - this.commandOptions - ) + this.commandOptions, + ), ); } return this.chain( new ZAddCommand( [args[0], args[1] as any, ...(args.slice(2) as any)], - this.commandOptions - ) + this.commandOptions, + ), ); }; @@ -932,7 +978,9 @@ export class Pipeline[] = []> { * @see https://redis.io/commands/zincrby */ zincrby = (key: string, increment: number, member: TData) => - this.chain(new ZIncrByCommand([key, increment, member], this.commandOptions)); + this.chain( + new ZIncrByCommand([key, increment, member], this.commandOptions), + ); /** * @see https://redis.io/commands/zinterstore @@ -971,17 +1019,17 @@ export class Pipeline[] = []> { ...args: | [key: string, min: number, max: number, opts?: ZRangeCommandOptions] | [ - key: string, - min: `(${string}` | `[${string}` | "-" | "+", - max: `(${string}` | `[${string}` | "-" | "+", - opts: { byLex: true } & ZRangeCommandOptions - ] + key: string, + min: `(${string}` | `[${string}` | "-" | "+", + max: `(${string}` | `[${string}` | "-" | "+", + opts: { byLex: true } & ZRangeCommandOptions, + ] | [ - key: string, - min: number | `(${number}` | "-inf" | "+inf", - max: number | `(${number}` | "-inf" | "+inf", - opts: { byScore: true } & ZRangeCommandOptions - ] + key: string, + min: number | `(${number}` | "-inf" | "+inf", + max: number | `(${number}` | "-inf" | "+inf", + opts: { byScore: true } & ZRangeCommandOptions, + ] ) => this.chain(new ZRangeCommand(args as any, this.commandOptions)); /**