feat: monorepo

This commit is contained in:
Henry
2024-12-12 14:34:10 +00:00
parent b8eed7a90c
commit 0c8d17dce5
370 changed files with 10280 additions and 39805 deletions

View File

@@ -0,0 +1,11 @@
import { type Config } from "drizzle-kit";
export default {
schema: "./src/server/db/schema.ts",
out: "./src/server/db/migrations",
driver: "pg",
dbCredentials: {
connectionString: process.env.POSTGRES_URL,
},
// tablesFilter: ["kan_*"],
} satisfies Config;

View File

@@ -0,0 +1,9 @@
import baseConfig from "@kan/eslint-config/base";
/** @type {import('typescript-eslint').Config} */
export default [
{
ignores: ["dist/**"],
},
...baseConfig,
];

View File

@@ -0,0 +1,317 @@
DO $$ BEGIN
CREATE TYPE "source" AS ENUM('trello');
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
CREATE TYPE "status" AS ENUM('started', 'success', 'failed');
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
CREATE TYPE "role" AS ENUM('admin', 'member', 'guest');
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "account" (
"userId" uuid NOT NULL,
"type" varchar(255) NOT NULL,
"provider" varchar(255) NOT NULL,
"providerAccountId" varchar(255) NOT NULL,
"refresh_token" text,
"access_token" text,
"expires_at" integer,
"token_type" varchar(255),
"scope" varchar(255),
"id_token" text,
"session_state" varchar(255),
CONSTRAINT account_provider_providerAccountId PRIMARY KEY("provider","providerAccountId")
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "board" (
"id" bigserial PRIMARY KEY NOT NULL,
"publicId" varchar(12) NOT NULL,
"name" varchar(255) NOT NULL,
"createdBy" uuid NOT NULL,
"createdAt" timestamp DEFAULT now() NOT NULL,
"updatedAt" timestamp,
"deletedAt" timestamp DEFAULT now(),
"deletedBy" uuid,
"importId" bigint,
"workspaceId" bigint NOT NULL,
CONSTRAINT "board_publicId_unique" UNIQUE("publicId")
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "_card_workspace_members" (
"cardId" bigint NOT NULL,
"workspaceMemberId" bigint NOT NULL,
CONSTRAINT _card_workspace_members_cardId_workspaceMemberId PRIMARY KEY("cardId","workspaceMemberId")
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "card" (
"id" bigserial PRIMARY KEY NOT NULL,
"publicId" varchar(12) NOT NULL,
"title" varchar(255) NOT NULL,
"description" text,
"index" integer NOT NULL,
"createdBy" uuid NOT NULL,
"createdAt" timestamp DEFAULT now() NOT NULL,
"updatedAt" timestamp,
"deletedAt" timestamp,
"deletedBy" uuid,
"listId" bigint NOT NULL,
"importId" bigint,
CONSTRAINT "card_publicId_unique" UNIQUE("publicId")
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "_card_labels" (
"cardId" bigint NOT NULL,
"labelId" bigint NOT NULL,
CONSTRAINT _card_labels_cardId_labelId PRIMARY KEY("cardId","labelId")
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "import" (
"id" bigserial PRIMARY KEY NOT NULL,
"publicId" varchar(12) NOT NULL,
"source" "source" NOT NULL,
"status" "status" NOT NULL,
"createdBy" uuid NOT NULL,
"createdAt" timestamp DEFAULT now() NOT NULL,
CONSTRAINT "import_publicId_unique" UNIQUE("publicId")
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "label" (
"id" bigserial PRIMARY KEY NOT NULL,
"publicId" varchar(12) NOT NULL,
"name" varchar(255) NOT NULL,
"colourCode" varchar(12),
"createdBy" uuid NOT NULL,
"createdAt" timestamp DEFAULT now() NOT NULL,
"updatedAt" timestamp,
"boardId" bigint NOT NULL,
"importId" bigint,
CONSTRAINT "label_publicId_unique" UNIQUE("publicId")
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "list" (
"id" bigserial PRIMARY KEY NOT NULL,
"publicId" varchar(12) NOT NULL,
"name" varchar(255) NOT NULL,
"index" integer NOT NULL,
"createdBy" uuid NOT NULL,
"createdAt" timestamp DEFAULT now() NOT NULL,
"updatedAt" timestamp,
"deletedAt" timestamp,
"deletedBy" uuid,
"boardId" bigint NOT NULL,
"importId" bigint,
CONSTRAINT "list_publicId_unique" UNIQUE("publicId")
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "session" (
"sessionToken" varchar(255) PRIMARY KEY NOT NULL,
"userId" uuid NOT NULL,
"expires" timestamp NOT NULL
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "user" (
"id" uuid PRIMARY KEY NOT NULL,
"name" varchar(255),
"email" varchar(255) NOT NULL,
"emailVerified" timestamp,
"image" varchar(255),
CONSTRAINT "user_email_unique" UNIQUE("email")
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "verificationToken" (
"identifier" varchar(255) NOT NULL,
"token" varchar(255) NOT NULL,
"expires" timestamp NOT NULL,
CONSTRAINT verificationToken_identifier_token PRIMARY KEY("identifier","token")
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "workspace_members" (
"id" bigserial PRIMARY KEY NOT NULL,
"publicId" varchar(12) NOT NULL,
"userId" uuid NOT NULL,
"workspaceId" bigint NOT NULL,
"createdBy" uuid NOT NULL,
"createdAt" timestamp DEFAULT now() NOT NULL,
"updatedAt" timestamp,
"deletedAt" timestamp,
"role" "role" NOT NULL,
CONSTRAINT "workspace_members_publicId_unique" UNIQUE("publicId")
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "workspace" (
"id" bigserial PRIMARY KEY NOT NULL,
"publicId" varchar(12) NOT NULL,
"name" varchar(255) NOT NULL,
"slug" varchar(255) NOT NULL,
"createdBy" uuid NOT NULL,
"createdAt" timestamp DEFAULT now() NOT NULL,
"updatedAt" timestamp,
"deletedAt" timestamp,
"deletedBy" uuid,
CONSTRAINT "workspace_publicId_unique" UNIQUE("publicId"),
CONSTRAINT "workspace_slug_unique" UNIQUE("slug")
);
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "account" ADD CONSTRAINT "account_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "board" ADD CONSTRAINT "board_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 $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "board" ADD CONSTRAINT "board_deletedBy_user_id_fk" FOREIGN KEY ("deletedBy") REFERENCES "user"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "board" ADD CONSTRAINT "board_importId_import_id_fk" FOREIGN KEY ("importId") REFERENCES "import"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "board" ADD CONSTRAINT "board_workspaceId_workspace_id_fk" FOREIGN KEY ("workspaceId") REFERENCES "workspace"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "_card_workspace_members" ADD CONSTRAINT "_card_workspace_members_cardId_card_id_fk" FOREIGN KEY ("cardId") REFERENCES "card"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "_card_workspace_members" ADD CONSTRAINT "_card_workspace_members_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" ADD CONSTRAINT "card_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 $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "card" ADD CONSTRAINT "card_deletedBy_user_id_fk" FOREIGN KEY ("deletedBy") REFERENCES "user"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "card" ADD CONSTRAINT "card_listId_list_id_fk" FOREIGN KEY ("listId") 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" ADD CONSTRAINT "card_importId_import_id_fk" FOREIGN KEY ("importId") REFERENCES "import"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "_card_labels" ADD CONSTRAINT "_card_labels_cardId_card_id_fk" FOREIGN KEY ("cardId") REFERENCES "card"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "_card_labels" ADD CONSTRAINT "_card_labels_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 "import" ADD CONSTRAINT "import_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 $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "label" ADD CONSTRAINT "label_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 $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "label" ADD CONSTRAINT "label_boardId_board_id_fk" FOREIGN KEY ("boardId") REFERENCES "board"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "label" ADD CONSTRAINT "label_importId_import_id_fk" FOREIGN KEY ("importId") REFERENCES "import"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "list" ADD CONSTRAINT "list_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 $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "list" ADD CONSTRAINT "list_deletedBy_user_id_fk" FOREIGN KEY ("deletedBy") REFERENCES "user"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "list" ADD CONSTRAINT "list_boardId_board_id_fk" FOREIGN KEY ("boardId") REFERENCES "board"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "list" ADD CONSTRAINT "list_importId_import_id_fk" FOREIGN KEY ("importId") REFERENCES "import"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "session" ADD CONSTRAINT "session_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "workspace_members" ADD CONSTRAINT "workspace_members_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "workspace_members" ADD CONSTRAINT "workspace_members_workspaceId_workspace_id_fk" FOREIGN KEY ("workspaceId") REFERENCES "workspace"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "workspace" ADD CONSTRAINT "workspace_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 $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "workspace" ADD CONSTRAINT "workspace_deletedBy_user_id_fk" FOREIGN KEY ("deletedBy") REFERENCES "user"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;

View File

@@ -0,0 +1 @@
ALTER TABLE "board" ALTER COLUMN "deletedAt" DROP DEFAULT;

View File

@@ -0,0 +1,66 @@
DROP TABLE IF EXISTS "account";--> statement-breakpoint
DROP TABLE IF EXISTS "session";--> statement-breakpoint
DROP TABLE IF EXISTS "verificationToken";--> statement-breakpoint
ALTER TABLE "board" DROP CONSTRAINT "board_workspaceId_workspace_id_fk";
--> statement-breakpoint
ALTER TABLE "_card_workspace_members" DROP CONSTRAINT "_card_workspace_members_cardId_card_id_fk";
--> statement-breakpoint
ALTER TABLE "card" DROP CONSTRAINT "card_listId_list_id_fk";
--> statement-breakpoint
ALTER TABLE "_card_labels" DROP CONSTRAINT IF EXISTS "_card_labels_cardId_card_id_fk";
--> statement-breakpoint
ALTER TABLE "_card_labels" DROP CONSTRAINT IF EXISTS "_card_labels_labelId_label_id_fk";
--> statement-breakpoint
ALTER TABLE "label" DROP CONSTRAINT "label_boardId_board_id_fk";
--> statement-breakpoint
ALTER TABLE "list" DROP CONSTRAINT "list_boardId_board_id_fk";
--> statement-breakpoint
ALTER TABLE "workspace_members" DROP CONSTRAINT "workspace_members_workspaceId_workspace_id_fk";
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "board" ADD CONSTRAINT "board_workspaceId_workspace_id_fk" FOREIGN KEY ("workspaceId") REFERENCES "workspace"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "_card_workspace_members" ADD CONSTRAINT "_card_workspace_members_workspaceMemberId_workspace_members_id_fk" FOREIGN KEY ("workspaceMemberId") REFERENCES "workspace_members"("id") ON DELETE CASCADE ON UPDATE NO ACTION;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "card" ADD CONSTRAINT "card_listId_list_id_fk" FOREIGN KEY ("listId") REFERENCES "list"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "_card_labels" ADD CONSTRAINT "_card_labels_cardId_card_id_fk" FOREIGN KEY ("cardId") REFERENCES "card"("id") ON DELETE CASCADE;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "_card_labels" ADD CONSTRAINT "_card_labels_labelId_label_id_fk" FOREIGN KEY ("labelId") REFERENCES "label"("id") ON DELETE CASCADE;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "label" ADD CONSTRAINT "label_boardId_board_id_fk" FOREIGN KEY ("boardId") REFERENCES "board"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "list" ADD CONSTRAINT "list_boardId_board_id_fk" FOREIGN KEY ("boardId") REFERENCES "board"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "workspace_members" ADD CONSTRAINT "workspace_members_workspaceId_workspace_id_fk" FOREIGN KEY ("workspaceId") REFERENCES "workspace"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;

View File

@@ -0,0 +1,22 @@
DO $$ BEGIN
CREATE TYPE "member_status" AS ENUM('invited', 'active', 'removed');
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
ALTER TABLE "_card_workspace_members" DROP CONSTRAINT "_card_workspace_members_cardId_card_id_fk";
--> statement-breakpoint
ALTER TABLE "_card_labels" DROP CONSTRAINT "_card_labels_cardId_card_id_fk";
--> statement-breakpoint
ALTER TABLE "workspace_members" ADD COLUMN "status" "member_status" DEFAULT 'invited' NOT NULL;--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "_card_workspace_members" ADD CONSTRAINT "_card_workspace_members_cardId_card_id_fk" FOREIGN KEY ("cardId") REFERENCES "card"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "_card_labels" ADD CONSTRAINT "_card_labels_cardId_card_id_fk" FOREIGN KEY ("cardId") REFERENCES "card"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;

View File

@@ -0,0 +1,6 @@
ALTER TABLE "workspace_members" ADD COLUMN "deletedBy" uuid;--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "workspace_members" ADD CONSTRAINT "workspace_members_deletedBy_user_id_fk" FOREIGN KEY ("deletedBy") REFERENCES "user"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;

View File

@@ -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 $$;

View File

@@ -0,0 +1,5 @@
DO $$ BEGIN
ALTER TABLE "card_activity" ADD CONSTRAINT "card_activity_fromListId_list_id_fk" FOREIGN KEY ("fromListId") REFERENCES "list"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;

View File

@@ -0,0 +1,30 @@
CREATE TABLE IF NOT EXISTS "card_comments" (
"id" bigserial PRIMARY KEY NOT NULL,
"publicId" varchar(12) NOT NULL,
"comment" text NOT NULL,
"cardId" bigint NOT NULL,
"createdBy" uuid NOT NULL,
"createdAt" timestamp DEFAULT now() NOT NULL,
"updatedAt" timestamp,
"deletedAt" timestamp,
"deletedBy" uuid,
CONSTRAINT "card_comments_publicId_unique" UNIQUE("publicId")
);
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "card_comments" ADD CONSTRAINT "card_comments_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_comments" ADD CONSTRAINT "card_comments_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 $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "card_comments" ADD CONSTRAINT "card_comments_deletedBy_user_id_fk" FOREIGN KEY ("deletedBy") REFERENCES "user"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;

View File

@@ -0,0 +1,11 @@
ALTER TYPE "card_activity_type" ADD VALUE 'card.updated.comment.added';--> statement-breakpoint
ALTER TYPE "card_activity_type" ADD VALUE 'card.updated.comment.updated';--> statement-breakpoint
ALTER TYPE "card_activity_type" ADD VALUE 'card.updated.comment.deleted';--> statement-breakpoint
ALTER TABLE "card_activity" ADD COLUMN "commentId" bigint;--> statement-breakpoint
ALTER TABLE "card_activity" ADD COLUMN "fromComment" text;--> statement-breakpoint
ALTER TABLE "card_activity" ADD COLUMN "toComment" text;--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "card_activity" ADD CONSTRAINT "card_activity_commentId_card_comments_id_fk" FOREIGN KEY ("commentId") REFERENCES "card_comments"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,69 @@
{
"version": "12",
"dialect": "pg",
"entries": [
{
"idx": 0,
"version": "5",
"when": 1711571659259,
"tag": "0000_legal_quicksilver",
"breakpoints": true
},
{
"idx": 1,
"version": "5",
"when": 1713021051974,
"tag": "0001_stale_mattie_franklin",
"breakpoints": true
},
{
"idx": 2,
"version": "5",
"when": 1724967733894,
"tag": "0002_clever_robin_chapel",
"breakpoints": true
},
{
"idx": 3,
"version": "5",
"when": 1728246215706,
"tag": "0003_naive_secret_warriors",
"breakpoints": true
},
{
"idx": 4,
"version": "5",
"when": 1730205607613,
"tag": "0004_rainy_archangel",
"breakpoints": true
},
{
"idx": 5,
"version": "5",
"when": 1730813108528,
"tag": "0005_blue_marvex",
"breakpoints": true
},
{
"idx": 6,
"version": "5",
"when": 1730967400524,
"tag": "0006_neat_korg",
"breakpoints": true
},
{
"idx": 7,
"version": "5",
"when": 1731934769875,
"tag": "0007_adorable_crystal",
"breakpoints": true
},
{
"idx": 8,
"version": "5",
"when": 1731958265600,
"tag": "0008_nasty_bloodstorm",
"breakpoints": true
}
]
}

58
packages/db/package.json Normal file
View File

@@ -0,0 +1,58 @@
{
"name": "@kan/db",
"version": "0.1.0",
"private": true,
"type": "module",
"exports": {
".": {
"types": "./dist/index.d.ts",
"default": "./src/index.ts"
},
"./client": {
"types": "./dist/client.d.ts",
"default": "./src/client.ts"
},
"./schema": {
"types": "./dist/schema.d.ts",
"default": "./src/schema.ts"
},
"./types/*": {
"types": "./dist/types/*.d.ts",
"default": "./src/types/*"
},
"./repository/*": {
"types": "./dist/repository/*.d.ts",
"default": "./src/repository/*.ts"
}
},
"license": "MIT",
"scripts": {
"build": "tsc",
"clean": "git clean -xdf .cache .turbo dist node_modules",
"dev": "tsc",
"format": "prettier --check . --ignore-path ../../.gitignore",
"lint": "eslint",
"push": "pnpm with-env drizzle-kit push",
"studio": "pnpm with-env drizzle-kit studio",
"typecheck": "tsc --noEmit --emitDeclarationOnly false",
"with-env": "dotenv -e ../../.env --"
},
"dependencies": {
"@kan/utils": "workspace:^",
"@vercel/postgres": "^0.10.0",
"drizzle-orm": "^0.36.4",
"drizzle-zod": "^0.5.1",
"zod": "catalog:"
},
"devDependencies": {
"@kan/eslint-config": "workspace:*",
"@kan/prettier-config": "workspace:*",
"@kan/tsconfig": "workspace:*",
"dotenv-cli": "^7.4.4",
"drizzle-kit": "^0.28.1",
"eslint": "catalog:",
"prettier": "catalog:",
"typescript": "catalog:"
},
"prettier": "@kan/prettier-config"
}

346
packages/db/seed.sql Normal file
View File

@@ -0,0 +1,346 @@
CREATE OR REPLACE FUNCTION reorder_lists(board_id BIGINT, list_id BIGINT, current_index INT, new_index INT)
RETURNS BOOLEAN
LANGUAGE PLPGSQL
AS $$
BEGIN
UPDATE list
SET index =
CASE
WHEN index = current_index AND id = list_id THEN new_index
WHEN current_index < new_index AND index > current_index AND index <= new_index THEN index - 1
WHEN current_index > new_index AND index >= new_index AND index < current_index THEN index + 1
ELSE index
END
WHERE "boardId" = board_id;
-- Check for duplicate indices after the update
IF EXISTS (
SELECT index, COUNT(*)
FROM list
WHERE "boardId" = board_id
AND "deletedAt" IS NULL
GROUP BY index
HAVING COUNT(*) > 1
) THEN
RAISE EXCEPTION 'Duplicate indices found after reordering in board %', board_id;
END IF;
RETURN TRUE;
END;
$$;
CREATE OR REPLACE FUNCTION reorder_cards(card_id BIGINT, current_list_id BIGINT, new_list_id BIGINT, current_index INT, new_index INT)
RETURNS BOOLEAN
LANGUAGE PLPGSQL
AS $$
DECLARE
card_index INT;
BEGIN
SELECT index INTO card_index FROM card WHERE "listId" = current_list_id AND id = card_id AND "deletedAt" IS NULL;
IF current_list_id = new_list_id THEN
UPDATE card
SET index =
CASE
WHEN index = current_index THEN new_index
WHEN current_index < new_index AND index > current_index AND index <= new_index THEN index - 1
WHEN current_index > new_index AND index >= new_index AND index < current_index THEN index + 1
ELSE index
END
WHERE "listId" = current_list_id AND "deletedAt" IS NULL;
ELSE
UPDATE card
SET index = index + 1
WHERE "listId" = new_list_id AND index >= new_index AND "deletedAt" IS NULL;
UPDATE card
SET index = index - 1
WHERE "listId" = current_list_id AND index >= current_index AND "deletedAt" IS NULL;
UPDATE card
SET "listId" = new_list_id, index = new_index
WHERE id = card_id AND "deletedAt" IS NULL;
END IF;
-- Check for duplicate indices in both affected lists
IF EXISTS (
SELECT index, COUNT(*)
FROM card
WHERE "listId" IN (current_list_id, new_list_id)
AND "deletedAt" IS NULL
GROUP BY "listId", index
HAVING COUNT(*) > 1
) THEN
RAISE EXCEPTION 'Duplicate indices found after reordering in list % or %', current_list_id, new_list_id;
END IF;
RETURN TRUE;
END;
$$;
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 push_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
AS $$
SELECT EXISTS (
SELECT 1
FROM workspace_members
WHERE "workspaceId" = workspace_id
AND "userId" = user_id
AND "role" = 'admin'
);
$$;
alter table "_card_labels" enable row level security;
alter table "_card_workspace_members" enable row level security;
alter table "board" enable row level security;
alter table "card" enable row level security;
alter table "import" enable row level security;
alter table "label" enable row level security;
alter table "user" enable row level security;
alter table "list" enable row level security;
alter table "workspace" enable row level security;
alter table "workspace_members" enable row level security;
CREATE POLICY "Allow access to boards in user's workspace"
ON public.board
AS PERMISSIVE
FOR ALL
TO authenticated
USING (
"workspaceId" IN (
SELECT "workspaceId"
FROM workspace_members
WHERE "userId" = auth.uid()
)
);
CREATE POLICY "Allow access to lists in user's workspace"
ON public.list
AS PERMISSIVE
FOR ALL
TO authenticated
USING (
"boardId" IN (
SELECT b.id
FROM board b
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
WHERE wm."userId" = auth.uid()
)
);
CREATE POLICY "Allow access to cards in user's workspace"
ON public.card
AS PERMISSIVE
FOR ALL
TO authenticated
USING (
"listId" IN (
SELECT l.id
FROM list l
JOIN board b ON l."boardId" = b."id"
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
WHERE wm."userId" = auth.uid()
)
);
CREATE POLICY "Allow access to labels in user's workspace"
ON public.label
AS PERMISSIVE
FOR ALL
TO authenticated
USING (
"boardId" IN (
SELECT b.id
FROM board b
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
WHERE wm."userId" = auth.uid()
)
);
CREATE POLICY "Allow access to card labels in user's workspace"
ON public._card_labels
AS PERMISSIVE
FOR ALL
TO authenticated
USING (
"cardId" IN (
SELECT c.id
FROM card c
JOIN list l ON c."listId" = l.id
JOIN board b ON l."boardId" = b.id
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
WHERE wm."userId" = auth.uid()
)
AND
"labelId" IN (
SELECT l.id
FROM label l
JOIN board b ON l."boardId" = b.id
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
WHERE wm."userId" = auth.uid()
)
);
CREATE POLICY "Allow access to card workspace members in user's workspace"
ON public._card_workspace_members
AS PERMISSIVE
FOR ALL
TO authenticated
USING (
"cardId" IN (
SELECT c.id
FROM card c
JOIN list l ON c."listId" = l.id
JOIN board b ON l."boardId" = b.id
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
WHERE wm."userId" = auth.uid()
)
AND
"workspaceMemberId" IN (
SELECT wm.id
FROM workspace_members wm
JOIN workspace w ON wm."workspaceId" = w.id
JOIN board b ON w.id = b."workspaceId"
WHERE wm."userId" = auth.uid()
)
);
CREATE POLICY "Allow viewing members in user's workspace"
ON public.user
AS PERMISSIVE
FOR SELECT
TO authenticated
USING (
id IN (
SELECT wm."userId"
FROM workspace_members wm
WHERE wm."workspaceId" IN (
SELECT "workspaceId"
FROM workspace_members
WHERE "userId" = auth.uid()
)
)
);
CREATE POLICY "Allow viewing user's workspaces"
ON public.workspace
AS PERMISSIVE
FOR SELECT
TO authenticated
USING (
id IN (
SELECT "workspaceId"
FROM workspace_members
WHERE "userId" = auth.uid()
)
OR
"createdBy" = auth.uid()
);
CREATE POLICY "Allow updating user's workspaces"
ON public.workspace
AS PERMISSIVE
FOR UPDATE
TO authenticated
USING (
id IN (
SELECT "workspaceId"
FROM workspace_members
WHERE "userId" = auth.uid()
)
);
CREATE POLICY "Allow deleting user's workspaces"
ON public.workspace
AS PERMISSIVE
FOR DELETE
TO authenticated
USING (
id IN (
SELECT "workspaceId"
FROM workspace_members
WHERE "userId" = auth.uid()
)
);
CREATE POLICY "Allow authenticated users to create workspaces"
ON public.workspace
AS PERMISSIVE
FOR INSERT
TO authenticated
USING (true);
CREATE POLICY "Allow members to view workspace membership"
ON public.workspace_members
AS PERMISSIVE
FOR SELECT
TO authenticated
USING (
"userId" = auth.uid() OR
is_workspace_admin(auth.uid(), "workspaceId")
);
CREATE POLICY "Allow admins to add workspace members"
ON public.workspace_members
AS PERMISSIVE
FOR INSERT
TO authenticated
WITH CHECK (
is_workspace_admin(auth.uid(), "workspaceId")
);
CREATE POLICY "Allow admins to update workspace members"
ON public.workspace_members
AS PERMISSIVE
FOR UPDATE
TO authenticated
USING (
is_workspace_admin(auth.uid(), "workspaceId")
);
CREATE POLICY "Allow admins to remove workspace members"
ON public.workspace_members
AS PERMISSIVE
FOR DELETE
TO authenticated
USING (
is_workspace_admin(auth.uid(), "workspaceId")
);
CREATE POLICY "Allow access to user's own imports"
ON public.import
AS PERMISSIVE
FOR ALL
TO authenticated
USING (
"createdBy" = auth.uid()
);

View File

@@ -0,0 +1,9 @@
import { sql } from "@vercel/postgres";
import { drizzle } from "drizzle-orm/vercel-postgres";
import * as schema from "./schema";
export const db = drizzle({
client: sql,
schema,
});

View File

@@ -0,0 +1,15 @@
import "dotenv/config";
import { drizzle } from "drizzle-orm/postgres-js";
import { migrate } from "drizzle-orm/postgres-js/migrator";
import postgres from "postgres";
const postgresUrl = process.env.POSTGRES_URL;
if (!postgresUrl) {
throw new Error("POSTGRES_URL environment variable is not set");
}
const migrationClient = postgres(postgresUrl, { max: 1 });
migrate(drizzle(migrationClient), {
migrationsFolder: "./src/server/db/migrations",
}).catch((e) => console.log(e));

View File

@@ -0,0 +1,191 @@
import type { SupabaseClient } from "@supabase/supabase-js";
import type { Database } from "@kan/db/types/database.types";
import { generateUID } from "@kan/utils";
export const getAllByWorkspaceId = async (
db: SupabaseClient<Database>,
workspaceId: number,
) => {
const { data } = await db
.from("board")
.select(`publicId, name`)
.is("deletedAt", null)
.eq("workspaceId", workspaceId);
return data ?? [];
};
export const getByPublicId = async (
db: SupabaseClient<Database>,
boardPublicId: string,
filters: {
members: string[];
labels: string[];
},
) => {
let query = db
.from("board")
.select(
`
publicId,
name,
workspace (
publicId,
members:workspace_members (
publicId,
user!workspace_members_userId_user_id_fk (
name
)
)
),
labels:label (
publicId,
name,
colourCode
),
lists:list (
publicId,
name,
boardId,
index,
cards:card (
publicId,
title,
description,
listId,
index,
labels:label${filters.labels.length > 0 ? "!inner" : ""} (
publicId,
name,
colourCode
),
members:workspace_members${filters.members.length > 0 ? "!inner" : ""} (
publicId,
user!workspace_members_userId_user_id_fk (
name
)
)
)
)
`,
)
.eq("publicId", boardPublicId)
.is("deletedAt", null)
.is("lists.deletedAt", null)
.is("lists.cards.deletedAt", null)
.is("workspace.members.deletedAt", null)
.is("lists.cards.members.deletedAt", null);
if (filters.labels.length > 0) {
query = query.in("lists.cards.labels.publicId", filters.labels);
}
if (filters.members.length > 0) {
query = query.in("lists.cards.members.publicId", filters.members);
}
const { data } = await query
.order("index", { foreignTable: "list", ascending: true })
.order("index", { foreignTable: "list.card", ascending: true })
.limit(1)
.single();
return data;
};
export const getWithListIdsByPublicId = async (
db: SupabaseClient<Database>,
boardPublicId: string,
) => {
const { data } = await db
.from("board")
.select(`id, lists:list (id)`)
.eq("publicId", boardPublicId)
.limit(1)
.single();
return data;
};
export const getWithLatestListIndexByPublicId = async (
db: SupabaseClient<Database>,
boardPublicId: string,
) => {
const { data } = await db
.from("board")
.select(`id, lists:list (index)`)
.eq("publicId", boardPublicId)
.order("index", { foreignTable: "list", ascending: false })
.is("list.deletedAt", null)
.limit(1)
.single();
return data;
};
export const create = async (
db: SupabaseClient<Database>,
boardInput: {
name: string;
createdBy: string;
workspaceId: number;
importId?: number;
},
) => {
const { data } = await db
.from("board")
.insert({
publicId: generateUID(),
name: boardInput.name,
createdBy: boardInput.createdBy,
workspaceId: boardInput.workspaceId,
importId: boardInput.importId,
})
.select(`id, publicId, name`)
.limit(1)
.single();
return data;
};
export const update = async (
db: SupabaseClient<Database>,
boardInput: { name: string; boardPublicId: string },
) => {
const { data } = await db
.from("board")
.update({ name: boardInput.name })
.eq("publicId", boardInput.boardPublicId)
.select(`publicId, name`)
.limit(1)
.single();
return data;
};
export const softDelete = async (
db: SupabaseClient<Database>,
args: {
boardId: number;
deletedAt: string;
deletedBy: string;
},
) => {
const result = db
.from("board")
.update({ deletedAt: args.deletedAt, deletedBy: args.deletedBy })
.eq("id", args.boardId)
.is("deletedAt", null);
return result;
};
export const hardDelete = async (
db: SupabaseClient<Database>,
workspaceId: number,
) => {
const result = db.from("board").delete().eq("workspaceId", workspaceId);
return result;
};

View File

@@ -0,0 +1,426 @@
import type { SupabaseClient } from "@supabase/supabase-js";
import type { Database } from "@kan/db/types/database.types";
import { generateUID } from "@kan/utils";
export const create = async (
db: SupabaseClient<Database>,
cardInput: {
title: string;
description: string;
createdBy: string;
listId: number;
index: number;
},
) => {
const { data } = await db
.from("card")
.insert({
publicId: generateUID(),
title: cardInput.title,
description: cardInput.description,
createdBy: cardInput.createdBy,
listId: cardInput.listId,
index: cardInput.index,
})
.select(`id`)
.limit(1)
.single();
return data;
};
export const bulkCreateCardLabelRelationships = async (
db: SupabaseClient<Database>,
cardLabelRelationshipInput: {
cardId: number;
labelId: number;
}[],
) => {
const { data } = await db
.from("_card_labels")
.insert(cardLabelRelationshipInput)
.select();
return data;
};
export const bulkCreateCardWorkspaceMemberRelationships = async (
db: SupabaseClient<Database>,
cardWorkspaceMemberRelationshipInput: {
cardId: number;
workspaceMemberId: number;
}[],
) => {
const { data } = await db
.from("_card_workspace_members")
.insert(cardWorkspaceMemberRelationshipInput)
.select();
return data;
};
export const update = async (
db: SupabaseClient<Database>,
cardInput: {
title: string;
description: string;
},
args: {
cardPublicId: string;
},
) => {
const { data } = await db
.from("card")
.update({ title: cardInput.title, description: cardInput.description })
.eq("publicId", args.cardPublicId)
.is("deletedAt", null)
.select(`id, publicId, title, description`)
.order("id", { ascending: true })
.limit(1)
.single();
return data;
};
export const getCardWithListByPublicId = async (
db: SupabaseClient<Database>,
cardPublicId: string,
) => {
const { data } = await db
.from("card")
.select(`id, index, list (id, boardId)`)
.eq("publicId", cardPublicId)
.is("deletedAt", null)
.limit(1)
.single();
return data;
};
export const getByPublicId = async (
db: SupabaseClient<Database>,
cardPublicId: string,
) => {
const { data } = await db
.from("card")
.select(`id, publicId, title, description`)
.eq("publicId", cardPublicId)
.limit(1)
.single();
return data;
};
export const getCardLabelRelationship = async (
db: SupabaseClient<Database>,
args: { cardId: number; labelId: number },
) => {
const { data } = await db
.from("_card_labels")
.select()
.eq("cardId", args.cardId)
.eq("labelId", args.labelId)
.limit(1)
.single();
return data;
};
export const bulkCreate = async (
db: SupabaseClient<Database>,
cardInput: {
publicId: string;
title: string;
description: string;
createdBy: string;
listId: number;
index: number;
importId?: number;
}[],
) => {
const { data } = await db.from("card").insert(cardInput).select(`id`);
return data;
};
export const createCardLabelRelationship = async (
db: SupabaseClient<Database>,
cardLabelRelationshipInput: { cardId: number; labelId: number },
) => {
const { data } = await db
.from("_card_labels")
.insert({
cardId: cardLabelRelationshipInput.cardId,
labelId: cardLabelRelationshipInput.labelId,
})
.select()
.limit(1)
.single();
return data;
};
export const getCardMemberRelationship = async (
db: SupabaseClient<Database>,
args: { cardId: number; memberId: number },
) => {
const { data } = await db
.from("_card_workspace_members")
.select()
.eq("cardId", args.cardId)
.eq("workspaceMemberId", args.memberId)
.limit(1)
.single();
return data;
};
export const createCardMemberRelationship = async (
db: SupabaseClient<Database>,
cardMemberRelationshipInput: { cardId: number; memberId: number },
) => {
const { error } = await db.from("_card_workspace_members").insert({
cardId: cardMemberRelationshipInput.cardId,
workspaceMemberId: cardMemberRelationshipInput.memberId,
});
return { success: !error };
};
export const getWithListAndMembersByPublicId = async (
db: SupabaseClient<Database>,
cardPublicId: string,
) => {
const { data } = await db
.from("card")
.select(
`
publicId,
title,
description,
labels:label (
publicId,
name,
colourCode
),
list (
publicId,
name,
board (
publicId,
name,
labels:label (
publicId,
colourCode,
name
),
lists:list (
publicId,
name
),
workspace (
publicId,
members:workspace_members (
publicId,
user!workspace_members_userId_user_id_fk (
id,
name
)
)
)
)
),
members:workspace_members (
publicId,
user!workspace_members_userId_user_id_fk (
id,
name
)
),
activities:card_activity (
publicId,
type,
createdAt,
fromIndex,
toIndex,
fromTitle,
toTitle,
fromDescription,
toDescription,
fromList:list!card_activity_fromListId_list_id_fk (
publicId,
name,
index
),
toList:list!card_activity_toListId_list_id_fk (
publicId,
name,
index
),
label!card_activity_labelId_label_id_fk (
publicId,
name
),
member:workspace_members!card_activity_workspaceMemberId_workspace_members_id_fk (
publicId,
user!workspace_members_userId_user_id_fk (
id,
name,
email
)
),
user!card_activity_createdBy_user_id_fk (
id,
name,
email
),
comment:card_comments!card_activity_commentId_card_comments_id_fk (
publicId,
comment,
createdBy,
updatedAt
)
)
`,
)
.eq("publicId", cardPublicId)
.is("deletedAt", null)
.is("list.board.lists.deletedAt", null)
.is("list.board.workspace.members.deletedAt", null)
.is("members.deletedAt", null)
.limit(1)
.single();
return data;
};
export const reorder = async (
db: SupabaseClient<Database>,
args: {
currentListId: number;
newListId: number;
currentIndex: number;
newIndex: number;
cardId: number;
},
) => {
const { error } = await db.rpc("reorder_cards", {
current_list_id: args.currentListId,
new_list_id: args.newListId,
current_index: args.currentIndex,
new_index: args.newIndex,
card_id: args.cardId,
});
return { success: !error };
};
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 pushIndex = async (
db: SupabaseClient<Database>,
args: {
listId: number;
cardIndex: number;
},
) => {
const { data } = await db.rpc("push_card_index", {
list_id: args.listId,
card_index: args.cardIndex,
});
return data;
};
export const softDelete = async (
db: SupabaseClient<Database>,
args: {
cardId: number;
deletedAt: string;
deletedBy: string;
},
) => {
const { data } = await db
.from("card")
.update({ deletedAt: args.deletedAt, deletedBy: args.deletedBy })
.eq("id", args.cardId)
.select(`id`)
.order("id", { ascending: true })
.limit(1)
.single();
return data;
};
export const softDeleteAllByListIds = async (
db: SupabaseClient<Database>,
args: {
listIds: number[];
deletedAt: string;
deletedBy: string;
},
) => {
const { data } = await db
.from("card")
.update({ deletedAt: args.deletedAt, deletedBy: args.deletedBy })
.in("listId", args.listIds)
.is("deletedAt", null)
.select(`id`);
return data;
};
export const hardDeleteCardMemberRelationship = async (
db: SupabaseClient<Database>,
args: { cardId: number; memberId: number },
) => {
const { error } = await db
.from("_card_workspace_members")
.delete()
.eq("cardId", args.cardId)
.eq("workspaceMemberId", args.memberId)
.select()
.order("cardId", { ascending: true })
.limit(1)
.single();
return { success: !error };
};
export const hardDeleteCardLabelRelationship = async (
db: SupabaseClient<Database>,
args: { cardId: number; labelId: number },
) => {
const { data } = await db
.from("_card_labels")
.delete()
.eq("cardId", args.cardId)
.eq("labelId", args.labelId)
.select()
.single();
return { data };
};
export const hardDeleteAllCardLabelRelationships = async (
db: SupabaseClient<Database>,
labelId: number,
) => {
const result = await db.from("_card_labels").delete().eq("labelId", labelId);
return result;
};

View File

@@ -0,0 +1,84 @@
import type { SupabaseClient } from "@supabase/supabase-js";
import type { Database } from "@kan/db/types/database.types";
import { generateUID } from "@kan/utils";
export const create = async (
db: SupabaseClient<Database>,
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;
commentId?: number;
fromComment?: string;
toComment?: 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,
commentId: activityInput.commentId,
fromComment: activityInput.fromComment,
toComment: activityInput.toComment,
})
.select(`id`)
.limit(1)
.single();
return data;
};
export const bulkCreate = async (
db: SupabaseClient<Database>,
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;
};

View File

@@ -0,0 +1,63 @@
import type { SupabaseClient } from "@supabase/supabase-js";
import type { Database } from "@kan/db/types/database.types";
import { generateUID } from "@kan/utils";
export const create = async (
db: SupabaseClient<Database>,
commentInput: {
cardId: number;
comment: string;
createdBy: string;
},
) => {
const { data } = await db
.from("card_comments")
.insert({
publicId: generateUID(),
comment: commentInput.comment,
createdBy: commentInput.createdBy,
cardId: commentInput.cardId,
})
.select(`id, publicId, comment`)
.limit(1)
.single();
return data;
};
export const getByPublicId = async (
db: SupabaseClient<Database>,
publicId: string,
) => {
const { data } = await db
.from("card_comments")
.select(`id, publicId, comment, createdBy`)
.eq("publicId", publicId)
.limit(1)
.single();
return data;
};
export const update = async (
db: SupabaseClient<Database>,
commentInput: {
id: number;
comment: string;
},
) => {
const { data } = await db
.from("card_comments")
.update({
comment: commentInput.comment,
updatedAt: new Date().toISOString(),
})
.eq("id", commentInput.id)
.select(`id, publicId, comment`)
.limit(1)
.order("id", { ascending: false })
.single();
return data;
};

View File

@@ -0,0 +1,38 @@
import type { SupabaseClient } from "@supabase/supabase-js";
import type { Database } from "@kan/db/types/database.types";
import { generateUID } from "@kan/utils";
export const create = async (
db: SupabaseClient<Database>,
importInput: { source: string; createdBy: string },
) => {
const { data } = await db
.from("import")
.insert({
publicId: generateUID(),
source: "trello",
createdBy: importInput.createdBy,
status: "started",
})
.select(`id`)
.limit(1)
.single();
return data;
};
export const update = async (
db: SupabaseClient<Database>,
importInput: { status: "started" | "success" | "failed" },
args: { importId: number },
) => {
const { data } = await db
.from("import")
.update({ status: importInput.status })
.eq("importId", args.importId)
.limit(1)
.single();
return data;
};

View File

@@ -0,0 +1,90 @@
import type { SupabaseClient } from "@supabase/supabase-js";
import type { Database } from "@kan/db/types/database.types";
import { generateUID } from "@kan/utils";
export const create = async (
db: SupabaseClient<Database>,
labelInput: {
name: string;
colourCode: string;
createdBy: string;
boardId: number;
cardId?: number;
},
) => {
const { data } = await db
.from("label")
.insert({
publicId: generateUID(),
name: labelInput.name,
colourCode: labelInput.colourCode,
createdBy: labelInput.createdBy,
boardId: labelInput.boardId,
})
.select(`id`)
.limit(1)
.single();
if (labelInput.cardId && data)
await db.from("_card_labels").insert({
cardId: labelInput.cardId,
labelId: data.id,
});
return data;
};
export const getAllByPublicIds = async (
db: SupabaseClient<Database>,
labelPublicIds: string[],
) => {
const { data } = await db
.from("label")
.select(`id`)
.in("publicId", labelPublicIds);
return data;
};
export const getByPublicId = async (
db: SupabaseClient<Database>,
labelPublicId: string,
) => {
const { data } = await db
.from("label")
.select(`id, publicId, name, colourCode`)
.eq("publicId", labelPublicId)
.limit(1)
.single();
return data;
};
export const update = async (
db: SupabaseClient<Database>,
labelInput: {
labelPublicId: string;
name: string;
colourCode: string;
},
) => {
const { data } = await db
.from("label")
.update({
name: labelInput.name,
colourCode: labelInput.colourCode,
})
.eq("publicId", labelInput.labelPublicId);
return data;
};
export const hardDelete = async (
db: SupabaseClient<Database>,
labelId: number,
) => {
const { data } = await db.from("label").delete().eq("id", labelId);
return data;
};

View File

@@ -0,0 +1,161 @@
import type { SupabaseClient } from "@supabase/supabase-js";
import type { Database } from "@kan/db/types/database.types";
import { generateUID } from "@kan/utils";
export const create = async (
db: SupabaseClient<Database>,
listInput: {
name: string;
createdBy: string;
boardId: number;
index: number;
importId?: number;
},
) => {
const { data } = await db
.from("list")
.insert({
publicId: generateUID(),
name: listInput.name,
createdBy: listInput.createdBy,
boardId: listInput.boardId,
index: listInput.index,
importId: listInput.importId,
})
.select(
`
id,
publicId,
name
`,
)
.limit(1)
.single();
return data;
};
export const getByPublicId = async (
db: SupabaseClient<Database>,
listPublicId: string,
) => {
const { data } = await db
.from("list")
.select(`id, boardId, index`)
.eq("publicId", listPublicId)
.limit(1)
.single();
return data;
};
export const getWithCardsByPublicId = async (
db: SupabaseClient<Database>,
listPublicId: string,
) => {
const { data } = await db
.from("list")
.select(`id, cards:card (index)`)
.eq("publicId", listPublicId)
.is("deletedAt", null)
.is("card.deletedAt", null)
.order("index", { foreignTable: "card", ascending: false })
.limit(1)
.single();
return data;
};
export const update = async (
db: SupabaseClient<Database>,
listInput: {
name: string;
},
args: {
listPublicId: string;
},
) => {
const { data } = await db
.from("list")
.update({ name: listInput.name })
.eq("publicId", args.listPublicId)
.is("deletedAt", null)
.select(`publicId, name`);
return data;
};
export const reorder = async (
db: SupabaseClient<Database>,
args: {
boardPublicId: number;
listPublicId: number;
currentIndex: number;
newIndex: number;
},
) => {
const { data } = await db.rpc("reorder_lists", {
board_id: args.boardPublicId,
list_id: args.listPublicId,
current_index: args.currentIndex,
new_index: args.newIndex,
});
return data;
};
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: SupabaseClient<Database>,
args: {
boardId: number;
deletedAt: string;
deletedBy: string;
},
) => {
const { data } = await db
.from("list")
.update({ deletedAt: args.deletedAt, deletedBy: args.deletedBy })
.eq("boardId", args.boardId)
.is("deletedAt", null)
.select(`id`)
.order("id", { ascending: true });
return data;
};
export const softDeleteById = async (
db: SupabaseClient<Database>,
args: {
listId: number;
deletedAt: string;
deletedBy: string;
},
) => {
const { data } = await db
.from("list")
.update({ deletedAt: args.deletedAt, deletedBy: args.deletedBy })
.eq("id", args.listId)
.is("deletedAt", null)
.select(`id`)
.order("id", { ascending: true })
.limit(1)
.single();
return data;
};

View File

@@ -0,0 +1,74 @@
import type { SupabaseClient } from "@supabase/supabase-js";
import type { Database } from "@kan/db/types/database.types";
import { generateUID } from "@kan/utils";
export const create = async (
db: SupabaseClient<Database>,
memberInput: {
userId: string;
workspaceId: number;
createdBy: string;
role: "admin" | "member" | "guest";
status: "invited" | "active" | "removed";
},
) => {
const { data } = await db
.from("workspace_members")
.insert({
publicId: generateUID(),
userId: memberInput.userId,
workspaceId: memberInput.workspaceId,
createdBy: memberInput.createdBy,
role: memberInput.role,
status: memberInput.status,
})
.select(`id, publicId`)
.limit(1)
.single();
return data;
};
export const getByPublicId = async (
db: SupabaseClient<Database>,
publicId: string,
) => {
const { data } = await db
.from("workspace_members")
.select()
.eq("publicId", publicId)
.limit(1)
.single();
return data;
};
export const acceptInvite = async (
db: SupabaseClient<Database>,
id: number,
) => {
const { data } = await db
.from("workspace_members")
.update({ status: "active" })
.eq("id", id);
return data;
};
export const softDelete = async (
db: SupabaseClient<Database>,
args: {
memberId: number;
deletedAt: string;
deletedBy: string;
},
) => {
const result = await db
.from("workspace_members")
.update({ deletedAt: args.deletedAt, deletedBy: args.deletedBy })
.eq("id", args.memberId)
.is("deletedAt", null);
return result;
};

View File

@@ -0,0 +1,42 @@
import type { SupabaseClient } from "@supabase/supabase-js";
import type { Database } from "@kan/db/types/database.types";
export const getById = async (db: SupabaseClient<Database>, userId: string) => {
const { data } = await db
.from("user")
.select(`id, name, email`)
.eq("id", userId)
.limit(1)
.single();
return data;
};
export const getByEmail = async (
db: SupabaseClient<Database>,
email: string,
) => {
const { data } = await db
.from("user")
.select(`id, name, email`)
.eq("email", email)
.limit(1)
.single();
return data;
};
export const create = async (
db: SupabaseClient<Database>,
user: { id: string; email: string },
) => {
const { data } = await db
.from("user")
.insert({ id: user.id, email: user.email })
.select()
.limit(1)
.single();
return data;
};

View File

@@ -0,0 +1,159 @@
import type { SupabaseClient } from "@supabase/supabase-js";
import type { Database } from "@kan/db/types/database.types";
import { generateUID } from "@kan/utils";
export const create = async (
db: SupabaseClient<Database>,
workspaceInput: {
name: string;
slug: string;
createdBy: string;
},
) => {
const { data } = await db
.from("workspace")
.insert({
publicId: generateUID(),
name: workspaceInput.name,
slug: workspaceInput.name.toLowerCase(),
createdBy: workspaceInput.createdBy,
})
.select(`id, publicId, name`)
.limit(1)
.single();
if (data)
await db.from("workspace_members").insert({
publicId: generateUID(),
userId: workspaceInput.createdBy,
workspaceId: data.id,
createdBy: workspaceInput.createdBy,
role: "admin",
});
const newWorkspace = { ...data };
delete newWorkspace.id;
return newWorkspace;
};
export const update = async (
db: SupabaseClient<Database>,
workspacePublicId: string,
name: string,
) => {
const { data } = await db
.from("workspace")
.update({ name })
.eq("publicId", workspacePublicId)
.is("deletedAt", null);
return data;
};
export const getByPublicId = async (
db: SupabaseClient<Database>,
workspacePublicId: string,
) => {
const { data } = await db
.from("workspace")
.select(`id, publicId, name`)
.is("deletedAt", null)
.eq("publicId", workspacePublicId)
.limit(1)
.single();
return data;
};
export const getByPublicIdWithMembers = async (
db: SupabaseClient<Database>,
workspacePublicId: string,
) => {
const { data } = await db
.from("workspace")
.select(
`
id,
publicId,
members: workspace_members (
publicId,
role,
status,
user!workspace_members_userId_user_id_fk (
id,
name,
email
)
)
`,
)
.eq("publicId", workspacePublicId)
.is("deletedAt", null)
.is("members.deletedAt", null)
.limit(1)
.single();
return data;
};
export const getAllByUserId = async (
db: SupabaseClient<Database>,
userId: string,
) => {
const { data } = await db
.from("workspace_members")
.select(
`
role,
workspace (
publicId,
name
)
`,
)
.eq("userId", userId)
.is("deletedAt", null);
return data ?? [];
};
export const getMemberByPublicId = async (
db: SupabaseClient<Database>,
memberPublicId: string,
) => {
const { data } = await db
.from("workspace_members")
.select(`id`)
.eq("publicId", memberPublicId)
.limit(1)
.single();
return data;
};
export const getAllMembersByPublicIds = async (
db: SupabaseClient<Database>,
memberPublicIds: string[],
) => {
const { data } = await db
.from("workspace_members")
.select(`id`)
.eq("publicId", memberPublicIds);
return data;
};
export const hardDelete = async (
db: SupabaseClient<Database>,
workspacePublicId: string,
) => {
const result = db
.from("workspace")
.delete()
.eq("publicId", workspacePublicId);
return result;
};

432
packages/db/src/schema.ts Normal file
View File

@@ -0,0 +1,432 @@
import { relations } from "drizzle-orm";
import {
integer,
bigserial,
uuid,
pgEnum,
pgTable,
primaryKey,
text,
timestamp,
varchar,
bigint,
} from "drizzle-orm/pg-core";
export const importSourceEnum = pgEnum("source", ["trello"]);
export const importStatusEnum = pgEnum("status", [
"started",
"success",
"failed",
]);
export const memberRoleEnum = pgEnum("role", ["admin", "member", "guest"]);
export const memberStatusEnum = pgEnum("member_status", [
"invited",
"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.updated.comment.added",
"card.updated.comment.updated",
"card.updated.comment.deleted",
"card.archived",
]);
export const boards = pgTable("board", {
id: bigserial("id", { mode: "number" }).primaryKey(),
publicId: varchar("publicId", { length: 12 }).notNull().unique(),
name: varchar("name", { length: 255 }).notNull(),
createdBy: uuid("createdBy")
.notNull()
.references(() => users.id),
createdAt: timestamp("createdAt").defaultNow().notNull(),
updatedAt: timestamp("updatedAt"),
deletedAt: timestamp("deletedAt"),
deletedBy: uuid("deletedBy").references(() => users.id),
importId: bigint("importId", { mode: "number" }).references(() => imports.id),
workspaceId: bigint("workspaceId", { mode: "number" })
.notNull()
.references(() => workspaces.id, { onDelete: "cascade" }),
});
export const boardsRelations = relations(boards, ({ one, many }) => ({
createdBy: one(users, {
fields: [boards.createdBy],
references: [users.id],
}),
lists: many(lists),
labels: many(labels),
deletedBy: one(users, {
fields: [boards.deletedBy],
references: [users.id],
}),
import: one(imports, {
fields: [boards.importId],
references: [imports.id],
}),
workspace: one(workspaces, {
fields: [boards.workspaceId],
references: [workspaces.id],
}),
}));
export const imports = pgTable("import", {
id: bigserial("id", { mode: "number" }).primaryKey(),
publicId: varchar("publicId", { length: 12 }).notNull().unique(),
source: importSourceEnum("source").notNull(),
status: importStatusEnum("status").notNull(),
createdBy: uuid("createdBy")
.notNull()
.references(() => users.id),
createdAt: timestamp("createdAt").defaultNow().notNull(),
});
export const importsRelations = relations(imports, ({ one, many }) => ({
createdBy: one(users, {
fields: [imports.createdBy],
references: [users.id],
}),
boards: many(boards),
cards: many(cards),
lists: many(lists),
labels: many(labels),
}));
export const labels = pgTable("label", {
id: bigserial("id", { mode: "number" }).primaryKey(),
publicId: varchar("publicId", { length: 12 }).notNull().unique(),
name: varchar("name", { length: 255 }).notNull(),
colourCode: varchar("colourCode", { length: 12 }),
createdBy: uuid("createdBy")
.notNull()
.references(() => users.id),
createdAt: timestamp("createdAt").defaultNow().notNull(),
updatedAt: timestamp("updatedAt"),
boardId: bigint("boardId", { mode: "number" })
.notNull()
.references(() => boards.id, { onDelete: "cascade" }),
importId: bigint("importId", { mode: "number" }).references(() => imports.id),
});
export const labelsRelations = relations(labels, ({ one, many }) => ({
createdBy: one(users, {
fields: [labels.createdBy],
references: [users.id],
}),
board: one(boards, {
fields: [labels.boardId],
references: [boards.id],
}),
cards: many(cardsToLabels),
import: one(imports, {
fields: [labels.importId],
references: [imports.id],
}),
}));
export const cardsToLabels = pgTable(
"_card_labels",
{
cardId: bigint("cardId", { mode: "number" })
.notNull()
.references(() => cards.id),
labelId: bigint("labelId", { mode: "number" })
.notNull()
.references(() => labels.id, { onDelete: "cascade" }),
},
(t) => ({
pk: primaryKey(t.cardId, t.labelId),
}),
);
export const cardToLabelsRelations = relations(cardsToLabels, ({ one }) => ({
card: one(cards, {
fields: [cardsToLabels.cardId],
references: [cards.id],
}),
label: one(labels, {
fields: [cardsToLabels.labelId],
references: [labels.id],
}),
}));
export const cardToWorkspaceMembers = pgTable(
"_card_workspace_members",
{
cardId: bigint("cardId", { mode: "number" })
.notNull()
.references(() => cards.id),
workspaceMemberId: bigint("workspaceMemberId", { mode: "number" })
.notNull()
.references(() => workspaceMembers.id, { onDelete: "cascade" }),
},
(t) => ({
pk: primaryKey(t.cardId, t.workspaceMemberId),
}),
);
export const cardToWorkspaceMembersRelations = relations(
cardToWorkspaceMembers,
({ one }) => ({
card: one(cards, {
fields: [cardToWorkspaceMembers.cardId],
references: [cards.id],
}),
member: one(workspaceMembers, {
fields: [cardToWorkspaceMembers.workspaceMemberId],
references: [workspaceMembers.id],
}),
}),
);
export const lists = pgTable("list", {
id: bigserial("id", { mode: "number" }).primaryKey(),
publicId: varchar("publicId", { length: 12 }).notNull().unique(),
name: varchar("name", { length: 255 }).notNull(),
index: integer("index").notNull(),
createdBy: uuid("createdBy")
.notNull()
.references(() => users.id),
createdAt: timestamp("createdAt").defaultNow().notNull(),
updatedAt: timestamp("updatedAt"),
deletedAt: timestamp("deletedAt"),
deletedBy: uuid("deletedBy").references(() => users.id),
boardId: bigint("boardId", { mode: "number" })
.notNull()
.references(() => boards.id, { onDelete: "cascade" }),
importId: bigint("importId", { mode: "number" }).references(() => imports.id),
});
export const listsRelations = relations(lists, ({ one, many }) => ({
createdBy: one(users, {
fields: [lists.createdBy],
references: [users.id],
}),
board: one(boards, {
fields: [lists.boardId],
references: [boards.id],
}),
cards: many(cards),
deletedBy: one(users, {
fields: [lists.deletedBy],
references: [users.id],
}),
import: one(imports, {
fields: [lists.importId],
references: [imports.id],
}),
}));
export const cards = pgTable("card", {
id: bigserial("id", { mode: "number" }).primaryKey(),
publicId: varchar("publicId", { length: 12 }).notNull().unique(),
title: varchar("title", { length: 255 }).notNull(),
description: text("description"),
index: integer("index").notNull(),
createdBy: uuid("createdBy")
.notNull()
.references(() => users.id),
createdAt: timestamp("createdAt").defaultNow().notNull(),
updatedAt: timestamp("updatedAt"),
deletedAt: timestamp("deletedAt"),
deletedBy: uuid("deletedBy").references(() => users.id),
listId: bigint("listId", { mode: "number" })
.notNull()
.references(() => lists.id, { onDelete: "cascade" }),
importId: bigint("importId", { mode: "number" }).references(() => imports.id),
});
export const cardsRelations = relations(cards, ({ one, many }) => ({
createdBy: one(users, {
fields: [cards.createdBy],
references: [users.id],
}),
list: one(lists, {
fields: [cards.listId],
references: [lists.id],
}),
deletedBy: one(users, {
fields: [cards.deletedBy],
references: [users.id],
}),
labels: many(cardsToLabels),
members: many(cardToWorkspaceMembers),
import: one(imports, {
fields: [cards.importId],
references: [imports.id],
}),
comments: many(comments),
}));
export const users = pgTable("user", {
id: uuid("id").notNull().primaryKey(),
name: varchar("name", { length: 255 }),
email: varchar("email", { length: 255 }).notNull().unique(),
emailVerified: timestamp("emailVerified", { mode: "date" }),
image: varchar("image", { length: 255 }),
});
export const usersRelations = relations(users, ({ many }) => ({
boards: many(boards),
cards: many(cards),
imports: many(imports),
lists: many(lists),
workspaces: many(workspaces),
}));
export const workspaces = pgTable("workspace", {
id: bigserial("id", { mode: "number" }).primaryKey(),
publicId: varchar("publicId", { length: 12 }).notNull().unique(),
name: varchar("name", { length: 255 }).notNull(),
slug: varchar("slug", { length: 255 }).notNull().unique(),
createdBy: uuid("createdBy")
.notNull()
.references(() => users.id),
createdAt: timestamp("createdAt").defaultNow().notNull(),
updatedAt: timestamp("updatedAt"),
deletedAt: timestamp("deletedAt"),
deletedBy: uuid("deletedBy").references(() => users.id),
});
export const workspaceRelations = relations(workspaces, ({ one, many }) => ({
user: one(users, { fields: [workspaces.createdBy], references: [users.id] }),
members: many(workspaceMembers),
}));
export const workspaceMembers = pgTable("workspace_members", {
id: bigserial("id", { mode: "number" }).primaryKey(),
publicId: varchar("publicId", { length: 12 }).notNull().unique(),
userId: uuid("userId")
.notNull()
.references(() => users.id),
workspaceId: bigint("workspaceId", { mode: "number" })
.notNull()
.references(() => workspaces.id, { onDelete: "cascade" }),
createdBy: uuid("createdBy").notNull(),
createdAt: timestamp("createdAt").defaultNow().notNull(),
updatedAt: timestamp("updatedAt"),
deletedAt: timestamp("deletedAt"),
deletedBy: uuid("deletedBy").references(() => users.id),
role: memberRoleEnum("role").notNull(),
status: memberStatusEnum("status").default("invited").notNull(),
});
export const usersToWorkspacesRelations = relations(
workspaceMembers,
({ one }) => ({
addedBy: one(users, {
fields: [workspaceMembers.createdBy],
references: [users.id],
}),
deletedBy: one(users, {
fields: [workspaceMembers.deletedBy],
references: [users.id],
}),
user: one(users, {
fields: [workspaceMembers.userId],
references: [users.id],
}),
workspace: one(workspaces, {
fields: [workspaceMembers.workspaceId],
references: [workspaces.id],
}),
}),
);
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" }).references(
() => lists.id,
),
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(),
commentId: bigint("commentId", { mode: "number" }).references(
() => comments.id,
),
fromComment: text("fromComment"),
toComment: text("toComment"),
});
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],
}),
}));
export const comments = pgTable("card_comments", {
id: bigserial("id", { mode: "number" }).primaryKey(),
publicId: varchar("publicId", { length: 12 }).notNull().unique(),
comment: text("comment").notNull(),
cardId: bigint("cardId", { mode: "number" })
.notNull()
.references(() => cards.id, { onDelete: "cascade" }),
createdBy: uuid("createdBy")
.notNull()
.references(() => users.id),
createdAt: timestamp("createdAt").defaultNow().notNull(),
updatedAt: timestamp("updatedAt"),
deletedAt: timestamp("deletedAt"),
deletedBy: uuid("deletedBy").references(() => users.id),
});
export const commentsRelations = relations(comments, ({ one }) => ({
card: one(cards, {
fields: [comments.cardId],
references: [cards.id],
}),
createdBy: one(users, {
fields: [comments.createdBy],
references: [users.id],
}),
deletedBy: one(users, {
fields: [comments.deletedBy],
references: [users.id],
}),
}));

