parent
738d18df76
commit
5e1be8b296
@ -0,0 +1,204 @@
|
|||||||
|
-- CreateEnum
|
||||||
|
CREATE TYPE "JobType" AS ENUM ('INTERN', 'FULLTIME');
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "OffersProfile" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"profileName" TEXT NOT NULL,
|
||||||
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"editToken" TEXT NOT NULL,
|
||||||
|
"userId" TEXT,
|
||||||
|
|
||||||
|
CONSTRAINT "OffersProfile_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "OffersBackground" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"totalYoe" INTEGER,
|
||||||
|
"offersProfileId" TEXT NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "OffersBackground_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "OffersSpecificYoe" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"yoe" INTEGER NOT NULL,
|
||||||
|
"domain" TEXT NOT NULL,
|
||||||
|
"backgroundId" TEXT NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "OffersSpecificYoe_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "OffersExperience" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"companyId" TEXT,
|
||||||
|
"jobType" "JobType",
|
||||||
|
"title" TEXT,
|
||||||
|
"durationInMonths" INTEGER,
|
||||||
|
"specialization" TEXT,
|
||||||
|
"level" TEXT,
|
||||||
|
"totalCompensationId" TEXT,
|
||||||
|
"monthlySalaryId" TEXT,
|
||||||
|
"backgroundId" TEXT NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "OffersExperience_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "OffersCurrency" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"value" INTEGER NOT NULL,
|
||||||
|
"currency" TEXT NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "OffersCurrency_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "OffersEducation" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"type" TEXT,
|
||||||
|
"field" TEXT,
|
||||||
|
"isAttending" BOOLEAN,
|
||||||
|
"school" TEXT,
|
||||||
|
"startDate" TIMESTAMP(3),
|
||||||
|
"endDate" TIMESTAMP(3),
|
||||||
|
"backgroundId" TEXT NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "OffersEducation_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "OffersReply" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"creator" TEXT NOT NULL,
|
||||||
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"message" TEXT NOT NULL,
|
||||||
|
"replyingToId" TEXT,
|
||||||
|
"profileId" TEXT NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "OffersReply_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "OffersOffer" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"profileId" TEXT NOT NULL,
|
||||||
|
"companyId" TEXT NOT NULL,
|
||||||
|
"monthYearReceived" TIMESTAMP(3) NOT NULL,
|
||||||
|
"location" TEXT NOT NULL,
|
||||||
|
"negotiationStrategy" TEXT,
|
||||||
|
"comments" TEXT,
|
||||||
|
"jobType" "JobType" NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "OffersOffer_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "OffersIntern" (
|
||||||
|
"offerId" TEXT NOT NULL,
|
||||||
|
"title" TEXT NOT NULL,
|
||||||
|
"specialization" TEXT NOT NULL,
|
||||||
|
"internshipCycle" TEXT NOT NULL,
|
||||||
|
"startYear" INTEGER NOT NULL,
|
||||||
|
"monthlySalaryId" TEXT NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "OffersIntern_pkey" PRIMARY KEY ("offerId")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "OffersFullTime" (
|
||||||
|
"offerId" TEXT NOT NULL,
|
||||||
|
"title" TEXT NOT NULL,
|
||||||
|
"specialization" TEXT NOT NULL,
|
||||||
|
"level" TEXT NOT NULL,
|
||||||
|
"totalCompensationId" TEXT NOT NULL,
|
||||||
|
"baseSalaryId" TEXT NOT NULL,
|
||||||
|
"bonusId" TEXT NOT NULL,
|
||||||
|
"stocksId" TEXT NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "OffersFullTime_pkey" PRIMARY KEY ("offerId")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "OffersBackground_offersProfileId_key" ON "OffersBackground"("offersProfileId");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "OffersExperience_totalCompensationId_key" ON "OffersExperience"("totalCompensationId");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "OffersExperience_monthlySalaryId_key" ON "OffersExperience"("monthlySalaryId");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "OffersIntern_monthlySalaryId_key" ON "OffersIntern"("monthlySalaryId");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "OffersFullTime_totalCompensationId_key" ON "OffersFullTime"("totalCompensationId");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "OffersFullTime_baseSalaryId_key" ON "OffersFullTime"("baseSalaryId");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "OffersFullTime_bonusId_key" ON "OffersFullTime"("bonusId");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "OffersFullTime_stocksId_key" ON "OffersFullTime"("stocksId");
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "OffersProfile" ADD CONSTRAINT "OffersProfile_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "OffersBackground" ADD CONSTRAINT "OffersBackground_offersProfileId_fkey" FOREIGN KEY ("offersProfileId") REFERENCES "OffersProfile"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "OffersSpecificYoe" ADD CONSTRAINT "OffersSpecificYoe_backgroundId_fkey" FOREIGN KEY ("backgroundId") REFERENCES "OffersBackground"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "OffersExperience" ADD CONSTRAINT "OffersExperience_companyId_fkey" FOREIGN KEY ("companyId") REFERENCES "Company"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "OffersExperience" ADD CONSTRAINT "OffersExperience_totalCompensationId_fkey" FOREIGN KEY ("totalCompensationId") REFERENCES "OffersCurrency"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "OffersExperience" ADD CONSTRAINT "OffersExperience_monthlySalaryId_fkey" FOREIGN KEY ("monthlySalaryId") REFERENCES "OffersCurrency"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "OffersExperience" ADD CONSTRAINT "OffersExperience_backgroundId_fkey" FOREIGN KEY ("backgroundId") REFERENCES "OffersBackground"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "OffersEducation" ADD CONSTRAINT "OffersEducation_backgroundId_fkey" FOREIGN KEY ("backgroundId") REFERENCES "OffersBackground"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "OffersReply" ADD CONSTRAINT "OffersReply_replyingToId_fkey" FOREIGN KEY ("replyingToId") REFERENCES "OffersReply"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "OffersReply" ADD CONSTRAINT "OffersReply_profileId_fkey" FOREIGN KEY ("profileId") REFERENCES "OffersProfile"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "OffersOffer" ADD CONSTRAINT "OffersOffer_profileId_fkey" FOREIGN KEY ("profileId") REFERENCES "OffersProfile"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "OffersOffer" ADD CONSTRAINT "OffersOffer_companyId_fkey" FOREIGN KEY ("companyId") REFERENCES "Company"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "OffersIntern" ADD CONSTRAINT "OffersIntern_offerId_fkey" FOREIGN KEY ("offerId") REFERENCES "OffersOffer"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "OffersIntern" ADD CONSTRAINT "OffersIntern_monthlySalaryId_fkey" FOREIGN KEY ("monthlySalaryId") REFERENCES "OffersCurrency"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "OffersFullTime" ADD CONSTRAINT "OffersFullTime_offerId_fkey" FOREIGN KEY ("offerId") REFERENCES "OffersOffer"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "OffersFullTime" ADD CONSTRAINT "OffersFullTime_totalCompensationId_fkey" FOREIGN KEY ("totalCompensationId") REFERENCES "OffersCurrency"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "OffersFullTime" ADD CONSTRAINT "OffersFullTime_baseSalaryId_fkey" FOREIGN KEY ("baseSalaryId") REFERENCES "OffersCurrency"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "OffersFullTime" ADD CONSTRAINT "OffersFullTime_bonusId_fkey" FOREIGN KEY ("bonusId") REFERENCES "OffersCurrency"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "OffersFullTime" ADD CONSTRAINT "OffersFullTime_stocksId_fkey" FOREIGN KEY ("stocksId") REFERENCES "OffersCurrency"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
@ -0,0 +1,25 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { trpc } from '~/utils/trpc';
|
||||||
|
|
||||||
|
function test() {
|
||||||
|
const data = trpc.useQuery([
|
||||||
|
'offers.list',
|
||||||
|
{
|
||||||
|
limit: 3,
|
||||||
|
location: 'Singapore, Singapore',
|
||||||
|
offset: 0,
|
||||||
|
yoeCategory: 0,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ul>
|
||||||
|
{data.data?.map((x) => {
|
||||||
|
return <li key={x.id}>{JSON.stringify(x)}</li>;
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default test;
|
@ -0,0 +1,229 @@
|
|||||||
|
import assert from 'assert';
|
||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
|
import { createRouter } from './context';
|
||||||
|
|
||||||
|
const yoeCategoryMap: Record<number, string> = {
|
||||||
|
0: 'Internship',
|
||||||
|
1: 'Fresh Grad',
|
||||||
|
2: 'Mid',
|
||||||
|
3: 'Senior',
|
||||||
|
};
|
||||||
|
|
||||||
|
const getYoeRange = (yoeCategory: number) => {
|
||||||
|
return yoeCategoryMap[yoeCategory] === 'Fresh Grad'
|
||||||
|
? { maxYoe: 3, minYoe: 0 }
|
||||||
|
: yoeCategoryMap[yoeCategory] === 'Mid'
|
||||||
|
? { maxYoe: 7, minYoe: 4 }
|
||||||
|
: yoeCategoryMap[yoeCategory] === 'Senior'
|
||||||
|
? { maxYoe: null, minYoe: 8 }
|
||||||
|
: null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const sortingKeys = ['date', 'tc', 'yoe'];
|
||||||
|
|
||||||
|
const createSortByValidationRegex = () => {
|
||||||
|
const startsWithPlusOrMinusOnly = '^[+-]{1}';
|
||||||
|
const sortingKeysRegex = sortingKeys.join('|');
|
||||||
|
return new RegExp(startsWithPlusOrMinusOnly + '(' + sortingKeysRegex + ')');
|
||||||
|
};
|
||||||
|
|
||||||
|
export const offersRouter = createRouter().query('list', {
|
||||||
|
input: z.object({
|
||||||
|
company: z.string().nullish(),
|
||||||
|
dateEnd: z.date().nullish(),
|
||||||
|
dateStart: z.date().nullish(),
|
||||||
|
limit: z.number().nonnegative(),
|
||||||
|
location: z.string(),
|
||||||
|
offset: z.number().nonnegative(),
|
||||||
|
salaryMax: z.number().nullish(),
|
||||||
|
salaryMin: z.number().nonnegative().nullish(),
|
||||||
|
sortby: z.string().regex(createSortByValidationRegex()).nullish(),
|
||||||
|
title: z.string().nullish(),
|
||||||
|
yoeCategory: z.number().min(0).max(3),
|
||||||
|
}),
|
||||||
|
async resolve({ ctx, input }) {
|
||||||
|
const yoeRange = getYoeRange(input.yoeCategory);
|
||||||
|
|
||||||
|
let data = !yoeRange
|
||||||
|
? await ctx.prisma.offersOffer.findMany({
|
||||||
|
// Internship
|
||||||
|
include: {
|
||||||
|
OffersFullTime: {
|
||||||
|
include: {
|
||||||
|
baseSalary: true,
|
||||||
|
bonus: true,
|
||||||
|
stocks: true,
|
||||||
|
totalCompensation: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
OffersIntern: {
|
||||||
|
include: {
|
||||||
|
monthlySalary: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
company: true,
|
||||||
|
},
|
||||||
|
skip: input.limit * input.offset,
|
||||||
|
take: input.limit,
|
||||||
|
where: {
|
||||||
|
AND: [
|
||||||
|
{
|
||||||
|
location: input.location,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
OffersIntern: {
|
||||||
|
isNot: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
OffersFullTime: {
|
||||||
|
is: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
: yoeRange.maxYoe
|
||||||
|
? await ctx.prisma.offersOffer.findMany({
|
||||||
|
include: {
|
||||||
|
OffersFullTime: {
|
||||||
|
include: {
|
||||||
|
baseSalary: true,
|
||||||
|
bonus: true,
|
||||||
|
stocks: true,
|
||||||
|
totalCompensation: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
OffersIntern: {
|
||||||
|
include: {
|
||||||
|
monthlySalary: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
company: true,
|
||||||
|
},
|
||||||
|
// Junior, Mid
|
||||||
|
skip: input.limit * input.offset,
|
||||||
|
take: input.limit,
|
||||||
|
where: {
|
||||||
|
AND: [
|
||||||
|
{
|
||||||
|
location: input.location,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
OffersIntern: {
|
||||||
|
is: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
OffersFullTime: {
|
||||||
|
isNot: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
profile: {
|
||||||
|
background: {
|
||||||
|
totalYoe: {
|
||||||
|
gte: yoeRange.minYoe,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
profile: {
|
||||||
|
background: {
|
||||||
|
totalYoe: {
|
||||||
|
gte: yoeRange.maxYoe,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
: await ctx.prisma.offersOffer.findMany({
|
||||||
|
// Senior
|
||||||
|
include: {
|
||||||
|
OffersFullTime: {
|
||||||
|
include: {
|
||||||
|
baseSalary: true,
|
||||||
|
bonus: true,
|
||||||
|
stocks: true,
|
||||||
|
totalCompensation: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
OffersIntern: {
|
||||||
|
include: {
|
||||||
|
monthlySalary: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
company: true,
|
||||||
|
},
|
||||||
|
skip: input.limit * input.offset,
|
||||||
|
take: input.limit,
|
||||||
|
where: {
|
||||||
|
AND: [
|
||||||
|
{
|
||||||
|
location: input.location,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
OffersIntern: {
|
||||||
|
is: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
OffersFullTime: {
|
||||||
|
isNot: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
profile: {
|
||||||
|
background: {
|
||||||
|
totalYoe: {
|
||||||
|
gte: yoeRange.minYoe,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
data = data.filter((offer) => {
|
||||||
|
let validRecord = true;
|
||||||
|
|
||||||
|
if (input.company) {
|
||||||
|
validRecord = validRecord && offer.company.name === input.company;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input.title) {
|
||||||
|
validRecord =
|
||||||
|
validRecord &&
|
||||||
|
(offer.OffersFullTime?.title === input.title ||
|
||||||
|
offer.OffersIntern?.title === input.title);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input.dateStart && input.dateEnd) {
|
||||||
|
validRecord =
|
||||||
|
validRecord &&
|
||||||
|
offer.monthYearReceived.getTime() >= input.dateStart.getTime() &&
|
||||||
|
offer.monthYearReceived.getTime() <= input.dateEnd.getTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input.salaryMin && input.salaryMax) {
|
||||||
|
const salary = offer.OffersFullTime?.totalCompensation.value
|
||||||
|
? offer.OffersFullTime?.totalCompensation.value
|
||||||
|
: offer.OffersIntern?.monthlySalary.value;
|
||||||
|
|
||||||
|
assert(salary);
|
||||||
|
|
||||||
|
validRecord =
|
||||||
|
validRecord && salary >= input.salaryMin && salary <= input.salaryMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
return validRecord;
|
||||||
|
});
|
||||||
|
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
});
|
Loading…
Reference in new issue