import { db } from '../../db/db_index' import { coupons, couponApplicableUsers, couponApplicableProducts, reservedCoupons, users, orders, orderStatus } from '../../db/schema' import { eq, and, like, or, inArray, lt, asc } from 'drizzle-orm' import { ICouponDbService, Coupon, NewCoupon, ReservedCoupon, NewReservedCoupon, CouponWithRelations } from '../../../../backend/src/trpc/apis/admin-apis/dataAccessors/interfaces/coupon-db-service.interface' export class CouponDbService implements ICouponDbService { async createCoupon(data: NewCoupon): Promise { const [coupon] = await db.insert(coupons).values(data).returning() return coupon } async getCouponById(id: number): Promise { const result = await db.query.coupons.findFirst({ where: eq(coupons.id, id), with: { creator: true, applicableUsers: { with: { user: true } }, applicableProducts: { with: { product: true } }, }, }) if (!result) return undefined return { ...result, productIds: (result.productIds as number[] | null) || null, } as CouponWithRelations } async getCouponByCode(code: string): Promise { return db.query.coupons.findFirst({ where: eq(coupons.couponCode, code), }) } async getAllCoupons(options: { cursor?: number; limit: number; search?: string }): Promise { const { cursor, limit, search } = options let whereCondition = undefined const conditions = [] if (cursor) { conditions.push(lt(coupons.id, cursor)) } if (search && search.trim()) { conditions.push(like(coupons.couponCode, `%${search}%`)) } if (conditions.length > 0) { whereCondition = and(...conditions) } const result = await db.query.coupons.findMany({ where: whereCondition, with: { creator: true, applicableUsers: { with: { user: true } }, applicableProducts: { with: { product: true } }, }, orderBy: (coupons, { desc }) => [desc(coupons.createdAt)], limit: limit + 1, }) return result.map((coupon) => ({ ...coupon, productIds: (coupon.productIds as number[] | null) || null, })) as CouponWithRelations[] } async updateCoupon(id: number, data: Partial): Promise { const [coupon] = await db.update(coupons).set(data).where(eq(coupons.id, id)).returning() return coupon } async invalidateCoupon(id: number): Promise { const [coupon] = await db.update(coupons).set({ isInvalidated: true }).where(eq(coupons.id, id)).returning() return coupon } async addApplicableUsers(couponId: number, userIds: number[]): Promise { await db.insert(couponApplicableUsers).values( userIds.map(userId => ({ couponId, userId })) ) } async addApplicableProducts(couponId: number, productIds: number[]): Promise { await db.insert(couponApplicableProducts).values( productIds.map(productId => ({ couponId, productId })) ) } async removeAllApplicableUsers(couponId: number): Promise { await db.delete(couponApplicableUsers).where(eq(couponApplicableUsers.couponId, couponId)) } async removeAllApplicableProducts(couponId: number): Promise { await db.delete(couponApplicableProducts).where(eq(couponApplicableProducts.couponId, couponId)) } async countApplicableUsers(couponId: number): Promise { return db.$count(couponApplicableUsers, eq(couponApplicableUsers.couponId, couponId)) } async createReservedCoupon(data: NewReservedCoupon): Promise { const [coupon] = await db.insert(reservedCoupons).values(data).returning() return coupon } async getReservedCoupons(options: { cursor?: number; limit: number; search?: string }): Promise { const { cursor, limit, search } = options let whereCondition = undefined const conditions = [] if (cursor) { conditions.push(lt(reservedCoupons.id, cursor)) } if (search && search.trim()) { conditions.push(or( like(reservedCoupons.secretCode, `%${search}%`), like(reservedCoupons.couponCode, `%${search}%`) )) } if (conditions.length > 0) { whereCondition = and(...conditions) } return db.query.reservedCoupons.findMany({ where: whereCondition, with: { redeemedUser: true, creator: true }, orderBy: (reservedCoupons, { desc }) => [desc(reservedCoupons.createdAt)], limit: limit + 1, }) } async getUsersByIds(ids: number[]): Promise> { return db.query.users.findMany({ where: inArray(users.id, ids), columns: { id: true, name: true, mobile: true }, }) } async getUsersBySearch(search: string, limit: number, offset: number): Promise> { const whereCondition = or( like(users.name, `%${search}%`), like(users.mobile, `%${search}%`) ) return db.query.users.findMany({ where: whereCondition, columns: { id: true, name: true, mobile: true }, limit, offset, orderBy: (users, { asc }) => [asc(users.name)], }) } async createUser(data: Partial): Promise { const [user] = await db.insert(users).values(data).returning() return user } async getUserByMobile(mobile: string): Promise { return db.query.users.findFirst({ where: eq(users.mobile, mobile), }) } async getOrderByIdWithUserAndStatus(id: number): Promise { return db.query.orders.findFirst({ where: eq(orders.id, id), with: { user: true, orderStatus: true, }, }) } async updateOrderStatusRefundCoupon(orderId: number, couponId: number): Promise { await db.update(orderStatus) .set({ refundCouponId: couponId }) .where(eq(orderStatus.orderId, orderId)) } async withTransaction(fn: (tx: any) => Promise): Promise { return db.transaction(fn) } } export const couponDbService: ICouponDbService = new CouponDbService()