Skip to content

Commit

Permalink
Add XTRIM command
Browse files Browse the repository at this point in the history
  • Loading branch information
ogzhanolguncu committed Dec 15, 2023
1 parent 8832b19 commit 07c3942
Show file tree
Hide file tree
Showing 6 changed files with 161 additions and 2 deletions.
1 change: 1 addition & 0 deletions pkg/commands/mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ export * from "./xdel";
export * from "./xlen";
export * from "./xrange";
export * from "./xrevrange";
export * from "./xtrim";
export * from "./zadd";
export * from "./zcard";
export * from "./zcount";
Expand Down
8 changes: 6 additions & 2 deletions pkg/commands/xrange.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@ describe("without options", () => {
const field2 = "field2";
const member2 = randomID();

await new XAddCommand([key, "*", { [field1]: member1, [field2]: member2 }]).exec(client);
await new XAddCommand([
key,
"*",
{ [field1]: member1, [field2]: member2 },
]).exec(client);

const res = await new XRangeCommand([key, "-", "+"]).exec(client);
expect(Object.keys(res).length).toBe(1);
Expand Down Expand Up @@ -49,7 +53,7 @@ describe("limit", () => {
});
});

test("many fields", () => {
describe("many fields", () => {
test("returns all fields", async () => {
const key = newKey();

Expand Down
107 changes: 107 additions & 0 deletions pkg/commands/xtrim.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import { keygen, newHttpClient, randomID } from "../test-utils";

import { afterAll, describe, expect, test } from "bun:test";
import { XAddCommand } from "./xadd";
import { XLenCommand } from "./xlen";
import { XTrimCommand } from "./xtrim";

const client = newHttpClient();

const { newKey, cleanup } = keygen();
afterAll(cleanup);

describe("XLEN", () => {
test(
"should approximately trim stream to 300 items",
async () => {
const key = newKey();

const promises = [];
for (let i = 1; i <= 10000; i++) {
promises.push(
new XAddCommand([key, "*", { [randomID()]: randomID() }]).exec(client)
);
}
await Promise.all(promises);

await new XTrimCommand([
key,
{ strategy: "MAXLEN", threshold: 300, exactness: "~" },
]).exec(client);

const len = await new XLenCommand([key]).exec(client);

expect(len).toBeGreaterThanOrEqual(290);
expect(len).toBeLessThanOrEqual(310);
},
{ timeout: 1000 * 60 }
);

test("should trim with zero threshold and remove everything", async () => {
const key = newKey();

const promises = [];
for (let i = 1; i <= 50; i++) {
promises.push(
new XAddCommand([key, "*", { [randomID()]: randomID() }]).exec(client)
);
}
await Promise.all(promises);

await new XTrimCommand([
key,
{ strategy: "MAXLEN", threshold: 0, exactness: "=" },
]).exec(client);

const len = await new XLenCommand([key]).exec(client);
expect(len).toBeLessThanOrEqual(1);
});

test(
"should trim with MINID and a limit and only remove 10 items that satisfies MINID",
async () => {
const key = newKey();
const baseTimestamp = Date.now();

for (let i = 0; i < 100; i++) {
const id = `${baseTimestamp}-${i}`;
await new XAddCommand([key, id, { data: `value${i}` }]).exec(client);
}

const midRangeId = `${baseTimestamp}-50`;

await new XTrimCommand([
key,
{ strategy: "MINID", threshold: midRangeId, limit: 10 },
]).exec(client);

const len = await new XLenCommand([key]).exec(client);
expect(len).toBeLessThanOrEqual(100);
},
{ timeout: 20000 }
);

test(
"should trim with MINID and a without limit and delete half of the elements",
async () => {
const key = newKey();
const baseTimestamp = Date.now();

for (let i = 0; i < 100; i++) {
const id = `${baseTimestamp}-${i}`;
await new XAddCommand([key, id, { data: `value${i}` }]).exec(client);
}

const midRangeId = `${baseTimestamp}-50`;

await new XTrimCommand([
key,
{ strategy: "MINID", threshold: midRangeId },
]).exec(client);

const len = await new XLenCommand([key]).exec(client);
expect(len).toBeLessThanOrEqual(50);
},
{ timeout: 20000 }
);
});
33 changes: 33 additions & 0 deletions pkg/commands/xtrim.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { Command, CommandOptions } from "./command";

/**
* @see https://redis.io/commands/xtrim
*/

type XTrimOptions = {
strategy: "MAXLEN" | "MINID";
exactness?: "~" | "=";
threshold: number | string;
limit?: number;
};

export class XTrimCommand extends Command<number, number> {
constructor(
[key, options]: [key: string, options: XTrimOptions],
opts?: CommandOptions<number, number>
) {
const { limit, strategy, threshold, exactness = "~" } = options;

super(
[
"XTRIM",
key,
strategy,
exactness,
threshold,
...(limit ? ["LIMIT", limit] : []),
],
opts
);
}
}
7 changes: 7 additions & 0 deletions pkg/pipeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ import {
XLenCommand,
XRangeCommand,
XRevRangeCommand,
XTrimCommand,
ZAddCommand,
ZAddCommandOptions,
ZCardCommand,
Expand Down Expand Up @@ -1015,6 +1016,12 @@ export class Pipeline<TCommands extends Command<any, any>[] = []> {
xlen = (...args: CommandArgs<typeof XLenCommand>) =>
this.chain(new XLenCommand(args, this.commandOptions));

/**
* @see https://redis.io/commands/xtrim
*/
xtrim = (...args: CommandArgs<typeof XTrimCommand>) =>
this.chain(new XTrimCommand(args, this.commandOptions));

/**
* @see https://redis.io/commands/xrange
*/
Expand Down
7 changes: 7 additions & 0 deletions pkg/redis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ import {
XLenCommand,
XRangeCommand,
XRevRangeCommand,
XTrimCommand,
ZAddCommand,
ZAddCommandOptions,
ZCardCommand,
Expand Down Expand Up @@ -1109,6 +1110,12 @@ export class Redis {
xlen = (...args: CommandArgs<typeof XLenCommand>) =>
new XLenCommand(args, this.opts).exec(this.client);

/**
* @see https://redis.io/commands/xtrim
*/
xtrim = (...args: CommandArgs<typeof XTrimCommand>) =>
new XTrimCommand(args, this.opts).exec(this.client);

/**
* @see https://redis.io/commands/xrange
*/
Expand Down

0 comments on commit 07c3942

Please sign in to comment.