diff --git a/server/src/modules/groups/groups.controller.ts b/server/src/modules/groups/groups.controller.ts index 904c44e..e7cdf7c 100644 --- a/server/src/modules/groups/groups.controller.ts +++ b/server/src/modules/groups/groups.controller.ts @@ -27,11 +27,14 @@ import { } from 'drizzle-orm' import { unionAll } from 'drizzle-orm/pg-core' import { RequestHandler } from 'express' -import { members } from '../members/members.schema' +import { membersTable } from '../members/members.schema' import { addMembers } from '../members/members.service' -import { messageRecipients, messages } from '../messages/messages.schema' -import { users } from '../users/users.schema' -import { groups } from './groups.schema' +import { + messageRecipientsTable, + messagesTable, +} from '../messages/messages.schema' +import { usersTable } from '../users/users.schema' +import { groupsTable } from './groups.schema' // CREATE @@ -39,7 +42,7 @@ export const createGroup: RequestHandler = async (req, res, next) => { try { const group = await db.transaction(async tx => { const [group] = await tx - .insert(groups) + .insert(groupsTable) .values({ name: req.body.name, ownerId: req.user!.id }) .returning() @@ -66,8 +69,8 @@ export const getGroup: RequestHandler = async (req, res, next) => { try { const [group] = await db .select() - .from(groups) - .where(eq(groups.id, Number(req.params.groupId))) + .from(groupsTable) + .where(eq(groupsTable.id, Number(req.params.groupId))) if (!group) { return notFound(res, 'Group') @@ -81,25 +84,25 @@ export const getGroup: RequestHandler = async (req, res, next) => { export const getNonGroupMembers: RequestHandler = async (req, res, next) => { try { const groupMembers = await db - .select({ userId: members.userId }) - .from(members) - .where(eq(members.groupId, Number(req.params.groupId))) + .select({ userId: membersTable.userId }) + .from(membersTable) + .where(eq(membersTable.groupId, Number(req.params.groupId))) // eslint-disable-next-line @typescript-eslint/no-unused-vars - const { password, ...columns } = getTableColumns(users) + const { password, ...columns } = getTableColumns(usersTable) const rows = await db .select(columns) - .from(users) + .from(usersTable) .where( and( - like(users.username, `%${req.query.query}%`), + like(usersTable.username, `%${req.query.query}%`), notInArray( - users.id, + usersTable.id, groupMembers.map(m => m.userId), ), ), ) .limit(Number(req.query.limit) || 5) - .orderBy(users.username) + .orderBy(usersTable.username) res.json(rows) } catch (error) { @@ -110,11 +113,14 @@ export const getNonGroupMembers: RequestHandler = async (req, res, next) => { export const listGroups: RequestHandler = async (req, res, next) => { try { const userGroupIds = await db - .select({ groupId: members.groupId }) - .from(members) - .where(eq(members.userId, req.user!.id)) + .select({ groupId: membersTable.groupId }) + .from(membersTable) + .where(eq(membersTable.userId, req.user!.id)) - const qb = db.select(getTableColumns(groups)).from(groups).$dynamic() + const qb = db + .select(getTableColumns(groupsTable)) + .from(groupsTable) + .$dynamic() const { cursor, limit } = getPaginationParams(req.query, 'number') @@ -124,13 +130,13 @@ export const listGroups: RequestHandler = async (req, res, next) => { where: and( userGroupIds.length ? notInArray( - groups.id, + groupsTable.id, userGroupIds.map(m => m.groupId), ) : undefined, - cursor ? lt(groups.id, cursor as number) : undefined, + cursor ? lt(groupsTable.id, cursor as number) : undefined, ), - orderBy: [desc(groups.id)], + orderBy: [desc(groupsTable.id)], }) res.json(result) @@ -146,22 +152,22 @@ export const listUserGroups: RequestHandler = async (req, res, next) => { .as( db .select({ - ...getTableColumns(messages), + ...getTableColumns(messagesTable), rowNumber: rowNumber().over({ - partitionBy: messages.groupId, - orderBy: desc(messages.createdAt), + partitionBy: messagesTable.groupId, + orderBy: desc(messagesTable.createdAt), as: 'row_number', }), }) - .from(messages) - .where(isNotNull(messages.groupId)), + .from(messagesTable) + .where(isNotNull(messagesTable.groupId)), ) const groupsWithLastMessage = db.$with('groups_with_last_message').as( db .with(groupMessagesWithRowNumber) .select({ - chatName: groups.name, + chatName: groupsTable.name, groupId: groupMessagesWithRowNumber.groupId, partnerId: groupMessagesWithRowNumber.receiverId, lastMessage: { @@ -170,19 +176,19 @@ export const listUserGroups: RequestHandler = async (req, res, next) => { }, lastActivity: coalesce( groupMessagesWithRowNumber.createdAt, - groups.createdAt, + groupsTable.createdAt, ).as('last_activity'), }) - .from(groups) + .from(groupsTable) .leftJoin( groupMessagesWithRowNumber, and( - eq(groups.id, groupMessagesWithRowNumber.groupId), + eq(groupsTable.id, groupMessagesWithRowNumber.groupId), eq(groupMessagesWithRowNumber.rowNumber, 1), ), ) - .innerJoin(members, eq(members.groupId, groups.id)) - .where(eq(members.userId, req.user!.id)), + .innerJoin(membersTable, eq(membersTable.groupId, groupsTable.id)) + .where(eq(membersTable.userId, req.user!.id)), ) const directMessagesWithPartner = db @@ -190,31 +196,31 @@ export const listUserGroups: RequestHandler = async (req, res, next) => { .as( db .select({ - ...getTableColumns(messages), + ...getTableColumns(messagesTable), partnerId: sql` CASE - WHEN ${messages.senderId} = ${req.user!.id} THEN ${messages.receiverId} - ELSE ${messages.senderId} + WHEN ${messagesTable.senderId} = ${req.user!.id} THEN ${messagesTable.receiverId} + ELSE ${messagesTable.senderId} END `.as('partner_id'), rowNumber: rowNumber().over({ partitionBy: sql` CASE - WHEN ${messages.senderId} = ${req.user!.id} THEN ${messages.receiverId} - ELSE ${messages.senderId} + WHEN ${messagesTable.senderId} = ${req.user!.id} THEN ${messagesTable.receiverId} + ELSE ${messagesTable.senderId} END `, - orderBy: desc(messages.createdAt), + orderBy: desc(messagesTable.createdAt), as: 'row_number', }), }) - .from(messages) + .from(messagesTable) .where( and( - isNull(messages.groupId), + isNull(messagesTable.groupId), or( - eq(messages.senderId, req.user!.id), - eq(messages.receiverId, req.user!.id), + eq(messagesTable.senderId, req.user!.id), + eq(messagesTable.receiverId, req.user!.id), ), ), ), @@ -226,7 +232,7 @@ export const listUserGroups: RequestHandler = async (req, res, next) => { db .with(directMessagesWithPartner) .select({ - chatName: users.username, + chatName: usersTable.username, groupId: directMessagesWithPartner.groupId, partnerId: directMessagesWithPartner.partnerId, lastMessage: { @@ -236,7 +242,10 @@ export const listUserGroups: RequestHandler = async (req, res, next) => { lastActivity: directMessagesWithPartner.createdAt, }) .from(directMessagesWithPartner) - .innerJoin(users, eq(directMessagesWithPartner.partnerId, users.id)) + .innerJoin( + usersTable, + eq(directMessagesWithPartner.partnerId, usersTable.id), + ) .where(eq(directMessagesWithPartner.rowNumber, 1)), ) @@ -244,46 +253,48 @@ export const listUserGroups: RequestHandler = async (req, res, next) => { unionAll( db .select({ - groupId: sql`${groups.id}`.as('unread_group_id'), + groupId: sql`${groupsTable.id}`.as('unread_group_id'), receiverId: nullAs('unread_receiver_id'), - unreadCount: count(messages.id).as('unread_count'), + unreadCount: count(messagesTable.id).as('unread_count'), }) - .from(groups) - .leftJoin(messages, eq(groups.id, messages.groupId)) + .from(groupsTable) + .leftJoin(messagesTable, eq(groupsTable.id, messagesTable.groupId)) .leftJoin( - messageRecipients, + messageRecipientsTable, and( - eq(messageRecipients.messageId, messages.id), - eq(messageRecipients.recipientId, req.user!.id), + eq(messageRecipientsTable.messageId, messagesTable.id), + eq(messageRecipientsTable.recipientId, req.user!.id), ), ) - .where(isNull(messageRecipients.messageId)) - .groupBy(groups.id), + .where(isNull(messageRecipientsTable.messageId)) + .groupBy(groupsTable.id), db .select({ groupId: nullAs('unread_group_id'), - receiverId: sql`${messages.receiverId}`.as('unread_receiver_id'), - unreadCount: count(messages.id).as('unread_count'), + receiverId: sql`${messagesTable.receiverId}`.as( + 'unread_receiver_id', + ), + unreadCount: count(messagesTable.id).as('unread_count'), }) - .from(messages) + .from(messagesTable) .where( and( - isNull(messages.groupId), - eq(messages.receiverId, req.user!.id), + isNull(messagesTable.groupId), + eq(messagesTable.receiverId, req.user!.id), notExists( db .select() - .from(messageRecipients) + .from(messageRecipientsTable) .where( and( - eq(messageRecipients.messageId, messages.id), - eq(messageRecipients.recipientId, req.user!.id), + eq(messageRecipientsTable.messageId, messagesTable.id), + eq(messageRecipientsTable.recipientId, req.user!.id), ), ), ), ), ) - .groupBy(messages.receiverId), + .groupBy(messagesTable.receiverId), ), ) @@ -345,8 +356,8 @@ export const addGroupMembers: RequestHandler = async (req, res, next) => { const groupId = Number(req.params.groupId) const [group] = await db .select() - .from(groups) - .where(eq(groups.id, groupId)) + .from(groupsTable) + .where(eq(groupsTable.id, groupId)) .limit(1) if (!group) { @@ -378,15 +389,15 @@ export const addGroupMembers: RequestHandler = async (req, res, next) => { export const changeMemberRole: RequestHandler = async (req, res, next) => { try { const [member] = await db - .select({ role: members.role }) - .from(members) + .select({ role: membersTable.role }) + .from(membersTable) .where( and( - eq(members.userId, Number(req.params.userId)), - eq(members.groupId, Number(req.params.groupId)), + eq(membersTable.userId, Number(req.params.userId)), + eq(membersTable.groupId, Number(req.params.groupId)), ), ) - .innerJoin(users, eq(members.userId, users.id)) + .innerJoin(usersTable, eq(membersTable.userId, usersTable.id)) if (!member) { return notFound(res, 'Member') @@ -414,12 +425,12 @@ export const changeMemberRole: RequestHandler = async (req, res, next) => { if (isRoleChangePermissible) { await db - .update(members) + .update(membersTable) .set({ role: req.body.role }) .where( and( - eq(members.userId, Number(req.params.userId)), - eq(members.groupId, Number(req.params.groupId)), + eq(membersTable.userId, Number(req.params.userId)), + eq(membersTable.groupId, Number(req.params.groupId)), ), ) return res.json({ message: 'Role changed successfully' }) @@ -437,7 +448,7 @@ export const deleteGroup: RequestHandler = async (req, res, next) => { const groupId = Number(req.params.groupId) await db.transaction(async tx => { - await tx.delete(groups).where(eq(groups.id, groupId)) + await tx.delete(groupsTable).where(eq(groupsTable.id, groupId)) await deleteGroupRoles(groupId) }) @@ -467,17 +478,23 @@ export const leaveGroup: RequestHandler = async (req, res, next) => { await db.transaction(async tx => { if (req.member?.role === 'owner') { await tx - .update(members) + .update(membersTable) .set({ role: 'owner' }) .where( - and(eq(members.groupId, groupId), eq(members.userId, newOwnerId)), + and( + eq(membersTable.groupId, groupId), + eq(membersTable.userId, newOwnerId), + ), ) } await tx - .delete(members) + .delete(membersTable) .where( - and(eq(members.groupId, groupId), eq(members.userId, req.user!.id)), + and( + eq(membersTable.groupId, groupId), + eq(membersTable.userId, req.user!.id), + ), ) await deleteMemberRole(groupId, req.user!.id) }) @@ -503,8 +520,13 @@ export const kickMember: RequestHandler = async (req, res, next) => { return badRequest(res, 'Cannot kick yourself') } await db - .delete(members) - .where(and(eq(members.groupId, groupId), eq(members.userId, memberId))) + .delete(membersTable) + .where( + and( + eq(membersTable.groupId, groupId), + eq(membersTable.userId, memberId), + ), + ) await deleteMemberRole(groupId, memberId) // TODO: send socket io event to kicked member as well existing members const io = req.app.get('io') as TypedIOServer diff --git a/server/src/modules/groups/groups.schema.ts b/server/src/modules/groups/groups.schema.ts index bc69307..08d6b56 100644 --- a/server/src/modules/groups/groups.schema.ts +++ b/server/src/modules/groups/groups.schema.ts @@ -1,14 +1,14 @@ import { baseSchema } from '@/database/constants' -import { users } from '@/modules/users/users.schema' +import { usersTable } from '@/modules/users/users.schema' import { bigint, pgTable, varchar } from 'drizzle-orm/pg-core' -export const groups = pgTable('groups', { +export const groupsTable = pgTable('groups', { ...baseSchema, name: varchar('name', { length: 50 }).notNull(), ownerId: bigint('owner_id', { mode: 'number' }) .notNull() - .references(() => users.id), + .references(() => usersTable.id), }) -export type Group = typeof groups.$inferSelect -export type NewGroup = typeof groups.$inferInsert +export type Group = typeof groupsTable.$inferSelect +export type NewGroup = typeof groupsTable.$inferInsert diff --git a/server/src/modules/members/members.controller.ts b/server/src/modules/members/members.controller.ts index a3ec94d..39dfd5f 100644 --- a/server/src/modules/members/members.controller.ts +++ b/server/src/modules/members/members.controller.ts @@ -6,8 +6,8 @@ import { TypedIOServer } from '@/socket/socket.interface' import { badRequest, notFound } from '@/utils/api' import { and, asc, eq, getTableColumns, gt, like } from 'drizzle-orm' import { RequestHandler } from 'express' -import { users } from '../users/users.schema' -import { MemberRole, members } from './members.schema' +import { usersTable } from '../users/users.schema' +import { MemberRole, membersTable } from './members.schema' export const joinRooms: RequestHandler = async (req, res, next) => { try { @@ -17,7 +17,7 @@ export const joinRooms: RequestHandler = async (req, res, next) => { } const rows = await db - .insert(members) + .insert(membersTable) .values( (groupIds as number[]).map(groupId => ({ groupId: Number(groupId), @@ -63,20 +63,23 @@ export const getGroupMembers: RequestHandler = async (req, res, next) => { const { cursor, limit } = getPaginationParams(req.query) const result = await withPagination( db - .select({ ...getTableColumns(members), username: users.username }) - .from(members) - .innerJoin(users, eq(members.userId, users.id)) + .select({ + ...getTableColumns(membersTable), + username: usersTable.username, + }) + .from(membersTable) + .innerJoin(usersTable, eq(membersTable.userId, usersTable.id)) .$dynamic(), { limit, cursorSelect: 'username', - orderBy: [asc(users.username)], + orderBy: [asc(usersTable.username)], where: and( - eq(members.groupId, Number(req.params.groupId)), - cursor ? gt(users.username, cursor as string) : undefined, + eq(membersTable.groupId, Number(req.params.groupId)), + cursor ? gt(usersTable.username, cursor as string) : undefined, req.query.query - ? like(users.username, `%${req.query.query}%`) + ? like(usersTable.username, `%${req.query.query}%`) : undefined, ), }, @@ -105,18 +108,18 @@ export const getGroupMember: RequestHandler = async (req, res, next) => { try { const [member] = await db .select({ - ...getTableColumns(members), - fullName: users.fullName, - username: users.username, + ...getTableColumns(membersTable), + fullName: usersTable.fullName, + username: usersTable.username, }) - .from(members) + .from(membersTable) .where( and( - eq(members.userId, Number(req.params.userId)), - eq(members.groupId, Number(req.params.groupId)), + eq(membersTable.userId, Number(req.params.userId)), + eq(membersTable.groupId, Number(req.params.groupId)), ), ) - .innerJoin(users, eq(members.userId, users.id)) + .innerJoin(usersTable, eq(membersTable.userId, usersTable.id)) if (!member) { return notFound(res, 'Member') diff --git a/server/src/modules/members/members.schema.ts b/server/src/modules/members/members.schema.ts index 4f3a084..b25ce06 100644 --- a/server/src/modules/members/members.schema.ts +++ b/server/src/modules/members/members.schema.ts @@ -1,7 +1,7 @@ import { baseSchema } from '@/database/constants' import { bigint, index, pgEnum, pgTable, unique } from 'drizzle-orm/pg-core' -import { groups } from '../groups/groups.schema' -import { users } from '../users/users.schema' +import { groupsTable } from '../groups/groups.schema' +import { usersTable } from '../users/users.schema' // order of roles shows auth precedence export const memberRoleEnum = pgEnum('member_role', [ @@ -10,16 +10,16 @@ export const memberRoleEnum = pgEnum('member_role', [ 'owner', ]) -export const members = pgTable( +export const membersTable = pgTable( 'members', { ...baseSchema, userId: bigint('user_id', { mode: 'number' }) .notNull() - .references(() => users.id), + .references(() => usersTable.id), groupId: bigint('group_id', { mode: 'number' }) .notNull() - .references(() => groups.id, { onDelete: 'cascade' }), + .references(() => groupsTable.id, { onDelete: 'cascade' }), role: memberRoleEnum('role').notNull().default('member'), }, table => ({ @@ -31,6 +31,6 @@ export const members = pgTable( export const memberRoles = memberRoleEnum.enumValues -export type Member = typeof members.$inferSelect -export type NewMember = typeof members.$inferInsert +export type Member = typeof membersTable.$inferSelect +export type NewMember = typeof membersTable.$inferInsert export type MemberRole = Member['role'] diff --git a/server/src/modules/members/members.service.ts b/server/src/modules/members/members.service.ts index c08abc1..244017d 100644 --- a/server/src/modules/members/members.service.ts +++ b/server/src/modules/members/members.service.ts @@ -5,7 +5,12 @@ import { TypedIOServer } from '@/socket/socket.interface' import { and, eq } from 'drizzle-orm' import { NodePgDatabase } from 'drizzle-orm/node-postgres' import { Group } from '../groups/groups.schema' -import { MemberRole, NewMember, memberRoles, members } from './members.schema' +import { + MemberRole, + NewMember, + memberRoles, + membersTable, +} from './members.schema' export const checkPermission = async ( groupId: number, @@ -16,9 +21,11 @@ export const checkPermission = async ( if (!memberRole) { const [member] = await db - .select({ role: members.role }) - .from(members) - .where(and(eq(members.groupId, groupId), eq(members.userId, userId))) + .select({ role: membersTable.role }) + .from(membersTable) + .where( + and(eq(membersTable.groupId, groupId), eq(membersTable.userId, userId)), + ) .limit(1) if (!member) { @@ -47,7 +54,10 @@ export const addMembers = async ( role: mid === group.ownerId ? 'owner' : 'member', })) - const newMembers = await db.insert(members).values(memberValues).returning() + const newMembers = await db + .insert(membersTable) + .values(memberValues) + .returning() const memberRoles: Record = {} diff --git a/server/src/modules/messages/messages.controller.ts b/server/src/modules/messages/messages.controller.ts index 90499c7..48cba42 100644 --- a/server/src/modules/messages/messages.controller.ts +++ b/server/src/modules/messages/messages.controller.ts @@ -2,13 +2,13 @@ import { db } from '@/database' import { getPaginationParams, withPagination } from '@/database/helpers' import { and, desc, eq, getTableColumns, lt, or } from 'drizzle-orm' import { RequestHandler } from 'express' -import { users } from '../users/users.schema' -import { messages } from './messages.schema' +import { usersTable } from '../users/users.schema' +import { messagesTable } from './messages.schema' export const createMessage: RequestHandler = async (req, res, next) => { try { const [message] = await db - .insert(messages) + .insert(messagesTable) .values({ groupId: req.body.groupId, content: req.body.text, @@ -28,23 +28,26 @@ export const listMessages: RequestHandler = async (req, res, next) => { const { cursor, limit } = getPaginationParams(req.query, 'number') const result = await withPagination( db - .select({ ...getTableColumns(messages), username: users.username }) - .from(messages) - .innerJoin(users, eq(messages.senderId, users.id)) + .select({ + ...getTableColumns(messagesTable), + username: usersTable.username, + }) + .from(messagesTable) + .innerJoin(usersTable, eq(messagesTable.senderId, usersTable.id)) .$dynamic(), { limit, cursorSelect: 'id', - orderBy: [desc(messages.id)], + orderBy: [desc(messagesTable.id)], where: and( - groupId ? eq(messages.groupId, groupId) : undefined, + groupId ? eq(messagesTable.groupId, groupId) : undefined, partnerId ? or( - eq(messages.receiverId, partnerId), - eq(messages.senderId, partnerId), + eq(messagesTable.receiverId, partnerId), + eq(messagesTable.senderId, partnerId), ) : undefined, - cursor ? lt(messages.id, cursor as number) : undefined, + cursor ? lt(messagesTable.id, cursor as number) : undefined, ), }, ) diff --git a/server/src/modules/messages/messages.schema.ts b/server/src/modules/messages/messages.schema.ts index e075439..88df2aa 100644 --- a/server/src/modules/messages/messages.schema.ts +++ b/server/src/modules/messages/messages.schema.ts @@ -1,20 +1,20 @@ import { baseSchema } from '@/database/constants' import { bigint, index, pgTable, text, unique } from 'drizzle-orm/pg-core' -import { groups } from '../groups/groups.schema' -import { users } from '../users/users.schema' +import { groupsTable } from '../groups/groups.schema' +import { usersTable } from '../users/users.schema' -export const messages = pgTable( +export const messagesTable = pgTable( 'messages', { ...baseSchema, senderId: bigint('sender_id', { mode: 'number' }) - .references(() => users.id) + .references(() => usersTable.id) .notNull(), receiverId: bigint('receiver_id', { mode: 'number' }).references( - () => users.id, + () => usersTable.id, ), groupId: bigint('group_id', { mode: 'number' }).references( - () => groups.id, + () => groupsTable.id, { onDelete: 'cascade' }, ), content: text('content').notNull(), @@ -25,15 +25,15 @@ export const messages = pgTable( }), ) -export const messageRecipients = pgTable( +export const messageRecipientsTable = pgTable( 'message_recipients', { ...baseSchema, messageId: bigint('message_id', { mode: 'number' }) - .references(() => messages.id, { onDelete: 'cascade' }) + .references(() => messagesTable.id, { onDelete: 'cascade' }) .notNull(), recipientId: bigint('recipient_id', { mode: 'number' }) - .references(() => users.id) + .references(() => usersTable.id) .notNull(), }, table => ({ @@ -44,5 +44,5 @@ export const messageRecipients = pgTable( }), ) -export type Message = typeof messages.$inferSelect -export type NewMessage = typeof messages.$inferInsert +export type Message = typeof messagesTable.$inferSelect +export type NewMessage = typeof messagesTable.$inferInsert diff --git a/server/src/modules/messages/messages.service.ts b/server/src/modules/messages/messages.service.ts index a3a5814..8c6d03a 100644 --- a/server/src/modules/messages/messages.service.ts +++ b/server/src/modules/messages/messages.service.ts @@ -1,9 +1,9 @@ import { db } from '@/database' import { and, eq, isNull } from 'drizzle-orm' -import { groups } from '../groups/groups.schema' +import { groupsTable } from '../groups/groups.schema' import { checkPermission } from '../members/members.service' -import { users } from '../users/users.schema' -import { messageRecipients, messages } from './messages.schema' +import { usersTable } from '../users/users.schema' +import { messageRecipientsTable, messagesTable } from './messages.schema' export const insertMessage = async ({ groupId, @@ -23,22 +23,22 @@ export const insertMessage = async ({ throw new Error('createMessage: Not authorized') } const [group] = await db - .select({ name: groups.name }) - .from(groups) - .where(eq(groups.id, groupId)) + .select({ name: groupsTable.name }) + .from(groupsTable) + .where(eq(groupsTable.id, groupId)) chatName = group.name } if (receiverId) { const [receiver] = await db - .select({ username: users.username }) - .from(users) - .where(eq(users.id, receiverId)) + .select({ username: usersTable.username }) + .from(usersTable) + .where(eq(usersTable.id, receiverId)) chatName = receiver.username } const [message] = await db - .insert(messages) + .insert(messagesTable) .values({ groupId, receiverId, @@ -55,12 +55,12 @@ export const markMessageAsRead = async ( ) => { const [message] = await db .select({ - senderId: messages.senderId, - receiverId: messages.receiverId, - groupId: messages.groupId, + senderId: messagesTable.senderId, + receiverId: messagesTable.receiverId, + groupId: messagesTable.groupId, }) - .from(messages) - .where(eq(messages.id, messageId)) + .from(messagesTable) + .where(eq(messagesTable.id, messageId)) .limit(1) if (!message.groupId && !message.receiverId) { throw new Error( @@ -83,7 +83,7 @@ export const markMessageAsRead = async ( } await db - .insert(messageRecipients) + .insert(messageRecipientsTable) .values({ messageId, recipientId, @@ -118,25 +118,25 @@ export const markChatMessagesAsRead = async ({ } const unreadMessages = await db - .select({ messageId: messages.id, senderId: messages.senderId }) - .from(messages) + .select({ messageId: messagesTable.id, senderId: messagesTable.senderId }) + .from(messagesTable) .leftJoin( - messageRecipients, + messageRecipientsTable, and( - eq(messageRecipients.messageId, messages.id), - eq(messageRecipients.recipientId, recipientId), + eq(messageRecipientsTable.messageId, messagesTable.id), + eq(messageRecipientsTable.recipientId, recipientId), ), ) .where( and( - groupId ? eq(messages.groupId, groupId) : undefined, - receiverId ? eq(messages.receiverId, receiverId) : undefined, - isNull(messageRecipients.messageId), + groupId ? eq(messagesTable.groupId, groupId) : undefined, + receiverId ? eq(messagesTable.receiverId, receiverId) : undefined, + isNull(messageRecipientsTable.messageId), ), ) if (unreadMessages.length) { - await db.insert(messageRecipients).values( + await db.insert(messageRecipientsTable).values( unreadMessages.map(message => ({ messageId: message.messageId, recipientId, diff --git a/server/src/modules/users/users.controller.ts b/server/src/modules/users/users.controller.ts index 8724b39..fc41476 100644 --- a/server/src/modules/users/users.controller.ts +++ b/server/src/modules/users/users.controller.ts @@ -5,16 +5,16 @@ import { removeAttrFromObject } from '@/utils/object' import { hash, verify } from 'argon2' import { and, eq, getTableColumns, like, ne } from 'drizzle-orm' import { RequestHandler } from 'express' -import { users } from './users.schema' +import { usersTable } from './users.schema' export const signUpUser: RequestHandler = async (req, res, next) => { try { const { username, password, fullName } = req.body console.log('req.body', req.body) const rows = await db - .select({ username: users.username }) - .from(users) - .where(eq(users.username, username)) + .select({ username: usersTable.username }) + .from(usersTable) + .where(eq(usersTable.username, username)) .limit(1) if (rows.length) { @@ -24,13 +24,13 @@ export const signUpUser: RequestHandler = async (req, res, next) => { const hashedPassword = await hash(password) const [user] = await db - .insert(users) + .insert(usersTable) .values({ username, fullName, password: hashedPassword }) .returning({ - id: users.id, - username: users.username, - fullName: users.fullName, - createdAt: users.createdAt, + id: usersTable.id, + username: usersTable.username, + fullName: usersTable.fullName, + createdAt: usersTable.createdAt, }) const accessToken = await signTokens(res, { @@ -50,8 +50,8 @@ export const loginUser: RequestHandler = async (req, res, next) => { const { username, password } = req.body const [user] = await db .select() - .from(users) - .where(eq(users.username, username)) + .from(usersTable) + .where(eq(usersTable.username, username)) .limit(1) if (!user) { @@ -82,18 +82,18 @@ export const loginUser: RequestHandler = async (req, res, next) => { export const getUsers: RequestHandler = async (req, res, next) => { try { // eslint-disable-next-line @typescript-eslint/no-unused-vars - const { password, ...columns } = getTableColumns(users) + const { password, ...columns } = getTableColumns(usersTable) const rows = await db .select(columns) - .from(users) + .from(usersTable) .where( and( - like(users.username, `%${req.query.query}%`), - ne(users.id, req.user!.id), + like(usersTable.username, `%${req.query.query}%`), + ne(usersTable.id, req.user!.id), ), ) .limit(Number(req.query.limit) || 5) - .orderBy(users.username) + .orderBy(usersTable.username) res.json(rows) } catch (error) { @@ -104,12 +104,12 @@ export const getUsers: RequestHandler = async (req, res, next) => { export const getUser: RequestHandler = async (req, res, next) => { try { // eslint-disable-next-line @typescript-eslint/no-unused-vars - const { password, ...columns } = getTableColumns(users) + const { password, ...columns } = getTableColumns(usersTable) const [user] = await db .select(columns) - .from(users) - .where(eq(users.id, Number(req.params.userId))) + .from(usersTable) + .where(eq(usersTable.id, Number(req.params.userId))) .limit(1) if (!user) { return notFound(res, 'User') diff --git a/server/src/modules/users/users.schema.ts b/server/src/modules/users/users.schema.ts index af39354..799c2d6 100644 --- a/server/src/modules/users/users.schema.ts +++ b/server/src/modules/users/users.schema.ts @@ -2,7 +2,7 @@ import { baseSchema } from '@/database/constants' import { sql } from 'drizzle-orm' import { pgTable, timestamp, varchar } from 'drizzle-orm/pg-core' -export const users = pgTable('users', { +export const usersTable = pgTable('users', { ...baseSchema, username: varchar('username', { length: 40 }).unique().notNull(), password: varchar('password').notNull(), @@ -12,5 +12,5 @@ export const users = pgTable('users', { .default(sql`now()`), }) -export type User = typeof users.$inferSelect -export type NewUser = typeof users.$inferInsert +export type User = typeof usersTable.$inferSelect +export type NewUser = typeof usersTable.$inferInsert diff --git a/server/src/scripts/seed.ts b/server/src/scripts/seed.ts index 229849e..9269680 100644 --- a/server/src/scripts/seed.ts +++ b/server/src/scripts/seed.ts @@ -1,8 +1,8 @@ import { connectDB, db } from '@/database' -import { NewGroup, groups } from '@/modules/groups/groups.schema' -import { NewMember, members } from '@/modules/members/members.schema' -import { NewMessage, messages } from '@/modules/messages/messages.schema' -import { NewUser, users } from '@/modules/users/users.schema' +import { NewGroup, groupsTable } from '@/modules/groups/groups.schema' +import { NewMember, membersTable } from '@/modules/members/members.schema' +import { NewMessage, messagesTable } from '@/modules/messages/messages.schema' +import { NewUser, usersTable } from '@/modules/users/users.schema' import { faker } from '@faker-js/faker' import { hash } from 'argon2' import 'colors' @@ -22,10 +22,10 @@ async function seedDatabase() { console.time('seed') console.log('Dropping tables'.yellow.bold) - await db.delete(messages) - await db.delete(members) - await db.delete(groups) - await db.delete(users) + await db.delete(messagesTable) + await db.delete(membersTable) + await db.delete(groupsTable) + await db.delete(usersTable) console.log('Seed started'.blue.bold) @@ -41,10 +41,12 @@ async function seedDatabase() { fullName: faker.person.fullName(), }) } - await db.insert(users).values(userValues) + await db.insert(usersTable).values(userValues) } - const insertedUsers = await db.select({ id: users.id }).from(users) + const insertedUsers = await db + .select({ id: usersTable.id }) + .from(usersTable) // Batch insert groups for (let i = 0; i < USER_COUNT * GROUP_COUNT_PER_USER; i += BATCH_SIZE) { @@ -60,12 +62,12 @@ async function seedDatabase() { ownerId: insertedUsers[userIndex].id, }) } - await db.insert(groups).values(groupValues) + await db.insert(groupsTable).values(groupValues) } const insertedGroups = await db - .select({ id: groups.id, ownerId: groups.ownerId }) - .from(groups) + .select({ id: groupsTable.id, ownerId: groupsTable.ownerId }) + .from(groupsTable) // Batch insert members and messages for (let i = 0; i < insertedGroups.length; i++) { @@ -107,9 +109,11 @@ async function seedDatabase() { // Insert members and messages in batches for (let k = 0; k < memberValues.length; k += BATCH_SIZE) { - await db.insert(members).values(memberValues.slice(k, k + BATCH_SIZE)) await db - .insert(messages) + .insert(membersTable) + .values(memberValues.slice(k, k + BATCH_SIZE)) + await db + .insert(messagesTable) .values( messageValues.slice( k * MESSAGE_PER_MEMBER, diff --git a/server/src/socket/events.ts b/server/src/socket/events.ts index b817c5c..d78f71b 100644 --- a/server/src/socket/events.ts +++ b/server/src/socket/events.ts @@ -1,6 +1,6 @@ import { db } from '@/database' -import { groups } from '@/modules/groups/groups.schema' -import { members } from '@/modules/members/members.schema' +import { groupsTable } from '@/modules/groups/groups.schema' +import { membersTable } from '@/modules/members/members.schema' import { insertMessage, markChatMessagesAsRead, @@ -42,10 +42,10 @@ export const registerSocketEvents = (io: TypedIOServer) => { socket.broadcast.emit('userOnline', socket.data.user.id) const userGroups = await db - .select({ id: groups.id }) - .from(groups) - .innerJoin(members, eq(members.groupId, groups.id)) - .where(eq(members.userId, socket.data.user.id)) + .select({ id: groupsTable.id }) + .from(groupsTable) + .innerJoin(membersTable, eq(membersTable.groupId, groupsTable.id)) + .where(eq(membersTable.userId, socket.data.user.id)) socket.join(roomKeys.USER_KEY(socket.data.user.id)) socket.join(userGroups.map(group => roomKeys.GROUP_KEY(group.id)))