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