refactor: move shift index into transaction

This commit is contained in:
Henry
2025-05-02 12:27:14 +01:00
parent 73d8799c75
commit 5996ad19c3
5 changed files with 80 additions and 77 deletions

View File

@@ -733,11 +733,6 @@ export const cardRouter = createTRPCRouter({
code: "INTERNAL_SERVER_ERROR",
});
await cardRepo.shiftIndex(ctx.supabaseClient, {
listId: card.list.id,
cardIndex: card.index,
});
await cardActivityRepo.create(ctx.db, {
type: "card.archived",
cardId: card.id,

View File

@@ -133,11 +133,6 @@ export const listRouter = createTRPCRouter({
await activityRepo.bulkCreate(ctx.db, activities);
await listRepo.shiftIndex(ctx.supabaseClient, {
boardId: list.boardId,
listIndex: list.index,
});
return { success: true };
}),
update: protectedProcedure

View File

@@ -1,21 +1,3 @@
CREATE OR REPLACE FUNCTION shift_list_index(board_id BIGINT, list_index INT)
RETURNS VOID
LANGUAGE SQL
AS $$
UPDATE list
SET index = index - 1
WHERE "boardId" = board_id AND index > list_index AND "deletedAt" IS NULL;
$$;
CREATE OR REPLACE FUNCTION shift_card_index(list_id BIGINT, card_index INT)
RETURNS VOID
LANGUAGE SQL
AS $$
UPDATE card
SET index = index - 1
WHERE "listId" = list_id AND index > card_index AND "deletedAt" IS NULL;
$$;
CREATE OR REPLACE FUNCTION is_workspace_admin(user_id UUID, workspace_id BIGINT)
RETURNS BOOLEAN
LANGUAGE SQL

View File

@@ -529,7 +529,7 @@ export const reorder = async (
const countExpr = sql<number>`COUNT(*)`.mapWith(Number);
const duplicateIndices = await db
const duplicateIndices = await tx
.select({
index: cards.index,
count: countExpr,
@@ -567,22 +567,6 @@ export const reorder = async (
});
};
// Again should be handled in update transaction
export const shiftIndex = async (
db: SupabaseClient<Database>,
args: {
listId: number;
cardIndex: number;
},
) => {
const { data } = await db.rpc("shift_card_index", {
list_id: args.listId,
card_index: args.cardIndex,
});
return data;
};
export const softDelete = async (
db: dbClient,
args: {
@@ -591,15 +575,46 @@ export const softDelete = async (
deletedBy: string;
},
) => {
const [result] = await db
.update(cards)
.set({ deletedAt: args.deletedAt, deletedBy: args.deletedBy })
.where(eq(cards.id, args.cardId))
.returning({
id: cards.id,
});
return db.transaction(async (tx) => {
const [result] = await tx
.update(cards)
.set({ deletedAt: args.deletedAt, deletedBy: args.deletedBy })
.where(eq(cards.id, args.cardId))
.returning({
id: cards.id,
listId: cards.listId,
index: cards.index,
});
return result;
if (!result)
throw new Error(`Unable to soft delete card ID ${args.cardId}`);
await tx.execute(sql`
UPDATE card
SET index = index - 1
WHERE "listId" = ${result.listId} AND index > ${result.index} AND "deletedAt" IS NULL;
`);
const countExpr = sql<number>`COUNT(*)`.mapWith(Number);
const duplicateIndices = await tx
.select({
index: cards.index,
count: countExpr,
})
.from(cards)
.where(and(eq(cards.listId, result.listId), isNull(cards.deletedAt)))
.groupBy(cards.listId, cards.index)
.having(gt(countExpr, 1));
if (duplicateIndices.length > 0) {
throw new Error(
`Duplicate indices found after soft deleting ${result.id}`,
);
}
return result;
});
};
export const softDeleteAllByListIds = async (

View File

@@ -122,7 +122,7 @@ export const reorder = async (
const countExpr = sql<number>`COUNT(*)`.mapWith(Number);
const duplicateIndices = await db
const duplicateIndices = await tx
.select({
index: lists.index,
count: countExpr,
@@ -150,21 +150,6 @@ export const reorder = async (
});
};
export const shiftIndex = async (
db: SupabaseClient<Database>,
args: {
boardId: number;
listIndex: number;
},
) => {
const { data } = await db.rpc("shift_list_index", {
board_id: args.boardId,
list_index: args.listIndex,
});
return data;
};
export const softDeleteAllByBoardId = async (
db: dbClient,
args: {
@@ -192,13 +177,44 @@ export const softDeleteById = async (
deletedBy: string;
},
) => {
const [updatedList] = await db
.update(lists)
.set({ deletedAt: args.deletedAt, deletedBy: args.deletedBy })
.where(and(eq(lists.id, args.listId), isNull(lists.deletedAt)))
.returning({
id: lists.id,
});
return db.transaction(async (tx) => {
const [result] = await tx
.update(lists)
.set({ deletedAt: args.deletedAt, deletedBy: args.deletedBy })
.where(and(eq(lists.id, args.listId), isNull(lists.deletedAt)))
.returning({
id: lists.id,
index: lists.index,
boardId: lists.boardId,
});
return updatedList;
if (!result)
throw new Error(`Unable to soft delete list ID ${args.listId}`);
await tx.execute(sql`
UPDATE list
SET index = index - 1
WHERE "boardId" = ${result.boardId} AND index > ${result.index} AND "deletedAt" IS NULL;
`);
const countExpr = sql<number>`COUNT(*)`.mapWith(Number);
const duplicateIndices = await tx
.select({
index: lists.index,
count: countExpr,
})
.from(lists)
.where(and(eq(lists.boardId, result.boardId), isNull(lists.deletedAt)))
.groupBy(lists.index)
.having(gt(countExpr, 1));
if (duplicateIndices.length > 0) {
throw new Error(
`Duplicate indices found after reordering in board ${result.boardId}`,
);
}
return result;
});
};