From 4fc2858a96bd15e272a015632ae3ee5b0ff5b791 Mon Sep 17 00:00:00 2001 From: ogzhanolguncu Date: Fri, 27 Oct 2023 11:34:47 +0300 Subject: [PATCH] Add copy command to SDK --- pkg/commands/copy.test.ts | 65 +++++++++++++++++++++++++++++++++++++++ pkg/commands/copy.ts | 21 +++++++++++++ pkg/commands/mod.ts | 1 + pkg/pipeline.ts | 7 +++++ pkg/redis.ts | 7 +++++ 5 files changed, 101 insertions(+) create mode 100644 pkg/commands/copy.test.ts create mode 100644 pkg/commands/copy.ts diff --git a/pkg/commands/copy.test.ts b/pkg/commands/copy.test.ts new file mode 100644 index 00000000..b072d301 --- /dev/null +++ b/pkg/commands/copy.test.ts @@ -0,0 +1,65 @@ +import { keygen, newHttpClient, randomID } from "../test-utils"; + +import { afterAll, describe, expect, test } from "bun:test"; +import { CopyCommand } from "./copy"; +import { SetCommand } from "./set"; +import { LPushCommand } from "./lpush"; + +const client = newHttpClient(); + +const { newKey, cleanup } = keygen(); +afterAll(cleanup); + +describe("COPY test", () => { + test("should copy key-value to another key", async () => { + const key = newKey(); + const destinationKey = newKey(); + const value = randomID(); + await new SetCommand([key, value]).exec(client); + const res = await new CopyCommand([key, destinationKey]).exec(client); + expect(res).toEqual("COPIED"); + }); + + test("should not override existing destination", async () => { + const key = newKey(); + const destinationKey = newKey(); + const value = randomID(); + await new SetCommand([key, value]).exec(client); + await new SetCommand([destinationKey, value]).exec(client); + const res = await new CopyCommand([key, destinationKey]).exec(client); + expect(res).toEqual("NOT_COPIED"); + }); + + test("should override existing destination with replace", async () => { + const key = newKey(); + const destinationKey = newKey(); + const value = randomID(); + await new SetCommand([key, value]).exec(client); + await new SetCommand([destinationKey, value]).exec(client); + const res = await new CopyCommand([key, destinationKey, { replace: true }]).exec(client); + expect(res).toEqual("COPIED"); + }); + + test("should handle non-existent source key", async () => { + const key = newKey(); + const destinationKey = newKey(); + const res = await new CopyCommand([key, destinationKey]).exec(client); + expect(res).toEqual("NOT_COPIED"); + }); + + test("should handle same source and destination keys", async () => { + const key = newKey(); + const value = randomID(); + await new SetCommand([key, value]).exec(client); + const res = await new CopyCommand([key, key]).exec(client); + expect(res).toEqual("NOT_COPIED"); + }); + + test("should copy list data type", async () => { + const key = newKey(); + const destinationKey = newKey(); + await new LPushCommand([key, "value1", "value2"]).exec(client); + const res = await new CopyCommand([key, destinationKey]).exec(client); + expect(res).toEqual("COPIED"); + }); +}); diff --git a/pkg/commands/copy.ts b/pkg/commands/copy.ts new file mode 100644 index 00000000..4a85c569 --- /dev/null +++ b/pkg/commands/copy.ts @@ -0,0 +1,21 @@ +import { Command, CommandOptions } from "./command"; + +/** + * @see https://redis.io/commands/copy + */ +export class CopyCommand extends Command { + constructor( + [key, destinationKey, opts]: [key: string, destinationKey: string, opts?: { replace: boolean }], + commandOptions?: CommandOptions + ) { + super(["COPY", key, destinationKey, ...(opts?.replace ? ["REPLACE"] : [])], { + ...commandOptions, + deserialize(result) { + if (result > 0) { + return "COPIED"; + } + return "NOT_COPIED"; + }, + }); + } +} diff --git a/pkg/commands/mod.ts b/pkg/commands/mod.ts index d5666f64..fc3be0e1 100644 --- a/pkg/commands/mod.ts +++ b/pkg/commands/mod.ts @@ -3,6 +3,7 @@ export * from "./bitcount"; export * from "./bitop"; export * from "./bitpos"; export * from "./command"; +export * from "./copy"; export * from "./dbsize"; export * from "./decr"; export * from "./decrby"; diff --git a/pkg/pipeline.ts b/pkg/pipeline.ts index dcc80741..50bc5da2 100644 --- a/pkg/pipeline.ts +++ b/pkg/pipeline.ts @@ -5,6 +5,7 @@ import { BitCountCommand, BitOpCommand, BitPosCommand, + CopyCommand, DBSizeCommand, DecrByCommand, DecrCommand, @@ -311,6 +312,12 @@ export class Pipeline[] = []> { bitpos = (...args: CommandArgs) => this.chain(new BitPosCommand(args, this.commandOptions)); + /** + * @see https://redis.io/commands/copy + */ + copy = (...args: CommandArgs) => + this.chain(new CopyCommand(args, this.commandOptions)); + /** * @see https://redis.io/commands/zdiffstore */ diff --git a/pkg/redis.ts b/pkg/redis.ts index 40c707b9..42bbf561 100644 --- a/pkg/redis.ts +++ b/pkg/redis.ts @@ -4,6 +4,7 @@ import { BitOpCommand, BitPosCommand, CommandOptions, + CopyCommand, DBSizeCommand, DecrByCommand, DecrCommand, @@ -455,6 +456,12 @@ export class Redis { bitpos = (...args: CommandArgs) => new BitPosCommand(args, this.opts).exec(this.client); + /** + * @see https://redis.io/commands/copy + */ + copy = (...args: CommandArgs) => + new CopyCommand(args, this.opts).exec(this.client); + /** * @see https://redis.io/commands/dbsize */