mirror of
https://github.com/Hestia-Homes/assessment-model.git
synced 2026-06-08 11:37:25 +00:00
commiting missing files
This commit is contained in:
parent
293738f89d
commit
c7edac7fb6
5 changed files with 493 additions and 0 deletions
17
src/app/api/portfolio/route.ts
Normal file
17
src/app/api/portfolio/route.ts
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import { eq } from "drizzle-orm";
|
||||
import { portfolio, portfolioUsers } from "@/app/db/schema/portfolio";
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { db } from "@/app/db/db";
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
// Get all portfolios for a user - use a relation
|
||||
console.log(request);
|
||||
|
||||
// const portfolios = await db
|
||||
// .select()
|
||||
// .from(portfolioUsers)
|
||||
// .where(eq(portfolioUsers.userId, 1));
|
||||
//
|
||||
const portfolios: String[] = [];
|
||||
return NextResponse.json(portfolios);
|
||||
}
|
||||
56
src/app/db/migrations/0003_past_gamora.sql
Normal file
56
src/app/db/migrations/0003_past_gamora.sql
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
DO $$ BEGIN
|
||||
CREATE TYPE "goal" AS ENUM('Valuation Improvement', 'Increasing EPC', 'Reducing CO2 emissions', 'Energy Savings', 'None');
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
CREATE TYPE "role" AS ENUM('creator', 'admin', 'read', 'write');
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
CREATE TYPE "status" AS ENUM('scoping', 'assessment', 'tendering', 'project underway', 'completion; status: on track', 'completion; status: delayed', 'completion; status: at risk', 'completion; status: completed', 'needs review');
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "portfolio" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"name" text NOT NULL,
|
||||
"budget" real,
|
||||
"status" "status" NOT NULL,
|
||||
"goal" "goal" NOT NULL,
|
||||
"cost" real,
|
||||
"number_of_properties" integer,
|
||||
"co2_equivalent_savings" real,
|
||||
"energy_savings" real,
|
||||
"energy_cost_savings" real,
|
||||
"property_valuation_increase" real,
|
||||
"rental_yield_increase" real,
|
||||
"total_work_hours" real,
|
||||
"created_at" timestamp (6) with time zone DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp (6) with time zone DEFAULT now() NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "portfolioUsers" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"user_id" integer NOT NULL,
|
||||
"portfolio_id" integer NOT NULL,
|
||||
"role" "role" NOT NULL,
|
||||
"created_at" timestamp (6) with time zone DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp (6) with time zone DEFAULT now() NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "portfolioUsers" ADD CONSTRAINT "portfolioUsers_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "user"("id") ON DELETE no action ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "portfolioUsers" ADD CONSTRAINT "portfolioUsers_portfolio_id_portfolio_id_fk" FOREIGN KEY ("portfolio_id") REFERENCES "portfolio"("id") ON DELETE no action ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
277
src/app/db/migrations/meta/0003_snapshot.json
Normal file
277
src/app/db/migrations/meta/0003_snapshot.json
Normal file
|
|
@ -0,0 +1,277 @@
|
|||
{
|
||||
"version": "5",
|
||||
"dialect": "pg",
|
||||
"id": "e43a69c5-c8ed-4de7-8915-0f0a23455bf1",
|
||||
"prevId": "4347e9a7-f388-4bac-8860-a482db2a5c8b",
|
||||
"tables": {
|
||||
"portfolio": {
|
||||
"name": "portfolio",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "serial",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"budget": {
|
||||
"name": "budget",
|
||||
"type": "real",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"status": {
|
||||
"name": "status",
|
||||
"type": "status",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"goal": {
|
||||
"name": "goal",
|
||||
"type": "goal",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"cost": {
|
||||
"name": "cost",
|
||||
"type": "real",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"number_of_properties": {
|
||||
"name": "number_of_properties",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"co2_equivalent_savings": {
|
||||
"name": "co2_equivalent_savings",
|
||||
"type": "real",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"energy_savings": {
|
||||
"name": "energy_savings",
|
||||
"type": "real",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"energy_cost_savings": {
|
||||
"name": "energy_cost_savings",
|
||||
"type": "real",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"property_valuation_increase": {
|
||||
"name": "property_valuation_increase",
|
||||
"type": "real",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"rental_yield_increase": {
|
||||
"name": "rental_yield_increase",
|
||||
"type": "real",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"total_work_hours": {
|
||||
"name": "total_work_hours",
|
||||
"type": "real",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp (6) with time zone",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp (6) with time zone",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {}
|
||||
},
|
||||
"portfolioUsers": {
|
||||
"name": "portfolioUsers",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "serial",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"user_id": {
|
||||
"name": "user_id",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"portfolio_id": {
|
||||
"name": "portfolio_id",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"role": {
|
||||
"name": "role",
|
||||
"type": "role",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp (6) with time zone",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp (6) with time zone",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"portfolioUsers_user_id_user_id_fk": {
|
||||
"name": "portfolioUsers_user_id_user_id_fk",
|
||||
"tableFrom": "portfolioUsers",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
"portfolioUsers_portfolio_id_portfolio_id_fk": {
|
||||
"name": "portfolioUsers_portfolio_id_portfolio_id_fk",
|
||||
"tableFrom": "portfolioUsers",
|
||||
"tableTo": "portfolio",
|
||||
"columnsFrom": [
|
||||
"portfolio_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {}
|
||||
},
|
||||
"user": {
|
||||
"name": "user",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "serial",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"firstName": {
|
||||
"name": "firstName",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"email": {
|
||||
"name": "email",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"oauth_id": {
|
||||
"name": "oauth_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"oauth_provider": {
|
||||
"name": "oauth_provider",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp (6) with time zone",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp (6) with time zone",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {}
|
||||
}
|
||||
},
|
||||
"enums": {
|
||||
"goal": {
|
||||
"name": "goal",
|
||||
"values": {
|
||||
"Valuation Improvement": "Valuation Improvement",
|
||||
"Increasing EPC": "Increasing EPC",
|
||||
"Reducing CO2 emissions": "Reducing CO2 emissions",
|
||||
"Energy Savings": "Energy Savings",
|
||||
"None": "None"
|
||||
}
|
||||
},
|
||||
"role": {
|
||||
"name": "role",
|
||||
"values": {
|
||||
"creator": "creator",
|
||||
"admin": "admin",
|
||||
"read": "read",
|
||||
"write": "write"
|
||||
}
|
||||
},
|
||||
"status": {
|
||||
"name": "status",
|
||||
"values": {
|
||||
"scoping": "scoping",
|
||||
"assessment": "assessment",
|
||||
"tendering": "tendering",
|
||||
"project underway": "project underway",
|
||||
"completion; status: on track": "completion; status: on track",
|
||||
"completion; status: delayed": "completion; status: delayed",
|
||||
"completion; status: at risk": "completion; status: at risk",
|
||||
"completion; status: completed": "completion; status: completed",
|
||||
"needs review": "needs review"
|
||||
}
|
||||
}
|
||||
},
|
||||
"schemas": {},
|
||||
"_meta": {
|
||||
"schemas": {},
|
||||
"tables": {},
|
||||
"columns": {}
|
||||
}
|
||||
}
|
||||
122
src/app/db/schema/portfolio.ts
Normal file
122
src/app/db/schema/portfolio.ts
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
import {
|
||||
serial,
|
||||
text,
|
||||
timestamp,
|
||||
pgTable,
|
||||
real,
|
||||
pgEnum,
|
||||
integer,
|
||||
} from "drizzle-orm/pg-core";
|
||||
import { user } from "./users";
|
||||
import { InferModel, relations } from "drizzle-orm";
|
||||
|
||||
export const PortfolioStatus: [string, ...string[]] = [
|
||||
"scoping",
|
||||
"assessment",
|
||||
"tendering",
|
||||
"project underway",
|
||||
"completion; status: on track",
|
||||
"completion; status: delayed",
|
||||
"completion; status: at risk",
|
||||
"completion; status: completed",
|
||||
"needs review",
|
||||
];
|
||||
|
||||
export const PortfolioGoal: [string, ...string[]] = [
|
||||
"Valuation Improvement",
|
||||
"Increasing EPC",
|
||||
"Reducing CO2 emissions",
|
||||
"Energy Savings",
|
||||
"None",
|
||||
];
|
||||
|
||||
export const PortfolioRole: [string, ...string[]] = [
|
||||
"creator",
|
||||
"admin",
|
||||
"read",
|
||||
"write",
|
||||
];
|
||||
|
||||
export const statusEnum = pgEnum("status", PortfolioStatus);
|
||||
export const goalEnum = pgEnum("goal", PortfolioGoal);
|
||||
export const roleEnum = pgEnum("role", PortfolioRole);
|
||||
|
||||
export const portfolio = pgTable("portfolio", {
|
||||
id: serial("id").primaryKey(),
|
||||
name: text("name").notNull(),
|
||||
budget: real("budget"),
|
||||
status: statusEnum("status").notNull(),
|
||||
goal: goalEnum("goal").notNull(),
|
||||
cost: real("cost"),
|
||||
numberOfProperties: integer("number_of_properties"),
|
||||
co2EquivalentSavings: real("co2_equivalent_savings"), // Unit is always tonnes so we don't need to store unit
|
||||
energySavings: real("energy_savings"), // Unit is always kWh so we don't need to store unit
|
||||
energyCostSavings: real("energy_cost_savings"), // Unit is always £ so we don't need to store unit for the moment
|
||||
propertyValuationIncrease: real("property_valuation_increase"), // Unit is always £ so we don't need to store unit for the moment
|
||||
rentalYieldIncrease: real("rental_yield_increase"), // Unit is always £ so we don't need to store unit for the moment
|
||||
totalWorkHours: real("total_work_hours"),
|
||||
createdAt: timestamp("created_at", {
|
||||
precision: 6,
|
||||
withTimezone: true,
|
||||
})
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
updatedAt: timestamp("updated_at", {
|
||||
precision: 6,
|
||||
withTimezone: true,
|
||||
})
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
});
|
||||
|
||||
// We have a many to many relationship between users and portfolios
|
||||
// One user can have many portfolios, and one portfolio can have many users
|
||||
// We use the Dizzle relational queries pattern to facilitate this
|
||||
|
||||
// Define relation from users to portfolios
|
||||
export const usersToPortfolioRelations = relations(user, ({ many }) => ({
|
||||
portfolios: many(portfolio),
|
||||
}));
|
||||
|
||||
export const portfolioUsers = pgTable("portfolioUsers", {
|
||||
id: serial("id").primaryKey(),
|
||||
// Define the foreign key constraints using references from Drizzle, from user_id to the users table
|
||||
userId: integer("user_id")
|
||||
.notNull()
|
||||
.references(() => user.id),
|
||||
// Define the foreign key constraints using references from Drizzle, from portfolio_id to the portfolios table
|
||||
portfolioId: integer("portfolio_id")
|
||||
.notNull()
|
||||
.references(() => portfolio.id),
|
||||
role: roleEnum("role").notNull(),
|
||||
createdAt: timestamp("created_at", {
|
||||
precision: 6,
|
||||
withTimezone: true,
|
||||
})
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
updatedAt: timestamp("updated_at", {
|
||||
precision: 6,
|
||||
withTimezone: true,
|
||||
})
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
});
|
||||
|
||||
// Define relation from portfolios to users
|
||||
export const portfolioToUsersRelations = relations(portfolio, ({ many }) => ({
|
||||
users: many(user),
|
||||
}));
|
||||
|
||||
// Define relation from portfolioUsers to portfolios (we can have many users to a portfolio)
|
||||
export const portfolioUsersToPortfolioRelations = relations(
|
||||
portfolioUsers,
|
||||
({ many }) => ({
|
||||
portfolio: many(portfolio),
|
||||
})
|
||||
);
|
||||
|
||||
export type Portfolio = InferModel<typeof portfolio, "select">;
|
||||
export type NewPortfolio = InferModel<typeof portfolio, "insert">;
|
||||
export type PortfolioUsers = InferModel<typeof portfolioUsers, "select">;
|
||||
export type NewPortfolioUsers = InferModel<typeof portfolioUsers, "insert">;
|
||||
21
src/app/home/utils.ts
Normal file
21
src/app/home/utils.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
import { portfolioUsers, PortfolioUsers } from "./../db/schema/portfolio";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { user } from "@/app/db/schema/users";
|
||||
import { db } from "@/app/db/db";
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { portfolio } from "@/app/db/schema/portfolio";
|
||||
import type { Portfolio } from "@/app/db/schema/portfolio";
|
||||
|
||||
export default async function getPortfolios(
|
||||
userId: number
|
||||
): Promise<Portfolio[]> {
|
||||
const userPortfolios = await db
|
||||
.select()
|
||||
.from(portfolio)
|
||||
.leftJoin(portfolioUsers, eq(portfolio.id, portfolioUsers.portfolioId))
|
||||
.where(eq(portfolioUsers.userId, userId));
|
||||
|
||||
const portfolios = userPortfolios.map((data) => data.portfolio);
|
||||
|
||||
return portfolios;
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue