IssueAssignee table

This commit is contained in:
Oliver Bryan
2026-01-16 22:43:40 +00:00
parent 047332ce0b
commit 6ffb05eb3b
5 changed files with 854 additions and 2 deletions

View File

@@ -0,0 +1,13 @@
CREATE TABLE "IssueAssignee" (
"id" integer PRIMARY KEY GENERATED ALWAYS AS IDENTITY (sequence name "IssueAssignee_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1),
"issueId" integer NOT NULL,
"userId" integer NOT NULL,
"assignedAt" timestamp DEFAULT now()
);
--> statement-breakpoint
ALTER TABLE "Issue" DROP CONSTRAINT "Issue_assigneeId_User_id_fk";
--> statement-breakpoint
ALTER TABLE "IssueAssignee" ADD CONSTRAINT "IssueAssignee_issueId_Issue_id_fk" FOREIGN KEY ("issueId") REFERENCES "public"."Issue"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "IssueAssignee" ADD CONSTRAINT "IssueAssignee_userId_User_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."User"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
CREATE UNIQUE INDEX "unique_issue_user" ON "IssueAssignee" USING btree ("issueId","userId");--> statement-breakpoint
ALTER TABLE "Issue" DROP COLUMN "assigneeId";

View File

@@ -0,0 +1,807 @@
{
"id": "549732ed-bf66-4658-873f-ce8f1e04d95e",
"prevId": "ee0d7b7b-8bab-4c07-b1d0-d233cefc1d8a",
"version": "7",
"dialect": "postgresql",
"tables": {
"public.Issue": {
"name": "Issue",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true,
"identity": {
"type": "always",
"name": "Issue_id_seq",
"schema": "public",
"increment": "1",
"startWith": "1",
"minValue": "1",
"maxValue": "2147483647",
"cache": "1",
"cycle": false
}
},
"projectId": {
"name": "projectId",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"number": {
"name": "number",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"title": {
"name": "title",
"type": "varchar(256)",
"primaryKey": false,
"notNull": true
},
"description": {
"name": "description",
"type": "varchar(2048)",
"primaryKey": false,
"notNull": true
},
"status": {
"name": "status",
"type": "varchar(24)",
"primaryKey": false,
"notNull": true,
"default": "'TO DO'"
},
"creatorId": {
"name": "creatorId",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"sprintId": {
"name": "sprintId",
"type": "integer",
"primaryKey": false,
"notNull": false
}
},
"indexes": {
"unique_project_issue_number": {
"name": "unique_project_issue_number",
"columns": [
{
"expression": "projectId",
"isExpression": false,
"asc": true,
"nulls": "last"
},
{
"expression": "number",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": true,
"concurrently": false,
"method": "btree",
"with": {}
}
},
"foreignKeys": {
"Issue_projectId_Project_id_fk": {
"name": "Issue_projectId_Project_id_fk",
"tableFrom": "Issue",
"tableTo": "Project",
"columnsFrom": [
"projectId"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
},
"Issue_creatorId_User_id_fk": {
"name": "Issue_creatorId_User_id_fk",
"tableFrom": "Issue",
"tableTo": "User",
"columnsFrom": [
"creatorId"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
},
"Issue_sprintId_Sprint_id_fk": {
"name": "Issue_sprintId_Sprint_id_fk",
"tableFrom": "Issue",
"tableTo": "Sprint",
"columnsFrom": [
"sprintId"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.IssueAssignee": {
"name": "IssueAssignee",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true,
"identity": {
"type": "always",
"name": "IssueAssignee_id_seq",
"schema": "public",
"increment": "1",
"startWith": "1",
"minValue": "1",
"maxValue": "2147483647",
"cache": "1",
"cycle": false
}
},
"issueId": {
"name": "issueId",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"userId": {
"name": "userId",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"assignedAt": {
"name": "assignedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": false,
"default": "now()"
}
},
"indexes": {
"unique_issue_user": {
"name": "unique_issue_user",
"columns": [
{
"expression": "issueId",
"isExpression": false,
"asc": true,
"nulls": "last"
},
{
"expression": "userId",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": true,
"concurrently": false,
"method": "btree",
"with": {}
}
},
"foreignKeys": {
"IssueAssignee_issueId_Issue_id_fk": {
"name": "IssueAssignee_issueId_Issue_id_fk",
"tableFrom": "IssueAssignee",
"tableTo": "Issue",
"columnsFrom": [
"issueId"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
},
"IssueAssignee_userId_User_id_fk": {
"name": "IssueAssignee_userId_User_id_fk",
"tableFrom": "IssueAssignee",
"tableTo": "User",
"columnsFrom": [
"userId"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.Organisation": {
"name": "Organisation",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true,
"identity": {
"type": "always",
"name": "Organisation_id_seq",
"schema": "public",
"increment": "1",
"startWith": "1",
"minValue": "1",
"maxValue": "2147483647",
"cache": "1",
"cycle": false
}
},
"name": {
"name": "name",
"type": "varchar(256)",
"primaryKey": false,
"notNull": true
},
"description": {
"name": "description",
"type": "varchar(1024)",
"primaryKey": false,
"notNull": false
},
"slug": {
"name": "slug",
"type": "varchar(64)",
"primaryKey": false,
"notNull": true
},
"statuses": {
"name": "statuses",
"type": "json",
"primaryKey": false,
"notNull": true,
"default": "'{\"TO DO\":\"#fafafa\",\"IN PROGRESS\":\"#f97316\",\"REVIEW\":\"#8952bc\",\"DONE\":\"#22c55e\",\"REJECTED\":\"#ef4444\",\"ARCHIVED\":\"#a1a1a1\",\"MERGED\":\"#a1a1a1\"}'::json"
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": false,
"default": "now()"
},
"updatedAt": {
"name": "updatedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": false,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"Organisation_slug_unique": {
"name": "Organisation_slug_unique",
"nullsNotDistinct": false,
"columns": [
"slug"
]
}
},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.OrganisationMember": {
"name": "OrganisationMember",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true,
"identity": {
"type": "always",
"name": "OrganisationMember_id_seq",
"schema": "public",
"increment": "1",
"startWith": "1",
"minValue": "1",
"maxValue": "2147483647",
"cache": "1",
"cycle": false
}
},
"organisationId": {
"name": "organisationId",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"userId": {
"name": "userId",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"role": {
"name": "role",
"type": "varchar(32)",
"primaryKey": false,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": false,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"OrganisationMember_organisationId_Organisation_id_fk": {
"name": "OrganisationMember_organisationId_Organisation_id_fk",
"tableFrom": "OrganisationMember",
"tableTo": "Organisation",
"columnsFrom": [
"organisationId"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
},
"OrganisationMember_userId_User_id_fk": {
"name": "OrganisationMember_userId_User_id_fk",
"tableFrom": "OrganisationMember",
"tableTo": "User",
"columnsFrom": [
"userId"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.Project": {
"name": "Project",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true,
"identity": {
"type": "always",
"name": "Project_id_seq",
"schema": "public",
"increment": "1",
"startWith": "1",
"minValue": "1",
"maxValue": "2147483647",
"cache": "1",
"cycle": false
}
},
"key": {
"name": "key",
"type": "varchar(4)",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "varchar(256)",
"primaryKey": false,
"notNull": true
},
"organisationId": {
"name": "organisationId",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"creatorId": {
"name": "creatorId",
"type": "integer",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Project_organisationId_Organisation_id_fk": {
"name": "Project_organisationId_Organisation_id_fk",
"tableFrom": "Project",
"tableTo": "Organisation",
"columnsFrom": [
"organisationId"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
},
"Project_creatorId_User_id_fk": {
"name": "Project_creatorId_User_id_fk",
"tableFrom": "Project",
"tableTo": "User",
"columnsFrom": [
"creatorId"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.Session": {
"name": "Session",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true,
"identity": {
"type": "always",
"name": "Session_id_seq",
"schema": "public",
"increment": "1",
"startWith": "1",
"minValue": "1",
"maxValue": "2147483647",
"cache": "1",
"cycle": false
}
},
"userId": {
"name": "userId",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"csrfToken": {
"name": "csrfToken",
"type": "varchar(64)",
"primaryKey": false,
"notNull": true
},
"expiresAt": {
"name": "expiresAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": false,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"Session_userId_User_id_fk": {
"name": "Session_userId_User_id_fk",
"tableFrom": "Session",
"tableTo": "User",
"columnsFrom": [
"userId"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.Sprint": {
"name": "Sprint",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true,
"identity": {
"type": "always",
"name": "Sprint_id_seq",
"schema": "public",
"increment": "1",
"startWith": "1",
"minValue": "1",
"maxValue": "2147483647",
"cache": "1",
"cycle": false
}
},
"projectId": {
"name": "projectId",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "varchar(64)",
"primaryKey": false,
"notNull": true
},
"color": {
"name": "color",
"type": "varchar(7)",
"primaryKey": false,
"notNull": true,
"default": "'#a1a1a1'"
},
"startDate": {
"name": "startDate",
"type": "timestamp",
"primaryKey": false,
"notNull": true
},
"endDate": {
"name": "endDate",
"type": "timestamp",
"primaryKey": false,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": false,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"Sprint_projectId_Project_id_fk": {
"name": "Sprint_projectId_Project_id_fk",
"tableFrom": "Sprint",
"tableTo": "Project",
"columnsFrom": [
"projectId"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.TimedSession": {
"name": "TimedSession",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true,
"identity": {
"type": "always",
"name": "TimedSession_id_seq",
"schema": "public",
"increment": "1",
"startWith": "1",
"minValue": "1",
"maxValue": "2147483647",
"cache": "1",
"cycle": false
}
},
"userId": {
"name": "userId",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"issueId": {
"name": "issueId",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"timestamps": {
"name": "timestamps",
"type": "timestamp[]",
"primaryKey": false,
"notNull": true
},
"endedAt": {
"name": "endedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": false,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"TimedSession_userId_User_id_fk": {
"name": "TimedSession_userId_User_id_fk",
"tableFrom": "TimedSession",
"tableTo": "User",
"columnsFrom": [
"userId"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
},
"TimedSession_issueId_Issue_id_fk": {
"name": "TimedSession_issueId_Issue_id_fk",
"tableFrom": "TimedSession",
"tableTo": "Issue",
"columnsFrom": [
"issueId"
],
"columnsTo": [
"id"
],
"onDelete": "set null",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.User": {
"name": "User",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true,
"identity": {
"type": "always",
"name": "User_id_seq",
"schema": "public",
"increment": "1",
"startWith": "1",
"minValue": "1",
"maxValue": "2147483647",
"cache": "1",
"cycle": false
}
},
"name": {
"name": "name",
"type": "varchar(64)",
"primaryKey": false,
"notNull": true
},
"username": {
"name": "username",
"type": "varchar(32)",
"primaryKey": false,
"notNull": true
},
"passwordHash": {
"name": "passwordHash",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"avatarURL": {
"name": "avatarURL",
"type": "varchar(512)",
"primaryKey": false,
"notNull": false
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": false,
"default": "now()"
},
"updatedAt": {
"name": "updatedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": false,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"User_username_unique": {
"name": "User_username_unique",
"nullsNotDistinct": false,
"columns": [
"username"
]
}
},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
}
},
"enums": {},
"schemas": {},
"sequences": {},
"roles": {},
"policies": {},
"views": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}

View File

@@ -127,6 +127,13 @@
"when": 1768176165908,
"tag": "0017_tiny_goliath",
"breakpoints": true
},
{
"idx": 18,
"version": "7",
"when": 1768599498899,
"tag": "0018_previous_puppet_master",
"breakpoints": true
}
]
}

View File

@@ -101,6 +101,8 @@ export {
USER_USERNAME_MAX_LENGTH,
} from "./constants";
export type {
IssueAssigneeInsert,
IssueAssigneeRecord,
IssueInsert,
IssueRecord,
IssueResponse,
@@ -128,6 +130,9 @@ export {
DEFAULT_STATUS_COLOUR,
DEFAULT_STATUS_COLOURS,
Issue,
IssueAssignee,
IssueAssigneeInsertSchema,
IssueAssigneeSelectSchema,
IssueInsertSchema,
IssueSelectSchema,
Organisation,

View File

@@ -121,7 +121,6 @@ export const Issue = pgTable(
creatorId: integer()
.notNull()
.references(() => User.id),
assigneeId: integer().references(() => User.id),
sprintId: integer().references(() => Sprint.id),
},
@@ -132,6 +131,21 @@ export const Issue = pgTable(
],
);
export const IssueAssignee = pgTable(
"IssueAssignee",
{
id: integer().primaryKey().generatedAlwaysAsIdentity(),
issueId: integer()
.notNull()
.references(() => Issue.id, { onDelete: "cascade" }),
userId: integer()
.notNull()
.references(() => User.id, { onDelete: "cascade" }),
assignedAt: timestamp({ withTimezone: false }).defaultNow(),
},
(t) => [uniqueIndex("unique_issue_user").on(t.issueId, t.userId)],
);
// Zod schemas
export const UserSelectSchema = createSelectSchema(User);
export const UserInsertSchema = createInsertSchema(User);
@@ -151,6 +165,9 @@ export const SprintInsertSchema = createInsertSchema(Sprint);
export const IssueSelectSchema = createSelectSchema(Issue);
export const IssueInsertSchema = createInsertSchema(Issue);
export const IssueAssigneeSelectSchema = createSelectSchema(IssueAssignee);
export const IssueAssigneeInsertSchema = createInsertSchema(IssueAssignee);
export const SessionSelectSchema = createSelectSchema(Session);
export const SessionInsertSchema = createInsertSchema(Session);
@@ -178,6 +195,9 @@ export type SprintInsert = z.infer<typeof SprintInsertSchema>;
export type IssueRecord = z.infer<typeof IssueSelectSchema>;
export type IssueInsert = z.infer<typeof IssueInsertSchema>;
export type IssueAssigneeRecord = z.infer<typeof IssueAssigneeSelectSchema>;
export type IssueAssigneeInsert = z.infer<typeof IssueAssigneeInsertSchema>;
export type SessionRecord = z.infer<typeof SessionSelectSchema>;
export type SessionInsert = z.infer<typeof SessionInsertSchema>;
@@ -189,7 +209,7 @@ export type TimedSessionInsert = z.infer<typeof TimedSessionInsertSchema>;
export type IssueResponse = {
Issue: IssueRecord;
Creator: UserRecord;
Assignee: UserRecord | null;
Assignees: UserRecord[];
};
export type ProjectResponse = {