refactor: update repo funcs to drizzle
This commit is contained in:
@@ -3,6 +3,7 @@ import type { NextRequest } from "next/server";
|
||||
import { NextResponse } from "next/server";
|
||||
import { Stripe } from "stripe";
|
||||
|
||||
import { createDrizzleClient } from "@kan/db/client";
|
||||
import * as memberRepo from "@kan/db/repository/member.repo";
|
||||
import * as userRepo from "@kan/db/repository/user.repo";
|
||||
import { createNextClient } from "@kan/supabase/clients";
|
||||
@@ -46,21 +47,23 @@ export default async function handler(req: NextRequest) {
|
||||
const response = NextResponse.next();
|
||||
|
||||
if ((tokenHash && type) ?? code) {
|
||||
const db = createNextClient(req, response);
|
||||
const supabaseClient = createNextClient(req, response);
|
||||
|
||||
if (tokenHash && type) {
|
||||
authRes = await db.auth.verifyOtp({
|
||||
authRes = await supabaseClient.auth.verifyOtp({
|
||||
type: type as EmailOtpType,
|
||||
token_hash: tokenHash,
|
||||
});
|
||||
}
|
||||
|
||||
if (code) {
|
||||
authRes = await db.auth.exchangeCodeForSession(code);
|
||||
authRes = await supabaseClient.auth.exchangeCodeForSession(code);
|
||||
}
|
||||
|
||||
const user = authRes?.data.user;
|
||||
|
||||
const db = createDrizzleClient();
|
||||
|
||||
if (user?.id && user.email) {
|
||||
const existingUser = await userRepo.getById(db, user.id);
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { NextRequest } from "next/server";
|
||||
import { NextResponse } from "next/server";
|
||||
import { Stripe } from "stripe";
|
||||
|
||||
import { createDrizzleClient } from "@kan/db/client";
|
||||
import * as userRepo from "@kan/db/repository/user.repo";
|
||||
import { createNextClient } from "@kan/supabase/clients";
|
||||
|
||||
@@ -25,8 +26,8 @@ export default async function handler(req: NextRequest) {
|
||||
|
||||
try {
|
||||
const response = NextResponse.next();
|
||||
const db = createNextClient(req, response);
|
||||
const { data } = await db.auth.getUser();
|
||||
const supabaseClient = createNextClient(req, response);
|
||||
const { data } = await supabaseClient.auth.getUser();
|
||||
|
||||
if (!data.user) {
|
||||
return new Response(JSON.stringify({ error: "Unauthorized" }), {
|
||||
@@ -35,6 +36,8 @@ export default async function handler(req: NextRequest) {
|
||||
});
|
||||
}
|
||||
|
||||
const db = createDrizzleClient();
|
||||
|
||||
const user = await userRepo.getById(db, data.user.id);
|
||||
|
||||
if (!user?.stripeCustomerId) {
|
||||
|
||||
@@ -3,6 +3,7 @@ import { NextResponse } from "next/server";
|
||||
import { Stripe } from "stripe";
|
||||
import { z } from "zod";
|
||||
|
||||
import { createDrizzleClient } from "@kan/db/client";
|
||||
import * as userRepo from "@kan/db/repository/user.repo";
|
||||
import * as workspaceRepo from "@kan/db/repository/workspace.repo";
|
||||
import { createNextClient } from "@kan/supabase/clients";
|
||||
@@ -42,9 +43,9 @@ export default async function handler(req: NextRequest) {
|
||||
try {
|
||||
const response = NextResponse.next();
|
||||
|
||||
const db = createNextClient(req, response);
|
||||
const supabaseClient = createNextClient(req, response);
|
||||
|
||||
const { data } = await db.auth.getUser();
|
||||
const { data } = await supabaseClient.auth.getUser();
|
||||
|
||||
if (!data.user) {
|
||||
return new Response(JSON.stringify({ error: "Unauthorized" }), {
|
||||
@@ -53,6 +54,8 @@ export default async function handler(req: NextRequest) {
|
||||
});
|
||||
}
|
||||
|
||||
const db = createDrizzleClient();
|
||||
|
||||
const user = await userRepo.getById(db, data.user.id);
|
||||
|
||||
if (!user) {
|
||||
@@ -87,7 +90,7 @@ export default async function handler(req: NextRequest) {
|
||||
const workspace = await workspaceRepo.getAllByUserId(db, user.id);
|
||||
|
||||
const isMemberOfWorkspace = workspace.some(
|
||||
({ workspace }) => workspace?.publicId === body.workspacePublicId,
|
||||
({ workspace }) => workspace.publicId === body.workspacePublicId,
|
||||
);
|
||||
|
||||
if (!isMemberOfWorkspace) {
|
||||
|
||||
@@ -17,7 +17,7 @@ export const authRouter = createTRPCRouter({
|
||||
.input(z.object({ email: z.string() }))
|
||||
.output(z.object({ success: z.boolean() }))
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
const { data } = await ctx.db.auth.signInWithOtp({
|
||||
const { data } = await ctx.supabaseClient.auth.signInWithOtp({
|
||||
email: input.email,
|
||||
options: {
|
||||
emailRedirectTo: `${process.env.WEBSITE_URL}`,
|
||||
@@ -52,7 +52,7 @@ export const authRouter = createTRPCRouter({
|
||||
code: "BAD_REQUEST",
|
||||
});
|
||||
|
||||
const { data } = await ctx.db.auth.signInWithOAuth({
|
||||
const { data } = await ctx.supabaseClient.auth.signInWithOAuth({
|
||||
provider: "google",
|
||||
options: {
|
||||
queryParams: {
|
||||
|
||||
@@ -333,7 +333,7 @@ export const cardRouter = createTRPCRouter({
|
||||
|
||||
const deletedComment = await cardCommentRepo.softDelete(ctx.db, {
|
||||
commentId: existingComment.id,
|
||||
deletedAt: new Date().toISOString(),
|
||||
deletedAt: new Date(),
|
||||
deletedBy: userId,
|
||||
});
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ export const userRouter = createTRPCRouter({
|
||||
code: "UNAUTHORIZED",
|
||||
});
|
||||
|
||||
const result = await userRepo.getById(ctx.drizzleDb, userId);
|
||||
const result = await userRepo.getById(ctx.db, userId);
|
||||
|
||||
if (!result?.name) {
|
||||
throw new TRPCError({
|
||||
|
||||
@@ -17,15 +17,15 @@ export interface User {
|
||||
|
||||
interface CreateContextOptions {
|
||||
user: User | null;
|
||||
db: SupabaseClient<Database>;
|
||||
drizzleDb: dbClient;
|
||||
supabaseClient: SupabaseClient<Database>;
|
||||
db: dbClient;
|
||||
}
|
||||
|
||||
export const createInnerTRPCContext = (opts: CreateContextOptions) => {
|
||||
return {
|
||||
user: opts.user,
|
||||
db: opts.db,
|
||||
drizzleDb: opts.drizzleDb,
|
||||
supabaseClient: opts.supabaseClient,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -33,36 +33,36 @@ export const createTRPCContext = async ({
|
||||
req,
|
||||
resHeaders,
|
||||
}: FetchCreateContextFnOptions) => {
|
||||
const db = createTRPCClient(req, resHeaders);
|
||||
const supabaseClient = createTRPCClient(req, resHeaders);
|
||||
|
||||
const {
|
||||
data: { user },
|
||||
} = await db.auth.getUser();
|
||||
} = await supabaseClient.auth.getUser();
|
||||
|
||||
const drizzleDb = createDrizzleClient();
|
||||
const db = createDrizzleClient();
|
||||
|
||||
return createInnerTRPCContext({ db, user, drizzleDb });
|
||||
return createInnerTRPCContext({ db, user, supabaseClient: supabaseClient });
|
||||
};
|
||||
|
||||
export const createRESTContext = async ({ req }: CreateNextContextOptions) => {
|
||||
const db = createNextApiClient(req);
|
||||
const supabaseClient = createNextApiClient(req);
|
||||
|
||||
const authHeader = req.headers.authorization;
|
||||
const accessToken = authHeader?.startsWith("Bearer ")
|
||||
? authHeader.substring(7)
|
||||
: null;
|
||||
|
||||
const drizzleDb = createDrizzleClient();
|
||||
const db = createDrizzleClient();
|
||||
|
||||
if (!accessToken) {
|
||||
return createInnerTRPCContext({ db, user: null, drizzleDb });
|
||||
return createInnerTRPCContext({ db, user: null, supabaseClient });
|
||||
}
|
||||
|
||||
const {
|
||||
data: { user },
|
||||
} = await db.auth.getUser(accessToken);
|
||||
} = await supabaseClient.auth.getUser(accessToken);
|
||||
|
||||
return createInnerTRPCContext({ db, user, drizzleDb });
|
||||
return createInnerTRPCContext({ db, user, supabaseClient });
|
||||
};
|
||||
|
||||
const t = initTRPC
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
import type { SupabaseClient } from "@supabase/supabase-js";
|
||||
import { and, asc, eq, inArray, isNull } from "drizzle-orm";
|
||||
|
||||
import type { dbClient } from "@kan/db/client";
|
||||
import type { Database } from "@kan/db/types/database.types";
|
||||
import { boards, cards, lists, workspaceMembers } from "@kan/db/schema";
|
||||
import { generateUID } from "@kan/shared/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 getAllByWorkspaceId = (db: dbClient, workspaceId: number) => {
|
||||
return db.query.boards.findMany({
|
||||
columns: {
|
||||
publicId: true,
|
||||
name: true,
|
||||
},
|
||||
where: and(eq(boards.workspaceId, workspaceId), isNull(boards.deletedAt)),
|
||||
});
|
||||
};
|
||||
|
||||
export const getIdByPublicId = async (
|
||||
@@ -31,93 +31,133 @@ export const getIdByPublicId = async (
|
||||
};
|
||||
|
||||
export const getByPublicId = async (
|
||||
db: SupabaseClient<Database>,
|
||||
db: dbClient,
|
||||
boardPublicId: string,
|
||||
filters: {
|
||||
members: string[];
|
||||
labels: string[];
|
||||
},
|
||||
) => {
|
||||
let query = db
|
||||
.from("board")
|
||||
.select(
|
||||
`
|
||||
publicId,
|
||||
name,
|
||||
slug,
|
||||
visibility,
|
||||
workspace (
|
||||
publicId,
|
||||
members:workspace_members (
|
||||
publicId,
|
||||
user!workspace_members_userId_user_id_fk (
|
||||
name,
|
||||
email,
|
||||
image
|
||||
)
|
||||
)
|
||||
),
|
||||
labels:label (
|
||||
publicId,
|
||||
name,
|
||||
colourCode
|
||||
),
|
||||
lists:list (
|
||||
publicId,
|
||||
name,
|
||||
boardId,
|
||||
index,
|
||||
cards:card (
|
||||
publicId,
|
||||
title,
|
||||
description,
|
||||
listId,
|
||||
index,
|
||||
labels:label(
|
||||
publicId,
|
||||
name,
|
||||
colourCode
|
||||
),
|
||||
_filteredLabels:label${filters.labels.length > 0 ? "!inner" : ""} (
|
||||
publicId
|
||||
),
|
||||
members:workspace_members (
|
||||
publicId,
|
||||
user!workspace_members_userId_user_id_fk (
|
||||
name,
|
||||
email,
|
||||
image
|
||||
)
|
||||
),
|
||||
_filteredMembers:workspace_members${filters.members.length > 0 ? "!inner" : ""} (
|
||||
publicId
|
||||
)
|
||||
)
|
||||
)
|
||||
`,
|
||||
)
|
||||
.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);
|
||||
const board = await db.query.boards.findFirst({
|
||||
columns: {
|
||||
publicId: true,
|
||||
name: true,
|
||||
slug: true,
|
||||
visibility: true,
|
||||
},
|
||||
with: {
|
||||
workspace: {
|
||||
columns: {
|
||||
publicId: true,
|
||||
},
|
||||
with: {
|
||||
members: {
|
||||
columns: {
|
||||
publicId: true,
|
||||
},
|
||||
with: {
|
||||
user: {
|
||||
columns: {
|
||||
name: true,
|
||||
email: true,
|
||||
image: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
where: isNull(workspaceMembers.deletedAt),
|
||||
},
|
||||
},
|
||||
},
|
||||
labels: {
|
||||
columns: {
|
||||
publicId: true,
|
||||
name: true,
|
||||
colourCode: true,
|
||||
},
|
||||
},
|
||||
lists: {
|
||||
columns: {
|
||||
publicId: true,
|
||||
name: true,
|
||||
boardId: true,
|
||||
index: true,
|
||||
},
|
||||
with: {
|
||||
cards: {
|
||||
columns: {
|
||||
publicId: true,
|
||||
title: true,
|
||||
description: true,
|
||||
listId: true,
|
||||
index: true,
|
||||
},
|
||||
with: {
|
||||
labels: {
|
||||
with: {
|
||||
label: {
|
||||
columns: {
|
||||
publicId: true,
|
||||
name: true,
|
||||
colourCode: true,
|
||||
},
|
||||
// where: inArray(label.publicId, filters.labels),
|
||||
},
|
||||
},
|
||||
},
|
||||
members: {
|
||||
with: {
|
||||
member: {
|
||||
columns: {
|
||||
publicId: true,
|
||||
deletedAt: true,
|
||||
},
|
||||
with: {
|
||||
user: {
|
||||
columns: {
|
||||
name: true,
|
||||
email: true,
|
||||
image: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
// https://github.com/drizzle-team/drizzle-orm/issues/2903
|
||||
// where: isNull(workspaceMembers.deletedAt),
|
||||
},
|
||||
},
|
||||
where:
|
||||
filters.members.length > 0
|
||||
? inArray(workspaceMembers, filters.members)
|
||||
: undefined,
|
||||
},
|
||||
},
|
||||
where: isNull(cards.deletedAt),
|
||||
orderBy: [asc(cards.index)],
|
||||
},
|
||||
},
|
||||
where: isNull(lists.deletedAt),
|
||||
orderBy: [asc(lists.index)],
|
||||
},
|
||||
},
|
||||
where: and(eq(boards.publicId, boardPublicId), isNull(boards.deletedAt)),
|
||||
});
|
||||
|
||||
if (filters.labels.length > 0) {
|
||||
query = query.in("lists.cards._filteredLabels.publicId", filters.labels);
|
||||
}
|
||||
if (!board) return null;
|
||||
|
||||
if (filters.members.length > 0) {
|
||||
query = query.in("lists.cards._filteredMembers.publicId", filters.members);
|
||||
}
|
||||
const formattedResult = {
|
||||
...board,
|
||||
lists: board.lists.map((list) => ({
|
||||
...list,
|
||||
cards: list.cards.map((card) => ({
|
||||
...card,
|
||||
labels: card.labels.map((label) => label.label),
|
||||
members: card.members
|
||||
.map((member) => member.member)
|
||||
.filter((member) => member.deletedAt === null),
|
||||
})),
|
||||
})),
|
||||
};
|
||||
|
||||
const { data } = await query
|
||||
.order("index", { foreignTable: "list", ascending: true })
|
||||
.order("index", { foreignTable: "list.card", ascending: true })
|
||||
.limit(1)
|
||||
.single();
|
||||
|
||||
return data;
|
||||
return formattedResult;
|
||||
};
|
||||
|
||||
export const getBySlug = async (
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import type { SupabaseClient } from "@supabase/supabase-js";
|
||||
|
||||
import type { Database } from "@kan/db/types/database.types";
|
||||
import type { dbClient } from "@kan/db/client";
|
||||
import type { ActivityType } from "@kan/db/schema";
|
||||
import { cardActivities } from "@kan/db/schema";
|
||||
import { generateUID } from "@kan/shared/utils";
|
||||
|
||||
export const create = async (
|
||||
db: SupabaseClient<Database>,
|
||||
db: dbClient,
|
||||
activityInput: {
|
||||
type: Database["public"]["Enums"]["card_activity_type"];
|
||||
type: ActivityType;
|
||||
cardId: number;
|
||||
fromIndex?: number;
|
||||
toIndex?: number;
|
||||
@@ -24,9 +24,9 @@ export const create = async (
|
||||
toComment?: string;
|
||||
},
|
||||
) => {
|
||||
const { data } = await db
|
||||
.from("card_activity")
|
||||
.insert({
|
||||
const [result] = await db
|
||||
.insert(cardActivities)
|
||||
.values({
|
||||
publicId: generateUID(),
|
||||
type: activityInput.type,
|
||||
cardId: activityInput.cardId,
|
||||
@@ -45,17 +45,15 @@ export const create = async (
|
||||
fromComment: activityInput.fromComment,
|
||||
toComment: activityInput.toComment,
|
||||
})
|
||||
.select(`id`)
|
||||
.limit(1)
|
||||
.single();
|
||||
.returning({ id: cardActivities.id });
|
||||
|
||||
return data;
|
||||
return result;
|
||||
};
|
||||
|
||||
export const bulkCreate = async (
|
||||
db: SupabaseClient<Database>,
|
||||
db: dbClient,
|
||||
activityInputs: {
|
||||
type: Database["public"]["Enums"]["card_activity_type"];
|
||||
type: ActivityType;
|
||||
cardId: number;
|
||||
fromIndex?: number;
|
||||
toIndex?: number;
|
||||
@@ -75,10 +73,10 @@ export const bulkCreate = async (
|
||||
publicId: generateUID(),
|
||||
}));
|
||||
|
||||
const { data } = await db
|
||||
.from("card_activity")
|
||||
.insert(activitiesWithPublicIds)
|
||||
.select("id");
|
||||
const results = await db
|
||||
.insert(cardActivities)
|
||||
.values(activitiesWithPublicIds)
|
||||
.returning({ id: cardActivities.id });
|
||||
|
||||
return data;
|
||||
return results;
|
||||
};
|
||||
|
||||
@@ -1,83 +1,82 @@
|
||||
import type { SupabaseClient } from "@supabase/supabase-js";
|
||||
import { eq } from "drizzle-orm";
|
||||
|
||||
import type { Database } from "@kan/db/types/database.types";
|
||||
import type { dbClient } from "@kan/db/client";
|
||||
import { comments } from "@kan/db/schema";
|
||||
import { generateUID } from "@kan/shared/utils";
|
||||
|
||||
export const create = async (
|
||||
db: SupabaseClient<Database>,
|
||||
db: dbClient,
|
||||
commentInput: {
|
||||
cardId: number;
|
||||
comment: string;
|
||||
createdBy: string;
|
||||
},
|
||||
) => {
|
||||
const { data } = await db
|
||||
.from("card_comments")
|
||||
.insert({
|
||||
const [result] = await db
|
||||
.insert(comments)
|
||||
.values({
|
||||
publicId: generateUID(),
|
||||
comment: commentInput.comment,
|
||||
createdBy: commentInput.createdBy,
|
||||
cardId: commentInput.cardId,
|
||||
})
|
||||
.select(`id, publicId, comment`)
|
||||
.limit(1)
|
||||
.single();
|
||||
.returning({
|
||||
id: comments.id,
|
||||
publicId: comments.publicId,
|
||||
comment: comments.comment,
|
||||
});
|
||||
|
||||
return data;
|
||||
return result;
|
||||
};
|
||||
|
||||
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 getByPublicId = (db: dbClient, publicId: string) => {
|
||||
return db.query.comments.findFirst({
|
||||
columns: {
|
||||
id: true,
|
||||
publicId: true,
|
||||
comment: true,
|
||||
createdBy: true,
|
||||
},
|
||||
where: eq(comments.publicId, publicId),
|
||||
});
|
||||
};
|
||||
|
||||
export const update = async (
|
||||
db: SupabaseClient<Database>,
|
||||
db: dbClient,
|
||||
commentInput: {
|
||||
id: number;
|
||||
comment: string;
|
||||
},
|
||||
) => {
|
||||
const { data } = await db
|
||||
.from("card_comments")
|
||||
.update({
|
||||
const [result] = await db
|
||||
.update(comments)
|
||||
.set({
|
||||
comment: commentInput.comment,
|
||||
updatedAt: new Date().toISOString(),
|
||||
updatedAt: new Date(),
|
||||
})
|
||||
.eq("id", commentInput.id)
|
||||
.select(`id, publicId, comment`)
|
||||
.limit(1)
|
||||
.order("id", { ascending: false })
|
||||
.single();
|
||||
.where(eq(comments.id, commentInput.id))
|
||||
.returning({
|
||||
id: comments.id,
|
||||
publicId: comments.publicId,
|
||||
comment: comments.comment,
|
||||
});
|
||||
|
||||
return data;
|
||||
return result;
|
||||
};
|
||||
|
||||
export const softDelete = async (
|
||||
db: SupabaseClient<Database>,
|
||||
db: dbClient,
|
||||
args: {
|
||||
commentId: number;
|
||||
deletedAt: string;
|
||||
deletedAt: Date;
|
||||
deletedBy: string;
|
||||
},
|
||||
) => {
|
||||
const { data } = await db
|
||||
.from("card_comments")
|
||||
.update({ deletedAt: args.deletedAt, deletedBy: args.deletedBy })
|
||||
.eq("id", args.commentId)
|
||||
.select(`id`)
|
||||
.order("id", { ascending: true })
|
||||
.limit(1)
|
||||
.single();
|
||||
const [result] = await db
|
||||
.update(comments)
|
||||
.set({ deletedAt: args.deletedAt, deletedBy: args.deletedBy })
|
||||
.where(eq(comments.id, args.commentId))
|
||||
.returning({ id: comments.id });
|
||||
|
||||
return data;
|
||||
return result;
|
||||
};
|
||||
|
||||
@@ -1,25 +1,22 @@
|
||||
import type { SupabaseClient } from "@supabase/supabase-js";
|
||||
|
||||
import type { Database } from "@kan/db/types/database.types";
|
||||
import type { dbClient } from "@kan/db/client";
|
||||
import { feedback } from "@kan/db/schema";
|
||||
|
||||
export const create = async (
|
||||
db: SupabaseClient<Database>,
|
||||
db: dbClient,
|
||||
feedbackInput: {
|
||||
feedback: string;
|
||||
createdBy: string;
|
||||
url: string;
|
||||
},
|
||||
) => {
|
||||
const { data } = await db
|
||||
.from("feedback")
|
||||
.insert({
|
||||
const [result] = await db
|
||||
.insert(feedback)
|
||||
.values({
|
||||
feedback: feedbackInput.feedback,
|
||||
createdBy: feedbackInput.createdBy,
|
||||
url: feedbackInput.url,
|
||||
})
|
||||
.select(`id`)
|
||||
.limit(1)
|
||||
.single();
|
||||
.returning({ id: feedback.id });
|
||||
|
||||
return data;
|
||||
return result;
|
||||
};
|
||||
|
||||
@@ -1,38 +1,36 @@
|
||||
import type { SupabaseClient } from "@supabase/supabase-js";
|
||||
import { eq } from "drizzle-orm";
|
||||
|
||||
import type { Database } from "@kan/db/types/database.types";
|
||||
import type { dbClient } from "@kan/db/client";
|
||||
import { imports } from "@kan/db/schema";
|
||||
import { generateUID } from "@kan/shared/utils";
|
||||
|
||||
export const create = async (
|
||||
db: SupabaseClient<Database>,
|
||||
db: dbClient,
|
||||
importInput: { source: string; createdBy: string },
|
||||
) => {
|
||||
const { data } = await db
|
||||
.from("import")
|
||||
.insert({
|
||||
const [result] = await db
|
||||
.insert(imports)
|
||||
.values({
|
||||
publicId: generateUID(),
|
||||
source: "trello",
|
||||
createdBy: importInput.createdBy,
|
||||
status: "started",
|
||||
})
|
||||
.select(`id`)
|
||||
.limit(1)
|
||||
.single();
|
||||
.returning({ id: imports.id });
|
||||
|
||||
return data;
|
||||
return result;
|
||||
};
|
||||
|
||||
export const update = async (
|
||||
db: SupabaseClient<Database>,
|
||||
db: dbClient,
|
||||
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();
|
||||
const [result] = await db
|
||||
.update(imports)
|
||||
.set({ status: importInput.status })
|
||||
.where(eq(imports.id, args.importId))
|
||||
.returning({ id: imports.id, status: imports.status });
|
||||
|
||||
return data;
|
||||
return result;
|
||||
};
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import type { SupabaseClient } from "@supabase/supabase-js";
|
||||
import { eq, inArray } from "drizzle-orm";
|
||||
|
||||
import type { Database } from "@kan/db/types/database.types";
|
||||
import type { dbClient } from "@kan/db/client";
|
||||
import { cardsToLabels, labels } from "@kan/db/schema";
|
||||
import { generateUID } from "@kan/shared/utils";
|
||||
|
||||
export const create = async (
|
||||
db: SupabaseClient<Database>,
|
||||
db: dbClient,
|
||||
labelInput: {
|
||||
name: string;
|
||||
colourCode: string;
|
||||
@@ -13,31 +14,30 @@ export const create = async (
|
||||
cardId?: number;
|
||||
},
|
||||
) => {
|
||||
const { data } = await db
|
||||
.from("label")
|
||||
.insert({
|
||||
const [result] = await db
|
||||
.insert(labels)
|
||||
.values({
|
||||
publicId: generateUID(),
|
||||
name: labelInput.name,
|
||||
colourCode: labelInput.colourCode,
|
||||
createdBy: labelInput.createdBy,
|
||||
boardId: labelInput.boardId,
|
||||
})
|
||||
.select(`id`)
|
||||
.limit(1)
|
||||
.single();
|
||||
.returning({ id: labels.id });
|
||||
|
||||
if (labelInput.cardId && data)
|
||||
await db.from("_card_labels").insert({
|
||||
if (labelInput.cardId && result) {
|
||||
await db.insert(cardsToLabels).values({
|
||||
cardId: labelInput.cardId,
|
||||
labelId: data.id,
|
||||
labelId: result.id,
|
||||
});
|
||||
}
|
||||
|
||||
return data;
|
||||
return result;
|
||||
};
|
||||
|
||||
export const bulkCreate = async (
|
||||
db: SupabaseClient<Database>,
|
||||
labels: {
|
||||
db: dbClient,
|
||||
labelsInput: {
|
||||
publicId: string;
|
||||
name: string;
|
||||
colourCode: string;
|
||||
@@ -45,61 +45,64 @@ export const bulkCreate = async (
|
||||
createdBy: string;
|
||||
}[],
|
||||
) => {
|
||||
const { data } = await db.from("label").insert(labels).select(`id`);
|
||||
const results = await db
|
||||
.insert(labels)
|
||||
.values(labelsInput)
|
||||
.returning({ id: labels.id });
|
||||
|
||||
return data;
|
||||
return results;
|
||||
};
|
||||
|
||||
export const getAllByPublicIds = async (
|
||||
db: SupabaseClient<Database>,
|
||||
labelPublicIds: string[],
|
||||
) => {
|
||||
const { data } = await db
|
||||
.from("label")
|
||||
.select(`id`)
|
||||
.in("publicId", labelPublicIds);
|
||||
|
||||
return data;
|
||||
export const getAllByPublicIds = (db: dbClient, labelPublicIds: string[]) => {
|
||||
return db.query.labels.findMany({
|
||||
columns: {
|
||||
id: true,
|
||||
},
|
||||
where: inArray(labels.publicId, labelPublicIds),
|
||||
});
|
||||
};
|
||||
|
||||
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 getByPublicId = async (db: dbClient, labelPublicId: string) => {
|
||||
return db.query.labels.findFirst({
|
||||
columns: {
|
||||
id: true,
|
||||
publicId: true,
|
||||
name: true,
|
||||
colourCode: true,
|
||||
},
|
||||
where: eq(labels.publicId, labelPublicId),
|
||||
});
|
||||
};
|
||||
|
||||
export const update = async (
|
||||
db: SupabaseClient<Database>,
|
||||
db: dbClient,
|
||||
labelInput: {
|
||||
labelPublicId: string;
|
||||
name: string;
|
||||
colourCode: string;
|
||||
},
|
||||
) => {
|
||||
const { data } = await db
|
||||
.from("label")
|
||||
.update({
|
||||
const [result] = await db
|
||||
.update(labels)
|
||||
.set({
|
||||
name: labelInput.name,
|
||||
colourCode: labelInput.colourCode,
|
||||
})
|
||||
.eq("publicId", labelInput.labelPublicId);
|
||||
.where(eq(labels.publicId, labelInput.labelPublicId))
|
||||
.returning({
|
||||
id: labels.id,
|
||||
name: labels.name,
|
||||
colourCode: labels.colourCode,
|
||||
});
|
||||
|
||||
return data;
|
||||
return result;
|
||||
};
|
||||
|
||||
export const hardDelete = async (
|
||||
db: SupabaseClient<Database>,
|
||||
labelId: number,
|
||||
) => {
|
||||
const { data } = await db.from("label").delete().eq("id", labelId);
|
||||
export const hardDelete = async (db: dbClient, labelId: number) => {
|
||||
const [result] = await db
|
||||
.delete(labels)
|
||||
.where(eq(labels.id, labelId))
|
||||
.returning({ id: labels.id });
|
||||
|
||||
return data;
|
||||
return result;
|
||||
};
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import type { SupabaseClient } from "@supabase/supabase-js";
|
||||
import { and, desc, eq, isNull } from "drizzle-orm";
|
||||
|
||||
import type { dbClient } from "@kan/db/client";
|
||||
import type { Database } from "@kan/db/types/database.types";
|
||||
import { lists } from "@kan/db/schema";
|
||||
import { generateUID } from "@kan/shared/utils";
|
||||
|
||||
export const create = async (
|
||||
db: SupabaseClient<Database>,
|
||||
db: dbClient,
|
||||
listInput: {
|
||||
name: string;
|
||||
createdBy: string;
|
||||
@@ -13,9 +16,9 @@ export const create = async (
|
||||
importId?: number;
|
||||
},
|
||||
) => {
|
||||
const { data } = await db
|
||||
.from("list")
|
||||
.insert({
|
||||
const [result] = await db
|
||||
.insert(lists)
|
||||
.values({
|
||||
publicId: generateUID(),
|
||||
name: listInput.name,
|
||||
createdBy: listInput.createdBy,
|
||||
@@ -23,48 +26,45 @@ export const create = async (
|
||||
index: listInput.index,
|
||||
importId: listInput.importId,
|
||||
})
|
||||
.select(
|
||||
`
|
||||
id,
|
||||
publicId,
|
||||
name
|
||||
`,
|
||||
)
|
||||
.limit(1)
|
||||
.single();
|
||||
.returning({
|
||||
id: lists.id,
|
||||
publicId: lists.publicId,
|
||||
name: lists.name,
|
||||
});
|
||||
|
||||
return data;
|
||||
return result;
|
||||
};
|
||||
|
||||
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 getByPublicId = async (db: dbClient, listPublicId: string) => {
|
||||
return db.query.lists.findFirst({
|
||||
columns: {
|
||||
id: true,
|
||||
boardId: true,
|
||||
index: true,
|
||||
},
|
||||
where: eq(lists.publicId, listPublicId),
|
||||
});
|
||||
};
|
||||
|
||||
export const getWithCardsByPublicId = async (
|
||||
db: SupabaseClient<Database>,
|
||||
db: dbClient,
|
||||
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;
|
||||
return db.query.lists.findFirst({
|
||||
columns: {
|
||||
id: true,
|
||||
},
|
||||
with: {
|
||||
cards: {
|
||||
columns: {
|
||||
index: true,
|
||||
},
|
||||
where: isNull(lists.deletedAt),
|
||||
orderBy: [desc(lists.index)],
|
||||
},
|
||||
},
|
||||
where: and(eq(lists.publicId, listPublicId), isNull(lists.deletedAt)),
|
||||
});
|
||||
};
|
||||
|
||||
export const update = async (
|
||||
@@ -121,41 +121,37 @@ export const shiftIndex = async (
|
||||
};
|
||||
|
||||
export const softDeleteAllByBoardId = async (
|
||||
db: SupabaseClient<Database>,
|
||||
db: dbClient,
|
||||
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 });
|
||||
const [result] = await db
|
||||
.update(lists)
|
||||
.set({ deletedAt: new Date(), deletedBy: args.deletedBy })
|
||||
.where(and(eq(lists.boardId, args.boardId), isNull(lists.deletedAt)))
|
||||
.returning({
|
||||
id: lists.id,
|
||||
});
|
||||
|
||||
return data;
|
||||
return result;
|
||||
};
|
||||
|
||||
export const softDeleteById = async (
|
||||
db: SupabaseClient<Database>,
|
||||
db: dbClient,
|
||||
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();
|
||||
const [updatedList] = await db
|
||||
.update(lists)
|
||||
.set({ deletedAt: new Date(), deletedBy: args.deletedBy })
|
||||
.where(and(eq(lists.id, args.listId), isNull(lists.deletedAt)))
|
||||
.returning({
|
||||
id: lists.id,
|
||||
});
|
||||
|
||||
return data;
|
||||
return updatedList;
|
||||
};
|
||||
|
||||
@@ -1,21 +1,23 @@
|
||||
import type { SupabaseClient } from "@supabase/supabase-js";
|
||||
import { and, eq, isNull } from "drizzle-orm";
|
||||
|
||||
import type { Database } from "@kan/db/types/database.types";
|
||||
import type { dbClient } from "@kan/db/client";
|
||||
import type { MemberRole, MemberStatus } from "@kan/db/schema";
|
||||
import { workspaceMembers } from "@kan/db/schema";
|
||||
import { generateUID } from "@kan/shared/utils";
|
||||
|
||||
export const create = async (
|
||||
db: SupabaseClient<Database>,
|
||||
db: dbClient,
|
||||
memberInput: {
|
||||
userId: string;
|
||||
workspaceId: number;
|
||||
createdBy: string;
|
||||
role: "admin" | "member" | "guest";
|
||||
status: "invited" | "active" | "removed";
|
||||
role: MemberRole;
|
||||
status: MemberStatus;
|
||||
},
|
||||
) => {
|
||||
const { data } = await db
|
||||
.from("workspace_members")
|
||||
.insert({
|
||||
const [result] = await db
|
||||
.insert(workspaceMembers)
|
||||
.values({
|
||||
publicId: generateUID(),
|
||||
userId: memberInput.userId,
|
||||
workspaceId: memberInput.workspaceId,
|
||||
@@ -23,52 +25,53 @@ export const create = async (
|
||||
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);
|
||||
.returning({
|
||||
id: workspaceMembers.id,
|
||||
publicId: workspaceMembers.publicId,
|
||||
});
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
export const getByPublicId = async (db: dbClient, publicId: string) => {
|
||||
return db.query.workspaceMembers.findFirst({
|
||||
where: eq(workspaceMembers.publicId, publicId),
|
||||
});
|
||||
};
|
||||
|
||||
export const acceptInvite = async (db: dbClient, id: number) => {
|
||||
const [result] = await db
|
||||
.update(workspaceMembers)
|
||||
.set({ status: "active" })
|
||||
.where(eq(workspaceMembers.id, id))
|
||||
.returning({
|
||||
id: workspaceMembers.id,
|
||||
publicId: workspaceMembers.publicId,
|
||||
});
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
export const softDelete = async (
|
||||
db: dbClient,
|
||||
args: {
|
||||
memberId: number;
|
||||
deletedBy: string;
|
||||
},
|
||||
) => {
|
||||
const [result] = await db
|
||||
.update(workspaceMembers)
|
||||
.set({ deletedAt: new Date(), deletedBy: args.deletedBy })
|
||||
.where(
|
||||
and(
|
||||
eq(workspaceMembers.id, args.memberId),
|
||||
isNull(workspaceMembers.deletedAt),
|
||||
),
|
||||
)
|
||||
.returning({
|
||||
id: workspaceMembers.id,
|
||||
publicId: workspaceMembers.publicId,
|
||||
});
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
import type { SupabaseClient } from "@supabase/supabase-js";
|
||||
import { eq } from "drizzle-orm";
|
||||
|
||||
import type { dbClient } from "@kan/db/client";
|
||||
import type { Database } from "@kan/db/types/database.types";
|
||||
import * as schema from "@kan/db/schema";
|
||||
import { users } from "@kan/db/schema";
|
||||
|
||||
export const getById = async (db: dbClient, userId: string) => {
|
||||
const data = await db.query.users.findFirst({
|
||||
return await db.query.users.findFirst({
|
||||
columns: {
|
||||
id: true,
|
||||
name: true,
|
||||
@@ -14,55 +12,48 @@ export const getById = async (db: dbClient, userId: string) => {
|
||||
image: true,
|
||||
stripeCustomerId: true,
|
||||
},
|
||||
where: eq(schema.users.id, userId),
|
||||
where: eq(users.id, userId),
|
||||
});
|
||||
|
||||
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 getByEmail = (db: dbClient, email: string) => {
|
||||
return db.query.users.findFirst({
|
||||
columns: {
|
||||
id: true,
|
||||
name: true,
|
||||
email: true,
|
||||
},
|
||||
where: eq(users.email, email),
|
||||
});
|
||||
};
|
||||
|
||||
export const create = async (
|
||||
db: SupabaseClient<Database>,
|
||||
export const create = (
|
||||
db: dbClient,
|
||||
user: { id: string; email: string; stripeCustomerId: string },
|
||||
) => {
|
||||
const { data } = await db
|
||||
.from("user")
|
||||
.insert({
|
||||
id: user.id,
|
||||
email: user.email,
|
||||
stripeCustomerId: user.stripeCustomerId,
|
||||
})
|
||||
.select()
|
||||
.limit(1)
|
||||
.single();
|
||||
|
||||
return data;
|
||||
return db.insert(users).values({
|
||||
id: user.id,
|
||||
email: user.email,
|
||||
stripeCustomerId: user.stripeCustomerId,
|
||||
});
|
||||
};
|
||||
|
||||
export const update = async (
|
||||
db: SupabaseClient<Database>,
|
||||
db: dbClient,
|
||||
userId: string,
|
||||
updates: { image?: string; name?: string },
|
||||
) => {
|
||||
const { data } = await db
|
||||
.from("user")
|
||||
.update({ image: updates.image, name: updates.name })
|
||||
.eq("id", userId)
|
||||
.select(`image, name`)
|
||||
.single();
|
||||
const [result] = await db
|
||||
.update(users)
|
||||
.set({
|
||||
name: updates.name,
|
||||
image: updates.image,
|
||||
})
|
||||
.where(eq(users.id, userId))
|
||||
.returning({
|
||||
name: users.name,
|
||||
image: users.image,
|
||||
});
|
||||
|
||||
return data;
|
||||
return result;
|
||||
};
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import type { SupabaseClient } from "@supabase/supabase-js";
|
||||
import { and, eq, inArray, isNull } from "drizzle-orm";
|
||||
|
||||
import type { Database } from "@kan/db/types/database.types";
|
||||
import type { dbClient } from "@kan/db/client";
|
||||
import { boards, workspaceMembers, workspaces } from "@kan/db/schema";
|
||||
import { generateUID } from "@kan/shared/utils";
|
||||
|
||||
export const create = async (
|
||||
db: SupabaseClient<Database>,
|
||||
db: dbClient,
|
||||
workspaceInput: {
|
||||
publicId?: string;
|
||||
name: string;
|
||||
@@ -12,37 +13,42 @@ export const create = async (
|
||||
createdBy: string;
|
||||
},
|
||||
) => {
|
||||
const { data } = await db
|
||||
.from("workspace")
|
||||
.insert({
|
||||
const [workspace] = await db
|
||||
.insert(workspaces)
|
||||
.values({
|
||||
publicId: workspaceInput.publicId ?? generateUID(),
|
||||
name: workspaceInput.name,
|
||||
slug: workspaceInput.slug,
|
||||
createdBy: workspaceInput.createdBy,
|
||||
})
|
||||
.select(`id, publicId, name, slug, description, plan`)
|
||||
.limit(1)
|
||||
.single();
|
||||
.returning({
|
||||
id: workspaces.id,
|
||||
publicId: workspaces.publicId,
|
||||
name: workspaces.name,
|
||||
slug: workspaces.slug,
|
||||
description: workspaces.description,
|
||||
plan: workspaces.plan,
|
||||
});
|
||||
|
||||
if (data)
|
||||
await db.from("workspace_members").insert({
|
||||
if (workspace) {
|
||||
await db.insert(workspaceMembers).values({
|
||||
publicId: generateUID(),
|
||||
userId: workspaceInput.createdBy,
|
||||
workspaceId: data.id,
|
||||
workspaceId: workspace.id,
|
||||
createdBy: workspaceInput.createdBy,
|
||||
role: "admin",
|
||||
status: "active",
|
||||
});
|
||||
}
|
||||
|
||||
const newWorkspace = { ...data };
|
||||
|
||||
const newWorkspace = { ...workspace };
|
||||
delete newWorkspace.id;
|
||||
|
||||
return newWorkspace;
|
||||
};
|
||||
|
||||
export const update = async (
|
||||
db: SupabaseClient<Database>,
|
||||
db: dbClient,
|
||||
workspacePublicId: string,
|
||||
workspaceInput: {
|
||||
name?: string;
|
||||
@@ -51,168 +57,162 @@ export const update = async (
|
||||
description?: string;
|
||||
},
|
||||
) => {
|
||||
const { data } = await db
|
||||
.from("workspace")
|
||||
.update({
|
||||
const [result] = await db
|
||||
.update(workspaces)
|
||||
.set({
|
||||
name: workspaceInput.name,
|
||||
slug: workspaceInput.slug,
|
||||
plan: workspaceInput.plan,
|
||||
description: workspaceInput.description,
|
||||
})
|
||||
.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, plan`)
|
||||
.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,
|
||||
image
|
||||
)
|
||||
)
|
||||
`,
|
||||
)
|
||||
.eq("publicId", workspacePublicId)
|
||||
.is("deletedAt", null)
|
||||
.is("members.deletedAt", null)
|
||||
.limit(1)
|
||||
.single();
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
export const getBySlugWithBoards = async (
|
||||
db: SupabaseClient<Database>,
|
||||
workspaceSlug: string,
|
||||
) => {
|
||||
const { data } = await db
|
||||
.from("workspace")
|
||||
.select(
|
||||
`
|
||||
publicId,
|
||||
name,
|
||||
description,
|
||||
slug,
|
||||
boards: board (
|
||||
publicId,
|
||||
slug,
|
||||
name
|
||||
)
|
||||
`,
|
||||
)
|
||||
.eq("slug", workspaceSlug)
|
||||
.is("deletedAt", null)
|
||||
.is("boards.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,
|
||||
description,
|
||||
slug,
|
||||
plan
|
||||
)
|
||||
`,
|
||||
)
|
||||
.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);
|
||||
.where(eq(workspaces.publicId, workspacePublicId))
|
||||
.returning({
|
||||
id: workspaces.id,
|
||||
publicId: workspaces.publicId,
|
||||
name: workspaces.name,
|
||||
slug: workspaces.slug,
|
||||
description: workspaces.description,
|
||||
plan: workspaces.plan,
|
||||
});
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
export const getByPublicId = (db: dbClient, workspacePublicId: string) => {
|
||||
return db.query.workspaces.findFirst({
|
||||
columns: {
|
||||
id: true,
|
||||
publicId: true,
|
||||
name: true,
|
||||
plan: true,
|
||||
},
|
||||
where: eq(workspaces.publicId, workspacePublicId),
|
||||
});
|
||||
};
|
||||
|
||||
export const getByPublicIdWithMembers = (
|
||||
db: dbClient,
|
||||
workspacePublicId: string,
|
||||
) => {
|
||||
return db.query.workspaces.findFirst({
|
||||
columns: {
|
||||
id: true,
|
||||
publicId: true,
|
||||
},
|
||||
with: {
|
||||
members: {
|
||||
columns: {
|
||||
publicId: true,
|
||||
role: true,
|
||||
status: true,
|
||||
},
|
||||
where: isNull(workspaceMembers.deletedAt),
|
||||
with: {
|
||||
user: {
|
||||
columns: {
|
||||
id: true,
|
||||
name: true,
|
||||
email: true,
|
||||
image: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
where: and(
|
||||
eq(workspaces.publicId, workspacePublicId),
|
||||
isNull(workspaces.deletedAt),
|
||||
),
|
||||
});
|
||||
};
|
||||
|
||||
export const getBySlugWithBoards = (db: dbClient, workspaceSlug: string) => {
|
||||
return db.query.workspaces.findFirst({
|
||||
columns: {
|
||||
publicId: true,
|
||||
name: true,
|
||||
description: true,
|
||||
slug: true,
|
||||
},
|
||||
with: {
|
||||
boards: {
|
||||
columns: {
|
||||
publicId: true,
|
||||
slug: true,
|
||||
name: true,
|
||||
},
|
||||
where: isNull(boards.deletedAt),
|
||||
},
|
||||
},
|
||||
where: and(
|
||||
eq(workspaces.slug, workspaceSlug),
|
||||
isNull(workspaces.deletedAt),
|
||||
),
|
||||
});
|
||||
};
|
||||
|
||||
export const getAllByUserId = (db: dbClient, userId: string) => {
|
||||
return db.query.workspaceMembers.findMany({
|
||||
columns: {
|
||||
role: true,
|
||||
},
|
||||
with: {
|
||||
workspace: {
|
||||
columns: {
|
||||
publicId: true,
|
||||
name: true,
|
||||
description: true,
|
||||
slug: true,
|
||||
plan: true,
|
||||
},
|
||||
// https://github.com/drizzle-team/drizzle-orm/issues/2903
|
||||
// where: isNull(workspaces.deletedAt),
|
||||
},
|
||||
},
|
||||
where: and(
|
||||
eq(workspaceMembers.userId, userId),
|
||||
isNull(workspaceMembers.deletedAt),
|
||||
),
|
||||
});
|
||||
};
|
||||
|
||||
export const getMemberByPublicId = (db: dbClient, memberPublicId: string) => {
|
||||
return db.query.workspaceMembers.findFirst({
|
||||
columns: {
|
||||
id: true,
|
||||
},
|
||||
where: eq(workspaceMembers.publicId, memberPublicId),
|
||||
});
|
||||
};
|
||||
|
||||
export const getAllMembersByPublicIds = (
|
||||
db: dbClient,
|
||||
memberPublicIds: string[],
|
||||
) => {
|
||||
return db.query.workspaceMembers.findMany({
|
||||
columns: {
|
||||
id: true,
|
||||
},
|
||||
where: inArray(workspaceMembers.publicId, memberPublicIds),
|
||||
});
|
||||
};
|
||||
|
||||
export const hardDelete = (db: dbClient, workspacePublicId: string) => {
|
||||
return db
|
||||
.delete(workspaces)
|
||||
.where(eq(workspaces.publicId, workspacePublicId));
|
||||
};
|
||||
|
||||
export const isWorkspaceSlugAvailable = async (
|
||||
db: SupabaseClient<Database>,
|
||||
db: dbClient,
|
||||
workspaceSlug: string,
|
||||
) => {
|
||||
const { data } = await db
|
||||
.from("workspace")
|
||||
.select("id")
|
||||
.eq("slug", workspaceSlug)
|
||||
.is("deletedAt", null)
|
||||
.limit(1)
|
||||
.single();
|
||||
const result = await db.query.workspaces.findFirst({
|
||||
columns: {
|
||||
id: true,
|
||||
},
|
||||
where: eq(workspaces.slug, workspaceSlug),
|
||||
});
|
||||
|
||||
return data === null;
|
||||
return result === undefined;
|
||||
};
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
import type { SupabaseClient } from "@supabase/supabase-js";
|
||||
import { eq } from "drizzle-orm";
|
||||
|
||||
import type { Database } from "@kan/db/types/database.types";
|
||||
import type { dbClient } from "@kan/db/client";
|
||||
import { slugs } from "@kan/db/schema";
|
||||
|
||||
export const getWorkspaceSlug = async (
|
||||
db: SupabaseClient<Database>,
|
||||
slug: string,
|
||||
) => {
|
||||
const { data } = await db
|
||||
.from("workspace_slugs")
|
||||
.select(`slug, type`)
|
||||
.eq("slug", slug)
|
||||
.single();
|
||||
|
||||
return data;
|
||||
export const getWorkspaceSlug = (db: dbClient, slug: string) => {
|
||||
return db.query.slugs.findFirst({
|
||||
columns: {
|
||||
slug: true,
|
||||
type: true,
|
||||
},
|
||||
where: eq(slugs.slug, slug),
|
||||
});
|
||||
};
|
||||
|
||||
@@ -18,7 +18,7 @@ import { lists } from "./lists";
|
||||
import { users } from "./users";
|
||||
import { workspaceMembers } from "./workspaces";
|
||||
|
||||
export const activityTypeEnum = pgEnum("card_activity_type", [
|
||||
export const activityTypes = [
|
||||
"card.created",
|
||||
"card.updated.title",
|
||||
"card.updated.description",
|
||||
@@ -32,7 +32,11 @@ export const activityTypeEnum = pgEnum("card_activity_type", [
|
||||
"card.updated.comment.updated",
|
||||
"card.updated.comment.deleted",
|
||||
"card.archived",
|
||||
]);
|
||||
] as const;
|
||||
|
||||
export type ActivityType = (typeof activityTypes)[number];
|
||||
|
||||
export const activityTypeEnum = pgEnum("card_activity_type", activityTypes);
|
||||
|
||||
export const cards = pgTable("card", {
|
||||
id: bigserial("id", { mode: "number" }).primaryKey(),
|
||||
|
||||
@@ -10,20 +10,24 @@ import {
|
||||
varchar,
|
||||
} from "drizzle-orm/pg-core";
|
||||
|
||||
import { boards } from "./boards";
|
||||
import { users } from "./users";
|
||||
|
||||
export const memberRoleEnum = pgEnum("role", ["admin", "member", "guest"]);
|
||||
export const memberStatusEnum = pgEnum("member_status", [
|
||||
"invited",
|
||||
"active",
|
||||
"removed",
|
||||
]);
|
||||
export const slugTypeEnum = pgEnum("slug_type", ["reserved", "premium"]);
|
||||
export const workspacePlanEnum = pgEnum("workspace_plan", [
|
||||
"free",
|
||||
"pro",
|
||||
"enterprise",
|
||||
]);
|
||||
export const memberRoles = ["admin", "member", "guest"] as const;
|
||||
export type MemberRole = (typeof memberRoles)[number];
|
||||
export const memberRoleEnum = pgEnum("role", memberRoles);
|
||||
|
||||
export const memberStatuses = ["invited", "active", "removed"] as const;
|
||||
export type MemberStatus = (typeof memberStatuses)[number];
|
||||
export const memberStatusEnum = pgEnum("member_status", memberStatuses);
|
||||
|
||||
export const slugTypes = ["reserved", "premium"] as const;
|
||||
export type SlugType = (typeof slugTypes)[number];
|
||||
export const slugTypeEnum = pgEnum("slug_type", slugTypes);
|
||||
|
||||
export const workspacePlans = ["free", "pro", "enterprise"] as const;
|
||||
export type WorkspacePlan = (typeof workspacePlans)[number];
|
||||
export const workspacePlanEnum = pgEnum("workspace_plan", workspacePlans);
|
||||
|
||||
export const workspaces = pgTable("workspace", {
|
||||
id: bigserial("id", { mode: "number" }).primaryKey(),
|
||||
@@ -44,6 +48,7 @@ export const workspaces = pgTable("workspace", {
|
||||
export const workspaceRelations = relations(workspaces, ({ one, many }) => ({
|
||||
user: one(users, { fields: [workspaces.createdBy], references: [users.id] }),
|
||||
members: many(workspaceMembers),
|
||||
boards: many(boards),
|
||||
}));
|
||||
|
||||
export const workspaceMembers = pgTable("workspace_members", {
|
||||
@@ -64,6 +69,20 @@ export const workspaceMembers = pgTable("workspace_members", {
|
||||
status: memberStatusEnum("status").default("invited").notNull(),
|
||||
}).enableRLS();
|
||||
|
||||
export const workspaceMembersRelations = relations(
|
||||
workspaceMembers,
|
||||
({ one }) => ({
|
||||
user: one(users, {
|
||||
fields: [workspaceMembers.userId],
|
||||
references: [users.id],
|
||||
}),
|
||||
workspace: one(workspaces, {
|
||||
fields: [workspaceMembers.workspaceId],
|
||||
references: [workspaces.id],
|
||||
}),
|
||||
}),
|
||||
);
|
||||
|
||||
export const slugs = pgTable("workspace_slugs", {
|
||||
slug: varchar("slug", { length: 255 }).notNull().unique(),
|
||||
type: slugTypeEnum("type").notNull(),
|
||||
|
||||
Reference in New Issue
Block a user