From 85b9cfcb215cc5dd0960ee201241a83f52df4eaa Mon Sep 17 00:00:00 2001 From: Henry Date: Wed, 6 Nov 2024 22:20:41 +0000 Subject: [PATCH] feat: setup card activity --- src/server/api/routers/board.ts | 27 +- src/server/api/routers/card.ts | 206 ++- src/server/api/routers/import.ts | 22 +- src/server/api/routers/list.ts | 25 +- src/server/db/migrations/0005_blue_marvex.sql | 55 + .../db/migrations/meta/0005_snapshot.json | 1233 +++++++++++++++++ src/server/db/migrations/meta/_journal.json | 7 + src/server/db/repository/card.repo.ts | 80 +- src/server/db/repository/cardActivity.repo.ts | 77 + src/server/db/repository/list.repo.ts | 18 +- src/server/db/schema.ts | 64 + src/types/database.types.ts | 1046 ++++++++------ 12 files changed, 2354 insertions(+), 506 deletions(-) create mode 100644 src/server/db/migrations/0005_blue_marvex.sql create mode 100644 src/server/db/migrations/meta/0005_snapshot.json create mode 100644 src/server/db/repository/cardActivity.repo.ts diff --git a/src/server/api/routers/board.ts b/src/server/api/routers/board.ts index 99d5539c..a057d84b 100644 --- a/src/server/api/routers/board.ts +++ b/src/server/api/routers/board.ts @@ -3,6 +3,7 @@ import { TRPCError } from "@trpc/server"; import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc"; +import * as activityRepo from "~/server/db/repository/cardActivity.repo"; import * as boardRepo from "~/server/db/repository/board.repo"; import * as cardRepo from "~/server/db/repository/card.repo"; import * as listRepo from "~/server/db/repository/list.repo"; @@ -203,17 +204,39 @@ export const boardRouter = createTRPCRouter({ }); if (listIds.length) { - await listRepo.softDeleteAllByBoardId(ctx.db, { + const deletedLists = await listRepo.softDeleteAllByBoardId(ctx.db, { boardId: board.id, deletedAt, deletedBy: userId, }); - await cardRepo.softDeleteAllByListIds(ctx.db, { + if (!deletedLists?.length) { + throw new TRPCError({ + message: `Failed to delete lists`, + code: "INTERNAL_SERVER_ERROR", + }); + } + + const deletedCards = await cardRepo.softDeleteAllByListIds(ctx.db, { listIds, deletedAt, deletedBy: userId, }); + + if (!deletedCards?.length) { + throw new TRPCError({ + message: `Failed to delete cards`, + code: "INTERNAL_SERVER_ERROR", + }); + } + + const activities = deletedCards.map((card) => ({ + type: "card.archived" as const, + createdBy: userId, + cardId: card.id, + })); + + await activityRepo.bulkCreate(ctx.db, activities); } return { success: true }; diff --git a/src/server/api/routers/card.ts b/src/server/api/routers/card.ts index efd6546e..558d7d63 100644 --- a/src/server/api/routers/card.ts +++ b/src/server/api/routers/card.ts @@ -4,6 +4,7 @@ import { TRPCError } from "@trpc/server"; import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc"; import * as cardRepo from "~/server/db/repository/card.repo"; +import * as cardActivityRepo from "~/server/db/repository/cardActivity.repo"; import * as labelRepo from "~/server/db/repository/label.repo"; import * as listRepo from "~/server/db/repository/list.repo"; import * as workspaceRepo from "~/server/db/repository/workspace.repo"; @@ -82,6 +83,12 @@ export const cardRouter = createTRPCRouter({ code: "INTERNAL_SERVER_ERROR", }); + await cardActivityRepo.create(ctx.db, { + type: "card.created", + cardId: newCard.id, + createdBy: userId, + }); + if (newCardId && input.labelPublicIds.length) { const labels = await labelRepo.getAllByPublicIds( ctx.db, @@ -99,7 +106,25 @@ export const cardRouter = createTRPCRouter({ labelId: label.id, })); - await cardRepo.bulkCreateCardLabelRelationships(ctx.db, labelsInsert); + const cardLabels = await cardRepo.bulkCreateCardLabelRelationships( + ctx.db, + labelsInsert, + ); + + if (!cardLabels?.length) + throw new TRPCError({ + message: `Failed to create card label relationships`, + code: "INTERNAL_SERVER_ERROR", + }); + + const cardActivitesInsert = cardLabels.map((cardLabel) => ({ + type: "card.updated.label.added" as const, + cardId: cardLabel.cardId, + labelId: cardLabel.labelId, + createdBy: userId, + })); + + await cardActivityRepo.bulkCreate(ctx.db, cardActivitesInsert); } if (newCardId && input.memberPublicIds.length) { @@ -119,10 +144,26 @@ export const cardRouter = createTRPCRouter({ workspaceMemberId: member.id, })); - await cardRepo.bulkCreateCardWorkspaceMemberRelationships( - ctx.db, - membersInsert, - ); + const cardMembers = + await cardRepo.bulkCreateCardWorkspaceMemberRelationships( + ctx.db, + membersInsert, + ); + + if (!cardMembers?.length) + throw new TRPCError({ + message: `Failed to create card member relationships`, + code: "INTERNAL_SERVER_ERROR", + }); + + const cardActivitesInsert = cardMembers.map((cardMember) => ({ + type: "card.updated.member.added" as const, + cardId: cardMember.cardId, + workspaceMemberId: cardMember.workspaceMemberId, + createdBy: userId, + })); + + await cardActivityRepo.bulkCreate(ctx.db, cardActivitesInsert); } return newCard; @@ -177,12 +218,40 @@ export const cardRouter = createTRPCRouter({ ); if (existingLabel) { - await cardRepo.hardDeleteCardLabelRelationship(ctx.db, cardLabelIds); + const deletedCardLabelRelationship = + await cardRepo.hardDeleteCardLabelRelationship(ctx.db, cardLabelIds); + + if (!deletedCardLabelRelationship) + throw new TRPCError({ + message: `Failed to remove label from card`, + code: "INTERNAL_SERVER_ERROR", + }); + + await cardActivityRepo.create(ctx.db, { + type: "card.updated.label.removed" as const, + cardId: card.id, + labelId: label.id, + createdBy: userId, + }); return { newLabel: false }; } - await cardRepo.createCardLabelRelationship(ctx.db, cardLabelIds); + const newCardLabelRelationship = + await cardRepo.createCardLabelRelationship(ctx.db, cardLabelIds); + + if (!newCardLabelRelationship) + throw new TRPCError({ + message: `Failed to add label to card`, + code: "INTERNAL_SERVER_ERROR", + }); + + await cardActivityRepo.create(ctx.db, { + type: "card.updated.label.added" as const, + cardId: card.id, + labelId: label.id, + createdBy: userId, + }); return { newLabel: true }; }), @@ -238,12 +307,43 @@ export const cardRouter = createTRPCRouter({ ); if (existingMember) { - await cardRepo.hardDeleteCardMemberRelationship(ctx.db, cardMemberIds); + const deletedCardMemberRelationship = + await cardRepo.hardDeleteCardMemberRelationship( + ctx.db, + cardMemberIds, + ); + + if (!deletedCardMemberRelationship?.success) + throw new TRPCError({ + message: `Failed to remove member from card`, + code: "INTERNAL_SERVER_ERROR", + }); + + await cardActivityRepo.create(ctx.db, { + type: "card.updated.member.removed" as const, + cardId: card.id, + workspaceMemberId: member.id, + createdBy: userId, + }); return { newMember: false }; } - await cardRepo.createCardMemberRelationship(ctx.db, cardMemberIds); + const newCardMemberRelationship = + await cardRepo.createCardMemberRelationship(ctx.db, cardMemberIds); + + if (!newCardMemberRelationship?.success) + throw new TRPCError({ + message: `Failed to add member to card`, + code: "INTERNAL_SERVER_ERROR", + }); + + await cardActivityRepo.create(ctx.db, { + type: "card.updated.member.added" as const, + cardId: card.id, + workspaceMemberId: member.id, + createdBy: userId, + }); return { newMember: true }; }), @@ -306,6 +406,18 @@ export const cardRouter = createTRPCRouter({ code: "UNAUTHORIZED", }); + const existingCard = await cardRepo.getByPublicId( + ctx.db, + input.cardPublicId, + ); + + if (!existingCard) { + throw new TRPCError({ + message: `Card with public ID ${input.cardPublicId} not found`, + code: "NOT_FOUND", + }); + } + const result = await cardRepo.update( ctx.db, { title: input.title, description: input.description }, @@ -318,6 +430,32 @@ export const cardRouter = createTRPCRouter({ code: "INTERNAL_SERVER_ERROR", }); + const activities = []; + + if (existingCard.title !== input.title) { + activities.push({ + type: "card.updated.title" as const, + cardId: result.id, + createdBy: userId, + fromTitle: existingCard.title, + toTitle: input.title, + }); + } + + if (existingCard.description !== input.description) { + activities.push({ + type: "card.updated.description" as const, + cardId: result.id, + createdBy: userId, + fromDescription: existingCard.description ?? undefined, + toDescription: input.description, + }); + } + + if (activities.length > 0) { + await cardActivityRepo.bulkCreate(ctx.db, activities); + } + return result; }), delete: protectedProcedure @@ -359,17 +497,29 @@ export const cardRouter = createTRPCRouter({ const deletedAt = new Date().toISOString(); - await cardRepo.softDelete(ctx.db, { + const deletedCard = await cardRepo.softDelete(ctx.db, { cardId: card.id, deletedAt, deletedBy: userId, }); + if (!deletedCard) + throw new TRPCError({ + message: `Failed to delete card`, + code: "INTERNAL_SERVER_ERROR", + }); + await cardRepo.shiftIndex(ctx.db, { listId: card.list.id, cardIndex: card.index, }); + await cardActivityRepo.create(ctx.db, { + type: "card.archived", + cardId: card.id, + createdBy: userId, + }); + return { success: true }; }), reorder: protectedProcedure @@ -435,7 +585,7 @@ export const cardRouter = createTRPCRouter({ newIndex = lastCardIndex !== undefined ? lastCardIndex + 1 : 0; } - const result = await cardRepo.reorder(ctx.db, { + const { success } = await cardRepo.reorder(ctx.db, { currentListId: currentList.id, newListId: newList.id, currentIndex, @@ -443,6 +593,38 @@ export const cardRouter = createTRPCRouter({ cardId: card.id, }); - return { success: !!result.error }; + if (!success) + throw new TRPCError({ + message: `Failed to reorder card`, + code: "INTERNAL_SERVER_ERROR", + }); + + const activities = []; + + if (currentIndex !== newIndex) { + activities.push({ + type: "card.updated.index" as const, + cardId: card.id, + createdBy: userId, + fromIndex: currentIndex, + toIndex: newIndex, + }); + } + + if (currentList.id !== newList.id) { + activities.push({ + type: "card.updated.list" as const, + cardId: card.id, + createdBy: userId, + fromListId: currentList.id, + toListId: newList.id, + }); + } + + if (activities.length > 0) { + await cardActivityRepo.bulkCreate(ctx.db, activities); + } + + return { success }; }), }); diff --git a/src/server/api/routers/import.ts b/src/server/api/routers/import.ts index f839197c..6b556780 100644 --- a/src/server/api/routers/import.ts +++ b/src/server/api/routers/import.ts @@ -5,6 +5,7 @@ import { generateUID } from "~/utils/generateUID"; import * as boardRepo from "~/server/db/repository/board.repo"; import * as cardRepo from "~/server/db/repository/card.repo"; +import * as cardActivityRepo from "~/server/db/repository/cardActivity.repo"; import * as importRepo from "~/server/db/repository/import.repo"; import * as listRepo from "~/server/db/repository/list.repo"; import * as workspaceRepo from "~/server/db/repository/workspace.repo"; @@ -196,9 +197,26 @@ export const importRouter = createTRPCRouter({ importId: newImportId, })); - await cardRepo.bulkCreate(ctx.db, cardsInsert); + const createdCards = await cardRepo.bulkCreate( + ctx.db, + cardsInsert, + ); - await ctx.db.from("card").insert(cardsInsert); + if (!createdCards?.length) + throw new TRPCError({ + message: "Failed to create new cards", + code: "INTERNAL_SERVER_ERROR", + }); + + const activities = createdCards.map((card) => ({ + type: "card.created" as const, + cardId: card.id, + createdBy: userId, + })); + + if (createdCards.length > 0) { + await cardActivityRepo.bulkCreate(ctx.db, activities); + } } listIndex++; diff --git a/src/server/api/routers/list.ts b/src/server/api/routers/list.ts index b3ae3db3..2383e83a 100644 --- a/src/server/api/routers/list.ts +++ b/src/server/api/routers/list.ts @@ -3,6 +3,7 @@ import { TRPCError } from "@trpc/server"; import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc"; +import * as activityRepo from "~/server/db/repository/cardActivity.repo"; import * as cardRepo from "~/server/db/repository/card.repo"; import * as boardRepo from "~/server/db/repository/board.repo"; import * as listRepo from "~/server/db/repository/list.repo"; @@ -142,18 +143,38 @@ export const listRouter = createTRPCRouter({ const deletedAt = new Date().toISOString(); - await listRepo.softDeleteById(ctx.db, { + const deletedList = await listRepo.softDeleteById(ctx.db, { listId: list.id, deletedAt, deletedBy: userId, }); - await cardRepo.softDeleteAllByListIds(ctx.db, { + if (!deletedList) + throw new TRPCError({ + message: `Failed to delete list`, + code: "INTERNAL_SERVER_ERROR", + }); + + const deletedCards = await cardRepo.softDeleteAllByListIds(ctx.db, { listIds: [list.id], deletedAt, deletedBy: userId, }); + if (!deletedCards?.length) + throw new TRPCError({ + message: `Failed to delete cards`, + code: "INTERNAL_SERVER_ERROR", + }); + + const activities = deletedCards.map((card) => ({ + type: "card.archived" as const, + createdBy: userId, + cardId: card.id, + })); + + await activityRepo.bulkCreate(ctx.db, activities); + await listRepo.shiftIndex(ctx.db, { boardId: list.boardId, listIndex: list.id, diff --git a/src/server/db/migrations/0005_blue_marvex.sql b/src/server/db/migrations/0005_blue_marvex.sql new file mode 100644 index 00000000..0f40da8c --- /dev/null +++ b/src/server/db/migrations/0005_blue_marvex.sql @@ -0,0 +1,55 @@ +DO $$ BEGIN + CREATE TYPE "card_activity_type" AS ENUM('card.created', 'card.updated.title', 'card.updated.description', 'card.updated.index', 'card.updated.list', 'card.updated.label.added', 'card.updated.label.removed', 'card.updated.member.added', 'card.updated.member.removed', 'card.archived'); +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "card_activity" ( + "id" bigserial PRIMARY KEY NOT NULL, + "publicId" varchar(12) NOT NULL, + "type" "card_activity_type" NOT NULL, + "cardId" bigint NOT NULL, + "fromIndex" integer, + "toIndex" integer, + "fromListId" bigint, + "toListId" bigint, + "labelId" bigint, + "workspaceMemberId" bigint, + "fromTitle" varchar(255), + "toTitle" varchar(255), + "fromDescription" text, + "toDescription" text, + "createdBy" uuid NOT NULL, + "createdAt" timestamp DEFAULT now() NOT NULL, + CONSTRAINT "card_activity_publicId_unique" UNIQUE("publicId") +); +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "card_activity" ADD CONSTRAINT "card_activity_cardId_card_id_fk" FOREIGN KEY ("cardId") REFERENCES "card"("id") ON DELETE cascade ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "card_activity" ADD CONSTRAINT "card_activity_toListId_list_id_fk" FOREIGN KEY ("toListId") REFERENCES "list"("id") ON DELETE no action ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "card_activity" ADD CONSTRAINT "card_activity_labelId_label_id_fk" FOREIGN KEY ("labelId") REFERENCES "label"("id") ON DELETE no action ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "card_activity" ADD CONSTRAINT "card_activity_workspaceMemberId_workspace_members_id_fk" FOREIGN KEY ("workspaceMemberId") REFERENCES "workspace_members"("id") ON DELETE no action ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "card_activity" ADD CONSTRAINT "card_activity_createdBy_user_id_fk" FOREIGN KEY ("createdBy") REFERENCES "user"("id") ON DELETE no action ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; diff --git a/src/server/db/migrations/meta/0005_snapshot.json b/src/server/db/migrations/meta/0005_snapshot.json new file mode 100644 index 00000000..a5021a82 --- /dev/null +++ b/src/server/db/migrations/meta/0005_snapshot.json @@ -0,0 +1,1233 @@ +{ + "version": "5", + "dialect": "pg", + "id": "d2d24b52-413e-4ad0-9d94-b7fff098a812", + "prevId": "96331efe-f7dd-4d0f-8f65-e5f706cc2083", + "tables": { + "board": { + "name": "board", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "publicId": { + "name": "publicId", + "type": "varchar(12)", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "createdBy": { + "name": "createdBy", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "deletedAt": { + "name": "deletedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "deletedBy": { + "name": "deletedBy", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "importId": { + "name": "importId", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "workspaceId": { + "name": "workspaceId", + "type": "bigint", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "board_createdBy_user_id_fk": { + "name": "board_createdBy_user_id_fk", + "tableFrom": "board", + "tableTo": "user", + "columnsFrom": [ + "createdBy" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "board_deletedBy_user_id_fk": { + "name": "board_deletedBy_user_id_fk", + "tableFrom": "board", + "tableTo": "user", + "columnsFrom": [ + "deletedBy" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "board_importId_import_id_fk": { + "name": "board_importId_import_id_fk", + "tableFrom": "board", + "tableTo": "import", + "columnsFrom": [ + "importId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "board_workspaceId_workspace_id_fk": { + "name": "board_workspaceId_workspace_id_fk", + "tableFrom": "board", + "tableTo": "workspace", + "columnsFrom": [ + "workspaceId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "board_publicId_unique": { + "name": "board_publicId_unique", + "nullsNotDistinct": false, + "columns": [ + "publicId" + ] + } + } + }, + "card_activity": { + "name": "card_activity", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "publicId": { + "name": "publicId", + "type": "varchar(12)", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "card_activity_type", + "primaryKey": false, + "notNull": true + }, + "cardId": { + "name": "cardId", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "fromIndex": { + "name": "fromIndex", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "toIndex": { + "name": "toIndex", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "fromListId": { + "name": "fromListId", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "toListId": { + "name": "toListId", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "labelId": { + "name": "labelId", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "workspaceMemberId": { + "name": "workspaceMemberId", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "fromTitle": { + "name": "fromTitle", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "toTitle": { + "name": "toTitle", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "fromDescription": { + "name": "fromDescription", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "toDescription": { + "name": "toDescription", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdBy": { + "name": "createdBy", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "card_activity_cardId_card_id_fk": { + "name": "card_activity_cardId_card_id_fk", + "tableFrom": "card_activity", + "tableTo": "card", + "columnsFrom": [ + "cardId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "card_activity_toListId_list_id_fk": { + "name": "card_activity_toListId_list_id_fk", + "tableFrom": "card_activity", + "tableTo": "list", + "columnsFrom": [ + "toListId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "card_activity_labelId_label_id_fk": { + "name": "card_activity_labelId_label_id_fk", + "tableFrom": "card_activity", + "tableTo": "label", + "columnsFrom": [ + "labelId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "card_activity_workspaceMemberId_workspace_members_id_fk": { + "name": "card_activity_workspaceMemberId_workspace_members_id_fk", + "tableFrom": "card_activity", + "tableTo": "workspace_members", + "columnsFrom": [ + "workspaceMemberId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "card_activity_createdBy_user_id_fk": { + "name": "card_activity_createdBy_user_id_fk", + "tableFrom": "card_activity", + "tableTo": "user", + "columnsFrom": [ + "createdBy" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "card_activity_publicId_unique": { + "name": "card_activity_publicId_unique", + "nullsNotDistinct": false, + "columns": [ + "publicId" + ] + } + } + }, + "_card_workspace_members": { + "name": "_card_workspace_members", + "schema": "", + "columns": { + "cardId": { + "name": "cardId", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "workspaceMemberId": { + "name": "workspaceMemberId", + "type": "bigint", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "_card_workspace_members_cardId_card_id_fk": { + "name": "_card_workspace_members_cardId_card_id_fk", + "tableFrom": "_card_workspace_members", + "tableTo": "card", + "columnsFrom": [ + "cardId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "_card_workspace_members_workspaceMemberId_workspace_members_id_fk": { + "name": "_card_workspace_members_workspaceMemberId_workspace_members_id_fk", + "tableFrom": "_card_workspace_members", + "tableTo": "workspace_members", + "columnsFrom": [ + "workspaceMemberId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "_card_workspace_members_cardId_workspaceMemberId": { + "name": "_card_workspace_members_cardId_workspaceMemberId", + "columns": [ + "cardId", + "workspaceMemberId" + ] + } + }, + "uniqueConstraints": {} + }, + "card": { + "name": "card", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "publicId": { + "name": "publicId", + "type": "varchar(12)", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "index": { + "name": "index", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "createdBy": { + "name": "createdBy", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "deletedAt": { + "name": "deletedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "deletedBy": { + "name": "deletedBy", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "listId": { + "name": "listId", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "importId": { + "name": "importId", + "type": "bigint", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "card_createdBy_user_id_fk": { + "name": "card_createdBy_user_id_fk", + "tableFrom": "card", + "tableTo": "user", + "columnsFrom": [ + "createdBy" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "card_deletedBy_user_id_fk": { + "name": "card_deletedBy_user_id_fk", + "tableFrom": "card", + "tableTo": "user", + "columnsFrom": [ + "deletedBy" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "card_listId_list_id_fk": { + "name": "card_listId_list_id_fk", + "tableFrom": "card", + "tableTo": "list", + "columnsFrom": [ + "listId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "card_importId_import_id_fk": { + "name": "card_importId_import_id_fk", + "tableFrom": "card", + "tableTo": "import", + "columnsFrom": [ + "importId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "card_publicId_unique": { + "name": "card_publicId_unique", + "nullsNotDistinct": false, + "columns": [ + "publicId" + ] + } + } + }, + "_card_labels": { + "name": "_card_labels", + "schema": "", + "columns": { + "cardId": { + "name": "cardId", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "labelId": { + "name": "labelId", + "type": "bigint", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "_card_labels_cardId_card_id_fk": { + "name": "_card_labels_cardId_card_id_fk", + "tableFrom": "_card_labels", + "tableTo": "card", + "columnsFrom": [ + "cardId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "_card_labels_labelId_label_id_fk": { + "name": "_card_labels_labelId_label_id_fk", + "tableFrom": "_card_labels", + "tableTo": "label", + "columnsFrom": [ + "labelId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "_card_labels_cardId_labelId": { + "name": "_card_labels_cardId_labelId", + "columns": [ + "cardId", + "labelId" + ] + } + }, + "uniqueConstraints": {} + }, + "import": { + "name": "import", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "publicId": { + "name": "publicId", + "type": "varchar(12)", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "source", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "status", + "primaryKey": false, + "notNull": true + }, + "createdBy": { + "name": "createdBy", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "import_createdBy_user_id_fk": { + "name": "import_createdBy_user_id_fk", + "tableFrom": "import", + "tableTo": "user", + "columnsFrom": [ + "createdBy" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "import_publicId_unique": { + "name": "import_publicId_unique", + "nullsNotDistinct": false, + "columns": [ + "publicId" + ] + } + } + }, + "label": { + "name": "label", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "publicId": { + "name": "publicId", + "type": "varchar(12)", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "colourCode": { + "name": "colourCode", + "type": "varchar(12)", + "primaryKey": false, + "notNull": false + }, + "createdBy": { + "name": "createdBy", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "boardId": { + "name": "boardId", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "importId": { + "name": "importId", + "type": "bigint", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "label_createdBy_user_id_fk": { + "name": "label_createdBy_user_id_fk", + "tableFrom": "label", + "tableTo": "user", + "columnsFrom": [ + "createdBy" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "label_boardId_board_id_fk": { + "name": "label_boardId_board_id_fk", + "tableFrom": "label", + "tableTo": "board", + "columnsFrom": [ + "boardId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "label_importId_import_id_fk": { + "name": "label_importId_import_id_fk", + "tableFrom": "label", + "tableTo": "import", + "columnsFrom": [ + "importId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "label_publicId_unique": { + "name": "label_publicId_unique", + "nullsNotDistinct": false, + "columns": [ + "publicId" + ] + } + } + }, + "list": { + "name": "list", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "publicId": { + "name": "publicId", + "type": "varchar(12)", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "index": { + "name": "index", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "createdBy": { + "name": "createdBy", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "deletedAt": { + "name": "deletedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "deletedBy": { + "name": "deletedBy", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "boardId": { + "name": "boardId", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "importId": { + "name": "importId", + "type": "bigint", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "list_createdBy_user_id_fk": { + "name": "list_createdBy_user_id_fk", + "tableFrom": "list", + "tableTo": "user", + "columnsFrom": [ + "createdBy" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "list_deletedBy_user_id_fk": { + "name": "list_deletedBy_user_id_fk", + "tableFrom": "list", + "tableTo": "user", + "columnsFrom": [ + "deletedBy" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "list_boardId_board_id_fk": { + "name": "list_boardId_board_id_fk", + "tableFrom": "list", + "tableTo": "board", + "columnsFrom": [ + "boardId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "list_importId_import_id_fk": { + "name": "list_importId_import_id_fk", + "tableFrom": "list", + "tableTo": "import", + "columnsFrom": [ + "importId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "list_publicId_unique": { + "name": "list_publicId_unique", + "nullsNotDistinct": false, + "columns": [ + "publicId" + ] + } + } + }, + "user": { + "name": "user", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "email": { + "name": "email", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "emailVerified": { + "name": "emailVerified", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "image": { + "name": "image", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_email_unique": { + "name": "user_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + } + } + }, + "workspace_members": { + "name": "workspace_members", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "publicId": { + "name": "publicId", + "type": "varchar(12)", + "primaryKey": false, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "workspaceId": { + "name": "workspaceId", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "createdBy": { + "name": "createdBy", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "deletedAt": { + "name": "deletedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "deletedBy": { + "name": "deletedBy", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "role": { + "name": "role", + "type": "role", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "member_status", + "primaryKey": false, + "notNull": true, + "default": "'invited'" + } + }, + "indexes": {}, + "foreignKeys": { + "workspace_members_userId_user_id_fk": { + "name": "workspace_members_userId_user_id_fk", + "tableFrom": "workspace_members", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "workspace_members_workspaceId_workspace_id_fk": { + "name": "workspace_members_workspaceId_workspace_id_fk", + "tableFrom": "workspace_members", + "tableTo": "workspace", + "columnsFrom": [ + "workspaceId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workspace_members_deletedBy_user_id_fk": { + "name": "workspace_members_deletedBy_user_id_fk", + "tableFrom": "workspace_members", + "tableTo": "user", + "columnsFrom": [ + "deletedBy" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "workspace_members_publicId_unique": { + "name": "workspace_members_publicId_unique", + "nullsNotDistinct": false, + "columns": [ + "publicId" + ] + } + } + }, + "workspace": { + "name": "workspace", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "publicId": { + "name": "publicId", + "type": "varchar(12)", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "slug": { + "name": "slug", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "createdBy": { + "name": "createdBy", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "deletedAt": { + "name": "deletedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "deletedBy": { + "name": "deletedBy", + "type": "uuid", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "workspace_createdBy_user_id_fk": { + "name": "workspace_createdBy_user_id_fk", + "tableFrom": "workspace", + "tableTo": "user", + "columnsFrom": [ + "createdBy" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "workspace_deletedBy_user_id_fk": { + "name": "workspace_deletedBy_user_id_fk", + "tableFrom": "workspace", + "tableTo": "user", + "columnsFrom": [ + "deletedBy" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "workspace_publicId_unique": { + "name": "workspace_publicId_unique", + "nullsNotDistinct": false, + "columns": [ + "publicId" + ] + }, + "workspace_slug_unique": { + "name": "workspace_slug_unique", + "nullsNotDistinct": false, + "columns": [ + "slug" + ] + } + } + } + }, + "enums": { + "card_activity_type": { + "name": "card_activity_type", + "values": { + "card.created": "card.created", + "card.updated.title": "card.updated.title", + "card.updated.description": "card.updated.description", + "card.updated.index": "card.updated.index", + "card.updated.list": "card.updated.list", + "card.updated.label.added": "card.updated.label.added", + "card.updated.label.removed": "card.updated.label.removed", + "card.updated.member.added": "card.updated.member.added", + "card.updated.member.removed": "card.updated.member.removed", + "card.archived": "card.archived" + } + }, + "source": { + "name": "source", + "values": { + "trello": "trello" + } + }, + "status": { + "name": "status", + "values": { + "started": "started", + "success": "success", + "failed": "failed" + } + }, + "role": { + "name": "role", + "values": { + "admin": "admin", + "member": "member", + "guest": "guest" + } + }, + "member_status": { + "name": "member_status", + "values": { + "invited": "invited", + "active": "active", + "removed": "removed" + } + } + }, + "schemas": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + } +} \ No newline at end of file diff --git a/src/server/db/migrations/meta/_journal.json b/src/server/db/migrations/meta/_journal.json index 59e8e124..44c796c4 100644 --- a/src/server/db/migrations/meta/_journal.json +++ b/src/server/db/migrations/meta/_journal.json @@ -36,6 +36,13 @@ "when": 1730205607613, "tag": "0004_rainy_archangel", "breakpoints": true + }, + { + "idx": 5, + "version": "5", + "when": 1730813108528, + "tag": "0005_blue_marvex", + "breakpoints": true } ] } \ No newline at end of file diff --git a/src/server/db/repository/card.repo.ts b/src/server/db/repository/card.repo.ts index 07d1588e..43ead6b5 100644 --- a/src/server/db/repository/card.repo.ts +++ b/src/server/db/repository/card.repo.ts @@ -36,9 +36,12 @@ export const bulkCreateCardLabelRelationships = async ( labelId: number; }[], ) => { - const result = db.from("_card_labels").insert(cardLabelRelationshipInput); + const { data } = await db + .from("_card_labels") + .insert(cardLabelRelationshipInput) + .select(); - return result; + return data; }; export const bulkCreateCardWorkspaceMemberRelationships = async ( @@ -48,11 +51,12 @@ export const bulkCreateCardWorkspaceMemberRelationships = async ( workspaceMemberId: number; }[], ) => { - const result = db + const { data } = await db .from("_card_workspace_members") - .insert(cardWorkspaceMemberRelationshipInput); + .insert(cardWorkspaceMemberRelationshipInput) + .select(); - return result; + return data; }; export const update = async ( @@ -69,7 +73,11 @@ export const update = async ( .from("card") .update({ title: cardInput.title, description: cardInput.description }) .eq("publicId", args.cardPublicId) - .is("deletedAt", null); + .is("deletedAt", null) + .select(`id, publicId, title, description`) + .order("id", { ascending: true }) + .limit(1) + .single(); return data; }; @@ -95,7 +103,7 @@ export const getByPublicId = async ( ) => { const { data } = await db .from("card") - .select(`id`) + .select(`id, publicId, title, description`) .eq("publicId", cardPublicId) .limit(1) .single(); @@ -130,7 +138,7 @@ export const bulkCreate = async ( importId?: number; }[], ) => { - const data = await db.from("card").insert(cardInput); + const { data } = await db.from("card").insert(cardInput).select(`id`); return data; }; @@ -139,10 +147,15 @@ export const createCardLabelRelationship = async ( db: SupabaseClient, cardLabelRelationshipInput: { cardId: number; labelId: number }, ) => { - const { data } = await db.from("_card_labels").insert({ - cardId: cardLabelRelationshipInput.cardId, - labelId: cardLabelRelationshipInput.labelId, - }); + const { data } = await db + .from("_card_labels") + .insert({ + cardId: cardLabelRelationshipInput.cardId, + labelId: cardLabelRelationshipInput.labelId, + }) + .select() + .limit(1) + .single(); return data; }; @@ -166,12 +179,12 @@ export const createCardMemberRelationship = async ( db: SupabaseClient, cardMemberRelationshipInput: { cardId: number; memberId: number }, ) => { - const { data } = await db.from("_card_workspace_members").insert({ + const { error } = await db.from("_card_workspace_members").insert({ cardId: cardMemberRelationshipInput.cardId, workspaceMemberId: cardMemberRelationshipInput.memberId, }); - return data; + return { success: !error }; }; export const getWithListAndMembersByPublicId = async ( @@ -247,7 +260,7 @@ export const reorder = async ( cardId: number; }, ) => { - const result = await db.rpc("reorder_cards", { + const { error } = await db.rpc("reorder_cards", { current_list_id: args.currentListId, new_list_id: args.newListId, current_index: args.currentIndex, @@ -255,7 +268,7 @@ export const reorder = async ( card_id: args.cardId, }); - return result; + return { success: !error }; }; export const shiftIndex = async ( @@ -296,12 +309,16 @@ export const softDelete = async ( deletedBy: string; }, ) => { - const result = await db + const { data } = await db .from("card") .update({ deletedAt: args.deletedAt, deletedBy: args.deletedBy }) - .eq("id", args.cardId); + .eq("id", args.cardId) + .select(`id`) + .order("id", { ascending: true }) + .limit(1) + .single(); - return result; + return data; }; export const softDeleteAllByListIds = async ( @@ -312,39 +329,46 @@ export const softDeleteAllByListIds = async ( deletedBy: string; }, ) => { - const result = await db + const { data } = await db .from("card") .update({ deletedAt: args.deletedAt, deletedBy: args.deletedBy }) .in("listId", args.listIds) - .is("deletedAt", null); + .is("deletedAt", null) + .select(`id`); - return result; + return data; }; export const hardDeleteCardMemberRelationship = async ( db: SupabaseClient, args: { cardId: number; memberId: number }, ) => { - const result = await db + const { error } = await db .from("_card_workspace_members") .delete() .eq("cardId", args.cardId) - .eq("workspaceMemberId", args.memberId); + .eq("workspaceMemberId", args.memberId) + .select() + .limit(1) + .single(); - return result; + return { success: !error }; }; export const hardDeleteCardLabelRelationship = async ( db: SupabaseClient, args: { cardId: number; labelId: number }, ) => { - const result = await db + const { data } = await db .from("_card_labels") .delete() .eq("cardId", args.cardId) - .eq("labelId", args.labelId); + .eq("labelId", args.labelId) + .select() + .limit(1) + .single(); - return result; + return { data }; }; export const hardDeleteAllCardLabelRelationships = async ( diff --git a/src/server/db/repository/cardActivity.repo.ts b/src/server/db/repository/cardActivity.repo.ts new file mode 100644 index 00000000..9f261b93 --- /dev/null +++ b/src/server/db/repository/cardActivity.repo.ts @@ -0,0 +1,77 @@ +import { generateUID } from "~/utils/generateUID"; +import { type Database } from "~/types/database.types"; +import { type SupabaseClient } from "@supabase/supabase-js"; + +export const create = async ( + db: SupabaseClient, + activityInput: { + type: Database["public"]["Enums"]["card_activity_type"]; + cardId: number; + fromIndex?: number; + toIndex?: number; + fromListId?: number; + toListId?: number; + labelId?: number; + workspaceMemberId?: number; + fromTitle?: string; + toTitle?: string; + fromDescription?: string; + toDescription?: string; + createdBy: string; + }, +) => { + const { data } = await db + .from("card_activity") + .insert({ + publicId: generateUID(), + type: activityInput.type, + cardId: activityInput.cardId, + fromListId: activityInput.fromListId, + toListId: activityInput.toListId, + fromIndex: activityInput.fromIndex, + toIndex: activityInput.toIndex, + labelId: activityInput.labelId, + workspaceMemberId: activityInput.workspaceMemberId, + fromTitle: activityInput.fromTitle, + toTitle: activityInput.toTitle, + fromDescription: activityInput.fromDescription, + toDescription: activityInput.toDescription, + createdBy: activityInput.createdBy, + }) + .select(`id`) + .limit(1) + .single(); + + return data; +}; + +export const bulkCreate = async ( + db: SupabaseClient, + activityInputs: { + type: Database["public"]["Enums"]["card_activity_type"]; + cardId: number; + fromIndex?: number; + toIndex?: number; + fromListId?: number; + toListId?: number; + labelId?: number; + workspaceMemberId?: number; + fromTitle?: string; + toTitle?: string; + fromDescription?: string; + toDescription?: string; + createdBy: string; + }[], +) => { + const activitiesWithPublicIds = activityInputs.map((activity) => ({ + ...activity, + publicId: generateUID(), + })); + + const { data } = await db + .from("card_activity") + .insert(activitiesWithPublicIds) + .select("id"); + + return data; +}; diff --git a/src/server/db/repository/list.repo.ts b/src/server/db/repository/list.repo.ts index ae21d19a..663259b2 100644 --- a/src/server/db/repository/list.repo.ts +++ b/src/server/db/repository/list.repo.ts @@ -127,13 +127,15 @@ export const softDeleteAllByBoardId = async ( deletedBy: string; }, ) => { - const result = await db + const { data } = await db .from("list") .update({ deletedAt: args.deletedAt, deletedBy: args.deletedBy }) .eq("boardId", args.boardId) - .is("deletedAt", null); + .is("deletedAt", null) + .select(`id`) + .order("id", { ascending: true }); - return result; + return data; }; export const softDeleteById = async ( @@ -144,11 +146,15 @@ export const softDeleteById = async ( deletedBy: string; }, ) => { - const result = await db + const { data } = await db .from("list") .update({ deletedAt: args.deletedAt, deletedBy: args.deletedBy }) .eq("id", args.listId) - .is("deletedAt", null); + .is("deletedAt", null) + .select(`id`) + .order("id", { ascending: true }) + .limit(1) + .single(); - return result; + return data; }; diff --git a/src/server/db/schema.ts b/src/server/db/schema.ts index 305f606b..e512167f 100644 --- a/src/server/db/schema.ts +++ b/src/server/db/schema.ts @@ -24,6 +24,18 @@ export const memberStatusEnum = pgEnum("member_status", [ "active", "removed", ]); +export const activityTypeEnum = pgEnum("card_activity_type", [ + "card.created", + "card.updated.title", + "card.updated.description", + "card.updated.index", + "card.updated.list", + "card.updated.label.added", + "card.updated.label.removed", + "card.updated.member.added", + "card.updated.member.removed", + "card.archived", +]); export const boards = pgTable("board", { id: bigserial("id", { mode: "number" }).primaryKey(), @@ -324,3 +336,55 @@ export const usersToWorkspacesRelations = relations( }), }), ); + +export const cardActivities = pgTable("card_activity", { + id: bigserial("id", { mode: "number" }).primaryKey(), + publicId: varchar("publicId", { length: 12 }).notNull().unique(), + type: activityTypeEnum("type").notNull(), + cardId: bigint("cardId", { mode: "number" }) + .notNull() + .references(() => cards.id, { onDelete: "cascade" }), + fromIndex: integer("fromIndex"), + toIndex: integer("toIndex"), + fromListId: bigint("fromListId", { mode: "number" }), + toListId: bigint("toListId", { mode: "number" }).references(() => lists.id), + labelId: bigint("labelId", { mode: "number" }).references(() => labels.id), + workspaceMemberId: bigint("workspaceMemberId", { mode: "number" }).references( + () => workspaceMembers.id, + ), + fromTitle: varchar("fromTitle", { length: 255 }), + toTitle: varchar("toTitle", { length: 255 }), + fromDescription: text("fromDescription"), + toDescription: text("toDescription"), + createdBy: uuid("createdBy") + .notNull() + .references(() => users.id), + createdAt: timestamp("createdAt").defaultNow().notNull(), +}); + +export const cardActivitiesRelations = relations(cardActivities, ({ one }) => ({ + card: one(cards, { + fields: [cardActivities.cardId], + references: [cards.id], + }), + fromList: one(lists, { + fields: [cardActivities.fromListId], + references: [lists.id], + }), + toList: one(lists, { + fields: [cardActivities.toListId], + references: [lists.id], + }), + label: one(labels, { + fields: [cardActivities.labelId], + references: [labels.id], + }), + workspaceMember: one(workspaceMembers, { + fields: [cardActivities.workspaceMemberId], + references: [workspaceMembers.id], + }), + createdBy: one(users, { + fields: [cardActivities.createdBy], + references: [users.id], + }), +})); diff --git a/src/types/database.types.ts b/src/types/database.types.ts index 8e3532a3..8788acad 100644 --- a/src/types/database.types.ts +++ b/src/types/database.types.ts @@ -1,569 +1,692 @@ +/* eslint-disable @typescript-eslint/no-redundant-type-constituents */ + export type Json = | string | number | boolean | null | { [key: string]: Json | undefined } - | Json[] + | Json[]; export type Database = { public: { Tables: { _card_labels: { Row: { - cardId: number - labelId: number - } + cardId: number; + labelId: number; + }; Insert: { - cardId: number - labelId: number - } + cardId: number; + labelId: number; + }; Update: { - cardId?: number - labelId?: number - } + cardId?: number; + labelId?: number; + }; Relationships: [ { - foreignKeyName: "_card_labels_cardId_card_id_fk" - columns: ["cardId"] - isOneToOne: false - referencedRelation: "card" - referencedColumns: ["id"] + foreignKeyName: "_card_labels_cardId_card_id_fk"; + columns: ["cardId"]; + isOneToOne: false; + referencedRelation: "card"; + referencedColumns: ["id"]; }, { - foreignKeyName: "_card_labels_labelId_label_id_fk" - columns: ["labelId"] - isOneToOne: false - referencedRelation: "label" - referencedColumns: ["id"] + foreignKeyName: "_card_labels_labelId_label_id_fk"; + columns: ["labelId"]; + isOneToOne: false; + referencedRelation: "label"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; _card_workspace_members: { Row: { - cardId: number - workspaceMemberId: number - } + cardId: number; + workspaceMemberId: number; + }; Insert: { - cardId: number - workspaceMemberId: number - } + cardId: number; + workspaceMemberId: number; + }; Update: { - cardId?: number - workspaceMemberId?: number - } + cardId?: number; + workspaceMemberId?: number; + }; Relationships: [ { - foreignKeyName: "_card_workspace_members_cardId_card_id_fk" - columns: ["cardId"] - isOneToOne: false - referencedRelation: "card" - referencedColumns: ["id"] + foreignKeyName: "_card_workspace_members_cardId_card_id_fk"; + columns: ["cardId"]; + isOneToOne: false; + referencedRelation: "card"; + referencedColumns: ["id"]; }, { - foreignKeyName: "_card_workspace_members_workspaceMemberId_workspace_members_id_" - columns: ["workspaceMemberId"] - isOneToOne: false - referencedRelation: "workspace_members" - referencedColumns: ["id"] + foreignKeyName: "_card_workspace_members_workspaceMemberId_workspace_members_id_"; + columns: ["workspaceMemberId"]; + isOneToOne: false; + referencedRelation: "workspace_members"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; board: { Row: { - createdAt: string - createdBy: string - deletedAt: string | null - deletedBy: string | null - id: number - importId: number | null - name: string - publicId: string - updatedAt: string | null - workspaceId: number - } + createdAt: string; + createdBy: string; + deletedAt: string | null; + deletedBy: string | null; + id: number; + importId: number | null; + name: string; + publicId: string; + updatedAt: string | null; + workspaceId: number; + }; Insert: { - createdAt?: string - createdBy: string - deletedAt?: string | null - deletedBy?: string | null - id?: number - importId?: number | null - name: string - publicId: string - updatedAt?: string | null - workspaceId: number - } + createdAt?: string; + createdBy: string; + deletedAt?: string | null; + deletedBy?: string | null; + id?: number; + importId?: number | null; + name: string; + publicId: string; + updatedAt?: string | null; + workspaceId: number; + }; Update: { - createdAt?: string - createdBy?: string - deletedAt?: string | null - deletedBy?: string | null - id?: number - importId?: number | null - name?: string - publicId?: string - updatedAt?: string | null - workspaceId?: number - } + createdAt?: string; + createdBy?: string; + deletedAt?: string | null; + deletedBy?: string | null; + id?: number; + importId?: number | null; + name?: string; + publicId?: string; + updatedAt?: string | null; + workspaceId?: number; + }; Relationships: [ { - foreignKeyName: "board_createdBy_user_id_fk" - columns: ["createdBy"] - isOneToOne: false - referencedRelation: "user" - referencedColumns: ["id"] + foreignKeyName: "board_createdBy_user_id_fk"; + columns: ["createdBy"]; + isOneToOne: false; + referencedRelation: "user"; + referencedColumns: ["id"]; }, { - foreignKeyName: "board_deletedBy_user_id_fk" - columns: ["deletedBy"] - isOneToOne: false - referencedRelation: "user" - referencedColumns: ["id"] + foreignKeyName: "board_deletedBy_user_id_fk"; + columns: ["deletedBy"]; + isOneToOne: false; + referencedRelation: "user"; + referencedColumns: ["id"]; }, { - foreignKeyName: "board_importId_import_id_fk" - columns: ["importId"] - isOneToOne: false - referencedRelation: "import" - referencedColumns: ["id"] + foreignKeyName: "board_importId_import_id_fk"; + columns: ["importId"]; + isOneToOne: false; + referencedRelation: "import"; + referencedColumns: ["id"]; }, { - foreignKeyName: "board_workspaceId_workspace_id_fk" - columns: ["workspaceId"] - isOneToOne: false - referencedRelation: "workspace" - referencedColumns: ["id"] + foreignKeyName: "board_workspaceId_workspace_id_fk"; + columns: ["workspaceId"]; + isOneToOne: false; + referencedRelation: "workspace"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; card: { Row: { - createdAt: string - createdBy: string - deletedAt: string | null - deletedBy: string | null - description: string | null - id: number - importId: number | null - index: number - listId: number - publicId: string - title: string - updatedAt: string | null - } + createdAt: string; + createdBy: string; + deletedAt: string | null; + deletedBy: string | null; + description: string | null; + id: number; + importId: number | null; + index: number; + listId: number; + publicId: string; + title: string; + updatedAt: string | null; + }; Insert: { - createdAt?: string - createdBy: string - deletedAt?: string | null - deletedBy?: string | null - description?: string | null - id?: number - importId?: number | null - index: number - listId: number - publicId: string - title: string - updatedAt?: string | null - } + createdAt?: string; + createdBy: string; + deletedAt?: string | null; + deletedBy?: string | null; + description?: string | null; + id?: number; + importId?: number | null; + index: number; + listId: number; + publicId: string; + title: string; + updatedAt?: string | null; + }; Update: { - createdAt?: string - createdBy?: string - deletedAt?: string | null - deletedBy?: string | null - description?: string | null - id?: number - importId?: number | null - index?: number - listId?: number - publicId?: string - title?: string - updatedAt?: string | null - } + createdAt?: string; + createdBy?: string; + deletedAt?: string | null; + deletedBy?: string | null; + description?: string | null; + id?: number; + importId?: number | null; + index?: number; + listId?: number; + publicId?: string; + title?: string; + updatedAt?: string | null; + }; Relationships: [ { - foreignKeyName: "card_createdBy_user_id_fk" - columns: ["createdBy"] - isOneToOne: false - referencedRelation: "user" - referencedColumns: ["id"] + foreignKeyName: "card_createdBy_user_id_fk"; + columns: ["createdBy"]; + isOneToOne: false; + referencedRelation: "user"; + referencedColumns: ["id"]; }, { - foreignKeyName: "card_deletedBy_user_id_fk" - columns: ["deletedBy"] - isOneToOne: false - referencedRelation: "user" - referencedColumns: ["id"] + foreignKeyName: "card_deletedBy_user_id_fk"; + columns: ["deletedBy"]; + isOneToOne: false; + referencedRelation: "user"; + referencedColumns: ["id"]; }, { - foreignKeyName: "card_importId_import_id_fk" - columns: ["importId"] - isOneToOne: false - referencedRelation: "import" - referencedColumns: ["id"] + foreignKeyName: "card_importId_import_id_fk"; + columns: ["importId"]; + isOneToOne: false; + referencedRelation: "import"; + referencedColumns: ["id"]; }, { - foreignKeyName: "card_listId_list_id_fk" - columns: ["listId"] - isOneToOne: false - referencedRelation: "list" - referencedColumns: ["id"] + foreignKeyName: "card_listId_list_id_fk"; + columns: ["listId"]; + isOneToOne: false; + referencedRelation: "list"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; + card_activity: { + Row: { + cardId: number; + createdAt: string; + createdBy: string; + fromDescription: string | null; + fromIndex: number | null; + fromListId: number | null; + fromTitle: string | null; + id: number; + labelId: number | null; + publicId: string; + toDescription: string | null; + toIndex: number | null; + toListId: number | null; + toTitle: string | null; + type: Database["public"]["Enums"]["card_activity_type"]; + workspaceMemberId: number | null; + }; + Insert: { + cardId: number; + createdAt?: string; + createdBy: string; + fromDescription?: string | null; + fromIndex?: number | null; + fromListId?: number | null; + fromTitle?: string | null; + id?: number; + labelId?: number | null; + publicId: string; + toDescription?: string | null; + toIndex?: number | null; + toListId?: number | null; + toTitle?: string | null; + type: Database["public"]["Enums"]["card_activity_type"]; + workspaceMemberId?: number | null; + }; + Update: { + cardId?: number; + createdAt?: string; + createdBy?: string; + fromDescription?: string | null; + fromIndex?: number | null; + fromListId?: number | null; + fromTitle?: string | null; + id?: number; + labelId?: number | null; + publicId?: string; + toDescription?: string | null; + toIndex?: number | null; + toListId?: number | null; + toTitle?: string | null; + type?: Database["public"]["Enums"]["card_activity_type"]; + workspaceMemberId?: number | null; + }; + Relationships: [ + { + foreignKeyName: "card_activity_cardId_card_id_fk"; + columns: ["cardId"]; + isOneToOne: false; + referencedRelation: "card"; + referencedColumns: ["id"]; + }, + { + foreignKeyName: "card_activity_createdBy_user_id_fk"; + columns: ["createdBy"]; + isOneToOne: false; + referencedRelation: "user"; + referencedColumns: ["id"]; + }, + { + foreignKeyName: "card_activity_labelId_label_id_fk"; + columns: ["labelId"]; + isOneToOne: false; + referencedRelation: "label"; + referencedColumns: ["id"]; + }, + { + foreignKeyName: "card_activity_toListId_list_id_fk"; + columns: ["toListId"]; + isOneToOne: false; + referencedRelation: "list"; + referencedColumns: ["id"]; + }, + { + foreignKeyName: "card_activity_workspaceMemberId_workspace_members_id_fk"; + columns: ["workspaceMemberId"]; + isOneToOne: false; + referencedRelation: "workspace_members"; + referencedColumns: ["id"]; + }, + ]; + }; import: { Row: { - createdAt: string - createdBy: string - id: number - publicId: string - source: Database["public"]["Enums"]["source"] - status: Database["public"]["Enums"]["status"] - } + createdAt: string; + createdBy: string; + id: number; + publicId: string; + source: Database["public"]["Enums"]["source"]; + status: Database["public"]["Enums"]["status"]; + }; Insert: { - createdAt?: string - createdBy: string - id?: number - publicId: string - source: Database["public"]["Enums"]["source"] - status: Database["public"]["Enums"]["status"] - } + createdAt?: string; + createdBy: string; + id?: number; + publicId: string; + source: Database["public"]["Enums"]["source"]; + status: Database["public"]["Enums"]["status"]; + }; Update: { - createdAt?: string - createdBy?: string - id?: number - publicId?: string - source?: Database["public"]["Enums"]["source"] - status?: Database["public"]["Enums"]["status"] - } + createdAt?: string; + createdBy?: string; + id?: number; + publicId?: string; + source?: Database["public"]["Enums"]["source"]; + status?: Database["public"]["Enums"]["status"]; + }; Relationships: [ { - foreignKeyName: "import_createdBy_user_id_fk" - columns: ["createdBy"] - isOneToOne: false - referencedRelation: "user" - referencedColumns: ["id"] + foreignKeyName: "import_createdBy_user_id_fk"; + columns: ["createdBy"]; + isOneToOne: false; + referencedRelation: "user"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; label: { Row: { - boardId: number - colourCode: string | null - createdAt: string - createdBy: string - id: number - importId: number | null - name: string - publicId: string - updatedAt: string | null - } + boardId: number; + colourCode: string | null; + createdAt: string; + createdBy: string; + id: number; + importId: number | null; + name: string; + publicId: string; + updatedAt: string | null; + }; Insert: { - boardId: number - colourCode?: string | null - createdAt?: string - createdBy: string - id?: number - importId?: number | null - name: string - publicId: string - updatedAt?: string | null - } + boardId: number; + colourCode?: string | null; + createdAt?: string; + createdBy: string; + id?: number; + importId?: number | null; + name: string; + publicId: string; + updatedAt?: string | null; + }; Update: { - boardId?: number - colourCode?: string | null - createdAt?: string - createdBy?: string - id?: number - importId?: number | null - name?: string - publicId?: string - updatedAt?: string | null - } + boardId?: number; + colourCode?: string | null; + createdAt?: string; + createdBy?: string; + id?: number; + importId?: number | null; + name?: string; + publicId?: string; + updatedAt?: string | null; + }; Relationships: [ { - foreignKeyName: "label_boardId_board_id_fk" - columns: ["boardId"] - isOneToOne: false - referencedRelation: "board" - referencedColumns: ["id"] + foreignKeyName: "label_boardId_board_id_fk"; + columns: ["boardId"]; + isOneToOne: false; + referencedRelation: "board"; + referencedColumns: ["id"]; }, { - foreignKeyName: "label_createdBy_user_id_fk" - columns: ["createdBy"] - isOneToOne: false - referencedRelation: "user" - referencedColumns: ["id"] + foreignKeyName: "label_createdBy_user_id_fk"; + columns: ["createdBy"]; + isOneToOne: false; + referencedRelation: "user"; + referencedColumns: ["id"]; }, { - foreignKeyName: "label_importId_import_id_fk" - columns: ["importId"] - isOneToOne: false - referencedRelation: "import" - referencedColumns: ["id"] + foreignKeyName: "label_importId_import_id_fk"; + columns: ["importId"]; + isOneToOne: false; + referencedRelation: "import"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; list: { Row: { - boardId: number - createdAt: string - createdBy: string - deletedAt: string | null - deletedBy: string | null - id: number - importId: number | null - index: number - name: string - publicId: string - updatedAt: string | null - } + boardId: number; + createdAt: string; + createdBy: string; + deletedAt: string | null; + deletedBy: string | null; + id: number; + importId: number | null; + index: number; + name: string; + publicId: string; + updatedAt: string | null; + }; Insert: { - boardId: number - createdAt?: string - createdBy: string - deletedAt?: string | null - deletedBy?: string | null - id?: number - importId?: number | null - index: number - name: string - publicId: string - updatedAt?: string | null - } + boardId: number; + createdAt?: string; + createdBy: string; + deletedAt?: string | null; + deletedBy?: string | null; + id?: number; + importId?: number | null; + index: number; + name: string; + publicId: string; + updatedAt?: string | null; + }; Update: { - boardId?: number - createdAt?: string - createdBy?: string - deletedAt?: string | null - deletedBy?: string | null - id?: number - importId?: number | null - index?: number - name?: string - publicId?: string - updatedAt?: string | null - } + boardId?: number; + createdAt?: string; + createdBy?: string; + deletedAt?: string | null; + deletedBy?: string | null; + id?: number; + importId?: number | null; + index?: number; + name?: string; + publicId?: string; + updatedAt?: string | null; + }; Relationships: [ { - foreignKeyName: "list_boardId_board_id_fk" - columns: ["boardId"] - isOneToOne: false - referencedRelation: "board" - referencedColumns: ["id"] + foreignKeyName: "list_boardId_board_id_fk"; + columns: ["boardId"]; + isOneToOne: false; + referencedRelation: "board"; + referencedColumns: ["id"]; }, { - foreignKeyName: "list_createdBy_user_id_fk" - columns: ["createdBy"] - isOneToOne: false - referencedRelation: "user" - referencedColumns: ["id"] + foreignKeyName: "list_createdBy_user_id_fk"; + columns: ["createdBy"]; + isOneToOne: false; + referencedRelation: "user"; + referencedColumns: ["id"]; }, { - foreignKeyName: "list_deletedBy_user_id_fk" - columns: ["deletedBy"] - isOneToOne: false - referencedRelation: "user" - referencedColumns: ["id"] + foreignKeyName: "list_deletedBy_user_id_fk"; + columns: ["deletedBy"]; + isOneToOne: false; + referencedRelation: "user"; + referencedColumns: ["id"]; }, { - foreignKeyName: "list_importId_import_id_fk" - columns: ["importId"] - isOneToOne: false - referencedRelation: "import" - referencedColumns: ["id"] + foreignKeyName: "list_importId_import_id_fk"; + columns: ["importId"]; + isOneToOne: false; + referencedRelation: "import"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; user: { Row: { - email: string - emailVerified: string | null - id: string - image: string | null - name: string | null - } + email: string; + emailVerified: string | null; + id: string; + image: string | null; + name: string | null; + }; Insert: { - email: string - emailVerified?: string | null - id: string - image?: string | null - name?: string | null - } + email: string; + emailVerified?: string | null; + id: string; + image?: string | null; + name?: string | null; + }; Update: { - email?: string - emailVerified?: string | null - id?: string - image?: string | null - name?: string | null - } - Relationships: [] - } + email?: string; + emailVerified?: string | null; + id?: string; + image?: string | null; + name?: string | null; + }; + Relationships: []; + }; workspace: { Row: { - createdAt: string - createdBy: string - deletedAt: string | null - deletedBy: string | null - id: number - name: string - publicId: string - slug: string - updatedAt: string | null - } + createdAt: string; + createdBy: string; + deletedAt: string | null; + deletedBy: string | null; + id: number; + name: string; + publicId: string; + slug: string; + updatedAt: string | null; + }; Insert: { - createdAt?: string - createdBy: string - deletedAt?: string | null - deletedBy?: string | null - id?: number - name: string - publicId: string - slug: string - updatedAt?: string | null - } + createdAt?: string; + createdBy: string; + deletedAt?: string | null; + deletedBy?: string | null; + id?: number; + name: string; + publicId: string; + slug: string; + updatedAt?: string | null; + }; Update: { - createdAt?: string - createdBy?: string - deletedAt?: string | null - deletedBy?: string | null - id?: number - name?: string - publicId?: string - slug?: string - updatedAt?: string | null - } + createdAt?: string; + createdBy?: string; + deletedAt?: string | null; + deletedBy?: string | null; + id?: number; + name?: string; + publicId?: string; + slug?: string; + updatedAt?: string | null; + }; Relationships: [ { - foreignKeyName: "workspace_createdBy_user_id_fk" - columns: ["createdBy"] - isOneToOne: false - referencedRelation: "user" - referencedColumns: ["id"] + foreignKeyName: "workspace_createdBy_user_id_fk"; + columns: ["createdBy"]; + isOneToOne: false; + referencedRelation: "user"; + referencedColumns: ["id"]; }, { - foreignKeyName: "workspace_deletedBy_user_id_fk" - columns: ["deletedBy"] - isOneToOne: false - referencedRelation: "user" - referencedColumns: ["id"] + foreignKeyName: "workspace_deletedBy_user_id_fk"; + columns: ["deletedBy"]; + isOneToOne: false; + referencedRelation: "user"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; workspace_members: { Row: { - createdAt: string - createdBy: string - deletedAt: string | null - id: number - publicId: string - role: Database["public"]["Enums"]["role"] - status: Database["public"]["Enums"]["member_status"] - updatedAt: string | null - userId: string - workspaceId: number - } + createdAt: string; + createdBy: string; + deletedAt: string | null; + deletedBy: string | null; + id: number; + publicId: string; + role: Database["public"]["Enums"]["role"]; + status: Database["public"]["Enums"]["member_status"]; + updatedAt: string | null; + userId: string; + workspaceId: number; + }; Insert: { - createdAt?: string - createdBy: string - deletedAt?: string | null - id?: number - publicId: string - role: Database["public"]["Enums"]["role"] - status?: Database["public"]["Enums"]["member_status"] - updatedAt?: string | null - userId: string - workspaceId: number - } + createdAt?: string; + createdBy: string; + deletedAt?: string | null; + deletedBy?: string | null; + id?: number; + publicId: string; + role: Database["public"]["Enums"]["role"]; + status?: Database["public"]["Enums"]["member_status"]; + updatedAt?: string | null; + userId: string; + workspaceId: number; + }; Update: { - createdAt?: string - createdBy?: string - deletedAt?: string | null - id?: number - publicId?: string - role?: Database["public"]["Enums"]["role"] - status?: Database["public"]["Enums"]["member_status"] - updatedAt?: string | null - userId?: string - workspaceId?: number - } + createdAt?: string; + createdBy?: string; + deletedAt?: string | null; + deletedBy?: string | null; + id?: number; + publicId?: string; + role?: Database["public"]["Enums"]["role"]; + status?: Database["public"]["Enums"]["member_status"]; + updatedAt?: string | null; + userId?: string; + workspaceId?: number; + }; Relationships: [ { - foreignKeyName: "workspace_members_userId_user_id_fk" - columns: ["userId"] - isOneToOne: false - referencedRelation: "user" - referencedColumns: ["id"] + foreignKeyName: "workspace_members_deletedBy_user_id_fk"; + columns: ["deletedBy"]; + isOneToOne: false; + referencedRelation: "user"; + referencedColumns: ["id"]; }, { - foreignKeyName: "workspace_members_workspaceId_workspace_id_fk" - columns: ["workspaceId"] - isOneToOne: false - referencedRelation: "workspace" - referencedColumns: ["id"] + foreignKeyName: "workspace_members_userId_user_id_fk"; + columns: ["userId"]; + isOneToOne: false; + referencedRelation: "user"; + referencedColumns: ["id"]; }, - ] - } - } + { + foreignKeyName: "workspace_members_workspaceId_workspace_id_fk"; + columns: ["workspaceId"]; + isOneToOne: false; + referencedRelation: "workspace"; + referencedColumns: ["id"]; + }, + ]; + }; + }; Views: { - [_ in never]: never - } + [_ in never]: never; + }; Functions: { + is_workspace_admin: { + Args: { + user_id: string; + workspace_id: number; + }; + Returns: boolean; + }; push_card_index: { Args: { - list_id: number - card_index: number - } - Returns: undefined - } + list_id: number; + card_index: number; + }; + Returns: undefined; + }; reorder_cards: { Args: { - card_id: number - current_list_id: number - new_list_id: number - current_index: number - new_index: number - } - Returns: undefined - } + card_id: number; + current_list_id: number; + new_list_id: number; + current_index: number; + new_index: number; + }; + Returns: undefined; + }; reorder_lists: { Args: { - board_id: number - list_id: number - current_index: number - new_index: number - } - Returns: undefined - } + board_id: number; + list_id: number; + current_index: number; + new_index: number; + }; + Returns: undefined; + }; shift_card_index: { Args: { - list_id: number - card_index: number - } - Returns: undefined - } + list_id: number; + card_index: number; + }; + Returns: undefined; + }; shift_list_index: { Args: { - board_id: number - list_index: number - } - Returns: undefined - } - } + board_id: number; + list_index: number; + }; + Returns: undefined; + }; + }; Enums: { - member_status: "invited" | "active" | "removed" - role: "admin" | "member" | "guest" - source: "trello" - status: "started" | "success" | "failed" - workspace_invite_status: "pending" | "accepted" | "cancelled" - } + card_activity_type: + | "card.created" + | "card.updated.title" + | "card.updated.description" + | "card.updated.index" + | "card.updated.list" + | "card.updated.label.added" + | "card.updated.label.removed" + | "card.updated.member.added" + | "card.updated.member.removed" + | "card.archived"; + member_status: "invited" | "active" | "removed"; + role: "admin" | "member" | "guest"; + source: "trello"; + status: "started" | "success" | "failed"; + workspace_invite_status: "pending" | "accepted" | "cancelled"; + }; CompositeTypes: { - [_ in never]: never - } - } -} + [_ in never]: never; + }; + }; +}; -type PublicSchema = Database[Extract] +type PublicSchema = Database[Extract]; export type Tables< PublicTableNameOrOptions extends @@ -576,7 +699,7 @@ export type Tables< > = PublicTableNameOrOptions extends { schema: keyof Database } ? (Database[PublicTableNameOrOptions["schema"]]["Tables"] & Database[PublicTableNameOrOptions["schema"]]["Views"])[TableName] extends { - Row: infer R + Row: infer R; } ? R : never @@ -584,11 +707,11 @@ export type Tables< PublicSchema["Views"]) ? (PublicSchema["Tables"] & PublicSchema["Views"])[PublicTableNameOrOptions] extends { - Row: infer R + Row: infer R; } ? R : never - : never + : never; export type TablesInsert< PublicTableNameOrOptions extends @@ -599,17 +722,17 @@ export type TablesInsert< : never = never, > = PublicTableNameOrOptions extends { schema: keyof Database } ? Database[PublicTableNameOrOptions["schema"]]["Tables"][TableName] extends { - Insert: infer I + Insert: infer I; } ? I : never : PublicTableNameOrOptions extends keyof PublicSchema["Tables"] ? PublicSchema["Tables"][PublicTableNameOrOptions] extends { - Insert: infer I + Insert: infer I; } ? I : never - : never + : never; export type TablesUpdate< PublicTableNameOrOptions extends @@ -620,17 +743,17 @@ export type TablesUpdate< : never = never, > = PublicTableNameOrOptions extends { schema: keyof Database } ? Database[PublicTableNameOrOptions["schema"]]["Tables"][TableName] extends { - Update: infer U + Update: infer U; } ? U : never : PublicTableNameOrOptions extends keyof PublicSchema["Tables"] ? PublicSchema["Tables"][PublicTableNameOrOptions] extends { - Update: infer U + Update: infer U; } ? U : never - : never + : never; export type Enums< PublicEnumNameOrOptions extends @@ -643,4 +766,19 @@ export type Enums< ? Database[PublicEnumNameOrOptions["schema"]]["Enums"][EnumName] : PublicEnumNameOrOptions extends keyof PublicSchema["Enums"] ? PublicSchema["Enums"][PublicEnumNameOrOptions] - : never + : never; + +export type CompositeTypes< + PublicCompositeTypeNameOrOptions extends + | keyof PublicSchema["CompositeTypes"] + | { schema: keyof Database }, + CompositeTypeName extends PublicCompositeTypeNameOrOptions extends { + schema: keyof Database; + } + ? keyof Database[PublicCompositeTypeNameOrOptions["schema"]]["CompositeTypes"] + : never = never, +> = PublicCompositeTypeNameOrOptions extends { schema: keyof Database } + ? Database[PublicCompositeTypeNameOrOptions["schema"]]["CompositeTypes"][CompositeTypeName] + : PublicCompositeTypeNameOrOptions extends keyof PublicSchema["CompositeTypes"] + ? PublicSchema["CompositeTypes"][PublicCompositeTypeNameOrOptions] + : never;