Skip to main content
Glama
explicit-table-ids.test.ts16.9 kB
import { RuleTester } from "@typescript-eslint/rule-tester"; import { explicitTableIds } from "../lib/explicitTableIds.js"; const ruleTester = new RuleTester({ languageOptions: { parserOptions: { ecmaVersion: 2020, sourceType: "module", projectService: { allowDefaultProject: ["*.ts*", "convex/*.ts*"], }, }, }, }); ruleTester.run("explicit-table-ids", explicitTableIds, { valid: [ // Already migrated get call { code: ` import { query } from "./_generated/server"; import { Id } from "./_generated/dataModel"; export const getMessage = query({ args: {}, handler: async (ctx, args) => { const messageId: Id<"messages"> = "123" as any; return await ctx.db.get("messages", messageId); }, }); `, filename: "convex/messages.ts", }, // Already migrated replace call { code: ` import { mutation } from "./_generated/server"; import { Id } from "./_generated/dataModel"; export const updateMessage = mutation({ args: {}, handler: async (ctx, args) => { const messageId: Id<"messages"> = "123" as any; await ctx.db.replace("messages", messageId, { text: "updated" }); }, }); `, filename: "convex/messages.ts", }, // Already migrated patch call { code: ` import { mutation } from "./_generated/server"; import { Id } from "./_generated/dataModel"; export const patchMessage = mutation({ args: {}, handler: async (ctx, args) => { const messageId: Id<"messages"> = "123" as any; await ctx.db.patch("messages", messageId, { text: "patched" }); }, }); `, filename: "convex/messages.ts", }, // Already migrated delete call { code: ` import { mutation } from "./_generated/server"; import { Id } from "./_generated/dataModel"; export const deleteMessage = mutation({ args: {}, handler: async (ctx, args) => { const messageId: Id<"messages"> = "123" as any; await ctx.db.delete("messages", messageId); }, }); `, filename: "convex/messages.ts", }, // Not a db call { code: ` import { query } from "./_generated/server"; export const list = query({ args: {}, handler: async (ctx, args) => { return await ctx.db.query("messages").collect(); }, }); `, filename: "convex/messages.ts", }, // Regression test for a false positive in IntDate.get from jsrsasign { code: ` declare namespace MyNamespace { function get(parameter: number): string; } async function _ignoreUnrelatedFunctionsFromNamespaces() { MyNamespace.get(1); } `, filename: "convex/messages.ts", }, // Ignore methods from lib types { code: ` new URL("https://www.convex.dev?test=1").searchParams.get("test"); `, filename: "convex/messages.ts", }, // Ignore .replace on string { code: ` console.log("test".replace("test", "test2")); `, filename: "convex/messages.ts", }, ], invalid: [ // Unmigrated get call { code: ` import { query } from "./_generated/server"; import { Id } from "./_generated/dataModel"; export const getMessage = query({ args: {}, handler: async (ctx, args) => { const messageId: Id<"messages"> = "123" as any; return await ctx.db.get(messageId); }, }); `, errors: [ { messageId: "missing-table-name", }, ], output: ` import { query } from "./_generated/server"; import { Id } from "./_generated/dataModel"; export const getMessage = query({ args: {}, handler: async (ctx, args) => { const messageId: Id<"messages"> = "123" as any; return await ctx.db.get("messages", messageId); }, }); `, filename: "convex/messages.ts", }, // Unmigrated replace call { code: ` import { mutation } from "./_generated/server"; import { Id } from "./_generated/dataModel"; export const updateMessage = mutation({ args: {}, handler: async (ctx, args) => { const messageId: Id<"messages"> = "123" as any; await ctx.db.replace(messageId, { text: "updated" }); }, }); `, errors: [ { messageId: "missing-table-name", }, ], output: ` import { mutation } from "./_generated/server"; import { Id } from "./_generated/dataModel"; export const updateMessage = mutation({ args: {}, handler: async (ctx, args) => { const messageId: Id<"messages"> = "123" as any; await ctx.db.replace("messages", messageId, { text: "updated" }); }, }); `, filename: "convex/messages.ts", }, // Unmigrated patch call { code: ` import { mutation } from "./_generated/server"; import { Id } from "./_generated/dataModel"; export const patchMessage = mutation({ args: {}, handler: async (ctx, args) => { const messageId: Id<"messages"> = "123" as any; await ctx.db.patch(messageId, { text: "patched" }); }, }); `, errors: [ { messageId: "missing-table-name", }, ], output: ` import { mutation } from "./_generated/server"; import { Id } from "./_generated/dataModel"; export const patchMessage = mutation({ args: {}, handler: async (ctx, args) => { const messageId: Id<"messages"> = "123" as any; await ctx.db.patch("messages", messageId, { text: "patched" }); }, }); `, filename: "convex/messages.ts", }, // Unmigrated delete call { code: ` import { mutation } from "./_generated/server"; import { Id } from "./_generated/dataModel"; export const deleteMessage = mutation({ args: {}, handler: async (ctx, args) => { const messageId: Id<"messages"> = "123" as any; await ctx.db.delete(messageId); }, }); `, errors: [ { messageId: "missing-table-name", }, ], output: ` import { mutation } from "./_generated/server"; import { Id } from "./_generated/dataModel"; export const deleteMessage = mutation({ args: {}, handler: async (ctx, args) => { const messageId: Id<"messages"> = "123" as any; await ctx.db.delete("messages", messageId); }, }); `, filename: "convex/messages.ts", }, // Multiple unmigrated calls in one function { code: ` import { mutation } from "./_generated/server"; import { Id } from "./_generated/dataModel"; export const updateMultiple = mutation({ args: {}, handler: async (ctx, args) => { const messageId: Id<"messages"> = "123" as any; const userId: Id<"users"> = "456" as any; const message = await ctx.db.get(messageId); const user = await ctx.db.get(userId); await ctx.db.patch(messageId, { author: user?.name }); }, }); `, errors: [ { messageId: "missing-table-name" }, { messageId: "missing-table-name" }, { messageId: "missing-table-name" }, ], output: ` import { mutation } from "./_generated/server"; import { Id } from "./_generated/dataModel"; export const updateMultiple = mutation({ args: {}, handler: async (ctx, args) => { const messageId: Id<"messages"> = "123" as any; const userId: Id<"users"> = "456" as any; const message = await ctx.db.get("messages", messageId); const user = await ctx.db.get("users", userId); await ctx.db.patch("messages", messageId, { author: user?.name }); }, }); `, filename: "convex/messages.ts", }, // Unmigrated call with different table name { code: ` import { query } from "./_generated/server"; import { Id } from "./_generated/dataModel"; export const getUser = query({ args: {}, handler: async (ctx, args) => { const userId: Id<"users"> = "123" as any; return await ctx.db.get(userId); }, }); `, errors: [ { messageId: "missing-table-name", }, ], output: ` import { query } from "./_generated/server"; import { Id } from "./_generated/dataModel"; export const getUser = query({ args: {}, handler: async (ctx, args) => { const userId: Id<"users"> = "123" as any; return await ctx.db.get("users", userId); }, }); `, filename: "convex/users.ts", }, // Type is `any` - should report error but no auto-fix { code: ` import { query } from "./_generated/server"; export const getMessage = query({ args: {}, handler: async (ctx, args) => { const id: any = "123"; return await ctx.db.get(id); }, }); `, errors: [ { messageId: "missing-table-name-no-inference", }, ], filename: "convex/messages.ts", }, // Type is `Id<any>` - should report error but no auto-fix { code: ` import { query } from "./_generated/server"; import { Id } from "./_generated/dataModel"; export const getMessage = query({ args: {}, handler: async (ctx, args) => { const id: Id<any> = "123" as Id<any>; return await ctx.db.get(id); }, }); `, errors: [ { messageId: "missing-table-name-no-inference", }, ], filename: "convex/messages.ts", }, // Type is `any` with db.patch - should report error but no auto-fix { code: ` import { mutation } from "./_generated/server"; export const updateMessage = mutation({ args: {}, handler: async (ctx, args) => { const id: any = "123"; await ctx.db.patch(id, { text: "updated" }); }, }); `, errors: [ { messageId: "missing-table-name-no-inference", }, ], filename: "convex/messages.ts", }, // Type is `Id<any>` with db.delete - should report error but no auto-fix { code: ` import { mutation } from "./_generated/server"; import { Id } from "./_generated/dataModel"; export const deleteMessage = mutation({ args: {}, handler: async (ctx, args) => { const id: Id<any> = "123" as Id<any>; await ctx.db.delete(id); }, }); `, errors: [ { messageId: "missing-table-name-no-inference", }, ], filename: "convex/messages.ts", }, // DatabaseReader type - should detect and auto-fix { code: ` import { Id } from "./_generated/dataModel"; import { DatabaseReader } from "./_generated/server"; async function fromDbReader(db: DatabaseReader, id: Id<"documents">) { await db.get(id); } `, errors: [ { messageId: "missing-table-name", }, ], output: ` import { Id } from "./_generated/dataModel"; import { DatabaseReader } from "./_generated/server"; async function fromDbReader(db: DatabaseReader, id: Id<"documents">) { await db.get("documents", id); } `, filename: "convex/helpers.ts", }, // GenericDatabaseReader type - should detect and auto-fix { code: ` import { GenericDatabaseReader, GenericDataModel, } from "convex/server"; import { Id } from "./_generated/dataModel"; async function fromGenericDbReader( db: GenericDatabaseReader<GenericDataModel>, id: Id<"documents">, ) { await db.get(id); } `, errors: [ { messageId: "missing-table-name", }, ], output: ` import { GenericDatabaseReader, GenericDataModel, } from "convex/server"; import { Id } from "./_generated/dataModel"; async function fromGenericDbReader( db: GenericDatabaseReader<GenericDataModel>, id: Id<"documents">, ) { await db.get("documents", id); } `, filename: "convex/helpers.ts", }, // GenericDatabaseReader with extends - should detect and auto-fix { code: ` import { GenericDatabaseReader, GenericDataModel, } from "convex/server"; import { Id } from "./_generated/dataModel"; async function fromGenericDbReaderExtends< SomeDataModel extends GenericDataModel, >(db: GenericDatabaseReader<SomeDataModel>, id: Id<"documents">) { await db.get(id); } `, errors: [ { messageId: "missing-table-name", }, ], output: ` import { GenericDatabaseReader, GenericDataModel, } from "convex/server"; import { Id } from "./_generated/dataModel"; async function fromGenericDbReaderExtends< SomeDataModel extends GenericDataModel, >(db: GenericDatabaseReader<SomeDataModel>, id: Id<"documents">) { await db.get("documents", id); } `, filename: "convex/helpers.ts", }, // DatabaseWriter type - should detect and auto-fix all methods { code: ` import { Id } from "./_generated/dataModel"; import { DatabaseWriter } from "./_generated/server"; async function fromDbWriter(db: DatabaseWriter, id: Id<"documents">) { await db.get(id); await db.replace(id, { name: "test2" }); await db.patch(id, { name: "test3" }); await db.delete(id); } `, errors: [ { messageId: "missing-table-name" }, { messageId: "missing-table-name" }, { messageId: "missing-table-name" }, { messageId: "missing-table-name" }, ], output: ` import { Id } from "./_generated/dataModel"; import { DatabaseWriter } from "./_generated/server"; async function fromDbWriter(db: DatabaseWriter, id: Id<"documents">) { await db.get("documents", id); await db.replace("documents", id, { name: "test2" }); await db.patch("documents", id, { name: "test3" }); await db.delete("documents", id); } `, filename: "convex/helpers.ts", }, // GenericDatabaseWriter type - should detect and auto-fix all methods { code: ` import { GenericDatabaseWriter, GenericDataModel, } from "convex/server"; import { Id } from "./_generated/dataModel"; async function fromGenericDbWriter( db: GenericDatabaseWriter<GenericDataModel>, id: Id<"documents">, ) { await db.get(id); await db.replace(id, { name: "test2" }); await db.patch(id, { name: "test3" }); await db.delete(id); } `, errors: [ { messageId: "missing-table-name" }, { messageId: "missing-table-name" }, { messageId: "missing-table-name" }, { messageId: "missing-table-name" }, ], output: ` import { GenericDatabaseWriter, GenericDataModel, } from "convex/server"; import { Id } from "./_generated/dataModel"; async function fromGenericDbWriter( db: GenericDatabaseWriter<GenericDataModel>, id: Id<"documents">, ) { await db.get("documents", id); await db.replace("documents", id, { name: "test2" }); await db.patch("documents", id, { name: "test3" }); await db.delete("documents", id); } `, filename: "convex/helpers.ts", }, ], });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/get-convex/convex-backend'

If you have feedback or need assistance with the MCP directory API, please join our Discord server