Skip to content

Commit

Permalink
feat(tutories): add minRating filter for getTutories method
Browse files Browse the repository at this point in the history
  • Loading branch information
elskow committed Nov 25, 2024
1 parent b2c028c commit 6f7322a
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 26 deletions.
17 changes: 16 additions & 1 deletion src/module/review/review.repository.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { db as dbType } from "@/db/config";
import { reviews, orders, learners, tutories } from "@/db/schema";
import { and, desc, eq, sql } from "drizzle-orm";
import { and, desc, eq, inArray, sql } from "drizzle-orm";

export class ReviewRepository {
constructor(private readonly db: typeof dbType) {}
Expand Down Expand Up @@ -62,4 +62,19 @@ export class ReviewRepository {

return result[0] || { avgRating: 0, totalReviews: 0 };
}

async getBatchAverageRatings(tutoriesIds: string[]) {
const results = await this.db
.select({
tutoriesId: orders.tutoriesId,
avgRating: sql<number>`COALESCE(AVG(${reviews.rating})::numeric(10,1), 0)`,
totalReviews: sql<number>`COUNT(${reviews.id})`,
})
.from(reviews)
.innerJoin(orders, eq(reviews.orderId, orders.id))
.where(inArray(orders.tutoriesId, tutoriesIds))
.groupBy(orders.tutoriesId);

return results;
}
}
16 changes: 12 additions & 4 deletions src/module/tutories/tutories.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,31 @@ import { z } from "zod";

const tutoriesService = new TutoriesService({
tutoriesRepository: container.tutoriesRepository,
reviewRepository: container.reviewRepository,
});

type GetTutoriesSchema = z.infer<typeof getTutoriesSchema>;
export const getAllTutories: Controller<GetTutoriesSchema> = async (
req,
res,
) => {
const { q, subjectId, minHourlyRate, maxHourlyRate, typeLesson, city } =
req.query;
const {
q,
subjectId,
minHourlyRate,
maxHourlyRate,
typeLesson,
city,
minRating,
} = req.query;

const filters = {
q: q || null,
subjectId: subjectId || null,
minHourlyRate: minHourlyRate ? parseInt(minHourlyRate as string) : null,
maxHourlyRate: maxHourlyRate ? parseInt(maxHourlyRate as string) : null,
typeLesson: typeLesson || null,
// minRating: minRating ? parseFloat(minRating as string) : null,
minRating: minRating ? parseFloat(minRating as string) : null,
city: city || null,
};

Expand All @@ -40,7 +48,7 @@ export const getAllTutories: Controller<GetTutoriesSchema> = async (
minHourlyRate: filters.minHourlyRate,
maxHourlyRate: filters.maxHourlyRate,
typeLesson: filters.typeLesson,
// minRating: filters.minRating,
minRating: filters.minRating,
city: filters.city,
});

Expand Down
13 changes: 2 additions & 11 deletions src/module/tutories/tutories.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,13 @@ type GetTutoriesFilters = {
typeLesson?: "online" | "offline" | "both" | null;
tutorId?: string | null;
city?: string | null;
minRating?: number | null;
};

export class TutoriesRepository {
constructor(private readonly db: typeof dbType) {}

async getTutories(
filters: GetTutoriesFilters = {
q: null,
subjectId: null,
minHourlyRate: null,
maxHourlyRate: null,
typeLesson: null,
tutorId: null,
city: null,
},
) {
async getTutories(filters: GetTutoriesFilters = {}) {
try {
const conditions = [];

Expand Down
43 changes: 33 additions & 10 deletions src/module/tutories/tutories.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import {
import { logger } from "@middleware/logging.middleware";
import { z } from "zod";
import { TutoriesRepository } from "./tutories.repository";
import { ReviewRepository } from "@/module/review/review.repository";

export interface TutorServiceServiceDependencies {
tutoriesRepository: TutoriesRepository;
reviewRepository: ReviewRepository;
}

type GetTutorServicesFilters = {
Expand All @@ -18,13 +20,19 @@ type GetTutorServicesFilters = {
typeLesson?: "online" | "offline" | "both" | null;
city?: string | null;
tutorId?: string | null;
minRating?: number | null;
};

export class TutoriesService {
private tutoriesRepository: TutoriesRepository;
private reviewRepository: ReviewRepository;

constructor({ tutoriesRepository }: TutorServiceServiceDependencies) {
constructor({
tutoriesRepository,
reviewRepository,
}: TutorServiceServiceDependencies) {
this.tutoriesRepository = tutoriesRepository;
this.reviewRepository = reviewRepository;
}

// TODO: Implement realtime updates for tutor service availability
Expand All @@ -37,15 +45,30 @@ export class TutoriesService {
// - Send booking confirmation notifications
// - Alert tutors of new booking requests
async getTutories(filters: GetTutorServicesFilters) {
return await this.tutoriesRepository.getTutories({
q: filters.q,
subjectId: filters.subjectId,
minHourlyRate: filters.minHourlyRate,
maxHourlyRate: filters.maxHourlyRate,
typeLesson: filters.typeLesson,
tutorId: filters.tutorId,
city: filters.city,
});
const tutories = await this.tutoriesRepository.getTutories(filters);

// Get ratings for all tutories in parallel
const tutoriesWithRatings = await Promise.all(
tutories.map(async (tutory) => {
const { avgRating, totalReviews } =
await this.reviewRepository.getAverageRating(tutory.id);
return {
...tutory,
avgRating,
totalReviews,
};
}),
);

// Filter by minimum rating if specified
if (filters.minRating !== null && filters.minRating !== undefined) {
return tutoriesWithRatings.filter(
(tutory) => tutory.avgRating >= filters.minRating!,
);
}

// Sort by rating in descending order
return tutoriesWithRatings.sort((a, b) => b.avgRating - a.avgRating);
}

async getTutoriesDetail(tutoriesId: string) {
Expand Down

0 comments on commit 6f7322a

Please sign in to comment.