From 551a868be97016c089889906b8b9d1d97c60d7ba Mon Sep 17 00:00:00 2001 From: Oliver Bryan <04oliverbryan@gmail.com> Date: Mon, 22 Dec 2025 20:01:51 +0000 Subject: [PATCH] Organisation and OrganisationMember tables additional changes to Project table and the schemas for Organisation things. this has caused some errors across the codebase that will be addressed in the coming commits --- .../backend/drizzle/0005_great_timeslip.sql | 26 ++ .../backend/drizzle/meta/0005_snapshot.json | 431 ++++++++++++++++++ packages/backend/drizzle/meta/_journal.json | 7 + packages/shared/src/schema.ts | 43 +- 4 files changed, 504 insertions(+), 3 deletions(-) create mode 100644 packages/backend/drizzle/0005_great_timeslip.sql create mode 100644 packages/backend/drizzle/meta/0005_snapshot.json diff --git a/packages/backend/drizzle/0005_great_timeslip.sql b/packages/backend/drizzle/0005_great_timeslip.sql new file mode 100644 index 0000000..c7f5e9b --- /dev/null +++ b/packages/backend/drizzle/0005_great_timeslip.sql @@ -0,0 +1,26 @@ +CREATE TABLE "Organisation" ( + "id" integer PRIMARY KEY GENERATED ALWAYS AS IDENTITY (sequence name "Organisation_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1), + "name" varchar(256) NOT NULL, + "description" varchar(1024), + "slug" varchar(64) NOT NULL, + "createdAt" timestamp DEFAULT now(), + "updatedAt" timestamp DEFAULT now(), + CONSTRAINT "Organisation_slug_unique" UNIQUE("slug") +); +--> statement-breakpoint +CREATE TABLE "OrganisationMember" ( + "id" integer PRIMARY KEY GENERATED ALWAYS AS IDENTITY (sequence name "OrganisationMember_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1), + "organisationId" integer NOT NULL, + "userId" integer NOT NULL, + "role" varchar(32) NOT NULL, + "createdAt" timestamp DEFAULT now() +); +--> statement-breakpoint +ALTER TABLE "Project" RENAME COLUMN "ownerId" TO "creatorId";--> statement-breakpoint +ALTER TABLE "Project" DROP CONSTRAINT "Project_ownerId_User_id_fk"; +--> statement-breakpoint +ALTER TABLE "Project" ADD COLUMN "organisationId" integer NOT NULL;--> statement-breakpoint +ALTER TABLE "OrganisationMember" ADD CONSTRAINT "OrganisationMember_organisationId_Organisation_id_fk" FOREIGN KEY ("organisationId") REFERENCES "public"."Organisation"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "OrganisationMember" ADD CONSTRAINT "OrganisationMember_userId_User_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."User"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "Project" ADD CONSTRAINT "Project_organisationId_Organisation_id_fk" FOREIGN KEY ("organisationId") REFERENCES "public"."Organisation"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "Project" ADD CONSTRAINT "Project_creatorId_User_id_fk" FOREIGN KEY ("creatorId") REFERENCES "public"."User"("id") ON DELETE no action ON UPDATE no action; \ No newline at end of file diff --git a/packages/backend/drizzle/meta/0005_snapshot.json b/packages/backend/drizzle/meta/0005_snapshot.json new file mode 100644 index 0000000..82b991c --- /dev/null +++ b/packages/backend/drizzle/meta/0005_snapshot.json @@ -0,0 +1,431 @@ +{ + "id": "c7a99155-1dc7-414d-88b6-8f485daa0c58", + "prevId": "7add1c5b-39bd-495a-9728-ef7da4b40405", + "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 + }, + "assigneeId": { + "name": "assigneeId", + "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_assigneeId_User_id_fk": { + "name": "Issue_assigneeId_User_id_fk", + "tableFrom": "Issue", + "tableTo": "User", + "columnsFrom": [ + "assigneeId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "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 + }, + "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 + } + }, + "blob": { + "name": "blob", + "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.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(256)", + "primaryKey": false, + "notNull": true + }, + "username": { + "name": "username", + "type": "varchar(32)", + "primaryKey": false, + "notNull": true + }, + "passwordHash": { + "name": "passwordHash", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "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": {} + } +} \ No newline at end of file diff --git a/packages/backend/drizzle/meta/_journal.json b/packages/backend/drizzle/meta/_journal.json index ab1ab28..dcde1a6 100644 --- a/packages/backend/drizzle/meta/_journal.json +++ b/packages/backend/drizzle/meta/_journal.json @@ -36,6 +36,13 @@ "when": 1766365630065, "tag": "0004_slow_demogoblin", "breakpoints": true + }, + { + "idx": 5, + "version": "7", + "when": 1766433489198, + "tag": "0005_great_timeslip", + "breakpoints": true } ] } \ No newline at end of file diff --git a/packages/shared/src/schema.ts b/packages/shared/src/schema.ts index 25e7b8f..786d8ab 100644 --- a/packages/shared/src/schema.ts +++ b/packages/shared/src/schema.ts @@ -1,6 +1,6 @@ import { integer, pgTable, timestamp, uniqueIndex, varchar } from "drizzle-orm/pg-core"; import { createInsertSchema, createSelectSchema } from "drizzle-zod"; -import { z } from "zod"; +import type { z } from "zod"; export const User = pgTable("User", { id: integer().primaryKey().generatedAlwaysAsIdentity(), @@ -11,11 +11,35 @@ export const User = pgTable("User", { updatedAt: timestamp({ withTimezone: false }).defaultNow(), }); +export const Organisation = pgTable("Organisation", { + id: integer().primaryKey().generatedAlwaysAsIdentity(), + name: varchar({ length: 256 }).notNull(), + description: varchar({ length: 1024 }), + slug: varchar({ length: 64 }).notNull().unique(), + createdAt: timestamp({ withTimezone: false }).defaultNow(), + updatedAt: timestamp({ withTimezone: false }).defaultNow(), +}); + +export const OrganisationMember = pgTable("OrganisationMember", { + id: integer().primaryKey().generatedAlwaysAsIdentity(), + organisationId: integer() + .notNull() + .references(() => Organisation.id), + userId: integer() + .notNull() + .references(() => User.id), + role: varchar({ length: 32 }).notNull(), + createdAt: timestamp({ withTimezone: false }).defaultNow(), +}); + export const Project = pgTable("Project", { id: integer().primaryKey().generatedAlwaysAsIdentity(), blob: varchar({ length: 4 }).notNull(), name: varchar({ length: 256 }).notNull(), - ownerId: integer() + organisationId: integer() + .notNull() + .references(() => Organisation.id), + creatorId: integer() .notNull() .references(() => User.id), }); @@ -46,6 +70,12 @@ export const Issue = pgTable( export const UserSelectSchema = createSelectSchema(User); export const UserInsertSchema = createInsertSchema(User); +export const OrganisationSelectSchema = createSelectSchema(Organisation); +export const OrganisationInsertSchema = createInsertSchema(Organisation); + +export const OrganisationMemberSelectSchema = createSelectSchema(OrganisationMember); +export const OrganisationMemberInsertSchema = createInsertSchema(OrganisationMember); + export const ProjectSelectSchema = createSelectSchema(Project); export const ProjectInsertSchema = createInsertSchema(Project); @@ -56,6 +86,12 @@ export const IssueInsertSchema = createInsertSchema(Issue); export type UserRecord = z.infer; export type UserInsert = z.infer; +export type OrganisationRecord = z.infer; +export type OrganisationInsert = z.infer; + +export type OrganisationMemberRecord = z.infer; +export type OrganisationMemberInsert = z.infer; + export type ProjectRecord = z.infer; export type ProjectInsert = z.infer; @@ -71,5 +107,6 @@ export type IssueResponse = { export type ProjectResponse = { Project: ProjectRecord; - User: UserRecord; + Organisation: OrganisationRecord; + Creator: UserRecord; };