Skip to content

Commit 5ce7fd6

Browse files
authored
237/granular tag types (#276)
* change schema prisma to have two tag models * finish seed file and changes to all services, controllers, types that use new prisma schema * prettier * prisma format * remove dotfile * move tags into tags folder * move tag services into one tag.service * prettier and lint fixes
1 parent 0df2a32 commit 5ce7fd6

14 files changed

Lines changed: 282 additions & 76 deletions

File tree

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
Warnings:
3+
4+
- You are about to drop the `Tag` table. If the table is not empty, all the data it contains will be lost.
5+
6+
*/
7+
-- DropForeignKey
8+
ALTER TABLE "public"."Tag" DROP CONSTRAINT "Tag_orgId_fkey";
9+
10+
-- DropForeignKey
11+
ALTER TABLE "public"."_PositionTags" DROP CONSTRAINT "_PositionTags_B_fkey";
12+
13+
-- DropForeignKey
14+
ALTER TABLE "public"."_TaskTemplateTags" DROP CONSTRAINT "_TaskTemplateTags_A_fkey";
15+
16+
-- DropForeignKey
17+
ALTER TABLE "public"."_TaskTemplateTags" DROP CONSTRAINT "_TaskTemplateTags_B_fkey";
18+
19+
-- DropTable
20+
DROP TABLE "public"."Tag";
21+
22+
-- CreateTable
23+
CREATE TABLE "public"."PositionTag" (
24+
"id" TEXT NOT NULL,
25+
"name" TEXT NOT NULL,
26+
"orgId" TEXT NOT NULL,
27+
"colorHexCode" TEXT NOT NULL,
28+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
29+
"updatedAt" TIMESTAMP(3) NOT NULL,
30+
31+
CONSTRAINT "PositionTag_pkey" PRIMARY KEY ("id")
32+
);
33+
34+
-- CreateTable
35+
CREATE TABLE "public"."TaskTemplateTag" (
36+
"id" TEXT NOT NULL,
37+
"name" TEXT NOT NULL,
38+
"orgId" TEXT NOT NULL,
39+
"colorHexCode" TEXT NOT NULL,
40+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
41+
"updatedAt" TIMESTAMP(3) NOT NULL,
42+
43+
CONSTRAINT "TaskTemplateTag_pkey" PRIMARY KEY ("id")
44+
);
45+
46+
-- CreateIndex
47+
CREATE INDEX "PositionTag_orgId_idx" ON "public"."PositionTag"("orgId");
48+
49+
-- CreateIndex
50+
CREATE UNIQUE INDEX "PositionTag_name_orgId_key" ON "public"."PositionTag"("name", "orgId");
51+
52+
-- CreateIndex
53+
CREATE INDEX "TaskTemplateTag_orgId_idx" ON "public"."TaskTemplateTag"("orgId");
54+
55+
-- CreateIndex
56+
CREATE UNIQUE INDEX "TaskTemplateTag_name_orgId_key" ON "public"."TaskTemplateTag"("name", "orgId");
57+
58+
-- AddForeignKey
59+
ALTER TABLE "public"."PositionTag" ADD CONSTRAINT "PositionTag_orgId_fkey" FOREIGN KEY ("orgId") REFERENCES "public"."Organization"("id") ON DELETE CASCADE ON UPDATE CASCADE;
60+
61+
-- AddForeignKey
62+
ALTER TABLE "public"."TaskTemplateTag" ADD CONSTRAINT "TaskTemplateTag_orgId_fkey" FOREIGN KEY ("orgId") REFERENCES "public"."Organization"("id") ON DELETE CASCADE ON UPDATE CASCADE;
63+
64+
-- AddForeignKey
65+
ALTER TABLE "public"."_PositionTags" ADD CONSTRAINT "_PositionTags_B_fkey" FOREIGN KEY ("B") REFERENCES "public"."PositionTag"("id") ON DELETE CASCADE ON UPDATE CASCADE;
66+
67+
-- AddForeignKey
68+
ALTER TABLE "public"."_TaskTemplateTags" ADD CONSTRAINT "_TaskTemplateTags_A_fkey" FOREIGN KEY ("A") REFERENCES "public"."TaskTemplate"("id") ON DELETE CASCADE ON UPDATE CASCADE;
69+
70+
-- AddForeignKey
71+
ALTER TABLE "public"."_TaskTemplateTags" ADD CONSTRAINT "_TaskTemplateTags_B_fkey" FOREIGN KEY ("B") REFERENCES "public"."TaskTemplateTag"("id") ON DELETE CASCADE ON UPDATE CASCADE;

prisma/schema.prisma

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ model Organization {
2424
taskTemplates TaskTemplate[]
2525
members Member[]
2626
invitations Invitation[]
27-
tags Tag[]
27+
positionTags PositionTag[]
28+
taskTemplateTags TaskTemplateTag[]
2829
}
2930

3031
// An internal user of the Sarge platform (e.g. recruiter, reviewer, admin). Users authenticate and may belong to one or more organizations.
@@ -64,7 +65,7 @@ model Position {
6465
applications Application[]
6566
organization Organization @relation(fields: [orgId], references: [id])
6667
creator User @relation("CreatedPositions", fields: [createdById], references: [id])
67-
tags Tag[] @relation("PositionTags")
68+
tags PositionTag[] @relation("PositionTags")
6869
assessmentTemplate AssessmentTemplate? @relation("derivedFromPosition", fields: [assessmentId], references: [id])
6970
}
7071

@@ -161,7 +162,7 @@ model TaskTemplate {
161162
organization Organization @relation(fields: [orgId], references: [id])
162163
author User @relation("AuthoredTaskTemplates", fields: [authorId], references: [id], onDelete: Restrict)
163164
tasks Task[] @relation("derivedFromTaskTemplate")
164-
tags Tag[] @relation("TaskTemplateTags")
165+
tags TaskTemplateTag[] @relation("TaskTemplateTags")
165166
languages TaskTemplateLanguage[]
166167
167168
assessments AssessmentTemplateTask[]
@@ -358,20 +359,33 @@ model Invitation {
358359
@@index([organizationId])
359360
}
360361

361-
// A label used to categorize and organize task templates within an organization.
362-
model Tag {
363-
id String @id @unique @default(cuid())
362+
// A label used to categorize and organize positions within an organization.
363+
model PositionTag {
364+
id String @id @default(cuid())
364365
name String
365366
orgId String
366367
colorHexCode String
367368
createdAt DateTime @default(now())
368369
updatedAt DateTime @updatedAt
369370
370371
organization Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
372+
positions Position[] @relation("PositionTags")
373+
374+
@@unique([name, orgId])
375+
@@index([orgId])
376+
}
377+
378+
// A label used to categorize and organize task templates within an organization.
379+
model TaskTemplateTag {
380+
id String @id @default(cuid())
381+
name String
382+
orgId String
383+
colorHexCode String
384+
createdAt DateTime @default(now())
385+
updatedAt DateTime @updatedAt
371386
372-
// These are taggable items.
387+
organization Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
373388
taskTemplates TaskTemplate[] @relation("TaskTemplateTags")
374-
positions Position[] @relation("PositionTags")
375389
376390
@@unique([name, orgId])
377391
@@index([orgId])
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
export const positionTagsData = [
2+
{
3+
id: 'position_tag_backend_001',
4+
name: 'Backend',
5+
colorHexCode: '#d6d7fe',
6+
orgId: 'org_nextlab_001',
7+
},
8+
{
9+
id: 'position_tag_fullstack_001',
10+
name: 'Full Stack',
11+
colorHexCode: '#d8f4d4',
12+
orgId: 'org_nextlab_001',
13+
},
14+
{
15+
id: 'position_tag_internship_001',
16+
name: 'Internship',
17+
colorHexCode: '#ffe9bb',
18+
orgId: 'org_nextlab_001',
19+
},
20+
];

prisma/seed-data/tags.seed.ts renamed to prisma/seed-data/task-template-tags.seed.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,30 @@
1-
export const tagsData = [
1+
export const taskTemplateTagsData = [
22
{
3-
id: 'tag_algorithm_001',
3+
id: 'task_template_tag_algorithm_001',
44
name: 'Algorithm',
55
colorHexCode: '#d6d7fe',
66
orgId: 'org_nextlab_001',
77
},
88
{
9-
id: 'tag_data_structure_001',
9+
id: 'task_template_tag_data_structure_001',
1010
name: 'Data Structure',
1111
colorHexCode: '#ededff',
1212
orgId: 'org_nextlab_001',
1313
},
1414
{
15-
id: 'tag_math_001',
15+
id: 'task_template_tag_math_001',
1616
name: 'Math',
1717
colorHexCode: '#ffe9bb',
1818
orgId: 'org_nextlab_001',
1919
},
2020
{
21-
id: 'tag_advanced_001',
21+
id: 'task_template_tag_advanced_001',
2222
name: 'Advanced',
2323
colorHexCode: '#f7c4c4',
2424
orgId: 'org_nextlab_001',
2525
},
2626
{
27-
id: 'tag_loops_001',
27+
id: 'task_template_tag_loops_001',
2828
name: 'Loops',
2929
colorHexCode: '#d8f4d4',
3030
orgId: 'org_nextlab_001',

prisma/seed.ts

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ import { candidatesData } from './seed-data/candidates.seed';
77
import { taskTemplatesData } from './seed-data/task-template.seed';
88
import { assessmentTemplatesData } from './seed-data/assessment-template.seed';
99
import { assessmentsData } from './seed-data/assessment.seed';
10-
import { tagsData } from './seed-data/tags.seed';
10+
import { positionTagsData } from './seed-data/position-tags.seed';
11+
import { taskTemplateTagsData } from './seed-data/task-template-tags.seed';
1112
import { languageData } from './seed-data/languages.seed';
1213

1314
/**
@@ -249,21 +250,21 @@ async function seedLanguages() {
249250
async function seedTags() {
250251
console.log('Seeding tags...');
251252

252-
for (const tag of tagsData) {
253-
await prisma.tag.upsert({
253+
for (const tag of taskTemplateTagsData) {
254+
await prisma.taskTemplateTag.upsert({
254255
where: { id: tag.id },
255256
update: {},
256257
create: tag,
257258
});
258259

259-
console.log(` Created tag: ${tag.name}`);
260+
console.log(` Created task template tag: ${tag.name}`);
260261
}
261262

262263
await prisma.taskTemplate.update({
263264
where: { id: taskTemplatesData[0].id },
264265
data: {
265266
tags: {
266-
connect: tagsData.map((tag) => ({ id: tag.id })),
267+
connect: taskTemplateTagsData.map((tag) => ({ id: tag.id })),
267268
},
268269
},
269270
});
@@ -272,7 +273,7 @@ async function seedTags() {
272273
where: { id: taskTemplatesData[1].id },
273274
data: {
274275
tags: {
275-
connect: [{ id: tagsData[0].id }, { id: tagsData[1].id }],
276+
connect: [{ id: taskTemplateTagsData[0].id }, { id: taskTemplateTagsData[1].id }],
276277
},
277278
},
278279
});
@@ -281,7 +282,7 @@ async function seedTags() {
281282
where: { id: taskTemplatesData[2].id },
282283
data: {
283284
tags: {
284-
connect: [{ id: tagsData[2].id }, { id: tagsData[0].id }],
285+
connect: [{ id: taskTemplateTagsData[2].id }, { id: taskTemplateTagsData[0].id }],
285286
},
286287
},
287288
});
@@ -290,7 +291,7 @@ async function seedTags() {
290291
where: { id: taskTemplatesData[3].id },
291292
data: {
292293
tags: {
293-
connect: [{ id: tagsData[3].id }, { id: tagsData[4].id }],
294+
connect: [{ id: taskTemplateTagsData[3].id }, { id: taskTemplateTagsData[4].id }],
294295
},
295296
},
296297
});
@@ -299,7 +300,7 @@ async function seedTags() {
299300
where: { id: taskTemplatesData[5].id },
300301
data: {
301302
tags: {
302-
connect: [{ id: tagsData[0].id }, { id: tagsData[3].id }],
303+
connect: [{ id: taskTemplateTagsData[0].id }, { id: taskTemplateTagsData[3].id }],
303304
},
304305
},
305306
});
@@ -308,7 +309,7 @@ async function seedTags() {
308309
where: { id: taskTemplatesData[6].id },
309310
data: {
310311
tags: {
311-
connect: [{ id: tagsData[0].id }, { id: tagsData[1].id }],
312+
connect: [{ id: taskTemplateTagsData[0].id }, { id: taskTemplateTagsData[1].id }],
312313
},
313314
},
314315
});
@@ -317,7 +318,7 @@ async function seedTags() {
317318
where: { id: taskTemplatesData[7].id },
318319
data: {
319320
tags: {
320-
connect: [{ id: tagsData[1].id }, { id: tagsData[0].id }],
321+
connect: [{ id: taskTemplateTagsData[1].id }, { id: taskTemplateTagsData[0].id }],
321322
},
322323
},
323324
});
@@ -326,7 +327,7 @@ async function seedTags() {
326327
where: { id: taskTemplatesData[8].id },
327328
data: {
328329
tags: {
329-
connect: [{ id: tagsData[1].id }, { id: tagsData[0].id }],
330+
connect: [{ id: taskTemplateTagsData[1].id }, { id: taskTemplateTagsData[0].id }],
330331
},
331332
},
332333
});
@@ -335,7 +336,26 @@ async function seedTags() {
335336
where: { id: taskTemplatesData[9].id },
336337
data: {
337338
tags: {
338-
connect: [{ id: tagsData[0].id }, { id: tagsData[1].id }],
339+
connect: [{ id: taskTemplateTagsData[0].id }, { id: taskTemplateTagsData[1].id }],
340+
},
341+
},
342+
});
343+
344+
for (const tag of positionTagsData) {
345+
await prisma.positionTag.upsert({
346+
where: { id: tag.id },
347+
update: {},
348+
create: tag,
349+
});
350+
351+
console.log(` Created position tag: ${tag.name}`);
352+
}
353+
354+
await prisma.position.update({
355+
where: { id: positionsData[0].id },
356+
data: {
357+
tags: {
358+
connect: [{ id: positionTagsData[0].id }, { id: positionTagsData[1].id }],
339359
},
340360
},
341361
});

prisma/teardown.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,15 @@ async function main() {
2121
"Application",
2222
"Candidate",
2323
"Position",
24-
"Tag",
24+
"PositionTag",
25+
"TaskTemplateTag",
2526
"Member",
2627
"Invitation",
2728
"Session",
2829
"Account",
2930
"Verification",
3031
"User",
3132
"Organization",
32-
"_TaskTemplateTags"
3333
RESTART IDENTITY CASCADE;
3434
`;
3535

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { getSession } from '@/lib/utils/auth.utils';
77
export async function GET() {
88
try {
99
const session = await getSession();
10-
const tags = await TagService.getTagsByOrgId(session.activeOrganizationId);
10+
const tags = await TagService.getPositionTagsByOrgId(session.activeOrganizationId);
1111
return Response.json({ data: tags }, { status: 200 });
1212
} catch (err) {
1313
return handleError(err);
@@ -20,7 +20,7 @@ export async function POST(request: NextRequest) {
2020
const body = await request.json();
2121
const parsed = createTagSchema.parse(body);
2222

23-
const tag = await TagService.createTag(
23+
const tag = await TagService.createPositionTag(
2424
parsed.name,
2525
session.activeOrganizationId,
2626
parsed.colorHexCode
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { type NextRequest } from 'next/server';
2+
import { handleError } from '@/lib/utils/errors.utils';
3+
import TagService from '@/lib/services/tag.service';
4+
import { createTagSchema } from '@/lib/schemas/tag.schema';
5+
import { getSession } from '@/lib/utils/auth.utils';
6+
7+
export async function GET() {
8+
try {
9+
const session = await getSession();
10+
const tags = await TagService.getTaskTemplateTagsByOrgId(session.activeOrganizationId);
11+
return Response.json({ data: tags }, { status: 200 });
12+
} catch (err) {
13+
return handleError(err);
14+
}
15+
}
16+
17+
export async function POST(request: NextRequest) {
18+
try {
19+
const session = await getSession();
20+
const body = await request.json();
21+
const parsed = createTagSchema.parse(body);
22+
23+
const tag = await TagService.createTaskTemplateTag(
24+
parsed.name,
25+
session.activeOrganizationId,
26+
parsed.colorHexCode
27+
);
28+
return Response.json({ data: tag }, { status: 201 });
29+
} catch (err) {
30+
return handleError(err);
31+
}
32+
}

0 commit comments

Comments
 (0)