Skip to content
Merged
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
74 changes: 74 additions & 0 deletions packages/convex-helpers/server/triggers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ const schema = defineSchema({
lastName: v.string(),
fullName: v.string(),
}),

userCount: defineTable({
count: v.number(),
}),
});
type DataModel = DataModelFromSchemaDefinition<typeof schema>;
const rawMutation = mutationGeneric as MutationBuilder<DataModel, "public">;
Expand Down Expand Up @@ -70,6 +74,20 @@ triggers.register("usersExplicitIncorrectTable", async (ctx, change) => {
}
});

// Keep a denormalized count of all users.
triggers.register("usersExplicit", async (ctx, change) => {
const countDoc = await ctx.db.query("userCount").first();
const currentCount = countDoc?.count ?? 0;
const countId =
countDoc?._id ?? (await ctx.db.insert("userCount", { count: 0 }));

if (change.operation === "insert") {
await ctx.db.patch("userCount", countId, { count: currentCount + 1 });
} else if (change.operation === "delete") {
await ctx.db.patch("userCount", countId, { count: currentCount - 1 });
}
});

const mutation = customMutation(rawMutation, customCtx(triggers.wrapDB));

export const createUser = mutation({
Expand Down Expand Up @@ -105,11 +123,30 @@ export const createUserExplicitIncorrectTable = mutation({
},
});

export const updateUser = mutation({
args: {
id: v.id("usersExplicit"),
firstName: v.string(),
},
handler: async (ctx, { id, firstName }) => {
return ctx.db.patch("usersExplicit", id, { firstName });
},
});

export const deleteUser = mutation({
args: { id: v.id("usersExplicit") },
handler: async (ctx, args) => {
return ctx.db.delete("usersExplicit", args.id);
},
});

const testApi: ApiFromModules<{
fns: {
createUser: typeof createUser;
createUserExplicit: typeof createUserExplicit;
createUserExplicitIncorrectTable: typeof createUserExplicitIncorrectTable;
updateUser: typeof updateUser;
deleteUser: typeof deleteUser;
};
}>["fns"] = anyApi["triggers.test"] as any;

Expand Down Expand Up @@ -148,3 +185,40 @@ test("trigger with wrong usage of explicit IDs fails", async () => {
"Invalid argument `id`, expected ID in table 'users' but got ID in table 'usersExplicitIncorrectTable'",
);
});

test("create, update and delete", async () => {
const t = convexTest(schema, modules);

async function getUserCount() {
return await t.run(async (ctx) => {
const countDoc = await ctx.db.query("userCount").first();
return countDoc?.count ?? null;
});
}

expect(await getUserCount()).toBeNull();

const userId = await t.mutation(testApi.createUserExplicit, {
firstName: "Jane",
lastName: "Smith",
});
expect(await getUserCount()).toBe(1);

const user2Id = await t.mutation(testApi.createUserExplicit, {
firstName: "Alex",
lastName: "Johnson",
});
expect(await getUserCount()).toBe(2);

await t.mutation(testApi.updateUser, {
id: userId,
firstName: "Janet",
});
expect(await getUserCount()).toBe(2);

await t.mutation(testApi.deleteUser, { id: userId });
expect(await getUserCount()).toBe(1);

await t.mutation(testApi.deleteUser, { id: user2Id });
expect(await getUserCount()).toBe(0);
});
2 changes: 1 addition & 1 deletion packages/convex-helpers/server/triggers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,7 @@ async function _queueTriggers<
db: writerWithTriggers(ctx, innerDb, triggers, true),
innerDb: innerDb,
};
for (const trigger of triggers.registered[tableName]!) {
for (const trigger of triggers.registered[tableName] ?? []) {
triggerQueue.push(async () => {
await trigger(recursiveCtx, change);
});
Expand Down
Loading