mirror of
https://github.com/yangshun/tech-interview-handbook.git
synced 2025-07-28 12:43:12 +08:00
[offers][refactor] Refactor the sorting to use prisma's ORDERBY api
This commit is contained in:
@ -9,8 +9,8 @@ function Test() {
|
|||||||
limit: 100,
|
limit: 100,
|
||||||
location: 'Singapore, Singapore',
|
location: 'Singapore, Singapore',
|
||||||
offset: 0,
|
offset: 0,
|
||||||
sortBy: '+totalCompensation',
|
sortBy: '-monthYearReceived',
|
||||||
yoeCategory: 1,
|
yoeCategory: 0,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
@ -10,6 +10,27 @@ import { Currency } from '~/utils/offers/currency/CurrencyEnum';
|
|||||||
|
|
||||||
import { createRouter } from '../context';
|
import { createRouter } from '../context';
|
||||||
|
|
||||||
|
const getOrder = (prefix: string) => {
|
||||||
|
if (prefix === '+') {
|
||||||
|
return 'asc';
|
||||||
|
}
|
||||||
|
return 'desc';
|
||||||
|
};
|
||||||
|
|
||||||
|
const sortingKeysMap = {
|
||||||
|
monthYearReceived: 'monthYearReceived',
|
||||||
|
totalCompensation: 'totalCompensation',
|
||||||
|
totalYoe: 'totalYoe',
|
||||||
|
};
|
||||||
|
|
||||||
|
const createSortByValidationRegex = () => {
|
||||||
|
const startsWithPlusOrMinusOnly = '^[+-]{1}';
|
||||||
|
const sortingKeysRegex = Object.entries(sortingKeysMap)
|
||||||
|
.map((entry) => entry[0])
|
||||||
|
.join('|');
|
||||||
|
return new RegExp(startsWithPlusOrMinusOnly + '(' + sortingKeysRegex + ')');
|
||||||
|
};
|
||||||
|
|
||||||
const yoeCategoryMap: Record<number, string> = {
|
const yoeCategoryMap: Record<number, string> = {
|
||||||
0: 'Internship',
|
0: 'Internship',
|
||||||
1: 'Fresh Grad',
|
1: 'Fresh Grad',
|
||||||
@ -27,16 +48,6 @@ const getYoeRange = (yoeCategory: number) => {
|
|||||||
: null; // Internship
|
: null; // Internship
|
||||||
};
|
};
|
||||||
|
|
||||||
const ascOrder = '+';
|
|
||||||
const descOrder = '-';
|
|
||||||
const sortingKeys = ['monthYearReceived', 'totalCompensation', 'totalYoe'];
|
|
||||||
|
|
||||||
const createSortByValidationRegex = () => {
|
|
||||||
const startsWithPlusOrMinusOnly = '^[+-]{1}';
|
|
||||||
const sortingKeysRegex = sortingKeys.join('|');
|
|
||||||
return new RegExp(startsWithPlusOrMinusOnly + '(' + sortingKeysRegex + ')');
|
|
||||||
};
|
|
||||||
|
|
||||||
export const offersRouter = createRouter().query('list', {
|
export const offersRouter = createRouter().query('list', {
|
||||||
input: z.object({
|
input: z.object({
|
||||||
companyId: z.string().nullish(),
|
companyId: z.string().nullish(),
|
||||||
@ -59,6 +70,15 @@ export const offersRouter = createRouter().query('list', {
|
|||||||
const yoeMin = input.yoeMin ? input.yoeMin : yoeRange?.minYoe;
|
const yoeMin = input.yoeMin ? input.yoeMin : yoeRange?.minYoe;
|
||||||
const yoeMax = input.yoeMax ? input.yoeMax : yoeRange?.maxYoe;
|
const yoeMax = input.yoeMax ? input.yoeMax : yoeRange?.maxYoe;
|
||||||
|
|
||||||
|
// Const orderBy = getSortingOrderAndKey(input.sortBy, input.yoeCategory);
|
||||||
|
|
||||||
|
if (!input.sortBy) {
|
||||||
|
input.sortBy = '-' + sortingKeysMap.monthYearReceived;
|
||||||
|
}
|
||||||
|
|
||||||
|
const order = getOrder(input.sortBy.charAt(0));
|
||||||
|
const sortingKey = input.sortBy.substring(1);
|
||||||
|
|
||||||
let data = !yoeRange
|
let data = !yoeRange
|
||||||
? await ctx.prisma.offersOffer.findMany({
|
? await ctx.prisma.offersOffer.findMany({
|
||||||
// Internship
|
// Internship
|
||||||
@ -83,9 +103,28 @@ export const offersRouter = createRouter().query('list', {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
orderBy: {
|
orderBy:
|
||||||
monthYearReceived: 'desc',
|
sortingKey === sortingKeysMap.monthYearReceived
|
||||||
|
? {
|
||||||
|
monthYearReceived: order,
|
||||||
|
}
|
||||||
|
: sortingKey === sortingKeysMap.totalCompensation
|
||||||
|
? {
|
||||||
|
offersIntern: {
|
||||||
|
monthlySalary: {
|
||||||
|
value: order,
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: sortingKey === sortingKeysMap.totalYoe
|
||||||
|
? {
|
||||||
|
profile: {
|
||||||
|
background: {
|
||||||
|
totalYoe: order,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
where: {
|
where: {
|
||||||
AND: [
|
AND: [
|
||||||
{
|
{
|
||||||
@ -126,6 +165,16 @@ export const offersRouter = createRouter().query('list', {
|
|||||||
? input.companyId
|
? input.companyId
|
||||||
: undefined,
|
: undefined,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
profile: {
|
||||||
|
background: {
|
||||||
|
totalYoe: {
|
||||||
|
gte: yoeMin,
|
||||||
|
lte: yoeMax,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
monthYearReceived: {
|
monthYearReceived: {
|
||||||
gte: input.dateStart ?? undefined,
|
gte: input.dateStart ?? undefined,
|
||||||
@ -158,9 +207,28 @@ export const offersRouter = createRouter().query('list', {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
orderBy: {
|
orderBy:
|
||||||
monthYearReceived: 'desc',
|
sortingKey === sortingKeysMap.monthYearReceived
|
||||||
|
? {
|
||||||
|
monthYearReceived: order,
|
||||||
|
}
|
||||||
|
: sortingKey === sortingKeysMap.totalCompensation
|
||||||
|
? {
|
||||||
|
offersFullTime: {
|
||||||
|
totalCompensation: {
|
||||||
|
value: order,
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: sortingKey === sortingKeysMap.totalYoe
|
||||||
|
? {
|
||||||
|
profile: {
|
||||||
|
background: {
|
||||||
|
totalYoe: order,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
where: {
|
where: {
|
||||||
AND: [
|
AND: [
|
||||||
{
|
{
|
||||||
@ -271,110 +339,110 @@ export const offersRouter = createRouter().query('list', {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SORTING
|
// SORTING
|
||||||
data = data.sort((offer1, offer2) => {
|
// data = data.sort((offer1, offer2) => {
|
||||||
const defaultReturn =
|
// const defaultReturn =
|
||||||
offer2.monthYearReceived.getTime() - offer1.monthYearReceived.getTime();
|
// offer2.monthYearReceived.getTime() - offer1.monthYearReceived.getTime();
|
||||||
|
|
||||||
if (!input.sortBy) {
|
// if (!input.sortBy) {
|
||||||
return defaultReturn;
|
// return defaultReturn;
|
||||||
}
|
// }
|
||||||
|
|
||||||
const order = input.sortBy.charAt(0);
|
// const order = input.sortBy.charAt(0);
|
||||||
const sortingKey = input.sortBy.substring(1);
|
// const sortingKey = input.sortBy.substring(1);
|
||||||
|
|
||||||
if (order === ascOrder) {
|
// if (order === ascOrder) {
|
||||||
return (() => {
|
// return (() => {
|
||||||
if (sortingKey === 'monthYearReceived') {
|
// if (sortingKey === 'monthYearReceived') {
|
||||||
return (
|
// return (
|
||||||
offer1.monthYearReceived.getTime() -
|
// offer1.monthYearReceived.getTime() -
|
||||||
offer2.monthYearReceived.getTime()
|
// offer2.monthYearReceived.getTime()
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (sortingKey === 'totalCompensation') {
|
// if (sortingKey === 'totalCompensation') {
|
||||||
const salary1 = offer1.offersFullTime?.totalCompensation.value
|
// const salary1 = offer1.offersFullTime?.totalCompensation.value
|
||||||
? offer1.offersFullTime?.totalCompensation.value
|
// ? offer1.offersFullTime?.totalCompensation.value
|
||||||
: offer1.offersIntern?.monthlySalary.value;
|
// : offer1.offersIntern?.monthlySalary.value;
|
||||||
|
|
||||||
const salary2 = offer2.offersFullTime?.totalCompensation.value
|
// const salary2 = offer2.offersFullTime?.totalCompensation.value
|
||||||
? offer2.offersFullTime?.totalCompensation.value
|
// ? offer2.offersFullTime?.totalCompensation.value
|
||||||
: offer2.offersIntern?.monthlySalary.value;
|
// : offer2.offersIntern?.monthlySalary.value;
|
||||||
|
|
||||||
if (salary1 == null || salary2 == null) {
|
// if (salary1 == null || salary2 == null) {
|
||||||
throw new TRPCError({
|
// throw new TRPCError({
|
||||||
code: 'NOT_FOUND',
|
// code: 'NOT_FOUND',
|
||||||
message: 'Total Compensation or Salary not found',
|
// message: 'Total Compensation or Salary not found',
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
return salary1 - salary2;
|
// return salary1 - salary2;
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (sortingKey === 'totalYoe') {
|
// if (sortingKey === 'totalYoe') {
|
||||||
const yoe1 = offer1.profile.background?.totalYoe;
|
// const yoe1 = offer1.profile.background?.totalYoe;
|
||||||
const yoe2 = offer2.profile.background?.totalYoe;
|
// const yoe2 = offer2.profile.background?.totalYoe;
|
||||||
|
|
||||||
if (yoe1 == null || yoe2 == null) {
|
// if (yoe1 == null || yoe2 == null) {
|
||||||
throw new TRPCError({
|
// throw new TRPCError({
|
||||||
code: 'NOT_FOUND',
|
// code: 'NOT_FOUND',
|
||||||
message: 'Total years of experience not found',
|
// message: 'Total years of experience not found',
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
return yoe1 - yoe2;
|
// return yoe1 - yoe2;
|
||||||
}
|
// }
|
||||||
|
|
||||||
return defaultReturn;
|
// return defaultReturn;
|
||||||
})();
|
// })();
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (order === descOrder) {
|
// if (order === descOrder) {
|
||||||
return (() => {
|
// return (() => {
|
||||||
if (sortingKey === 'monthYearReceived') {
|
// if (sortingKey === 'monthYearReceived') {
|
||||||
return (
|
// return (
|
||||||
offer2.monthYearReceived.getTime() -
|
// offer2.monthYearReceived.getTime() -
|
||||||
offer1.monthYearReceived.getTime()
|
// offer1.monthYearReceived.getTime()
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (sortingKey === 'totalCompensation') {
|
// if (sortingKey === 'totalCompensation') {
|
||||||
const salary1 = offer1.offersFullTime?.totalCompensation.value
|
// const salary1 = offer1.offersFullTime?.totalCompensation.value
|
||||||
? offer1.offersFullTime?.totalCompensation.value
|
// ? offer1.offersFullTime?.totalCompensation.value
|
||||||
: offer1.offersIntern?.monthlySalary.value;
|
// : offer1.offersIntern?.monthlySalary.value;
|
||||||
|
|
||||||
const salary2 = offer2.offersFullTime?.totalCompensation.value
|
// const salary2 = offer2.offersFullTime?.totalCompensation.value
|
||||||
? offer2.offersFullTime?.totalCompensation.value
|
// ? offer2.offersFullTime?.totalCompensation.value
|
||||||
: offer2.offersIntern?.monthlySalary.value;
|
// : offer2.offersIntern?.monthlySalary.value;
|
||||||
|
|
||||||
if (salary1 == null || salary2 == null) {
|
// if (salary1 == null || salary2 == null) {
|
||||||
throw new TRPCError({
|
// throw new TRPCError({
|
||||||
code: 'NOT_FOUND',
|
// code: 'NOT_FOUND',
|
||||||
message: 'Total Compensation or Salary not found',
|
// message: 'Total Compensation or Salary not found',
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
return salary2 - salary1;
|
// return salary2 - salary1;
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (sortingKey === 'totalYoe') {
|
// if (sortingKey === 'totalYoe') {
|
||||||
const yoe1 = offer1.profile.background?.totalYoe;
|
// const yoe1 = offer1.profile.background?.totalYoe;
|
||||||
const yoe2 = offer2.profile.background?.totalYoe;
|
// const yoe2 = offer2.profile.background?.totalYoe;
|
||||||
|
|
||||||
if (yoe1 == null || yoe2 == null) {
|
// if (yoe1 == null || yoe2 == null) {
|
||||||
throw new TRPCError({
|
// throw new TRPCError({
|
||||||
code: 'NOT_FOUND',
|
// code: 'NOT_FOUND',
|
||||||
message: 'Total years of experience not found',
|
// message: 'Total years of experience not found',
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
return yoe2 - yoe1;
|
// return yoe2 - yoe1;
|
||||||
}
|
// }
|
||||||
|
|
||||||
return defaultReturn;
|
// return defaultReturn;
|
||||||
})();
|
// })();
|
||||||
}
|
// }
|
||||||
return defaultReturn;
|
// return defaultReturn;
|
||||||
});
|
// });
|
||||||
|
|
||||||
const startRecordIndex: number = input.limit * input.offset;
|
const startRecordIndex: number = input.limit * input.offset;
|
||||||
const endRecordIndex: number =
|
const endRecordIndex: number =
|
||||||
|
Reference in New Issue
Block a user