Skip to content

Commit

Permalink
perf(posting): serve postings from cache (#124)
Browse files Browse the repository at this point in the history
  • Loading branch information
amandesai01 authored Sep 7, 2024
1 parent 2bc02c0 commit e7d9924
Show file tree
Hide file tree
Showing 9 changed files with 121 additions and 105 deletions.
22 changes: 15 additions & 7 deletions server/api/posting/index.delete.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { eq } from 'drizzle-orm';
import { jobPostingsTable } from '../../db/schema';
import { type JobPosting, jobPostingsTable } from '../../db/schema';
import authenticateAdminRequest from '../../utils/admin';
import { deleteJobPostingSchema } from '~~/shared/schemas/posting';

export default defineEventHandler(async (event) => {
const session = await authenticateAdminRequest(event);

await authenticateAdminRequest(event);
const q = await getValidatedQuery(event, deleteJobPostingSchema.parse);

const jobPostingId = q.id;
Expand All @@ -17,11 +16,20 @@ export default defineEventHandler(async (event) => {
.where(eq(jobPostingsTable.id, jobPostingId))
.returning({ id: jobPostingsTable.id });

if (!(Array.isArray(jobPostingsResult) && jobPostingsResult.length == 1)) {
if (jobPostingsResult.length == 0) {
throw createError({
statusCode: 400,
message:
'Invalid posting id. Contact support if you think this is a mistake.',
statusCode: 404,
statusMessage: 'Job posting not found',
});
}

const deletedPostingId = jobPostingsResult[0]?.id;

const postings =
(await general_memoryStorage.getItem<JobPosting[]>('postings')) || [];

await general_memoryStorage.setItem(
'postings',
postings.filter((p) => p.id !== deletedPostingId)
);
});
28 changes: 17 additions & 11 deletions server/api/posting/index.get.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
import { eq } from 'drizzle-orm';
import { jobPostingsTable } from '../../db/schema';
import { type JobPosting } from '../../db/schema';
import authenticateAdminRequest from '../../utils/admin';
import { fetchJobPostingFilterSchema } from '~~/shared/schemas/posting';

/**
* In future, if totalApplicants needed on posting page from admin side,
* either revamp caching or use database straight away for applicants.
*/
export default defineEventHandler(async (event) => {
await authenticateAdminRequest(event);
const q = await getValidatedQuery(event, fetchJobPostingFilterSchema.parse);

const database = await useDatabase();
const postings =
(await general_memoryStorage.getItem<JobPosting[]>('postings')) || [];

return (
await database
.select()
.from(jobPostingsTable)
.where(eq(jobPostingsTable.id, q.id))
.orderBy(jobPostingsTable.createdAt)
.limit(1)
)[0];
const posting = postings.find((p) => p.id === q.id);

if (!posting) {
throw createError({
statusCode: 404,
statusMessage: 'Posting not found',
});
}

return posting;
});
12 changes: 9 additions & 3 deletions server/api/posting/index.post.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import authenticateAdminRequest from '../../utils/admin';
import { createJobPostingSchema } from '~~/shared/schemas/posting';
import { jobPostingsTable } from '../../db/schema';
import { type JobPosting, jobPostingsTable } from '../../db/schema';

export default defineEventHandler(async (event) => {
const session = await authenticateAdminRequest(event);
Expand All @@ -15,10 +15,16 @@ export default defineEventHandler(async (event) => {

const database = await useDatabase();

return (
const newPosting = (
await database
.insert(jobPostingsTable)
.values({ ...jobPostingRequest, owner: session.user.id })
.returning()
)[0];
)[0] as JobPosting;

const postings =
(await general_memoryStorage.getItem<JobPosting[]>('postings')) || [];

postings.unshift(newPosting);
await general_memoryStorage.setItem('postings', postings);
});
25 changes: 18 additions & 7 deletions server/api/posting/index.put.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { jobPostingsTable } from '../../db/schema';
import { type JobPosting, jobPostingsTable } from '../../db/schema';
import authenticateAdminRequest from '../../utils/admin';
import { eq } from 'drizzle-orm';
import { updateJobPostingSchema } from '~~/shared/schemas/posting';
Expand All @@ -18,11 +18,22 @@ export default defineEventHandler(async (event) => {
updatedAt: new Date(),
};

const updatedJobPosting = await database
.update(jobPostingsTable)
.set(updateQuery)
.where(eq(jobPostingsTable.id, q.id))
.returning();
const updatedJobPosting = (
await database
.update(jobPostingsTable)
.set(updateQuery)
.where(eq(jobPostingsTable.id, q.id))
.returning()
)[0] as JobPosting;

return updatedJobPosting;
const postings =
(await general_memoryStorage.getItem<JobPosting[]>('postings')) || [];

await general_memoryStorage.setItem(
'postings',
postings.map((p) => {
if (p.id == updatedJobPosting.id) return updatedJobPosting;
return p;
})
);
});
58 changes: 25 additions & 33 deletions server/api/postings/index.get.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,33 @@
import { jobPostingsTable } from '../../db/schema';
import { type JobPosting, jobPostingsTable } from '../../db/schema';
import authenticateAdminRequest from '../../utils/admin';
import { and, eq, getTableColumns, or } from 'drizzle-orm';
import { listJobPostingsFilterSchema } from '~~/shared/schemas/posting';
import { desc } from 'drizzle-orm';

/**
* DB lookup for totalApplicants and cache lookup for everything else.
*/
export default defineEventHandler(async (event) => {
const database = await useDatabase();

const session = await authenticateAdminRequest(event);
const q = await getValidatedQuery(event, listJobPostingsFilterSchema.parse);
await authenticateAdminRequest(event);

const { contents, ...columns } = getTableColumns(jobPostingsTable);
const database = await useDatabase();

const conditions = [];
const totalApplicantsRecord = await database
.select({
id: jobPostingsTable.id,
totalApplicants: jobPostingsTable.totalApplicants,
})
.from(jobPostingsTable)
.orderBy(desc(jobPostingsTable.createdAt));

if (q && q.id) {
conditions.push(eq(jobPostingsTable.id, q.id));
} else if (q && q.ownerId) {
// If owner specified, just return published postings.
conditions.push(
and(
eq(jobPostingsTable.owner, q.ownerId),
eq(jobPostingsTable.isPublished, true)
)
);
} else {
// If owner not specified, just return published postings + postings by admin himself
conditions.push(
or(
eq(jobPostingsTable.isPublished, true),
eq(jobPostingsTable.owner, session.user.id)
)
);
}
const totalApplicantsById: Record<string, number> = {};
totalApplicantsRecord.forEach(
(tar) => (totalApplicantsById[tar.id] = tar.totalApplicants)
);

return database
.select(columns)
.from(jobPostingsTable)
.where(conditions.length ? and(...conditions) : undefined)
.orderBy(jobPostingsTable.createdAt);
const postings =
(await general_memoryStorage.getItem<JobPosting[]>('postings')) || [];
return postings.map((p) => ({
...p,
contents: null,
totalApplicants: totalApplicantsById[p.id] || 0,
}));
});
12 changes: 4 additions & 8 deletions server/api/postings/lite.get.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
import { desc } from 'drizzle-orm';
import { jobPostingsTable } from '~~/server/db/schema';
import { type JobPosting } from '~~/server/db/schema';
import authenticateAdminRequest from '~~/server/utils/admin';

export default defineEventHandler(async (event) => {
await authenticateAdminRequest(event);

const db = await useDatabase();
const postings =
(await general_memoryStorage.getItem<JobPosting[]>('postings')) || [];

const postings = await db
.select({ id: jobPostingsTable.id, title: jobPostingsTable.title })
.from(jobPostingsTable)
.orderBy(desc(jobPostingsTable.createdAt));
if (IS_DEV) {
console.log('[/api/postings/lite] found', postings.length, 'postings');
}

return postings;
return postings.map((p) => ({ id: p.id, title: p.title }));
});
31 changes: 11 additions & 20 deletions server/api/public/posting.get.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import { and, eq } from 'drizzle-orm';
import { jobPostingsTable } from '~~/server/db/schema';
import { type JobPosting } from '~~/server/db/schema';

export default defineEventHandler(async (event) => {
const database = await useDatabase();

const query = getQuery<{ id: string }>(event);

if (IS_DEV) {
Expand All @@ -18,23 +15,17 @@ export default defineEventHandler(async (event) => {
}

const postings = (
await database
.select()
.from(jobPostingsTable)
.where(
and(
eq(jobPostingsTable.isPublished, true),
eq(jobPostingsTable.id, query.id)
)
)
).map((p) => {
return {
...p,
totalApplicants: 0,
};
});
(await general_memoryStorage.getItem<JobPosting[]>('postings')) || []
)
.filter((p) => p.id === query.id && p.isPublished)
.map((p) => {
return {
...p,
owner: null,
};
});

if (!(Array.isArray(postings) && postings.length == 1)) {
if (postings.length != 1) {
throw createError({
statusCode: 404,
statusMessage: 'Posting not found',
Expand Down
25 changes: 11 additions & 14 deletions server/api/public/postings.get.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,19 @@
import { eq, getTableColumns } from 'drizzle-orm';
import { type JobPosting, jobPostingsTable } from '~~/server/db/schema';
import { type JobPosting } from '~~/server/db/schema';

export default defineEventHandler(async (_) => {
const database = await useDatabase();

const { contents, owner, isPublished, totalApplicants, ...requiredColumns } =
getTableColumns(jobPostingsTable);

const postings = await database
.select({
...requiredColumns,
})
.from(jobPostingsTable)
.where(eq(jobPostingsTable.isPublished, true));
const postings = (
(await general_memoryStorage.getItem<JobPosting[]>('postings')) || []
)
.filter((p) => p.isPublished)
.map((p) => ({
...p,
contents: null,
owner: null,
}));

if (IS_DEV) {
console.log('[PUBLIC] postings page found', postings.length, 'postings.');
}

return postings as JobPosting[];
return postings;
});
13 changes: 11 additions & 2 deletions server/utils/tasks/seed-cache.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { inArray } from 'drizzle-orm';
import { desc, inArray } from 'drizzle-orm';
import type { GeneralSettings } from '~~/shared/schemas/setting';
import { metaDataTable } from '~~/server/db/schema';
import { jobPostingsTable, metaDataTable } from '~~/server/db/schema';

export async function seedCache() {
console.log('Seeding Cache');
Expand All @@ -18,6 +18,14 @@ export async function seedCache() {
])
);

// Do not save totalApplicants in cache
const jobPostings = (
await db
.select()
.from(jobPostingsTable)
.orderBy(desc(jobPostingsTable.createdAt))
).map((p) => ({ ...p, totalApplicants: -1 }));

const settings: GeneralSettings = {
careerSite: {},
seo: {},
Expand All @@ -40,6 +48,7 @@ export async function seedCache() {
settings_memoryStorage.setItem('seoConfig', settings.seo),
general_memoryStorage.setItem('firstSetupAccessKey', firstSetupAccessKey),
general_memoryStorage.setItem('remoteAssetBase', remoteAssetBase),
general_memoryStorage.setItem('postings', jobPostings),
]);

return { result: true };
Expand Down

0 comments on commit e7d9924

Please sign in to comment.