View File

@@ -0,0 +1,868 @@
/* eslint-disable @typescript-eslint/no-redundant-type-constituents */
export type Json =
| string
| number
| boolean
| null
| { [key: string]: Json | undefined }
| Json[];
export type Database = {
public: {
Tables: {
_card_labels: {
Row: {
cardId: number;
labelId: number;
};
Insert: {
cardId: number;
labelId: number;
};
Update: {
cardId?: number;
labelId?: number;
};
Relationships: [
{
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"];
},
];
};
_card_workspace_members: {
Row: {
cardId: number;
workspaceMemberId: number;
};
Insert: {
cardId: number;
workspaceMemberId: number;
};
Update: {
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_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;
};
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;
};
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;
};
Relationships: [
{
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_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"];
},
];
};
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;
};
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;
};
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;
};
Relationships: [
{
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_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"];
},
];
};
card_activity: {
Row: {
cardId: number;
commentId: number | null;
createdAt: string;
createdBy: string;
fromComment: string | null;
fromDescription: string | null;
fromIndex: number | null;
fromListId: number | null;
fromTitle: string | null;
id: number;
labelId: number | null;
publicId: string;
toComment: string | null;
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;
commentId?: number | null;
createdAt?: string;
createdBy: string;
fromComment?: string | null;
fromDescription?: string | null;
fromIndex?: number | null;
fromListId?: number | null;
fromTitle?: string | null;
id?: number;
labelId?: number | null;
publicId: string;
toComment?: string | null;
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;
commentId?: number | null;
createdAt?: string;
createdBy?: string;
fromComment?: string | null;
fromDescription?: string | null;
fromIndex?: number | null;
fromListId?: number | null;
fromTitle?: string | null;
id?: number;
labelId?: number | null;
publicId?: string;
toComment?: string | null;
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_commentId_card_comments_id_fk";
columns: ["commentId"];
isOneToOne: false;
referencedRelation: "card_comments";
referencedColumns: ["id"];
},
{
foreignKeyName: "card_activity_createdBy_user_id_fk";
columns: ["createdBy"];
isOneToOne: false;
referencedRelation: "user";
referencedColumns: ["id"];
},
{
foreignKeyName: "card_activity_fromListId_list_id_fk";
columns: ["fromListId"];
isOneToOne: false;
referencedRelation: "list";
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"];
},
];
};
card_comments: {
Row: {
cardId: number;
comment: string;
createdAt: string;
createdBy: string;
deletedAt: string | null;
deletedBy: string | null;
id: number;
publicId: string;
updatedAt: string | null;
};
Insert: {
cardId: number;
comment: string;
createdAt?: string;
createdBy: string;
deletedAt?: string | null;
deletedBy?: string | null;
id?: number;
publicId: string;
updatedAt?: string | null;
};
Update: {
cardId?: number;
comment?: string;
createdAt?: string;
createdBy?: string;
deletedAt?: string | null;
deletedBy?: string | null;
id?: number;
publicId?: string;
updatedAt?: string | null;
};
Relationships: [
{
foreignKeyName: "card_comments_cardId_card_id_fk";
columns: ["cardId"];
isOneToOne: false;
referencedRelation: "card";
referencedColumns: ["id"];
},
{
foreignKeyName: "card_comments_createdBy_user_id_fk";
columns: ["createdBy"];
isOneToOne: false;
referencedRelation: "user";
referencedColumns: ["id"];
},
{
foreignKeyName: "card_comments_deletedBy_user_id_fk";
columns: ["deletedBy"];
isOneToOne: false;
referencedRelation: "user";
referencedColumns: ["id"];
},
];
};
import: {
Row: {
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"];
};
Update: {
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"];
},
];
};
label: {
Row: {
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;
};
Update: {
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_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"];
},
];
};
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;
};
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;
};
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;
};
Relationships: [
{
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_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"];
},
];
};
user: {
Row: {
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;
};
Update: {
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;
};
Insert: {
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;
};
Relationships: [
{
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"];
},
];
};
workspace_members: {
Row: {
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;
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;
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_deletedBy_user_id_fk";
columns: ["deletedBy"];
isOneToOne: false;
referencedRelation: "user";
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;
};
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;
};
reorder_cards: {
Args: {
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;
};
shift_card_index: {
Args: {
list_id: number;
card_index: number;
};
Returns: undefined;
};
shift_list_index: {
Args: {
board_id: number;
list_index: number;
};
Returns: undefined;
};
};
Enums: {
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"
| "card.updated.comment.added"
| "card.updated.comment.updated"
| "card.updated.comment.deleted";
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;
};
};
};
type PublicSchema = Database[Extract<keyof Database, "public">];
export type Tables<
PublicTableNameOrOptions extends
| keyof (PublicSchema["Tables"] & PublicSchema["Views"])
| { schema: keyof Database },
TableName extends PublicTableNameOrOptions extends { schema: keyof Database }
? keyof (Database[PublicTableNameOrOptions["schema"]]["Tables"] &
Database[PublicTableNameOrOptions["schema"]]["Views"])
: never = never,
> = PublicTableNameOrOptions extends { schema: keyof Database }
? (Database[PublicTableNameOrOptions["schema"]]["Tables"] &
Database[PublicTableNameOrOptions["schema"]]["Views"])[TableName] extends {
Row: infer R;
}
? R
: never
: PublicTableNameOrOptions extends keyof (PublicSchema["Tables"] &
PublicSchema["Views"])
? (PublicSchema["Tables"] &
PublicSchema["Views"])[PublicTableNameOrOptions] extends {
Row: infer R;
}
? R
: never
: never;
export type TablesInsert<
PublicTableNameOrOptions extends
| keyof PublicSchema["Tables"]
| { schema: keyof Database },
TableName extends PublicTableNameOrOptions extends { schema: keyof Database }
? keyof Database[PublicTableNameOrOptions["schema"]]["Tables"]
: never = never,
> = PublicTableNameOrOptions extends { schema: keyof Database }
? Database[PublicTableNameOrOptions["schema"]]["Tables"][TableName] extends {
Insert: infer I;
}
? I
: never
: PublicTableNameOrOptions extends keyof PublicSchema["Tables"]
? PublicSchema["Tables"][PublicTableNameOrOptions] extends {
Insert: infer I;
}
? I
: never
: never;
export type TablesUpdate<
PublicTableNameOrOptions extends
| keyof PublicSchema["Tables"]
| { schema: keyof Database },
TableName extends PublicTableNameOrOptions extends { schema: keyof Database }
? keyof Database[PublicTableNameOrOptions["schema"]]["Tables"]
: never = never,
> = PublicTableNameOrOptions extends { schema: keyof Database }
? Database[PublicTableNameOrOptions["schema"]]["Tables"][TableName] extends {
Update: infer U;
}
? U
: never
: PublicTableNameOrOptions extends keyof PublicSchema["Tables"]
? PublicSchema["Tables"][PublicTableNameOrOptions] extends {
Update: infer U;
}
? U
: never
: never;
export type Enums<
PublicEnumNameOrOptions extends
| keyof PublicSchema["Enums"]
| { schema: keyof Database },
EnumName extends PublicEnumNameOrOptions extends { schema: keyof Database }
? keyof Database[PublicEnumNameOrOptions["schema"]]["Enums"]
: never = never,
> = PublicEnumNameOrOptions extends { schema: keyof Database }
? Database[PublicEnumNameOrOptions["schema"]]["Enums"][EnumName]
: PublicEnumNameOrOptions extends keyof PublicSchema["Enums"]
? PublicSchema["Enums"][PublicEnumNameOrOptions]
: 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;

View File

@@ -0,0 +1,8 @@
{
"extends": "@kan/tsconfig/internal-package.json",
"include": ["src"],
"exclude": ["node_modules"],
"compilerOptions": {
"rootDir": "./src"
}
}