import { Injectable } from "@nestjs/common"; import { InjectRepository } from "@nestjs/typeorm"; import { Brackets, IsNull, Not, Repository } from "typeorm"; import { SubscriptionStatus } from "../../subscriptions/enums/subscription-status.enum"; import { PaginationUtils } from "../../utils/providers/pagination.utils"; import { DanakServicesGlobalSearchDto, DanakServicesQueryDto, DanakServicesSearchQueryDto } from "../DTO/danak-services-search-query.dto"; import { DanakService } from "../entities/danak-service.entity"; import { ReviewStatus } from "../enums/review-status.enum"; @Injectable() export class DanakServicesRepository extends Repository { constructor(@InjectRepository(DanakService) danakServicesRepository: Repository) { super(danakServicesRepository.target, danakServicesRepository.manager, danakServicesRepository.queryRunner); } async findOneByName(name: string, id?: string): Promise { return this.findOneBy({ name, deletedAt: IsNull(), ...(id && { id: Not(id) }) }); } async findServiceById(id: string): Promise { return this.findOneBy({ id, deletedAt: IsNull() }); } //+******************** async getServicesForAdmin(queryDto: DanakServicesSearchQueryDto) { const { limit, skip } = PaginationUtils(queryDto); const queryBuilder = this.createQueryBuilder("service") .leftJoinAndSelect("service.category", "category") .loadRelationCountAndMap("service.subscriptionCount", "service.subscriptionPlans") .orderBy("service.createdAt", "DESC") .where("service.deletedAt IS NULL") .skip(skip) .take(limit); if (queryDto.isActive) { queryBuilder.andWhere("service.isActive = :isActive", { isActive: queryDto.isActive === 1 }); } if (queryDto.isDanakSuggest) { queryBuilder.andWhere("service.isDanakSuggest = :isDanakSuggest", { isDanakSuggest: queryDto.isDanakSuggest === 1 }); } if (queryDto.categoryId) { queryBuilder.andWhere("service.categoryId = :categoryId", { categoryId: queryDto.categoryId }); } if (queryDto.q) { queryBuilder.andWhere( new Brackets((qb) => { qb.where("service.name LIKE :q", { q: `%${queryDto.q}%` }) .orWhere("service.description LIKE :q", { q: `%${queryDto.q}%` }) .orWhere("service.softwareLanguage LIKE :q", { q: `%${queryDto.q}%` }) .orWhere("service.author LIKE :q", { q: `%${queryDto.q}%` }); }), ); } const [services, count] = await queryBuilder.getManyAndCount(); return { services, count, }; } //+******************** async getServicesForUser(queryDto: DanakServicesQueryDto) { const { limit, skip } = PaginationUtils(queryDto); const queryBuilder = this.createQueryBuilder("service"); queryBuilder .innerJoin("service.subscriptionPlans", "subscriptionPlans", "subscriptionPlans.isActive = :isActive", { isActive: true }) .leftJoinAndSelect("service.category", "category") .where("service.isActive = :isActive", { isActive: true }) .andWhere("service.deletedAt IS NULL") // .andWhere("service.isDanakSuggest = :isDanakSuggest", { isDanakSuggest: true }) .orderBy("service.createdAt", "DESC") .skip(skip) .take(limit); if (queryDto.categoryId) { queryBuilder.andWhere("service.categoryId = :categoryId", { categoryId: queryDto.categoryId }); } const [services, count] = await queryBuilder.getManyAndCount(); return { services, count, }; } //+******************** async getDanakServiceById(serviceId: string, isAdmin: boolean) { const serviceQueryBuilder = this.createQueryBuilder("service") .where("service.deletedAt IS NULL") .leftJoin("service.category", "category") .addSelect(["category.id", "category.title"]) .leftJoinAndSelect("service.images", "images") .leftJoinAndSelect("service.subscriptionPlans", "subscriptionPlans") .leftJoinAndSelect("subscriptionPlans.directDiscount", "directDiscount", "directDiscount.id IS NOT NULL") .leftJoin("service.reviews", "reviews", "reviews.status = :reviewStatus", { reviewStatus: ReviewStatus.APPROVED }) .leftJoin("reviews.user", "user") .addSelect([ "reviews.id", "reviews.comment", "reviews.rating", "reviews.title", "reviews.createdAt", "reviews.status", "user.id", "user.firstName", "user.lastName", "user.profilePic", ]) // .loadRelationCountAndMap("service.reviewCount", "service.reviews") // .addSelect( // (subQuery) => // subQuery // .select("CAST(AVG(rating) AS DECIMAL(10,2))", "averageRating") // .from(DanakServiceReview, "r") // .where("r.serviceId = service.id") // .andWhere("r.status = :reviewStatus", { reviewStatus: ReviewStatus.APPROVED }), // "averageRating", // ) .andWhere("service.id = :serviceId", { serviceId }) .groupBy("service.id,category.id, images.id, subscriptionPlans.id, reviews.id, user.id, directDiscount.id"); if (!isAdmin) { serviceQueryBuilder .andWhere("service.isActive = :isActive", { isActive: true }) .andWhere("subscriptionPlans.isActive = :planActive", { planActive: true }); } serviceQueryBuilder.orderBy("subscriptionPlans.price", "ASC"); return serviceQueryBuilder.getOne(); } //+******************** async getServiceBySlug(slug: string, isAdmin: boolean) { const serviceQueryBuilder = this.createQueryBuilder("service") .where("service.deletedAt IS NULL") .leftJoin("service.category", "category") .addSelect(["category.id", "category.title"]) .leftJoinAndSelect("service.images", "images") .leftJoinAndSelect("service.subscriptionPlans", "subscriptionPlans") .leftJoinAndSelect("subscriptionPlans.directDiscount", "directDiscount", "directDiscount.id IS NOT NULL") .leftJoin("service.reviews", "reviews", "reviews.status = :reviewStatus", { reviewStatus: ReviewStatus.APPROVED }) .leftJoin("reviews.user", "user") .addSelect([ "reviews.id", "reviews.comment", "reviews.rating", "reviews.title", "reviews.createdAt", "reviews.status", "user.id", "user.firstName", "user.lastName", "user.profilePic", ]) // .loadRelationCountAndMap("service.reviewCount", "service.reviews") // .addSelect( // (subQuery) => // subQuery // .select("CAST(AVG(rating) AS DECIMAL(10,2))", "averageRating") // .from(DanakServiceReview, "r") // .where("r.serviceId = service.id") // .andWhere("r.status = :reviewStatus", { reviewStatus: ReviewStatus.APPROVED }), // "averageRating", // ) .andWhere("service.slug = :slug", { slug }) .groupBy("service.id,category.id, images.id, subscriptionPlans.id, reviews.id, user.id, directDiscount.id"); if (!isAdmin) { serviceQueryBuilder .andWhere("service.isActive = :isActive", { isActive: true }) .andWhere("subscriptionPlans.isActive = :planActive", { planActive: true }); } serviceQueryBuilder.orderBy("subscriptionPlans.price", "ASC"); return serviceQueryBuilder.getOne(); } //+******************** async getUsersByService(serviceId: string) { const users = await this.createQueryBuilder("service") .innerJoin("service.subscriptionPlans", "subscriptionPlans") .innerJoin("subscriptionPlans.userSubscriptions", "userSubscriptions") .innerJoin("user", "user", "userSubscriptions.userId = user.id") .select([ "DISTINCT user.id AS id", "user.firstName AS firstName", "user.lastName AS lastName", "user.email AS email", "user.profilePic AS profilePic", ]) .where("service.id = :serviceId", { serviceId }) .andWhere("userSubscriptions.status = :status", { status: SubscriptionStatus.ACTIVE }) .andWhere("userSubscriptions.endDate > NOW()") .getRawMany(); return users; } async getDanakSuggestServices() { return this.find({ where: { isDanakSuggest: true, isActive: true, deletedAt: IsNull(), category: { isActive: true, deletedAt: IsNull() } }, relations: { category: true }, select: { id: true, name: true, title: true, description: true, slug: true, coverUrl: true, userCount: true, createDate: true, icon: true, createdAt: true, isActive: true, isDanakSuggest: true, metaDescription: true, category: { id: true, title: true, }, }, order: { createdAt: "DESC" }, withDeleted: false, }); } async searchServices(queryDto: DanakServicesGlobalSearchDto) { const servicesQuery = this.createQueryBuilder("service") .leftJoin("service.category", "category") .leftJoin("service.subscriptionPlans", "subscriptionPlans") .select(["service.id", "service.name", "service.description", "service.icon", "category.id", "category.title"]) .where("service.isActive = :isActive", { isActive: true }) .andWhere("service.deletedAt IS NULL") .andWhere("category.isActive = :categoryActive", { categoryActive: true }) .andWhere("category.deletedAt IS NULL") .andWhere("subscriptionPlans.isActive = :planActive", { planActive: true }); if (queryDto.q) { servicesQuery.andWhere("service.name ILIKE :searchQuery", { searchQuery: `%${queryDto.q}%` }); } return servicesQuery.getMany(); } }