Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions src/client/create-schema.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { getAuthTables } from "better-auth/db";
import { describe, expect, it } from "vitest";
import { options } from "../auth-options.js";
import { createSchema } from "./create-schema.js";

describe("createSchema", () => {
it("generates the index used to clean up expired rate limits", async () => {
const { code } = await createSchema({
tables: getAuthTables(options),
});

expect(code).toContain('.index("lastRequest", ["lastRequest"])');
});
});
2 changes: 1 addition & 1 deletion src/client/create-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const resolveCdTarget = (
// all fields in the schema specialFields are automatically indexed
export const indexFields = {
account: ["accountId", ["accountId", "providerId"], ["providerId", "userId"]],
rateLimit: ["key"],
rateLimit: ["key", "lastRequest"],
session: ["expiresAt", ["expiresAt", "userId"]],
verification: ["expiresAt", "identifier"],
user: [["email", "name"], "name", "userId"],
Expand Down
52 changes: 52 additions & 0 deletions src/client/rate-limit-index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/// <reference types="vite/client" />

import { convexTest } from "convex-test";
import { makeFunctionReference } from "convex/server";
import type { FunctionArgs, FunctionReturnType } from "convex/server";
import { afterEach, describe, expect, it, vi } from "vitest";
import type { ComponentApi } from "../component/_generated/component.js";
import schema from "../component/schema.js";

type DeleteMany = ComponentApi["adapter"]["deleteMany"];
const deleteMany = makeFunctionReference<
"mutation",
FunctionArgs<DeleteMany>,
FunctionReturnType<DeleteMany>
>("adapter:deleteMany");

describe("rate limit cleanup", () => {
afterEach(() => {
vi.restoreAllMocks();
});

it("uses the lastRequest index for range deletion", async () => {
const t = convexTest(schema, import.meta.glob("../component/**/*.*s"));
await t.run(async (ctx) => {
await ctx.db.insert("rateLimit", {
key: "expired",
count: 1,
lastRequest: 100,
});
await ctx.db.insert("rateLimit", {
key: "current",
count: 1,
lastRequest: 300,
});
});
const warn = vi.spyOn(console, "warn").mockImplementation(() => {});

const result = await t.mutation(deleteMany, {
input: {
model: "rateLimit",
where: [{ field: "lastRequest", operator: "lt", value: 200 }],
},
paginationOpts: { cursor: null, numItems: 100 },
});

expect(result.count).toBe(1);
expect(warn).not.toHaveBeenCalled();
await expect(
t.run((ctx) => ctx.db.query("rateLimit").collect())
).resolves.toMatchObject([{ key: "current", lastRequest: 300 }]);
});
});
3 changes: 2 additions & 1 deletion src/component/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,8 @@ export const tables = {
count: v.number(),
lastRequest: v.number(),
})
.index("key", ["key"]),
.index("key", ["key"])
.index("lastRequest", ["lastRequest"]),
};

const schema = defineSchema(tables);
Expand Down