From 0e02e79a131dc39c22c001b70af648460e5b5574 Mon Sep 17 00:00:00 2001 From: rcole1919 Date: Mon, 14 Oct 2024 22:07:28 +0400 Subject: [PATCH] add services --- src/shared/constants/index.ts | 1 + src/shared/constants/offer.ts | 2 + .../comment/default-comment.service.ts | 10 ++--- .../modules/comment/dto/update-comment.dto.ts | 3 ++ src/shared/modules/comment/index.ts | 1 + .../types/comment-service.interface.ts | 4 +- .../modules/offer/default-offer.service.ts | 22 ++++++++-- .../modules/offer/dto/update-offer.dto.ts | 27 ++++++------ src/shared/modules/offer/index.ts | 1 + src/shared/modules/offer/offer.aggregation.ts | 43 +++++++++++++++++++ .../offer/types/offer-service.interface.ts | 1 + .../modules/user/default-user.service.ts | 29 ++++++++++++- .../modules/user/dto/update-user.dto.ts | 9 ++++ src/shared/modules/user/index.ts | 2 + .../user/types/user-service.interface.ts | 5 ++- src/shared/modules/user/user.aggregation.ts | 8 ++++ 16 files changed, 140 insertions(+), 28 deletions(-) create mode 100644 src/shared/modules/comment/dto/update-comment.dto.ts create mode 100644 src/shared/modules/offer/offer.aggregation.ts create mode 100644 src/shared/modules/user/dto/update-user.dto.ts create mode 100644 src/shared/modules/user/user.aggregation.ts diff --git a/src/shared/constants/index.ts b/src/shared/constants/index.ts index 1113170..56968eb 100644 --- a/src/shared/constants/index.ts +++ b/src/shared/constants/index.ts @@ -6,6 +6,7 @@ export { ROOMS_NUMBER, PRICE, DEFAULT_OFFER_COUNT, + INC_COMMENT_COUNT_NUMBER, } from './offer.js'; export { diff --git a/src/shared/constants/offer.ts b/src/shared/constants/offer.ts index 91b5b4f..0abb661 100644 --- a/src/shared/constants/offer.ts +++ b/src/shared/constants/offer.ts @@ -31,3 +31,5 @@ export const OFFER_RATING = { }; export const DEFAULT_OFFER_COUNT = 60; + +export const INC_COMMENT_COUNT_NUMBER = 1; diff --git a/src/shared/modules/comment/default-comment.service.ts b/src/shared/modules/comment/default-comment.service.ts index 502614e..c64600e 100644 --- a/src/shared/modules/comment/default-comment.service.ts +++ b/src/shared/modules/comment/default-comment.service.ts @@ -2,7 +2,7 @@ import { DocumentType, types } from '@typegoose/typegoose'; import { inject, injectable } from 'inversify'; import { ICommentService } from './types/index.js'; -import { CommentEntity, CreateCommentDTO } from './index.js'; +import { CommentEntity, CreateCommentDTO, UpdateCommentDTO } from './index.js'; import { COMPONENT, DEFAULT_COMMENTS_COUNT } from '../../constants/index.js'; import { ILogger } from '../../libs/logger/types/index.js'; import { ESortType } from '../../types/sort-type.enum.js'; @@ -30,11 +30,9 @@ export class DefaultCommentService implements ICommentService { .exec(); } - public async deleteByOfferId(offerId: string): Promise { - const result = await this.commentModel - .deleteMany({ offerId }) + public async updateRating(offerId: string, dto: UpdateCommentDTO): Promise | null> { + return this.commentModel + .findByIdAndUpdate(offerId, dto, { new: true }) .exec(); - - return result.deletedCount; } } diff --git a/src/shared/modules/comment/dto/update-comment.dto.ts b/src/shared/modules/comment/dto/update-comment.dto.ts new file mode 100644 index 0000000..9d9bda5 --- /dev/null +++ b/src/shared/modules/comment/dto/update-comment.dto.ts @@ -0,0 +1,3 @@ +export class UpdateCommentDTO { + public rating!: number; +} diff --git a/src/shared/modules/comment/index.ts b/src/shared/modules/comment/index.ts index 332abe0..f129a2d 100644 --- a/src/shared/modules/comment/index.ts +++ b/src/shared/modules/comment/index.ts @@ -1,4 +1,5 @@ export { CommentEntity, CommentModel } from './comment.entity.js'; export { CreateCommentDTO } from './dto/create-comment.dto.js'; +export { UpdateCommentDTO } from './dto/update-comment.dto.js'; export { DefaultCommentService } from './default-comment.service.js'; export { createCommentContainer } from './comment.container.js'; diff --git a/src/shared/modules/comment/types/comment-service.interface.ts b/src/shared/modules/comment/types/comment-service.interface.ts index 94b0ec3..bdea7e0 100644 --- a/src/shared/modules/comment/types/comment-service.interface.ts +++ b/src/shared/modules/comment/types/comment-service.interface.ts @@ -1,9 +1,9 @@ import { DocumentType } from '@typegoose/typegoose'; -import { CreateCommentDTO, CommentEntity } from '../index.js'; +import { CreateCommentDTO, CommentEntity, UpdateCommentDTO } from '../index.js'; export interface ICommentService { create(dto: CreateCommentDTO): Promise>; findByOfferId(offerId: string): Promise[]>; - deleteByOfferId(offerId: string): Promise; + updateRating(offerId: string, dto: UpdateCommentDTO): Promise | null>; } diff --git a/src/shared/modules/offer/default-offer.service.ts b/src/shared/modules/offer/default-offer.service.ts index 3866ad9..22b47ac 100644 --- a/src/shared/modules/offer/default-offer.service.ts +++ b/src/shared/modules/offer/default-offer.service.ts @@ -2,8 +2,15 @@ import { DocumentType, types } from '@typegoose/typegoose'; import { inject, injectable } from 'inversify'; import { IOfferService } from './types/index.js'; -import { OfferEntity, CreateOfferDTO, UpdateOfferDTO } from './index.js'; -import { COMPONENT, DEFAULT_OFFER_COUNT } from '../../constants/index.js'; +import { + OfferEntity, + CreateOfferDTO, + UpdateOfferDTO, + populateAuthor, + populateCommentsCount, + populateComments, +} from './index.js'; +import { COMPONENT, DEFAULT_OFFER_COUNT, INC_COMMENT_COUNT_NUMBER } from '../../constants/index.js'; import { ILogger } from '../../libs/logger/types/index.js'; import { ESortType } from '../../types/index.js'; @@ -24,7 +31,7 @@ export class DefaultOfferService implements IOfferService { public async findById(offerId: string): Promise | null> { return this.offerModel .findById(offerId) - .populate('authorId') + .aggregate([populateAuthor, ...populateComments]) .exec(); } @@ -35,7 +42,7 @@ export class DefaultOfferService implements IOfferService { .find() .sort({ createdDate: ESortType.DESC }) .limit(limit) - .populate('authorId') + .aggregate([populateAuthor, ...populateCommentsCount]) .exec(); } @@ -49,4 +56,11 @@ export class DefaultOfferService implements IOfferService { .findByIdAndDelete(offerId) .exec(); } + + public async incCommentCount(offerId: string): Promise | null> { + return this.offerModel + .findByIdAndUpdate(offerId, {'$inc': { + commentCount: INC_COMMENT_COUNT_NUMBER, + }}).exec(); + } } diff --git a/src/shared/modules/offer/dto/update-offer.dto.ts b/src/shared/modules/offer/dto/update-offer.dto.ts index f377c57..d871f1f 100644 --- a/src/shared/modules/offer/dto/update-offer.dto.ts +++ b/src/shared/modules/offer/dto/update-offer.dto.ts @@ -1,17 +1,18 @@ import { EHousing, EFacilities, TCoords } from '../../../types/index.js'; export class UpdateOfferDTO { - public title!: string; - public description!: string; - public createdDate!: Date; - public city!: string; - public previewImagePath!: string; - public photos!: string[]; - public isPremium!: boolean; - public housingType!: EHousing; - public roomsNumber!: number; - public visitorsNumber!: number; - public price!: number; - public facilities!: EFacilities[]; - public coords!: TCoords; + public title?: string; + public description?: string; + public createdDate?: Date; + public city?: string; + public previewImagePath?: string; + public photos?: string[]; + public isPremium?: boolean; + public housingType?: EHousing; + public roomsNumber?: number; + public visitorsNumber?: number; + public price?: number; + public facilities?: EFacilities[]; + public coords?: TCoords; + public rating?: number; } diff --git a/src/shared/modules/offer/index.ts b/src/shared/modules/offer/index.ts index 38b8dec..6a41186 100644 --- a/src/shared/modules/offer/index.ts +++ b/src/shared/modules/offer/index.ts @@ -3,3 +3,4 @@ export { CreateOfferDTO } from './dto/create-offer.dto.js'; export { UpdateOfferDTO } from './dto/update-offer.dto.js'; export { DefaultOfferService } from './default-offer.service.js'; export { createOfferContainer } from './offer.container.js'; +export { populateAuthor, populateComments, populateCommentsCount } from './offer.aggregation.js'; diff --git a/src/shared/modules/offer/offer.aggregation.ts b/src/shared/modules/offer/offer.aggregation.ts new file mode 100644 index 0000000..e320cb8 --- /dev/null +++ b/src/shared/modules/offer/offer.aggregation.ts @@ -0,0 +1,43 @@ +import { DEFAULT_COMMENTS_COUNT } from '../../constants/index.js'; +import { ESortType } from '../../types/index.js'; + +export const populateAuthor = { + $lookup: { + from: 'users', + localField: 'authorId', + foreignField: '_id', + as: 'author', + }, +}; + +export const populateCommentsCount = [ + { + $lookup: { + from: 'comments', + let: { offerId: '$_id' }, + pipeline: [ + { $match: { $expr: { $eq: ['$offerId', '$$offerId'] } } }, + { $project: { _id: 1 } }, + ], + as: 'comments', + } + }, + { id: { $toString: '$_id'}, commentsCount: { $size: '$comments'} }, + { $unset: 'comments' } +]; + +export const populateComments = [ + { + $lookup: { + from: 'comments', + let: { offerId: '$_id' }, + pipeline: [ + { $match: { $expr: { $eq: ['$offerId', '$$offerId'] } } }, + { $project: { _id: 1, text: 1, rating: 1 } }, + ], + as: 'comments', + } + }, + { $limit: DEFAULT_COMMENTS_COUNT }, + { $sort: { createdDate: ESortType.DESC } } +]; diff --git a/src/shared/modules/offer/types/offer-service.interface.ts b/src/shared/modules/offer/types/offer-service.interface.ts index c28a38f..a6f3ce6 100644 --- a/src/shared/modules/offer/types/offer-service.interface.ts +++ b/src/shared/modules/offer/types/offer-service.interface.ts @@ -8,4 +8,5 @@ export interface IOfferService { find(count?: number): Promise[]>; deleteById(offerId: string): Promise | null>; updateById(offerId: string, dto: UpdateOfferDTO): Promise | null>; + incCommentCount(offerId: string): Promise | null>; } diff --git a/src/shared/modules/user/default-user.service.ts b/src/shared/modules/user/default-user.service.ts index 2b01cba..da88ef2 100644 --- a/src/shared/modules/user/default-user.service.ts +++ b/src/shared/modules/user/default-user.service.ts @@ -2,7 +2,7 @@ import { DocumentType, types } from '@typegoose/typegoose'; import { inject, injectable } from 'inversify'; import { IUserService } from './types/index.js'; -import { UserEntity, CreateUserDTO } from './index.js'; +import { UserEntity, CreateUserDTO, UpdateUserDTO, populateFavorites } from './index.js'; import { COMPONENT } from '../../constants/index.js'; import { ILogger } from '../../libs/logger/types/index.js'; @@ -23,7 +23,10 @@ export class DefaultUserService implements IUserService { } public async findByEmail(email: string): Promise | null> { - return this.userModel.findOne({ email }); + return this.userModel + .findOne({ email }) + .aggregate([populateFavorites]) + .exec(); } public async findOrCreate(dto: CreateUserDTO, salt: string): Promise> { @@ -35,4 +38,26 @@ export class DefaultUserService implements IUserService { return this.create(dto, salt); } + + public async updateById(userId: string, dto: UpdateUserDTO): Promise | null> { + return this.userModel + .findByIdAndUpdate(userId, dto, { new: true }) + .exec(); + } + + public async addFavorite(userId: string ,offerId: string): Promise | null> { + return this.userModel + .findByIdAndUpdate(userId, { + $addToSet: { favorites: offerId }, + }, { new: true }) + .exec(); + } + + public async deleteFavorite(userId: string, offerId: string): Promise | null> { + return this.userModel + .findByIdAndUpdate(userId, { + $pull: { favorites: offerId }, + }, { new: true }) + .exec(); + } } diff --git a/src/shared/modules/user/dto/update-user.dto.ts b/src/shared/modules/user/dto/update-user.dto.ts new file mode 100644 index 0000000..2dd8fba --- /dev/null +++ b/src/shared/modules/user/dto/update-user.dto.ts @@ -0,0 +1,9 @@ +import { EUserType } from '../../../types/index.js'; + +export class UpdateUserDTO { + public email?: string; + public avatarPath?: string; + public name?: string; + public type?: EUserType; + public password?: string; +} diff --git a/src/shared/modules/user/index.ts b/src/shared/modules/user/index.ts index 8858af2..3635575 100644 --- a/src/shared/modules/user/index.ts +++ b/src/shared/modules/user/index.ts @@ -1,4 +1,6 @@ export { UserEntity, UserModel } from './user.entity.js'; export { CreateUserDTO } from './dto/create-user.dto.js'; +export { UpdateUserDTO } from './dto/update-user.dto.js'; export { DefaultUserService } from './default-user.service.js'; export { createUserContainer } from './user.container.js'; +export { populateFavorites } from './user.aggregation.js'; diff --git a/src/shared/modules/user/types/user-service.interface.ts b/src/shared/modules/user/types/user-service.interface.ts index 491d00f..6742c19 100644 --- a/src/shared/modules/user/types/user-service.interface.ts +++ b/src/shared/modules/user/types/user-service.interface.ts @@ -1,9 +1,12 @@ import { DocumentType } from '@typegoose/typegoose'; -import { CreateUserDTO, UserEntity } from '../index.js'; +import { CreateUserDTO, UserEntity, UpdateUserDTO } from '../index.js'; export interface IUserService { create(dto: CreateUserDTO, salt: string): Promise>; findByEmail(email: string): Promise | null>; findOrCreate(dto: CreateUserDTO, salt: string): Promise>; + updateById(userId: string, dto: UpdateUserDTO): Promise | null>; + addFavorite(userId: string, offerId: string): Promise | null>; + deleteFavorite(userId: string, offerId: string): Promise | null>; } diff --git a/src/shared/modules/user/user.aggregation.ts b/src/shared/modules/user/user.aggregation.ts new file mode 100644 index 0000000..908efab --- /dev/null +++ b/src/shared/modules/user/user.aggregation.ts @@ -0,0 +1,8 @@ +export const populateFavorites = { + $lookup: { + from: 'offers', + localField: 'favorites', + foreignField: '_id', + as: 'favorites', + }, +};