feat: add tiptap markdown support, add checklist support from trello (#245)

* feat: add tiptap markdown support, add checklist support from trello

* feat(api): implement bulk creation of checklists and items
This commit is contained in:
exception-raised
2025-11-17 22:31:57 +02:00
committed by GitHub
parent c30da618ec
commit c0a3c37d95
5 changed files with 356 additions and 51 deletions

View File

@@ -46,6 +46,7 @@ export const createItem = async (
checklistId: number;
title: string;
createdBy: string;
completed?: boolean;
},
) => {
return db.transaction(async (tx) => {
@@ -65,7 +66,7 @@ export const createItem = async (
createdBy: checklistItemInput.createdBy,
checklistId: checklistItemInput.checklistId,
index: lastItem ? lastItem.index + 1 : 0,
completed: false,
completed: checklistItemInput.completed ?? false,
})
.returning({
id: checklistItems.id,
@@ -214,3 +215,129 @@ export const updateChecklistById = async (
.returning({ publicId: checklists.publicId, name: checklists.name });
return result;
};
export const bulkCreate = async (
db: dbClient,
checklistInput: {
cardId: number;
name: string;
createdBy: string;
index: number;
}[],
) => {
if (checklistInput.length === 0) return [];
return db.transaction(async (tx) => {
const byCard = groupByKey(checklistInput, "cardId");
const allValuesToInsert: {
publicId: string;
cardId: number;
name: string;
createdBy: string;
index: number;
}[] = [];
for (const [cardId, items] of byCard.entries()) {
const last = await tx.query.checklists.findFirst({
columns: { index: true },
where: and(eq(checklists.cardId, cardId), isNull(checklists.deletedAt)),
orderBy: [desc(checklists.index)],
});
let nextIndex = last ? last.index + 1 : 0;
const sorted = [...items].sort((a, b) => a.index - b.index);
for (const item of sorted) {
allValuesToInsert.push({
publicId: generateUID(),
...item,
index: nextIndex++,
});
}
}
const inserted = await tx
.insert(checklists)
.values(allValuesToInsert)
.returning({ id: checklists.id, publicId: checklists.publicId });
return inserted;
});
};
export const bulkCreateItems = async (
db: dbClient,
checklistItemInput: {
checklistId: number;
title: string;
createdBy: string;
index: number;
completed: boolean;
}[],
) => {
if (checklistItemInput.length === 0) return [];
return db.transaction(async (tx) => {
const byChecklist = groupByKey(checklistItemInput, "checklistId");
const allValuesToInsert: {
publicId: string;
checklistId: number;
title: string;
createdBy: string;
index: number;
completed: boolean;
}[] = [];
for (const [checklistId, items] of byChecklist.entries()) {
const last = await tx.query.checklistItems.findFirst({
columns: { index: true },
where: and(
eq(checklistItems.checklistId, checklistId),
isNull(checklistItems.deletedAt),
),
orderBy: [desc(checklistItems.index)],
});
let nextIndex = last ? last.index + 1 : 0;
const sorted = [...items].sort((a, b) => a.index - b.index);
for (const item of sorted) {
allValuesToInsert.push({
publicId: generateUID(),
...item,
index: nextIndex++,
});
}
}
const inserted = await tx
.insert(checklistItems)
.values(allValuesToInsert)
.returning({
id: checklistItems.id,
publicId: checklistItems.publicId,
title: checklistItems.title,
completed: checklistItems.completed,
});
return inserted;
});
};
const groupByKey = <T extends Record<string, unknown>>(
items: T[],
keyField: keyof T,
): Map<number, T[]> => {
const grouped = new Map<number, T[]>();
for (const item of items) {
const key = item[keyField] as number;
const arr = grouped.get(key) ?? [];
arr.push(item);
grouped.set(key, arr);
}
return grouped;
};